Skip to content

Commit

Permalink
chore(user/profile-validate): migrate ops & refs
Browse files Browse the repository at this point in the history
  • Loading branch information
ABCxFF committed Dec 21, 2024
1 parent 1ffa3f3 commit 9545b63
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 17 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/api/identity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition.workspace = true
rivet-convert.workspace = true
api-helper.workspace = true
async-trait = "0.1"
chirp-workflow.workspace = true
chirp-client.workspace = true
rivet-operation.workspace = true
futures-util = "0.3"
Expand Down Expand Up @@ -50,11 +51,11 @@ token-create.workspace = true
token-get.workspace = true
token-revoke.workspace = true
upload-prepare.workspace = true
user.workspace = true
user-avatar-upload-complete.workspace = true
user-get.workspace = true
user-identity-get.workspace = true
user-pending-delete-toggle.workspace = true
user-profile-validate.workspace = true
rivet-config.workspace = true
rivet-env.workspace = true

Expand Down
11 changes: 5 additions & 6 deletions packages/api/identity/src/route/identities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,12 @@ pub async fn validate_profile(
"invalid parameter account_number`"
);

let res = op!([ctx] user_profile_validate {
user_id: Some(user_ent.user_id.into()),
let res = (*ctx).op(::user::ops::profile_validate::Input {
user_id: user_ent.user_id,
display_name: body.display_name.clone(),
account_number:
body.account_number
.map(|n| n.api_try_into())
.transpose()?,
account_number: body.account_number
.map(|n| n.api_try_into())
.transpose()?,
bio: body.bio.clone(),
})
.await?;
Expand Down
1 change: 1 addition & 0 deletions packages/services/user/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ linode.workspace = true
rivet-config.workspace = true
rivet-operation.workspace = true
token-create.workspace = true
user-get.workspace = true

[dependencies.sqlx]
workspace = true
Expand Down
3 changes: 2 additions & 1 deletion packages/services/user/src/ops/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod profile_validate;
pub mod resolve_display_name;
pub mod team_list;
pub mod resolve_email;
pub mod team_list;
pub mod token_create;
109 changes: 109 additions & 0 deletions packages/services/user/src/ops/profile_validate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use chirp_workflow::prelude::*;
use rivet_operation::prelude::common;

#[derive(Debug)]
pub struct Input {
pub user_id: Uuid,
pub display_name: Option<String>,
pub account_number: Option<u32>,
pub bio: Option<String>,
}

#[derive(Debug)]
pub struct Output {
pub errors: Vec<common::ValidationError>,
}


#[operation]
pub async fn profile_validate(
ctx: &OperationCtx,
input: &Input
) -> GlobalResult<Output> {
let mut errors = Vec::new();

// Validate display name
if let Some(display_name) = &input.display_name {
if display_name.is_empty() {
errors.push(util::err_path!["display-name", "too-short"]);
} else if display_name.len() > util::check::MAX_DISPLAY_NAME_LEN {
errors.push(util::err_path!["display-name", "too-long"]);
}

if !util::check::display_name(display_name) {
errors.push(util::err_path!["display-name", "invalid"]);
}
}

// Validate account number
if let Some(account_number) = &input.account_number {
if *account_number < 1 || *account_number > 9999 {
errors.push(util::err_path!["account-number-invalid"]);
}
}

// Validate biography
if let Some(bio) = &input.bio {
if bio.len() > util::check::MAX_BIOGRAPHY_LEN {
errors.push(util::err_path!["bio", "too-long"]);
}

if !util::check::biography(bio) {
errors.push(util::err_path!["bio", "invalid"]);
}
}

// Only validate handle uniqueness if at least one of the two handle components is given
if input.display_name.is_some() || input.account_number.is_some() {
// If either the display name or account number are missing, fetch them from the given user
let (display_name, account_number) =
if input.display_name.is_none() || input.account_number.is_none() {
let users_res = op!([ctx] user_get {
user_ids: vec![input.user_id.into()],
})
.await?;

let user = users_res.users.first();
let user = unwrap_ref!(user, "user not found");

(
input.display_name
.clone()
.unwrap_or(user.display_name.clone()),
input.account_number.unwrap_or(user.account_number),
)
} else {
(
unwrap_ref!(input.display_name).clone(),
*unwrap_ref!(input.account_number),
)
};

// Find user by handle
let (user_exists,) = sql_fetch_one!(
[ctx, (bool,)]
"
SELECT EXISTS (
SELECT 1
FROM db_user.users
WHERE display_name = $1 and account_number = $2
)
",
display_name,
account_number as i64,
)
.await?;

// Validate handle uniqueness
if user_exists {
errors.push(util::err_path!["handle-not-unique"]);
}
}

Ok(Output {
errors: errors
.into_iter()
.map(|path| common::ValidationError { path })
.collect::<Vec<_>>(),
})
}
1 change: 0 additions & 1 deletion packages/services/user/worker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ upload-list-for-user.workspace = true
user.workspace = true
user-get.workspace = true
user-identity-delete.workspace = true
user-profile-validate.workspace = true
rivet-config.workspace = true

[dev-dependencies]
Expand Down
15 changes: 9 additions & 6 deletions packages/services/user/worker/src/workers/profile_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ async fn worker(ctx: &OperationContext<user::msg::profile_set::Message>) -> Glob
ensure!(!query_components.is_empty());

// Validate profile
let validation_res = op!([ctx] user_profile_validate {
user_id: body.user_id,
display_name: display_name.clone(),
account_number: *account_number,
bio: bio.clone()
})
let validation_res = chirp_workflow::compat::op(
&ctx,
::user::ops::profile_validate::Input {
user_id: user_id.as_uuid(),
display_name: display_name.clone(),
account_number: *account_number,
bio: bio.clone()
},
)
.await?;
if !validation_res.errors.is_empty() {
tracing::warn!(errors = ?validation_res.errors, "validation errors");
Expand Down

0 comments on commit 9545b63

Please sign in to comment.