Merge pull request #821 from AppFlowy-IO/feat/workspace-invite-fields
feat: additional fields for workspace invitation
This commit is contained in:
commit
eed23a353a
|
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n id AS invite_id,\n workspace_id,\n (SELECT workspace_name FROM public.af_workspace WHERE workspace_id = af_workspace_invitation.workspace_id),\n (SELECT email FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_email,\n (SELECT name FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_name,\n status,\n updated_at\n FROM\n public.af_workspace_invitation\n WHERE af_workspace_invitation.invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)\n AND ($2::SMALLINT IS NULL OR status = $2)\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "invite_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "workspace_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "inviter_email",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "inviter_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "status",
|
||||
"type_info": "Int2"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int2"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "2c1152b8867bebcb63b637820eb44ac932ee88c6326ecaf9b4b4c7f690eff41c"
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n i.id AS invite_id,\n i.workspace_id,\n w.workspace_name,\n u_inviter.email AS inviter_email,\n u_inviter.name AS inviter_name,\n i.status,\n i.updated_at,\n u_inviter.metadata->>'icon_url' AS inviter_icon,\n w.icon AS workspace_icon,\n (SELECT COUNT(*) FROM public.af_workspace_member m WHERE m.workspace_id = i.workspace_id) AS member_count\n FROM\n public.af_workspace_invitation i\n JOIN public.af_workspace w ON i.workspace_id = w.workspace_id\n JOIN public.af_user u_inviter ON i.inviter = u_inviter.uid\n JOIN public.af_user u_invitee ON u_invitee.uuid = $1\n WHERE\n i.invitee_email = u_invitee.email\n AND i.id = $2;\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "invite_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "workspace_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "inviter_email",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "inviter_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "status",
|
||||
"type_info": "Int2"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "inviter_icon",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "workspace_icon",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "member_count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
false,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "2ee385e58e042071290226289646965553938838c83085273f68f687c976767a"
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n id AS invite_id,\n workspace_id,\n (SELECT workspace_name FROM public.af_workspace WHERE workspace_id = af_workspace_invitation.workspace_id),\n (SELECT email FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_email,\n (SELECT name FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_name,\n status,\n updated_at\n FROM public.af_workspace_invitation\n WHERE af_workspace_invitation.invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)\n AND id = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "invite_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "workspace_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "inviter_email",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "inviter_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "status",
|
||||
"type_info": "Int2"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "6dd7f6db2d364cc37b1b46c611fe111d06e327edd9f3a98a4b0636bfe8fd6319"
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT EXISTS(\n SELECT 1\n FROM af_workspace_invitation\n WHERE id = $1 AND invitee_email = (SELECT email FROM af_user WHERE uuid = $2)\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "7c8b84da6d70cb4ae59ae618e6f7aa7bde3dbd6630bd7e7fcafe1606d63651c8"
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n i.id AS invite_id,\n i.workspace_id,\n w.workspace_name,\n u_inviter.email AS inviter_email,\n u_inviter.name AS inviter_name,\n i.status,\n i.updated_at,\n u_inviter.metadata->>'icon_url' AS inviter_icon,\n w.icon AS workspace_icon,\n (SELECT COUNT(*) FROM public.af_workspace_member m WHERE m.workspace_id = i.workspace_id) AS member_count\n FROM\n public.af_workspace_invitation i\n JOIN public.af_workspace w ON i.workspace_id = w.workspace_id\n JOIN public.af_user u_inviter ON i.inviter = u_inviter.uid\n JOIN public.af_user u_invitee ON u_invitee.uuid = $1\n WHERE\n i.invitee_email = u_invitee.email\n AND ($2::SMALLINT IS NULL OR i.status = $2);\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "invite_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "workspace_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "inviter_email",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "inviter_name",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "status",
|
||||
"type_info": "Int2"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "updated_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "inviter_icon",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "workspace_icon",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "member_count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Int2"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
false,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "de595bd6554d8e1f58c9c4bb94ea14b5ae2fd15b3c5d2b84d5dd5a551954ecde"
|
||||
}
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
</table>
|
||||
|
||||
<br />
|
||||
<h4>Pending Invitation</h4>
|
||||
<h4>Invitation(s) from other user(s)</h4>
|
||||
<table class="purple-table table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -142,6 +142,9 @@ pub enum AppError {
|
|||
|
||||
#[error("{0}")]
|
||||
InvalidFolderView(String),
|
||||
|
||||
#[error("{0}")]
|
||||
NotInviteeOfWorkspaceInvitation(String),
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
|
|
@ -208,6 +211,7 @@ impl AppError {
|
|||
AppError::InvalidContentType(_) => ErrorCode::InvalidContentType,
|
||||
AppError::InvalidPublishedOutline(_) => ErrorCode::InvalidPublishedOutline,
|
||||
AppError::InvalidFolderView(_) => ErrorCode::InvalidFolderView,
|
||||
AppError::NotInviteeOfWorkspaceInvitation(_) => ErrorCode::NotInviteeOfWorkspaceInvitation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -328,6 +332,7 @@ pub enum ErrorCode {
|
|||
AppleRevokeTokenError = 1038,
|
||||
InvalidPublishedOutline = 1039,
|
||||
InvalidFolderView = 1040,
|
||||
NotInviteeOfWorkspaceInvitation = 1041,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
|
|
|
|||
|
|
@ -601,6 +601,9 @@ pub struct AFWorkspaceInvitation {
|
|||
pub inviter_name: Option<String>,
|
||||
pub status: AFWorkspaceInvitationStatus,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
pub inviter_icon: Option<String>,
|
||||
pub workspace_icon: String,
|
||||
pub member_count: Option<i64>, // use unwrap_or(0) to get the value
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -409,22 +409,31 @@ pub async fn select_workspace_invitations_for_user(
|
|||
let res = sqlx::query_as!(
|
||||
AFWorkspaceInvitation,
|
||||
r#"
|
||||
SELECT
|
||||
id AS invite_id,
|
||||
workspace_id,
|
||||
(SELECT workspace_name FROM public.af_workspace WHERE workspace_id = af_workspace_invitation.workspace_id),
|
||||
(SELECT email FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_email,
|
||||
(SELECT name FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_name,
|
||||
status,
|
||||
updated_at
|
||||
FROM
|
||||
public.af_workspace_invitation
|
||||
WHERE af_workspace_invitation.invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)
|
||||
AND ($2::SMALLINT IS NULL OR status = $2)
|
||||
SELECT
|
||||
i.id AS invite_id,
|
||||
i.workspace_id,
|
||||
w.workspace_name,
|
||||
u_inviter.email AS inviter_email,
|
||||
u_inviter.name AS inviter_name,
|
||||
i.status,
|
||||
i.updated_at,
|
||||
u_inviter.metadata->>'icon_url' AS inviter_icon,
|
||||
w.icon AS workspace_icon,
|
||||
(SELECT COUNT(*) FROM public.af_workspace_member m WHERE m.workspace_id = i.workspace_id) AS member_count
|
||||
FROM
|
||||
public.af_workspace_invitation i
|
||||
JOIN public.af_workspace w ON i.workspace_id = w.workspace_id
|
||||
JOIN public.af_user u_inviter ON i.inviter = u_inviter.uid
|
||||
JOIN public.af_user u_invitee ON u_invitee.uuid = $1
|
||||
WHERE
|
||||
i.invitee_email = u_invitee.email
|
||||
AND ($2::SMALLINT IS NULL OR i.status = $2);
|
||||
"#,
|
||||
invitee_uuid,
|
||||
status_filter.map(|s| s as i16)
|
||||
).fetch_all(pg_pool).await?;
|
||||
)
|
||||
.fetch_all(pg_pool)
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
|
@ -437,21 +446,31 @@ pub async fn select_workspace_invitation_for_user(
|
|||
let res = sqlx::query_as!(
|
||||
AFWorkspaceInvitation,
|
||||
r#"
|
||||
SELECT
|
||||
id AS invite_id,
|
||||
workspace_id,
|
||||
(SELECT workspace_name FROM public.af_workspace WHERE workspace_id = af_workspace_invitation.workspace_id),
|
||||
(SELECT email FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_email,
|
||||
(SELECT name FROM public.af_user WHERE uid = af_workspace_invitation.inviter) AS inviter_name,
|
||||
status,
|
||||
updated_at
|
||||
FROM public.af_workspace_invitation
|
||||
WHERE af_workspace_invitation.invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)
|
||||
AND id = $2
|
||||
SELECT
|
||||
i.id AS invite_id,
|
||||
i.workspace_id,
|
||||
w.workspace_name,
|
||||
u_inviter.email AS inviter_email,
|
||||
u_inviter.name AS inviter_name,
|
||||
i.status,
|
||||
i.updated_at,
|
||||
u_inviter.metadata->>'icon_url' AS inviter_icon,
|
||||
w.icon AS workspace_icon,
|
||||
(SELECT COUNT(*) FROM public.af_workspace_member m WHERE m.workspace_id = i.workspace_id) AS member_count
|
||||
FROM
|
||||
public.af_workspace_invitation i
|
||||
JOIN public.af_workspace w ON i.workspace_id = w.workspace_id
|
||||
JOIN public.af_user u_inviter ON i.inviter = u_inviter.uid
|
||||
JOIN public.af_user u_invitee ON u_invitee.uuid = $1
|
||||
WHERE
|
||||
i.invitee_email = u_invitee.email
|
||||
AND i.id = $2;
|
||||
"#,
|
||||
invitee_uuid,
|
||||
invite_id,
|
||||
).fetch_one(pg_pool).await?;
|
||||
)
|
||||
.fetch_one(pg_pool)
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
|
@ -1357,3 +1376,24 @@ pub async fn delete_reaction_from_comment<'a, E: Executor<'a, Database = Postgre
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn select_user_is_invitee_for_workspace_invitation(
|
||||
pg_pool: &PgPool,
|
||||
invitee_uuid: &Uuid,
|
||||
invite_id: &Uuid,
|
||||
) -> Result<bool, AppError> {
|
||||
let res = sqlx::query_scalar!(
|
||||
r#"
|
||||
SELECT EXISTS(
|
||||
SELECT 1
|
||||
FROM af_workspace_invitation
|
||||
WHERE id = $1 AND invitee_email = (SELECT email FROM af_user WHERE uuid = $2)
|
||||
)
|
||||
"#,
|
||||
invite_id,
|
||||
invitee_uuid,
|
||||
)
|
||||
.fetch_one(pg_pool)
|
||||
.await?;
|
||||
res.map_or(Ok(false), Ok)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use access_control::collab::CollabAccessControl;
|
|||
use app_error::AppError;
|
||||
use appflowy_collaborate::actix_ws::entities::ClientStreamMessage;
|
||||
use appflowy_collaborate::indexer::IndexerProvider;
|
||||
use authentication::jwt::{OptionalUserUuid, UserUuid};
|
||||
use authentication::jwt::{Authorization, OptionalUserUuid, UserUuid};
|
||||
use collab_rt_entity::realtime_proto::HttpRealtimeMessage;
|
||||
use collab_rt_entity::RealtimeMessage;
|
||||
use collab_rt_protocol::validate_encode_collab;
|
||||
|
|
@ -41,6 +41,7 @@ use crate::biz;
|
|||
use crate::biz::collab::ops::{
|
||||
get_user_favorite_folder_views, get_user_recent_folder_views, get_user_trash_folder_views,
|
||||
};
|
||||
use crate::biz::user::user_verify::verify_token;
|
||||
use crate::biz::workspace;
|
||||
use crate::biz::workspace::ops::{
|
||||
create_comment_on_published_view, create_reaction_on_comment, get_comments_on_published_view,
|
||||
|
|
@ -333,16 +334,20 @@ async fn get_workspace_invite_by_id_handler(
|
|||
}
|
||||
|
||||
async fn post_accept_workspace_invite_handler(
|
||||
user_uuid: UserUuid,
|
||||
auth: Authorization,
|
||||
invite_id: web::Path<Uuid>,
|
||||
state: Data<AppState>,
|
||||
) -> Result<JsonAppResponse<()>> {
|
||||
let _is_new = verify_token(&auth.token, state.as_ref()).await?;
|
||||
let user_uuid = auth.uuid()?;
|
||||
let user_uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||
let invite_id = invite_id.into_inner();
|
||||
// TODO(zack): insert a workspace member in the af_workspace_member by calling workspace::ops::add_workspace_members.
|
||||
// Currently, when the server get restarted, the policy in access control will be lost.
|
||||
workspace::ops::accept_workspace_invite(
|
||||
&state.pg_pool,
|
||||
&state.workspace_access_control,
|
||||
user_uid,
|
||||
&user_uuid,
|
||||
&invite_id,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -302,12 +302,21 @@ pub async fn open_workspace(
|
|||
pub async fn accept_workspace_invite(
|
||||
pg_pool: &PgPool,
|
||||
workspace_access_control: &impl WorkspaceAccessControl,
|
||||
user_uid: i64,
|
||||
user_uuid: &Uuid,
|
||||
invite_id: &Uuid,
|
||||
) -> Result<(), AppError> {
|
||||
let mut txn = pg_pool.begin().await?;
|
||||
update_workspace_invitation_set_status_accepted(&mut txn, user_uuid, invite_id).await?;
|
||||
let inv = get_invitation_by_id(&mut txn, invite_id).await?;
|
||||
if let Some(invitee_uid) = inv.invitee_uid {
|
||||
if invitee_uid != user_uid {
|
||||
return Err(AppError::NotInviteeOfWorkspaceInvitation(format!(
|
||||
"User with uid {} is not the invitee for invite_id {}",
|
||||
user_uid, invite_id
|
||||
)));
|
||||
}
|
||||
}
|
||||
update_workspace_invitation_set_status_accepted(&mut txn, user_uuid, invite_id).await?;
|
||||
let invited_uid = inv
|
||||
.invitee_uid
|
||||
.ok_or_else(|| AppError::Internal(anyhow::anyhow!("Invitee uid is missing for {:?}", inv)))?;
|
||||
|
|
@ -400,7 +409,7 @@ pub async fn invite_workspace_members(
|
|||
// Generate a link such that when clicked, the user is added to the workspace.
|
||||
let accept_url = {
|
||||
match appflowy_web_url {
|
||||
Some(appflowy_web_url) => format!("{}/accept-invitation?invitated_id={}", appflowy_web_url, invite_id),
|
||||
Some(appflowy_web_url) => format!("{}/accept-invitation?invited_id={}", appflowy_web_url, invite_id),
|
||||
None => {
|
||||
gotrue_client
|
||||
.admin_generate_link(
|
||||
|
|
@ -469,6 +478,14 @@ pub async fn get_workspace_invitations_for_user(
|
|||
user_uuid: &Uuid,
|
||||
invite_id: &Uuid,
|
||||
) -> Result<AFWorkspaceInvitation, AppError> {
|
||||
let user_is_invitee =
|
||||
select_user_is_invitee_for_workspace_invitation(pg_pool, user_uuid, invite_id).await?;
|
||||
if !user_is_invitee {
|
||||
return Err(AppError::NotInviteeOfWorkspaceInvitation(format!(
|
||||
"User with uuid {} is not the invitee for invite_id {}",
|
||||
user_uuid, invite_id
|
||||
)));
|
||||
}
|
||||
let invitation = select_workspace_invitation_for_user(pg_pool, user_uuid, invite_id).await?;
|
||||
Ok(invitation)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@ impl Mailer {
|
|||
|
||||
HANDLEBARS
|
||||
.write()
|
||||
.unwrap()
|
||||
.map_err(|err| anyhow::anyhow!(format!("Failed to write handlebars: {}", err)))?
|
||||
.register_template_string("workspace_invite", workspace_invite_template)
|
||||
.unwrap();
|
||||
.map_err(|err| anyhow::anyhow!(format!("Failed to register handlebars template: {}", err)))?;
|
||||
|
||||
Ok(Self {
|
||||
smtp_transport,
|
||||
|
|
@ -51,10 +51,10 @@ impl Mailer {
|
|||
email: String,
|
||||
param: WorkspaceInviteMailerParam,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let rendered = HANDLEBARS
|
||||
.read()
|
||||
.unwrap()
|
||||
.render("workspace_invite", ¶m)?;
|
||||
let rendered = match HANDLEBARS.read() {
|
||||
Ok(registory) => registory.render("workspace_invite", ¶m)?,
|
||||
Err(err) => anyhow::bail!(format!("Failed to render handlebars template: {}", err)),
|
||||
};
|
||||
|
||||
let email = Message::builder()
|
||||
.from(lettre::message::Mailbox::new(
|
||||
|
|
@ -63,7 +63,7 @@ impl Mailer {
|
|||
))
|
||||
.to(lettre::message::Mailbox::new(
|
||||
Some(param.username.clone()),
|
||||
email.parse().unwrap(),
|
||||
email.parse()?,
|
||||
))
|
||||
.subject(format!(
|
||||
"Action required: {} invited you to {} in AppFlowy",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use app_error::ErrorCode;
|
||||
use client_api_test::generate_unique_registered_user_client;
|
||||
use database_entity::dto::{AFRole, AFWorkspaceInvitationStatus};
|
||||
use shared_entity::dto::workspace_dto::{QueryWorkspaceParam, WorkspaceMemberInvitation};
|
||||
|
|
@ -59,12 +60,33 @@ async fn invite_workspace_crud() {
|
|||
|
||||
assert_eq!(invitation.inviter_email, Some(alice.email));
|
||||
assert_eq!(invitation.status, AFWorkspaceInvitationStatus::Pending);
|
||||
assert_eq!(invitation.member_count.unwrap_or(0), 1);
|
||||
|
||||
let (charlie_client, _charlie) = generate_unique_registered_user_client().await;
|
||||
let err = charlie_client
|
||||
.get_workspace_invitation(&invite_id)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert_eq!(err.code, ErrorCode::NotInviteeOfWorkspaceInvitation);
|
||||
let err = charlie_client
|
||||
.accept_workspace_invitation(&invite_id)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert_eq!(err.code, ErrorCode::NotInviteeOfWorkspaceInvitation);
|
||||
|
||||
bob_client
|
||||
.accept_workspace_invitation(&invite_id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let invitation = bob_client
|
||||
.get_workspace_invitation(&invite_id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(invitation.status, AFWorkspaceInvitationStatus::Accepted);
|
||||
assert_eq!(invitation.member_count.unwrap_or(0), 2);
|
||||
|
||||
// list invitation with accepted filter
|
||||
let accepted_invs = bob_client
|
||||
.list_workspace_invitations(Some(AFWorkspaceInvitationStatus::Accepted))
|
||||
|
|
|
|||
Loading…
Reference in New Issue