Compare commits

...

2 Commits

Author SHA1 Message Date
Mathijs van Veluw dec3a9603a
Update crates and web-vault to v2025.1.0 (#5368) 1 week ago
Mathijs van Veluw 86aaf27659
Prevent new users/members to be stored in db when invite fails (#5350) 1 week ago
  1. 100
      Cargo.lock
  2. 4
      Cargo.toml
  3. 4
      docker/DockerSettings.yaml
  4. 12
      docker/Dockerfile.alpine
  5. 12
      docker/Dockerfile.debian
  6. 131
      src/api/core/organizations.rs
  7. 37
      src/api/core/public.rs

100
Cargo.lock

@ -176,7 +176,7 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18"
dependencies = [
"event-listener 5.3.1",
"event-listener 5.4.0",
"event-listener-strategy",
"pin-project-lite",
]
@ -194,7 +194,7 @@ dependencies = [
"async-task",
"blocking",
"cfg-if",
"event-listener 5.3.1",
"event-listener 5.4.0",
"futures-lite",
"rustix",
"tracing",
@ -275,9 +275,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
[[package]]
name = "async-trait"
version = "0.1.84"
version = "0.1.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0"
checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
dependencies = [
"proc-macro2",
"quote",
@ -721,6 +721,37 @@ dependencies = [
"powerfmt",
]
[[package]]
name = "derive_builder"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_builder_macro"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn",
]
[[package]]
name = "devise"
version = "0.4.2"
@ -948,9 +979,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "event-listener"
version = "5.3.1"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba"
checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae"
dependencies = [
"concurrent-queue",
"parking",
@ -963,7 +994,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
dependencies = [
"event-listener 5.3.1",
"event-listener 5.4.0",
"pin-project-lite",
]
@ -1268,17 +1299,18 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]]
name = "handlebars"
version = "6.2.0"
version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315"
checksum = "3d6b224b95c1e668ac0270325ad563b2eef1469fbbb8959bc7c692c844b813d9"
dependencies = [
"derive_builder",
"log",
"num-order",
"pest",
"pest_derive",
"serde",
"serde_json",
"thiserror 1.0.69",
"thiserror 2.0.9",
"walkdir",
]
@ -1922,9 +1954,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "litemap"
@ -2437,9 +2469,9 @@ dependencies = [
[[package]]
name = "phf"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_macros",
"phf_shared",
@ -2447,9 +2479,9 @@ dependencies = [
[[package]]
name = "phf_codegen"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared",
@ -2457,9 +2489,9 @@ dependencies = [
[[package]]
name = "phf_generator"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared",
"rand",
@ -2467,9 +2499,9 @@ dependencies = [
[[package]]
name = "phf_macros"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
dependencies = [
"phf_generator",
"phf_shared",
@ -2480,9 +2512,9 @@ dependencies = [
[[package]]
name = "phf_shared"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
"siphasher",
]
@ -2495,9 +2527,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "pin-project-lite"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
@ -3005,9 +3037,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustix"
version = "0.38.42"
version = "0.38.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
dependencies = [
"bitflags",
"errno",
@ -3162,9 +3194,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.13.0"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5"
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
dependencies = [
"core-foundation-sys",
"libc",
@ -3208,9 +3240,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.134"
version = "1.0.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
dependencies = [
"itoa",
"memchr",
@ -3309,9 +3341,9 @@ dependencies = [
[[package]]
name = "siphasher"
version = "0.3.11"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "slab"
@ -3404,9 +3436,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.94"
version = "2.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3"
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
dependencies = [
"proc-macro2",
"quote",

4
Cargo.toml

@ -71,7 +71,7 @@ tokio = { version = "1.42.0", features = ["rt-multi-thread", "fs", "io-util", "p
# A generic serialization/deserialization framework
serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.134"
serde_json = "1.0.135"
# A safe, extensible ORM and Query builder
diesel = { version = "2.2.6", features = ["chrono", "r2d2", "numeric"] }
@ -120,7 +120,7 @@ percent-encoding = "2.3.1" # URL encoding library used for URL's in the emails
email_address = "0.2.9"
# HTML Template library
handlebars = { version = "6.2.0", features = ["dir_source"] }
handlebars = { version = "6.3.0", features = ["dir_source"] }
# HTTP client (Used for favicons, version check, DUO and HIBP API)
reqwest = { version = "0.12.12", features = ["native-tls-alpn", "stream", "json", "gzip", "brotli", "socks", "cookies"] }

4
docker/DockerSettings.yaml

@ -1,6 +1,6 @@
---
vault_version: "v2024.12.0"
vault_image_digest: "sha256:75a537ea5a4077bf5042b40094b7aa12cf53fecbb5483a1547b544dd6397c5fb"
vault_version: "v2025.1.0"
vault_image_digest: "sha256:72d636334b4ad6fe9ba1d12e0cda562cd31772cf28772f6b2fe4121a537b72a8"
# Cross Compile Docker Helper Scripts v1.6.1
# We use the linux/amd64 platform shell scripts since there is no difference between the different platform scripts
# https://github.com/tonistiigi/xx | https://hub.docker.com/r/tonistiigi/xx/tags

12
docker/Dockerfile.alpine

@ -19,15 +19,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to.
# - From the command line:
# $ docker pull docker.io/vaultwarden/web-vault:v2024.12.0
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2024.12.0
# [docker.io/vaultwarden/web-vault@sha256:75a537ea5a4077bf5042b40094b7aa12cf53fecbb5483a1547b544dd6397c5fb]
# $ docker pull docker.io/vaultwarden/web-vault:v2025.1.0
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.1.0
# [docker.io/vaultwarden/web-vault@sha256:72d636334b4ad6fe9ba1d12e0cda562cd31772cf28772f6b2fe4121a537b72a8]
#
# - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:75a537ea5a4077bf5042b40094b7aa12cf53fecbb5483a1547b544dd6397c5fb
# [docker.io/vaultwarden/web-vault:v2024.12.0]
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:72d636334b4ad6fe9ba1d12e0cda562cd31772cf28772f6b2fe4121a537b72a8
# [docker.io/vaultwarden/web-vault:v2025.1.0]
#
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:75a537ea5a4077bf5042b40094b7aa12cf53fecbb5483a1547b544dd6397c5fb AS vault
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:72d636334b4ad6fe9ba1d12e0cda562cd31772cf28772f6b2fe4121a537b72a8 AS vault
########################## ALPINE BUILD IMAGES ##########################
## NOTE: The Alpine Base Images do not support other platforms then linux/amd64

12
docker/Dockerfile.debian

@ -19,15 +19,15 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to.
# - From the command line:
# $ docker pull docker.io/vaultwarden/web-vault:v2024.12.0
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2024.12.0
# [docker.io/vaultwarden/web-vault@sha256:75a537ea5a4077bf5042b40094b7aa12cf53fecbb5483a1547b544dd6397c5fb]
# $ docker pull docker.io/vaultwarden/web-vault:v2025.1.0
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.1.0
# [docker.io/vaultwarden/web-vault@sha256:72d636334b4ad6fe9ba1d12e0cda562cd31772cf28772f6b2fe4121a537b72a8]
#
# - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:75a537ea5a4077bf5042b40094b7aa12cf53fecbb5483a1547b544dd6397c5fb
# [docker.io/vaultwarden/web-vault:v2024.12.0]
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:72d636334b4ad6fe9ba1d12e0cda562cd31772cf28772f6b2fe4121a537b72a8
# [docker.io/vaultwarden/web-vault:v2025.1.0]
#
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:75a537ea5a4077bf5042b40094b7aa12cf53fecbb5483a1547b544dd6397c5fb AS vault
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:72d636334b4ad6fe9ba1d12e0cda562cd31772cf28772f6b2fe4121a537b72a8 AS vault
########################## Cross Compile Docker Helper Scripts ##########################
## We use the linux/amd64 no matter which Build Platform, since these are all bash scripts

131
src/api/core/organizations.rs

@ -895,6 +895,7 @@ async fn send_invite(org_id: &str, data: Json<InviteData>, headers: AdminHeaders
data.access_all = true;
}
let mut user_created: bool = false;
for email in data.emails.iter() {
let mut user_org_status = UserOrgStatus::Invited as i32;
let user = match User::find_by_mail(email, &mut conn).await {
@ -908,13 +909,13 @@ async fn send_invite(org_id: &str, data: Json<InviteData>, headers: AdminHeaders
}
if !CONFIG.mail_enabled() {
let invitation = Invitation::new(email);
invitation.save(&mut conn).await?;
Invitation::new(email).save(&mut conn).await?;
}
let mut user = User::new(email.clone());
user.save(&mut conn).await?;
user
let mut new_user = User::new(email.clone());
new_user.save(&mut conn).await?;
user_created = true;
new_user
}
Some(user) => {
if UserOrganization::find_by_user_and_org(&user.uuid, org_id, &mut conn).await.is_some() {
@ -929,11 +930,49 @@ async fn send_invite(org_id: &str, data: Json<InviteData>, headers: AdminHeaders
}
};
let mut new_user = UserOrganization::new(user.uuid.clone(), String::from(org_id));
let mut new_member = UserOrganization::new(user.uuid.clone(), String::from(org_id));
let access_all = data.access_all;
new_user.access_all = access_all;
new_user.atype = new_type;
new_user.status = user_org_status;
new_member.access_all = access_all;
new_member.atype = new_type;
new_member.status = user_org_status;
new_member.save(&mut conn).await?;
if CONFIG.mail_enabled() {
let org_name = match Organization::find_by_uuid(org_id, &mut conn).await {
Some(org) => org.name,
None => err!("Error looking up organization"),
};
if let Err(e) = mail::send_invite(
&user,
Some(String::from(org_id)),
Some(new_member.uuid.clone()),
&org_name,
Some(headers.user.email.clone()),
)
.await
{
// Upon error delete the user, invite and org member records when needed
if user_created {
user.delete(&mut conn).await?;
} else {
new_member.delete(&mut conn).await?;
}
err!(format!("Error sending invite: {e:?} "));
};
}
log_event(
EventType::OrganizationUserInvited as i32,
&new_member.uuid.clone(),
org_id,
&headers.user.uuid,
headers.device.atype,
&headers.ip.ip,
&mut conn,
)
.await;
// If no accessAll, add the collections received
if !access_all {
@ -954,39 +993,10 @@ async fn send_invite(org_id: &str, data: Json<InviteData>, headers: AdminHeaders
}
}
new_user.save(&mut conn).await?;
for group in data.groups.iter() {
let mut group_entry = GroupUser::new(String::from(group), new_user.uuid.clone());
let mut group_entry = GroupUser::new(String::from(group), new_member.uuid.clone());
group_entry.save(&mut conn).await?;
}
log_event(
EventType::OrganizationUserInvited as i32,
&new_user.uuid,
org_id,
&headers.user.uuid,
headers.device.atype,
&headers.ip.ip,
&mut conn,
)
.await;
if CONFIG.mail_enabled() {
let org_name = match Organization::find_by_uuid(org_id, &mut conn).await {
Some(org) => org.name,
None => err!("Error looking up organization"),
};
mail::send_invite(
&user,
Some(String::from(org_id)),
Some(new_user.uuid),
&org_name,
Some(headers.user.email.clone()),
)
.await?;
}
}
Ok(())
@ -1064,7 +1074,7 @@ async fn _reinvite_user(org_id: &str, user_org: &str, invited_by_email: &str, co
let invitation = Invitation::new(&user.email);
invitation.save(conn).await?;
} else {
let _ = Invitation::take(&user.email, conn).await;
Invitation::take(&user.email, conn).await;
let mut user_org = user_org;
user_org.status = UserOrgStatus::Accepted as i32;
user_org.save(conn).await?;
@ -2026,6 +2036,9 @@ struct OrgImportData {
users: Vec<OrgImportUserData>,
}
/// This function seems to be deprected
/// It is only used with older directory connectors
/// TODO: Cleanup Tech debt
#[post("/organizations/<org_id>/import", data = "<data>")]
async fn import(org_id: &str, data: Json<OrgImportData>, headers: Headers, mut conn: DbConn) -> EmptyResult {
let data = data.into_inner();
@ -2069,23 +2082,10 @@ async fn import(org_id: &str, data: Json<OrgImportData>, headers: Headers, mut c
UserOrgStatus::Accepted as i32 // Automatically mark user as accepted if no email invites
};
let mut new_org_user = UserOrganization::new(user.uuid.clone(), String::from(org_id));
new_org_user.access_all = false;
new_org_user.atype = UserOrgType::User as i32;
new_org_user.status = user_org_status;
new_org_user.save(&mut conn).await?;
log_event(
EventType::OrganizationUserInvited as i32,
&new_org_user.uuid,
org_id,
&headers.user.uuid,
headers.device.atype,
&headers.ip.ip,
&mut conn,
)
.await;
let mut new_member = UserOrganization::new(user.uuid.clone(), String::from(org_id));
new_member.access_all = false;
new_member.atype = UserOrgType::User as i32;
new_member.status = user_org_status;
if CONFIG.mail_enabled() {
let org_name = match Organization::find_by_uuid(org_id, &mut conn).await {
@ -2096,12 +2096,27 @@ async fn import(org_id: &str, data: Json<OrgImportData>, headers: Headers, mut c
mail::send_invite(
&user,
Some(String::from(org_id)),
Some(new_org_user.uuid),
Some(new_member.uuid.clone()),
&org_name,
Some(headers.user.email.clone()),
)
.await?;
}
// Save the member after sending an email
// If sending fails the member will not be saved to the database, and will not result in the admin needing to reinvite the users manually
new_member.save(&mut conn).await?;
log_event(
EventType::OrganizationUserInvited as i32,
&new_member.uuid,
org_id,
&headers.user.uuid,
headers.device.atype,
&headers.ip.ip,
&mut conn,
)
.await;
}
}
}

37
src/api/core/public.rs

@ -52,6 +52,7 @@ async fn ldap_import(data: Json<OrgImportData>, token: PublicToken, mut conn: Db
let data = data.into_inner();
for user_data in &data.members {
let mut user_created: bool = false;
if user_data.deleted {
// If user is marked for deletion and it exists, revoke it
if let Some(mut user_org) =
@ -97,9 +98,9 @@ async fn ldap_import(data: Json<OrgImportData>, token: PublicToken, mut conn: Db
new_user.save(&mut conn).await?;
if !CONFIG.mail_enabled() {
let invitation = Invitation::new(&new_user.email);
invitation.save(&mut conn).await?;
Invitation::new(&new_user.email).save(&mut conn).await?;
}
user_created = true;
new_user
}
};
@ -109,13 +110,13 @@ async fn ldap_import(data: Json<OrgImportData>, token: PublicToken, mut conn: Db
UserOrgStatus::Accepted as i32 // Automatically mark user as accepted if no email invites
};
let mut new_org_user = UserOrganization::new(user.uuid.clone(), org_id.clone());
new_org_user.set_external_id(Some(user_data.external_id.clone()));
new_org_user.access_all = false;
new_org_user.atype = UserOrgType::User as i32;
new_org_user.status = user_org_status;
let mut new_member = UserOrganization::new(user.uuid.clone(), org_id.clone());
new_member.set_external_id(Some(user_data.external_id.clone()));
new_member.access_all = false;
new_member.atype = UserOrgType::User as i32;
new_member.status = user_org_status;
new_org_user.save(&mut conn).await?;
new_member.save(&mut conn).await?;
if CONFIG.mail_enabled() {
let (org_name, org_email) = match Organization::find_by_uuid(&org_id, &mut conn).await {
@ -123,8 +124,24 @@ async fn ldap_import(data: Json<OrgImportData>, token: PublicToken, mut conn: Db
None => err!("Error looking up organization"),
};
mail::send_invite(&user, Some(org_id.clone()), Some(new_org_user.uuid), &org_name, Some(org_email))
.await?;
if let Err(e) = mail::send_invite(
&user,
Some(org_id.clone()),
Some(new_member.uuid.clone()),
&org_name,
Some(org_email),
)
.await
{
// Upon error delete the user, invite and org member records when needed
if user_created {
user.delete(&mut conn).await?;
} else {
new_member.delete(&mut conn).await?;
}
err!(format!("Error sending invite: {e:?} "));
}
}
}
}

Loading…
Cancel
Save