Skip to content

Commit f129825

Browse files
committed
feat(user/workflows): profile set signal
1 parent 9e1d115 commit f129825

File tree

3 files changed

+167
-3
lines changed

3 files changed

+167
-3
lines changed

packages/api/identity/src/route/identities.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,22 @@ pub async fn update_profile(
194194
"invalid parameter account_number`"
195195
);
196196

197-
msg!([ctx] user::msg::profile_set(user_ent.user_id) -> user::msg::update {
198-
user_id: Some(user_ent.user_id.into()),
197+
let mut sub = ctx
198+
.subscribe::<::user::workflows::user::ProfileSetStatus>(("user_id", user_ent.user_id))
199+
.await?;
200+
201+
ctx.signal(::user::workflows::user::ProfileSet {
199202
display_name: body.display_name.clone(),
200203
account_number: body.account_number.map(|n| n.api_try_into()).transpose()?,
201204
bio: body.bio.clone(),
202205
})
206+
.tag("user_id", user_ent.user_id)
207+
.send()
203208
.await?;
204-
209+
210+
let status_msg = sub.next().await?;
211+
ensure!(status_msg.res.is_ok(), "bad profile set request");
212+
205213
Ok(serde_json::json!({}))
206214
}
207215

packages/services/pegboard/src/workflows/client.rs

+1
Original file line numberDiff line numberDiff line change
@@ -648,3 +648,4 @@ join_signal!(Main {
648648
Undrain,
649649
Destroy,
650650
});
651+

packages/services/user/src/workflows/user/mod.rs

+155
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,30 @@ pub async fn user(ctx: &mut WorkflowCtx, input: &Input) -> GlobalResult<()> {
5555
.send()
5656
.await?;
5757
},
58+
Main::ProfileSet(sig) => {
59+
let res = ctx.activity(ProfileSetInput {
60+
user_id,
61+
display_name: sig.display_name,
62+
account_number: sig.account_number,
63+
bio: sig.bio
64+
}).await?;
65+
66+
ctx.msg(ProfileSetStatus { res: res.clone() })
67+
.tag("user_id", user_id)
68+
.send()
69+
.await?;
70+
71+
if res.is_ok() {
72+
ctx.activity(PublishProfileSetAnalyticsInput {
73+
user_id
74+
}).await?;
75+
76+
ctx.msg(Update {})
77+
.tag("user_id", user_id)
78+
.send()
79+
.await?;
80+
}
81+
},
5882
Main::Delete(_) => {
5983
return Ok(Loop::Break(()));
6084
},
@@ -117,6 +141,121 @@ async fn admin_set(ctx: &ActivityCtx, input: &AdminSetInput) -> GlobalResult<()>
117141
Ok(())
118142
}
119143

144+
// ProfileSet
145+
#[derive(Debug, Clone, Serialize, Deserialize, Hash)]
146+
struct ProfileSetInput {
147+
user_id: Uuid,
148+
display_name: Option<String>,
149+
account_number: Option<u32>,
150+
bio: Option<String>,
151+
}
152+
153+
#[derive(Debug, Clone, Serialize, Deserialize, Hash)]
154+
pub enum ProfileSetError {
155+
ValidationFailure,
156+
MissingParameters,
157+
}
158+
159+
#[activity(ProfileSetActivity)]
160+
async fn profile_set(ctx: &ActivityCtx, input: &ProfileSetInput) -> GlobalResult<Result<(), ProfileSetError>> {
161+
let mut query_components = Vec::new();
162+
163+
// Check if each component exists
164+
if input.display_name.is_some() {
165+
query_components.push(format!("display_name = ${}", query_components.len() + 2));
166+
}
167+
if input.account_number.is_some() {
168+
query_components.push(format!("account_number = ${}", query_components.len() + 2));
169+
}
170+
if input.bio.is_some() {
171+
query_components.push(format!("bio = ${}", query_components.len() + 2));
172+
}
173+
174+
let val = !query_components.is_empty();
175+
if !val {
176+
return Ok(Err(ProfileSetError::MissingParameters));
177+
}
178+
179+
let validation_res = ctx.op(crate::ops::profile_validate::Input {
180+
user_id: input.user_id,
181+
display_name: input.display_name.clone(),
182+
account_number: input.account_number,
183+
bio: input.bio.clone()
184+
})
185+
.await?;
186+
187+
if !validation_res.errors.is_empty() {
188+
tracing::warn!(errors = ?validation_res.errors, "validation errors");
189+
190+
return Ok(Err(ProfileSetError::ValidationFailure));
191+
}
192+
193+
ctx.cache().purge("user", [input.user_id]).await?;
194+
195+
// Build query
196+
let built_query = query_components.join(",");
197+
let query_string = format!(
198+
"UPDATE db_user.users SET {} WHERE user_id = $1",
199+
built_query
200+
);
201+
202+
// TODO: Convert this to sql_execute! macro
203+
let query = sqlx::query(&query_string).bind(input.user_id);
204+
205+
// Bind display name
206+
let query = if let Some(display_name) = &input.display_name {
207+
query.bind(display_name)
208+
} else {
209+
query
210+
};
211+
212+
// Bind account number
213+
let query = if let Some(account_number) = input.account_number {
214+
query.bind(account_number as i64)
215+
} else {
216+
query
217+
};
218+
219+
// Bind bio
220+
let query = if let Some(bio) = &input.bio {
221+
query.bind(util::format::biography(bio))
222+
} else {
223+
query
224+
};
225+
226+
query.execute(&ctx.crdb().await?).await?;
227+
228+
Ok(Ok(()))
229+
}
230+
231+
#[derive(Debug, Clone, Serialize, Deserialize, Hash)]
232+
struct PublishProfileSetAnalyticsInput {
233+
user_id: Uuid
234+
}
235+
236+
#[activity(PublishProfileSetAnalytics)]
237+
async fn publish_profile_set_analytics(
238+
ctx: &ActivityCtx,
239+
input: &PublishProfileSetAnalyticsInput
240+
) -> GlobalResult<()> {
241+
msg!([ctx] analytics::msg::event_create() {
242+
events: vec![
243+
analytics::msg::event_create::Event {
244+
event_id: Some(Uuid::new_v4().into()),
245+
name: "user.profile_set".into(),
246+
properties_json: Some(serde_json::to_string(&json!({
247+
"user_id": input.user_id.to_string()
248+
}))?),
249+
..Default::default()
250+
},
251+
],
252+
})
253+
.await?;
254+
255+
Ok(())
256+
}
257+
258+
120259
// Creation
121260
#[derive(Debug, Clone, Serialize, Deserialize, Hash)]
122261
struct InsertDbInput {
@@ -362,14 +501,30 @@ pub struct Update {}
362501
#[message("user_delete_complete")]
363502
pub struct DeleteComplete {}
364503

504+
#[message("user_event")]
505+
pub struct Event {}
506+
507+
#[message("user_profile_set_status")]
508+
pub struct ProfileSetStatus {
509+
pub res: Result<(), ProfileSetError>,
510+
}
511+
365512
#[signal("user_admin_set")]
366513
pub struct AdminSet {}
367514

515+
#[signal("user_profile_set")]
516+
pub struct ProfileSet {
517+
pub display_name: Option<String>,
518+
pub account_number: Option<u32>,
519+
pub bio: Option<String>,
520+
}
521+
368522
#[signal("user_delete")]
369523
pub struct Delete {}
370524

371525
join_signal!(Main {
372526
AdminSet,
527+
ProfileSet,
373528
Delete,
374529
});
375530

0 commit comments

Comments
 (0)