Additional invitation stuff
This commit is contained in:
parent
761305fbbd
commit
7c33a4943c
@ -2,6 +2,11 @@
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.selectItem.capitalize,
|
||||
.optionItem.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.selectItem.priority.highest > .styledIcon,
|
||||
.optionItem.priority.highest > .styledIcon {
|
||||
color: var(--highest);
|
||||
|
@ -256,6 +256,7 @@ impl ToStyledSelectChild for jirs_data::UserRole {
|
||||
|
||||
StyledSelectChild::build()
|
||||
.add_class(name.as_str())
|
||||
.add_class("capitalize")
|
||||
.text(name)
|
||||
.value(self.clone().into())
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use jirs_data::UserRole;
|
||||
use jirs_data::{ToVec, UsersFieldId};
|
||||
use jirs_data::{UserRole, WsMsg};
|
||||
|
||||
use crate::api::send_ws_msg;
|
||||
use crate::model::{Model, Page, PageContent, UsersPage};
|
||||
use crate::shared::styled_button::StyledButton;
|
||||
use crate::shared::styled_field::StyledField;
|
||||
@ -50,6 +51,10 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
}
|
||||
|
||||
pub fn view(model: &Model) -> Node<Msg> {
|
||||
if model.user.is_none() {
|
||||
return empty![];
|
||||
}
|
||||
|
||||
let page = match &model.page_content {
|
||||
PageContent::Users(page) => page,
|
||||
_ => return empty![],
|
||||
|
@ -23,6 +23,7 @@ pub type ProjectId = i32;
|
||||
pub type UserId = i32;
|
||||
pub type CommentId = i32;
|
||||
pub type TokenId = i32;
|
||||
pub type InvitationId = i32;
|
||||
pub type EmailString = String;
|
||||
pub type UsernameString = String;
|
||||
|
||||
@ -403,6 +404,31 @@ impl Into<ProjectCategory> for u32 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(FromSqlRow, AsExpression))]
|
||||
#[cfg_attr(feature = "backend", sql_type = "InvitationStateType")]
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialOrd, PartialEq, Hash)]
|
||||
pub enum InvitationState {
|
||||
Sent,
|
||||
Accepted,
|
||||
Revoked,
|
||||
}
|
||||
|
||||
impl Default for InvitationState {
|
||||
fn default() -> Self {
|
||||
InvitationState::Sent
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for InvitationState {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
InvitationState::Sent => f.write_str("sent"),
|
||||
InvitationState::Accepted => f.write_str("accepted"),
|
||||
InvitationState::Revoked => f.write_str("revoked"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug, PartialEq)]
|
||||
pub struct ErrorResponse {
|
||||
pub errors: Vec<String>,
|
||||
@ -632,6 +658,24 @@ pub enum WsMsg {
|
||||
SignUpSuccess,
|
||||
SignUpPairTaken,
|
||||
|
||||
// invitations
|
||||
InvitationListRequest,
|
||||
InvitationListLoaded(Vec<Invitation>),
|
||||
InvitedUsersRequest,
|
||||
InvitedUsersLoaded(Vec<User>),
|
||||
InvitationSendRequest {
|
||||
name: UsernameString,
|
||||
email: EmailString,
|
||||
},
|
||||
InvitationSendSuccess,
|
||||
InvitationSendFailure,
|
||||
//
|
||||
InvitationRevokeRequest(InvitationId),
|
||||
InvitationRevokeSuccess(InvitationId),
|
||||
//
|
||||
InvitationAcceptRequest(InvitationId),
|
||||
InvitationAcceptSuccess(InvitationId),
|
||||
|
||||
// project page
|
||||
ProjectRequest,
|
||||
ProjectLoaded(Project),
|
||||
|
@ -2,7 +2,7 @@ use std::io::Write;
|
||||
|
||||
use diesel::{deserialize::*, pg::*, serialize::*, *};
|
||||
|
||||
use crate::{IssuePriority, IssueStatus, IssueType, ProjectCategory, UserRole};
|
||||
use crate::{InvitationState, IssuePriority, IssueStatus, IssueType, ProjectCategory, UserRole};
|
||||
|
||||
#[derive(SqlType)]
|
||||
#[postgres(type_name = "IssuePriorityType")]
|
||||
@ -201,3 +201,43 @@ impl ToSql<UserRoleType, Pg> for UserRole {
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SqlType)]
|
||||
#[postgres(type_name = "InvitationStateType")]
|
||||
pub struct InvitationStateType;
|
||||
|
||||
impl diesel::query_builder::QueryId for InvitationState {
|
||||
type QueryId = InvitationState;
|
||||
}
|
||||
|
||||
fn invitation_state_from_sql(bytes: Option<&[u8]>) -> deserialize::Result<InvitationState> {
|
||||
match not_none!(bytes) {
|
||||
b"sent" => Ok(InvitationState::Sent),
|
||||
b"accepted" => Ok(InvitationState::Accepted),
|
||||
b"revoked" => Ok(InvitationState::Revoked),
|
||||
_ => Ok(InvitationState::Sent),
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<InvitationStateType, Pg> for InvitationState {
|
||||
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
|
||||
invitation_state_from_sql(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<sql_types::Text, Pg> for InvitationState {
|
||||
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
|
||||
invitation_state_from_sql(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<InvitationStateType, Pg> for InvitationState {
|
||||
fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
|
||||
match *self {
|
||||
InvitationState::Sent => out.write_all(b"sent")?,
|
||||
InvitationState::Accepted => out.write_all(b"accepted")?,
|
||||
InvitationState::Revoked => out.write_all(b"revoked")?,
|
||||
}
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,2 @@
|
||||
drop TABLE IF EXISTS invitations CASCADE;
|
||||
drop TYPE IF EXISTS "InvitationStateType" CASCADE;
|
@ -0,0 +1,16 @@
|
||||
create type "InvitationStateType" AS ENUM (
|
||||
'sent',
|
||||
'accepted',
|
||||
'revoked'
|
||||
);
|
||||
|
||||
create table invitations (
|
||||
id serial primary key not null,
|
||||
name text not null,
|
||||
email text not null,
|
||||
state "InvitationStateType" not null default 'sent',
|
||||
project_id integer not null references projects (id),
|
||||
invited_by_id integer not null references users (id),
|
||||
created_at timestamp not null default now(),
|
||||
updated_at timestamp not null default now()
|
||||
);
|
@ -2,7 +2,10 @@ use chrono::NaiveDateTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use jirs_data::{IssuePriority, IssueStatus, IssueType, ProjectCategory, UserRole};
|
||||
use jirs_data::{
|
||||
InvitationState, InvitationStateType, IssuePriority, IssueStatus, IssueType, ProjectCategory,
|
||||
UserRole,
|
||||
};
|
||||
|
||||
use crate::schema::*;
|
||||
|
||||
@ -217,7 +220,6 @@ pub struct UserForm {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Queryable)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Token {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
@ -242,7 +244,6 @@ impl Into<jirs_data::Token> for Token {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Insertable)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[table_name = "tokens"]
|
||||
pub struct TokenForm {
|
||||
pub user_id: i32,
|
||||
@ -250,3 +251,25 @@ pub struct TokenForm {
|
||||
pub refresh_token: Uuid,
|
||||
pub bind_token: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Queryable)]
|
||||
pub struct Invitation {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub state: InvitationState,
|
||||
pub project_id: i32,
|
||||
pub invited_by_id: i32,
|
||||
pub created_at: NaiveDateTime,
|
||||
pub updated_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Insertable)]
|
||||
#[table_name = "invitations"]
|
||||
pub struct InvitationForm {
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub state: InvitationState,
|
||||
pub project_id: i32,
|
||||
pub invited_by_id: i32,
|
||||
}
|
||||
|
@ -47,6 +47,65 @@ table! {
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
use diesel::sql_types::*;
|
||||
use jirs_data::sql::*;
|
||||
|
||||
/// Representation of the `invitations` table.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
invitations (id) {
|
||||
/// The `id` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `Int4`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
id -> Int4,
|
||||
/// The `name` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `Text`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
name -> Text,
|
||||
/// The `email` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `Text`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
email -> Text,
|
||||
/// The `state` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `InvitationStateType`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
state -> InvitationStateType,
|
||||
/// The `project_id` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `Int4`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
project_id -> Int4,
|
||||
/// The `invited_by_id` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `Int4`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
invited_by_id -> Int4,
|
||||
/// The `created_at` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `Timestamp`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
created_at -> Timestamp,
|
||||
/// The `updated_at` column of the `invitations` table.
|
||||
///
|
||||
/// Its SQL type is `Timestamp`.
|
||||
///
|
||||
/// (Automatically generated by Diesel.)
|
||||
updated_at -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
use diesel::sql_types::*;
|
||||
use jirs_data::sql::*;
|
||||
@ -356,6 +415,8 @@ table! {
|
||||
|
||||
joinable!(comments -> issues (issue_id));
|
||||
joinable!(comments -> users (user_id));
|
||||
joinable!(invitations -> projects (project_id));
|
||||
joinable!(invitations -> users (invited_by_id));
|
||||
joinable!(issue_assignees -> issues (issue_id));
|
||||
joinable!(issue_assignees -> users (user_id));
|
||||
joinable!(issues -> projects (project_id));
|
||||
@ -365,6 +426,7 @@ joinable!(users -> projects (project_id));
|
||||
|
||||
allow_tables_to_appear_in_same_query!(
|
||||
comments,
|
||||
invitations,
|
||||
issue_assignees,
|
||||
issues,
|
||||
projects,
|
||||
|
Loading…
Reference in New Issue
Block a user