feat: reuse email link
This commit is contained in:
parent
4e510bb452
commit
572271f751
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "\n UPDATE public.af_workspace_invitation\n SET status = 1\n WHERE invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)\n AND id = $2\n ",
|
"query": "\n UPDATE public.af_workspace_invitation\n SET status = 1\n WHERE invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)\n AND id = $2\n AND status = 0\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
|
@ -11,5 +11,5 @@
|
||||||
},
|
},
|
||||||
"nullable": []
|
"nullable": []
|
||||||
},
|
},
|
||||||
"hash": "3b3dd104bf9e1fb9cf6d413e0e59db0cdbb009c92dce1c1e67900c44efdb8db4"
|
"hash": "5d2ab1eb7ab9ebea8c162f4b742c72dbea7f3d18849f6cd7865068be9b01d759"
|
||||||
}
|
}
|
||||||
|
|
@ -143,6 +143,23 @@ pub async fn get_pending_workspace_invitations(
|
||||||
from_json_response(resp).await
|
from_json_response(resp).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_accepted_workspace_invitations(
|
||||||
|
access_token: &str,
|
||||||
|
appflowy_cloud_base_url: &str,
|
||||||
|
) -> Result<Vec<AFWorkspaceInvitation>, Error> {
|
||||||
|
let http_client = reqwest::Client::new();
|
||||||
|
let resp = http_client
|
||||||
|
.get(format!(
|
||||||
|
"{}/api/workspace/invite?status=Accepted",
|
||||||
|
appflowy_cloud_base_url
|
||||||
|
))
|
||||||
|
.header("Authorization", format!("Bearer {}", access_token))
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
from_json_response(resp).await
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_user_workspace_limits(
|
async fn get_user_workspace_limits(
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
access_token: &str,
|
access_token: &str,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::askama_entities::WorkspaceWithMembers;
|
use crate::askama_entities::WorkspaceWithMembers;
|
||||||
use crate::error::WebAppError;
|
use crate::error::WebAppError;
|
||||||
use crate::ext::api::{
|
use crate::ext::api::{
|
||||||
accept_workspace_invitation, get_pending_workspace_invitations, get_user_owned_workspaces,
|
accept_workspace_invitation, get_accepted_workspace_invitations,
|
||||||
get_user_profile, get_user_workspace_limit, get_user_workspace_usages, get_user_workspaces,
|
get_pending_workspace_invitations, get_user_owned_workspaces, get_user_profile,
|
||||||
get_workspace_members, verify_token_cloud,
|
get_user_workspace_limit, get_user_workspace_usages, get_user_workspaces, get_workspace_members,
|
||||||
|
verify_token_cloud,
|
||||||
};
|
};
|
||||||
use crate::models::{OAuthLoginAction, WebAppOAuthLoginRequest};
|
use crate::models::{OAuthLoginAction, WebAppOAuthLoginRequest};
|
||||||
use crate::session::{self, new_session_cookie, UserSession};
|
use crate::session::{self, new_session_cookie, UserSession};
|
||||||
|
|
@ -68,35 +69,51 @@ async fn login_callback_handler() -> Result<Html<String>, WebAppError> {
|
||||||
|
|
||||||
async fn login_callback_query_handler(
|
async fn login_callback_query_handler(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
|
session: Option<UserSession>,
|
||||||
Query(query): Query<WebAppOAuthLoginRequest>,
|
Query(query): Query<WebAppOAuthLoginRequest>,
|
||||||
mut jar: CookieJar,
|
mut jar: CookieJar,
|
||||||
) -> Result<(CookieJar, Html<String>), WebAppError> {
|
) -> Result<(CookieJar, Html<String>), WebAppError> {
|
||||||
if let Some(err) = query.error {
|
let refresh_token = {
|
||||||
tracing::error!(
|
match query.refresh_token {
|
||||||
"OAuth login error: {:?}, code: {:?}, description: {:?}",
|
Some(refresh_token) => refresh_token,
|
||||||
err,
|
None => match session {
|
||||||
query.error_code,
|
Some(session) => session.token.refresh_token,
|
||||||
query.error_description
|
None => match query.error {
|
||||||
);
|
Some(err) => {
|
||||||
return Ok((jar, render_template(templates::Redirect {
|
tracing::error!(
|
||||||
redirect_url: format!(
|
"OAuth login error: {:?}, code: {:?}, description: {:?}",
|
||||||
"https://appflowy.io/invitation/expired?workspace_name={}&workspace_icon={}&user_name={}&user_icon={}&workspace_member_count={}",
|
err,
|
||||||
query.workspace_name.unwrap_or_default(),
|
query.error_code,
|
||||||
query.workspace_icon.unwrap_or_default(),
|
query.error_description
|
||||||
query.user_name.unwrap_or_default(),
|
);
|
||||||
query.user_icon.unwrap_or_default(),
|
let expired_url = format!(
|
||||||
query.workspace_member_count.unwrap_or_default()),
|
"https://appflowy.io/invitation/expired?workspace_name={}&workspace_icon={}&user_name={}&user_icon={}&workspace_member_count={}",
|
||||||
})?));
|
query.workspace_name.unwrap_or_default(),
|
||||||
|
query.workspace_icon.unwrap_or_default(),
|
||||||
|
query.user_name.unwrap_or_default(),
|
||||||
|
query.user_icon.unwrap_or_default(),
|
||||||
|
query.workspace_member_count.unwrap_or_default());
|
||||||
|
return Ok((
|
||||||
|
jar,
|
||||||
|
render_template(templates::Redirect {
|
||||||
|
redirect_url: expired_url,
|
||||||
|
})?,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return Err(WebAppError::BadRequest(
|
||||||
|
"refresh_token not found".to_string(),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let token = state
|
let token = state
|
||||||
.gotrue_client
|
.gotrue_client
|
||||||
.token(&gotrue::grant::Grant::RefreshToken(
|
.token(&gotrue::grant::Grant::RefreshToken(
|
||||||
gotrue::grant::RefreshTokenGrant {
|
gotrue::grant::RefreshTokenGrant { refresh_token },
|
||||||
refresh_token: query.refresh_token.ok_or(WebAppError::BadRequest(
|
|
||||||
"refresh_token not found".to_string(),
|
|
||||||
))?,
|
|
||||||
},
|
|
||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
@ -129,6 +146,22 @@ async fn login_callback_query_handler(
|
||||||
.ok_or(WebAppError::BadRequest(
|
.ok_or(WebAppError::BadRequest(
|
||||||
"workspace_invitation_id not found".to_string(),
|
"workspace_invitation_id not found".to_string(),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
{
|
||||||
|
// If user has already accepted the invitation, redirect to open or download AppFlowy
|
||||||
|
let accepted_invitations = get_accepted_workspace_invitations(
|
||||||
|
&new_session.token.access_token,
|
||||||
|
&state.appflowy_cloud_url,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let found = accepted_invitations
|
||||||
|
.iter()
|
||||||
|
.find(|w| w.invite_id.to_string() == invite_id);
|
||||||
|
if let Some(_) = found {
|
||||||
|
return Ok((jar, render_template(templates::OpenAppFlowyOrDownload {})?));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(err) = accept_workspace_invitation(
|
if let Err(err) = accept_workspace_invitation(
|
||||||
&new_session.token.access_token,
|
&new_session.token.access_token,
|
||||||
&invite_id,
|
&invite_id,
|
||||||
|
|
@ -137,10 +170,17 @@ async fn login_callback_query_handler(
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
tracing::error!("accepting workspace invitation: {:?}", err);
|
tracing::error!("accepting workspace invitation: {:?}", err);
|
||||||
|
let expired_url = format!(
|
||||||
|
"https://appflowy.io/invitation/expired?workspace_name={}&workspace_icon={}&user_name={}&user_icon={}&workspace_member_count={}",
|
||||||
|
query.workspace_name.unwrap_or_default(),
|
||||||
|
query.workspace_icon.unwrap_or_default(),
|
||||||
|
query.user_name.unwrap_or_default(),
|
||||||
|
query.user_icon.unwrap_or_default(),
|
||||||
|
query.workspace_member_count.unwrap_or_default());
|
||||||
return Ok((
|
return Ok((
|
||||||
jar,
|
jar,
|
||||||
render_template(templates::Redirect {
|
render_template(templates::Redirect {
|
||||||
redirect_url: "https://test.appflowy.io/invitation/expired".to_string(),
|
redirect_url: expired_url,
|
||||||
})?,
|
})?,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,7 @@ pub async fn update_workspace_invitation_set_status_accepted(
|
||||||
SET status = 1
|
SET status = 1
|
||||||
WHERE invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)
|
WHERE invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)
|
||||||
AND id = $2
|
AND id = $2
|
||||||
|
AND status = 0
|
||||||
"#,
|
"#,
|
||||||
invitee_uuid,
|
invitee_uuid,
|
||||||
invite_id,
|
invite_id,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue