feat: improve email workspace invitations
This commit is contained in:
parent
721f0c759b
commit
9adf3f883c
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n SELECT invitee_email\n FROM public.af_workspace_invitation\n WHERE workspace_id = $1\n AND status = 0\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "invitee_email",
|
||||||
|
"type_info": "Text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Uuid"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "374c2d7b26f923328edd09b0d515d59426119615a8d5d8a46101f6ccec00d617"
|
||||||
|
}
|
||||||
|
|
@ -30,7 +30,8 @@ RUN cargo build --profile=release --features "${FEATURES}" --bin appflowy_cloud
|
||||||
FROM debian:bookworm-slim AS runtime
|
FROM debian:bookworm-slim AS runtime
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apt-get update -y \
|
RUN apt-get update -y \
|
||||||
&& apt-get install -y --no-install-recommends openssl \
|
&& apt-get install -y --no-install-recommends openssl ca-certificates \
|
||||||
|
&& update-ca-certificates \
|
||||||
# Clean up
|
# Clean up
|
||||||
&& apt-get autoremove -y \
|
&& apt-get autoremove -y \
|
||||||
&& apt-get clean -y \
|
&& apt-get clean -y \
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use sqlx::{
|
||||||
types::{uuid, Uuid},
|
types::{uuid, Uuid},
|
||||||
Executor, PgPool, Postgres, Transaction,
|
Executor, PgPool, Postgres, Transaction,
|
||||||
};
|
};
|
||||||
use std::ops::DerefMut;
|
use std::{collections::HashSet, ops::DerefMut};
|
||||||
use tracing::{event, instrument};
|
use tracing::{event, instrument};
|
||||||
|
|
||||||
use crate::pg_row::AFWorkspaceMemberPermRow;
|
use crate::pg_row::AFWorkspaceMemberPermRow;
|
||||||
|
|
@ -705,3 +705,22 @@ pub async fn select_workspace_member_count_from_workspace_id(
|
||||||
.await?;
|
.await?;
|
||||||
Ok(workspace_count)
|
Ok(workspace_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn select_workspace_pending_invitations(
|
||||||
|
pool: &PgPool,
|
||||||
|
workspace_id: &Uuid,
|
||||||
|
) -> Result<HashSet<String>, AppError> {
|
||||||
|
let invitee_emails = sqlx::query_scalar!(
|
||||||
|
r#"
|
||||||
|
SELECT invitee_email
|
||||||
|
FROM public.af_workspace_invitation
|
||||||
|
WHERE workspace_id = $1
|
||||||
|
AND status = 0
|
||||||
|
"#,
|
||||||
|
workspace_id
|
||||||
|
)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await?;
|
||||||
|
Ok(invitee_emails.into_iter().collect())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -297,11 +297,11 @@ async fn post_accept_workspace_invite_handler(
|
||||||
|
|
||||||
#[instrument(skip_all, err)]
|
#[instrument(skip_all, err)]
|
||||||
async fn get_workspace_members_handler(
|
async fn get_workspace_members_handler(
|
||||||
user_uuid: UserUuid,
|
_user_uuid: UserUuid,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
workspace_id: web::Path<Uuid>,
|
workspace_id: web::Path<Uuid>,
|
||||||
) -> Result<JsonAppResponse<Vec<AFWorkspaceMember>>> {
|
) -> Result<JsonAppResponse<Vec<AFWorkspaceMember>>> {
|
||||||
let members = workspace::ops::get_workspace_members(&state.pg_pool, &user_uuid, &workspace_id)
|
let members = workspace::ops::get_workspace_members(&state.pg_pool, &workspace_id)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|member| AFWorkspaceMember {
|
.map(|member| AFWorkspaceMember {
|
||||||
|
|
|
||||||
|
|
@ -178,19 +178,39 @@ pub async fn invite_workspace_members(
|
||||||
.context("Begin transaction to invite workspace members")?;
|
.context("Begin transaction to invite workspace members")?;
|
||||||
let admin_token = gotrue_admin.token(gotrue_client).await?;
|
let admin_token = gotrue_admin.token(gotrue_client).await?;
|
||||||
|
|
||||||
for invitation in invitations {
|
let inviter_name = database::user::select_name_from_uuid(pg_pool, inviter).await?;
|
||||||
let inviter_name = database::user::select_name_from_uuid(pg_pool, inviter).await?;
|
let workspace_name =
|
||||||
let workspace_name =
|
database::workspace::select_workspace_name_from_workspace_id(pg_pool, workspace_id)
|
||||||
database::workspace::select_workspace_name_from_workspace_id(pg_pool, workspace_id)
|
.await?
|
||||||
.await?
|
.unwrap_or_default();
|
||||||
.unwrap_or_default();
|
let workspace_member_count =
|
||||||
let workspace_member_count =
|
database::workspace::select_workspace_member_count_from_workspace_id(pg_pool, workspace_id)
|
||||||
database::workspace::select_workspace_member_count_from_workspace_id(pg_pool, workspace_id)
|
.await?
|
||||||
.await?
|
.unwrap_or_default();
|
||||||
.unwrap_or_default()
|
let workspace_members_by_email: HashMap<_, _> =
|
||||||
.to_string();
|
database::workspace::select_workspace_member_list(pg_pool, workspace_id)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| (row.email, row.role))
|
||||||
|
.collect();
|
||||||
|
let pending_invitations =
|
||||||
|
database::workspace::select_workspace_pending_invitations(pg_pool, workspace_id).await?;
|
||||||
|
|
||||||
// default icon until we have workspace icon
|
for invitation in invitations {
|
||||||
|
if workspace_members_by_email.contains_key(&invitation.email) {
|
||||||
|
tracing::warn!("User already in workspace: {}", invitation.email);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if pending_invitations.contains(&invitation.email) {
|
||||||
|
tracing::warn!("User already invited: {}", invitation.email);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let inviter_name = inviter_name.clone();
|
||||||
|
let workspace_name = workspace_name.clone();
|
||||||
|
let workspace_member_count = workspace_member_count.to_string();
|
||||||
|
|
||||||
|
// use default icon until we have workspace icon
|
||||||
let workspace_icon_url =
|
let workspace_icon_url =
|
||||||
"https://miro.medium.com/v2/resize:fit:2400/1*mTPfm7CwU31-tLhtLNkyJw.png".to_string();
|
"https://miro.medium.com/v2/resize:fit:2400/1*mTPfm7CwU31-tLhtLNkyJw.png".to_string();
|
||||||
let user_icon_url =
|
let user_icon_url =
|
||||||
|
|
@ -390,7 +410,6 @@ pub async fn remove_workspace_members(
|
||||||
|
|
||||||
pub async fn get_workspace_members(
|
pub async fn get_workspace_members(
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
_user_uuid: &Uuid,
|
|
||||||
workspace_id: &Uuid,
|
workspace_id: &Uuid,
|
||||||
) -> Result<Vec<AFWorkspaceMemberRow>, AppResponseError> {
|
) -> Result<Vec<AFWorkspaceMemberRow>, AppResponseError> {
|
||||||
Ok(select_workspace_member_list(pg_pool, workspace_id).await?)
|
Ok(select_workspace_member_list(pg_pool, workspace_id).await?)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue