feat: use email for af workspace invitation table
This commit is contained in:
parent
ba1fa8f307
commit
9b28edb5bc
|
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n UPDATE public.af_workspace_invitation\n SET status = 1\n WHERE invitee = (SELECT uid FROM public.af_user WHERE uuid = $1)\n AND id = $2\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid",
|
|
||||||
"Uuid"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "15b177321fc6b28e249bd1ae6863bda18a7d0e4461f2239c25e6ee448b279d3e"
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n SELECT\n workspace_id,\n inviter AS inviter_uid,\n invitee AS invitee_uid,\n status,\n role_id AS role\n FROM\n public.af_workspace_invitation\n WHERE id = $1\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"ordinal": 0,
|
|
||||||
"name": "workspace_id",
|
|
||||||
"type_info": "Uuid"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 1,
|
|
||||||
"name": "inviter_uid",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 2,
|
|
||||||
"name": "invitee_uid",
|
|
||||||
"type_info": "Int8"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 3,
|
|
||||||
"name": "status",
|
|
||||||
"type_info": "Int2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ordinal": 4,
|
|
||||||
"name": "role",
|
|
||||||
"type_info": "Int4"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": [
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hash": "5479b2f4b07cf39ff655024d7436223b5812940ae3801cd76cbf5276530ac851"
|
|
||||||
}
|
|
||||||
|
|
@ -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 = (SELECT uid 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": "bd39ce152d3468956db3896d892242603963e3a5435c4c9e2457c5afcbbdc510"
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n INSERT INTO public.af_workspace_invitation (\n workspace_id,\n inviter,\n invitee,\n role_id\n )\n VALUES (\n $1,\n (SELECT uid FROM public.af_user WHERE uuid = $2),\n (SELECT uid FROM public.af_user WHERE email = $3),\n $4\n )\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid",
|
|
||||||
"Uuid",
|
|
||||||
"Text",
|
|
||||||
"Int4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "e3e2533f5b58394d3eaef0d90c2ff9a5e00eb7bfd696e5156ffc840ae401dfc1"
|
|
||||||
}
|
|
||||||
|
|
@ -146,7 +146,7 @@ pub async fn admin_users_handler(
|
||||||
) -> Result<Html<String>, WebAppError> {
|
) -> Result<Html<String>, WebAppError> {
|
||||||
let users = state
|
let users = state
|
||||||
.gotrue_client
|
.gotrue_client
|
||||||
.admin_list_user(&session.token.access_token)
|
.admin_list_user(&session.token.access_token, None)
|
||||||
.await
|
.await
|
||||||
.map_or_else(
|
.map_or_else(
|
||||||
|err| {
|
|err| {
|
||||||
|
|
|
||||||
|
|
@ -430,6 +430,19 @@ impl Client {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filter is postgre sql like filter
|
||||||
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
|
pub async fn admin_list_users(
|
||||||
|
&self,
|
||||||
|
filter: Option<&str>,
|
||||||
|
) -> Result<Vec<User>, AppResponseError> {
|
||||||
|
let user = self
|
||||||
|
.gotrue_client
|
||||||
|
.admin_list_user(&self.access_token()?, filter)
|
||||||
|
.await?;
|
||||||
|
Ok(user.users)
|
||||||
|
}
|
||||||
|
|
||||||
/// Only expose this method for testing
|
/// Only expose this method for testing
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub fn token(&self) -> Arc<RwLock<ClientToken>> {
|
pub fn token(&self) -> Arc<RwLock<ClientToken>> {
|
||||||
|
|
|
||||||
|
|
@ -175,11 +175,11 @@ pub struct AFSnapshotRow {
|
||||||
pub workspace_id: Uuid,
|
pub workspace_id: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromRow, Deserialize, Serialize)]
|
#[derive(Debug, FromRow, Deserialize, Serialize)]
|
||||||
pub struct AFWorkspaceInvitationMinimal {
|
pub struct AFWorkspaceInvitationMinimal {
|
||||||
pub workspace_id: Uuid,
|
pub workspace_id: Uuid,
|
||||||
pub inviter_uid: i64,
|
pub inviter_uid: i64,
|
||||||
pub invitee_uid: i64,
|
pub invitee_uid: Option<i64>,
|
||||||
pub status: AFWorkspaceInvitationStatus,
|
pub status: AFWorkspaceInvitationStatus,
|
||||||
pub role: AFRole,
|
pub role: AFRole,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,13 +248,13 @@ pub async fn insert_workspace_invitation(
|
||||||
INSERT INTO public.af_workspace_invitation (
|
INSERT INTO public.af_workspace_invitation (
|
||||||
workspace_id,
|
workspace_id,
|
||||||
inviter,
|
inviter,
|
||||||
invitee,
|
invitee_email,
|
||||||
role_id
|
role_id
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
$1,
|
$1,
|
||||||
(SELECT uid FROM public.af_user WHERE uuid = $2),
|
(SELECT uid FROM public.af_user WHERE uuid = $2),
|
||||||
(SELECT uid FROM public.af_user WHERE email = $3),
|
$3,
|
||||||
$4
|
$4
|
||||||
)
|
)
|
||||||
"#,
|
"#,
|
||||||
|
|
@ -269,7 +269,7 @@ pub async fn insert_workspace_invitation(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_workspace_invitation_set_invited(
|
pub async fn update_workspace_invitation_set_status_accepted(
|
||||||
txn: &mut Transaction<'_, sqlx::Postgres>,
|
txn: &mut Transaction<'_, sqlx::Postgres>,
|
||||||
invitee_uuid: &Uuid,
|
invitee_uuid: &Uuid,
|
||||||
invite_id: &Uuid,
|
invite_id: &Uuid,
|
||||||
|
|
@ -278,7 +278,7 @@ pub async fn update_workspace_invitation_set_invited(
|
||||||
r#"
|
r#"
|
||||||
UPDATE public.af_workspace_invitation
|
UPDATE public.af_workspace_invitation
|
||||||
SET status = 1
|
SET status = 1
|
||||||
WHERE invitee = (SELECT uid 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
|
||||||
"#,
|
"#,
|
||||||
invitee_uuid,
|
invitee_uuid,
|
||||||
|
|
@ -312,7 +312,7 @@ pub async fn get_invitation_by_id(
|
||||||
SELECT
|
SELECT
|
||||||
workspace_id,
|
workspace_id,
|
||||||
inviter AS inviter_uid,
|
inviter AS inviter_uid,
|
||||||
invitee AS invitee_uid,
|
(SELECT uid FROM public.af_user WHERE email = invitee_email) AS invitee_uid,
|
||||||
status,
|
status,
|
||||||
role_id AS role
|
role_id AS role
|
||||||
FROM
|
FROM
|
||||||
|
|
@ -346,7 +346,7 @@ pub async fn select_workspace_invitations_for_user(
|
||||||
updated_at
|
updated_at
|
||||||
FROM
|
FROM
|
||||||
public.af_workspace_invitation
|
public.af_workspace_invitation
|
||||||
WHERE af_workspace_invitation.invitee = (SELECT uid FROM public.af_user WHERE uuid = $1)
|
WHERE af_workspace_invitation.invitee_email = (SELECT email FROM public.af_user WHERE uuid = $1)
|
||||||
AND ($2::SMALLINT IS NULL OR status = $2)
|
AND ($2::SMALLINT IS NULL OR status = $2)
|
||||||
"#,
|
"#,
|
||||||
invitee_uuid,
|
invitee_uuid,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use super::grant::Grant;
|
use super::grant::Grant;
|
||||||
use crate::params::{
|
use crate::params::{
|
||||||
AdminDeleteUserParams, AdminUserParams, CreateSSOProviderParams, GenerateLinkParams,
|
AdminDeleteUserParams, AdminUserParams, CreateSSOProviderParams, GenerateLinkParams,
|
||||||
GenerateLinkResponse, MagicLinkParams,
|
GenerateLinkResponse, InviteUserParams, MagicLinkParams,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use gotrue_entity::dto::{
|
use gotrue_entity::dto::{
|
||||||
|
|
@ -139,12 +139,14 @@ impl Client {
|
||||||
pub async fn admin_list_user(
|
pub async fn admin_list_user(
|
||||||
&self,
|
&self,
|
||||||
access_token: &str,
|
access_token: &str,
|
||||||
|
filter: Option<&str>,
|
||||||
) -> Result<AdminListUsersResponse, GoTrueError> {
|
) -> Result<AdminListUsersResponse, GoTrueError> {
|
||||||
let url = format!("{}/admin/users", self.base_url);
|
let url = format!("{}/admin/users", self.base_url);
|
||||||
let resp = self
|
let mut req = self.http_client_with_auth(Method::GET, &url, access_token);
|
||||||
.http_client_with_auth(Method::GET, &url, access_token)
|
if let Some(filter) = filter {
|
||||||
.send()
|
req = req.query(&[("filter", filter)]);
|
||||||
.await?;
|
}
|
||||||
|
let resp = req.send().await?;
|
||||||
to_gotrue_result(resp).await
|
to_gotrue_result(resp).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,6 +193,20 @@ impl Client {
|
||||||
to_gotrue_result(resp).await
|
to_gotrue_result(resp).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn admin_invite_user(
|
||||||
|
&self,
|
||||||
|
access_token: &str,
|
||||||
|
admin_user_params: &InviteUserParams,
|
||||||
|
) -> Result<User, GoTrueError> {
|
||||||
|
let url = format!("{}/invite", self.base_url);
|
||||||
|
let resp = self
|
||||||
|
.http_client_with_auth(Method::POST, &url, access_token)
|
||||||
|
.json(&admin_user_params)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
to_gotrue_result(resp).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn admin_add_user(
|
pub async fn admin_add_user(
|
||||||
&self,
|
&self,
|
||||||
access_token: &str,
|
access_token: &str,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@ pub struct AdminDeleteUserParams {
|
||||||
pub should_soft_delete: bool,
|
pub should_soft_delete: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Serialize)]
|
||||||
|
pub struct InviteUserParams {
|
||||||
|
pub email: String,
|
||||||
|
pub data: serde_json::Value,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct AdminUserParams {
|
pub struct AdminUserParams {
|
||||||
pub aud: String,
|
pub aud: String,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use crate::middleware::access_control_mw::MiddlewareAccessControlTransform;
|
||||||
use crate::middleware::metrics_mw::MetricsMiddleware;
|
use crate::middleware::metrics_mw::MetricsMiddleware;
|
||||||
use crate::middleware::request_id::RequestIdMiddleware;
|
use crate::middleware::request_id::RequestIdMiddleware;
|
||||||
use crate::self_signed::create_self_signed_certificate;
|
use crate::self_signed::create_self_signed_certificate;
|
||||||
use crate::state::{AppMetrics, AppState, UserCache};
|
use crate::state::{AppMetrics, AppState, GoTrueAdmin, UserCache};
|
||||||
use actix::Actor;
|
use actix::Actor;
|
||||||
use actix_identity::IdentityMiddleware;
|
use actix_identity::IdentityMiddleware;
|
||||||
use actix_session::storage::RedisSessionStore;
|
use actix_session::storage::RedisSessionStore;
|
||||||
|
|
@ -182,7 +182,7 @@ pub async fn init_state(config: &Config, rt_cmd_tx: RTCommandSender) -> Result<A
|
||||||
// Gotrue
|
// Gotrue
|
||||||
info!("Connecting to GoTrue...");
|
info!("Connecting to GoTrue...");
|
||||||
let gotrue_client = get_gotrue_client(&config.gotrue).await?;
|
let gotrue_client = get_gotrue_client(&config.gotrue).await?;
|
||||||
setup_admin_account(&gotrue_client, &pg_pool, &config.gotrue).await?;
|
let gotrue_admin = setup_admin_account(&gotrue_client, &pg_pool, &config.gotrue).await?;
|
||||||
|
|
||||||
// Redis
|
// Redis
|
||||||
info!("Connecting to Redis...");
|
info!("Connecting to Redis...");
|
||||||
|
|
@ -244,6 +244,7 @@ pub async fn init_state(config: &Config, rt_cmd_tx: RTCommandSender) -> Result<A
|
||||||
pg_listeners,
|
pg_listeners,
|
||||||
access_control,
|
access_control,
|
||||||
metrics,
|
metrics,
|
||||||
|
gotrue_admin,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,9 +252,14 @@ async fn setup_admin_account(
|
||||||
gotrue_client: &gotrue::api::Client,
|
gotrue_client: &gotrue::api::Client,
|
||||||
pg_pool: &PgPool,
|
pg_pool: &PgPool,
|
||||||
gotrue_setting: &GoTrueSetting,
|
gotrue_setting: &GoTrueSetting,
|
||||||
) -> Result<(), Error> {
|
) -> Result<GoTrueAdmin, Error> {
|
||||||
let admin_email = gotrue_setting.admin_email.as_str();
|
let admin_email = gotrue_setting.admin_email.as_str();
|
||||||
let password = gotrue_setting.admin_password.as_str();
|
let password = gotrue_setting.admin_password.as_str();
|
||||||
|
let gotrue_admin = GoTrueAdmin {
|
||||||
|
admin_email: admin_email.to_owned(),
|
||||||
|
password: admin_email.to_owned().into(),
|
||||||
|
};
|
||||||
|
|
||||||
let res_resp = gotrue_client.sign_up(admin_email, password, None).await;
|
let res_resp = gotrue_client.sign_up(admin_email, password, None).await;
|
||||||
match res_resp {
|
match res_resp {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
@ -261,7 +267,7 @@ async fn setup_admin_account(
|
||||||
match (err.code, err.msg.as_str()) {
|
match (err.code, err.msg.as_str()) {
|
||||||
(400, "User already registered") => {
|
(400, "User already registered") => {
|
||||||
info!("Admin user already registered");
|
info!("Admin user already registered");
|
||||||
Ok(())
|
Ok(gotrue_admin)
|
||||||
},
|
},
|
||||||
_ => Err(err.into()),
|
_ => Err(err.into()),
|
||||||
}
|
}
|
||||||
|
|
@ -279,7 +285,7 @@ async fn setup_admin_account(
|
||||||
match admin_user.role.as_str() {
|
match admin_user.role.as_str() {
|
||||||
"supabase_admin" => {
|
"supabase_admin" => {
|
||||||
info!("Admin user already created and set role to supabase_admin");
|
info!("Admin user already created and set role to supabase_admin");
|
||||||
Ok(())
|
Ok(gotrue_admin)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let user_id = admin_user.id.parse::<uuid::Uuid>()?;
|
let user_id = admin_user.id.parse::<uuid::Uuid>()?;
|
||||||
|
|
@ -298,7 +304,7 @@ async fn setup_admin_account(
|
||||||
assert_eq!(result.rows_affected(), 1);
|
assert_eq!(result.rows_affected(), 1);
|
||||||
info!("Admin user created and set role to supabase_admin");
|
info!("Admin user created and set role to supabase_admin");
|
||||||
|
|
||||||
Ok(())
|
Ok(gotrue_admin)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use app_error::AppError;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tokio::io::{self, AsyncRead, ReadBuf};
|
use tokio::io::{self, AsyncRead, ReadBuf};
|
||||||
|
|
@ -42,3 +43,19 @@ where
|
||||||
&self.reader
|
&self.reader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn check_user_exists(
|
||||||
|
admin_token: &str,
|
||||||
|
gotrue_client: &gotrue::api::Client,
|
||||||
|
email: &str,
|
||||||
|
) -> Result<bool, AppError> {
|
||||||
|
let users = gotrue_client
|
||||||
|
.admin_list_user(admin_token, Some(email))
|
||||||
|
.await?;
|
||||||
|
for user in users.users {
|
||||||
|
if user.email == email {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ use database::workspace::{
|
||||||
change_workspace_icon, delete_from_workspace, delete_workspace_members, get_invitation_by_id,
|
change_workspace_icon, delete_from_workspace, delete_workspace_members, get_invitation_by_id,
|
||||||
insert_user_workspace, insert_workspace_invitation, rename_workspace, select_all_user_workspaces,
|
insert_user_workspace, insert_workspace_invitation, rename_workspace, select_all_user_workspaces,
|
||||||
select_workspace, select_workspace_invitations_for_user, select_workspace_member_list,
|
select_workspace, select_workspace_invitations_for_user, select_workspace_member_list,
|
||||||
update_updated_at_of_workspace, update_workspace_invitation_set_invited, upsert_workspace_member,
|
update_updated_at_of_workspace, update_workspace_invitation_set_status_accepted,
|
||||||
upsert_workspace_member_with_txn,
|
upsert_workspace_member, upsert_workspace_member_with_txn,
|
||||||
};
|
};
|
||||||
use database_entity::dto::{
|
use database_entity::dto::{
|
||||||
AFAccessLevel, AFRole, AFWorkspace, AFWorkspaceInvitation, AFWorkspaceInvitationStatus,
|
AFAccessLevel, AFRole, AFWorkspace, AFWorkspaceInvitation, AFWorkspaceInvitationStatus,
|
||||||
|
|
@ -144,10 +144,13 @@ pub async fn accept_workspace_invite(
|
||||||
invite_id: &Uuid,
|
invite_id: &Uuid,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
let mut txn = pg_pool.begin().await?;
|
let mut txn = pg_pool.begin().await?;
|
||||||
update_workspace_invitation_set_invited(&mut txn, user_uuid, invite_id).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?;
|
let inv = get_invitation_by_id(&mut txn, invite_id).await?;
|
||||||
|
let invited_uid = inv
|
||||||
|
.invitee_uid
|
||||||
|
.ok_or_else(|| AppError::Internal(anyhow::anyhow!("Invitee uid is missing for {:?}", inv)))?;
|
||||||
workspace_access_control
|
workspace_access_control
|
||||||
.insert_role(&inv.invitee_uid, &inv.workspace_id, inv.role)
|
.insert_role(&invited_uid, &inv.workspace_id, inv.role)
|
||||||
.await?;
|
.await?;
|
||||||
txn.commit().await?;
|
txn.commit().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
28
src/state.rs
28
src/state.rs
|
|
@ -4,6 +4,8 @@ use crate::biz::pg_listener::PgListeners;
|
||||||
|
|
||||||
use crate::config::config::Config;
|
use crate::config::config::Config;
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
|
use gotrue::grant::{Grant, PasswordGrant};
|
||||||
|
use secrecy::{ExposeSecret, Secret};
|
||||||
|
|
||||||
use crate::api::metrics::RequestMetrics;
|
use crate::api::metrics::RequestMetrics;
|
||||||
use crate::biz::casbin::access_control::AccessControl;
|
use crate::biz::casbin::access_control::AccessControl;
|
||||||
|
|
@ -40,6 +42,7 @@ pub struct AppState {
|
||||||
pub pg_listeners: Arc<PgListeners>,
|
pub pg_listeners: Arc<PgListeners>,
|
||||||
pub access_control: AccessControl,
|
pub access_control: AccessControl,
|
||||||
pub metrics: AppMetrics,
|
pub metrics: AppMetrics,
|
||||||
|
pub gotrue_admin: GoTrueAdmin,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
|
|
@ -132,3 +135,28 @@ impl AppMetrics {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GoTrueAdmin {
|
||||||
|
pub admin_email: String,
|
||||||
|
pub password: Secret<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GoTrueAdmin {
|
||||||
|
pub fn new(admin_email: String, password: String) -> Self {
|
||||||
|
Self {
|
||||||
|
admin_email,
|
||||||
|
password: password.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn token(&self, client: &gotrue::api::Client) -> Result<String, AppError> {
|
||||||
|
let token = client
|
||||||
|
.token(&Grant::Password(PasswordGrant {
|
||||||
|
email: self.admin_email.clone(),
|
||||||
|
password: self.password.expose_secret().clone(),
|
||||||
|
}))
|
||||||
|
.await?;
|
||||||
|
Ok(token.access_token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ async fn admin_user_create_list_edit_delete() {
|
||||||
|
|
||||||
// list users
|
// list users
|
||||||
let users = gotrue_client
|
let users = gotrue_client
|
||||||
.admin_list_user(&admin_token.access_token)
|
.admin_list_user(&admin_token.access_token, None)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.users;
|
.users;
|
||||||
|
|
@ -94,7 +94,7 @@ async fn admin_user_create_list_edit_delete() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let users = gotrue_client
|
let users = gotrue_client
|
||||||
.admin_list_user(&admin_token.access_token)
|
.admin_list_user(&admin_token.access_token, None)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.users;
|
.users;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue