Working diff viewer

This commit is contained in:
ToxicMushroom 2025-04-06 01:25:35 +02:00
parent 339a20947a
commit a708d8c938
No known key found for this signature in database
3 changed files with 75 additions and 38 deletions
server/core

View file

@ -10,7 +10,7 @@ use askama::Template;
use askama_axum::IntoResponse;
use axum::extract::{Query, State};
use axum::http::Uri;
use axum::response::Response;
use axum::response::{Redirect, Response};
use axum::Extension;
use axum_extra::extract::cookie::CookieJar;
use axum_extra::extract::Form;
@ -60,6 +60,18 @@ pub(crate) struct SaveProfileQuery {
primary_email_index: u16,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct CommitSaveProfileQuery {
#[serde(rename = "account_name")]
account_name: String,
#[serde(rename = "display_name")]
display_name: String,
#[serde(rename = "emails[]")]
emails: Vec<String>,
#[serde(rename = "new_primary_mail")]
new_primary_mail: Option<String>
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct ProfileAttributes {
account_name: String,
@ -73,7 +85,9 @@ struct ProfileChangesPartialView {
menu_active_item: ProfileMenuItems,
can_rw: bool,
person: ScimPerson,
primary_mail: Option<String>,
new_attrs: ProfileAttributes,
new_primary_mail: Option<String>,
}
#[derive(Template, Clone)]
@ -109,7 +123,7 @@ pub(crate) async fn view_profile_get(
&kopid,
client_auth_info.clone(),
)
.await?;
.await?;
let time = time::OffsetDateTime::now_utc() + time::Duration::new(60, 0);
@ -149,8 +163,7 @@ pub(crate) async fn view_profile_diff_start_save_post(
state,
&kopid,
client_auth_info.clone(),
)
.await?;
).await?;
let primary_index = query
.emails_indexes
@ -166,23 +179,28 @@ pub(crate) async fn view_profile_diff_start_save_post(
value: email.to_string(),
})
.collect();
let old_primary_mail = scim_person.mails.iter()
.find(|sm| sm.primary)
.map(|sm| sm.value.clone());
let profile_view = ProfileChangesPartialView {
menu_active_item: ProfileMenuItems::UserProfile,
can_rw,
person: scim_person,
primary_mail: old_primary_mail,
new_attrs: ProfileAttributes {
account_name: query.account_name,
display_name: query.display_name,
emails: new_mails,
},
new_primary_mail: query.emails.get(primary_index).cloned(),
};
Ok((
HxPushUrl(Uri::from_static("/ui/profile/diff")),
profile_view,
)
.into_response())
).into_response())
}
pub(crate) async fn view_profile_diff_confirm_save_post(
@ -191,14 +209,14 @@ pub(crate) async fn view_profile_diff_confirm_save_post(
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
DomainInfo(domain_info): DomainInfo,
// Form must be the last parameter because it consumes the request body
Form(mut new_attrs): Form<ProfileAttributes>,
Form(query): Form<CommitSaveProfileQuery>,
) -> axum::response::Result<Response> {
let uat: UserAuthToken = state
.qe_r_ref
.handle_whoami_uat(client_auth_info.clone(), kopid.eventid)
.map_err(|op_err| HtmxError::new(&kopid, op_err, domain_info.clone()))
.await?;
dbg!(&new_attrs);
dbg!(&query);
let filter = filter_all!(f_and!([f_id(uat.uuid.to_string().as_str())]));
@ -208,24 +226,26 @@ pub(crate) async fn view_profile_diff_confirm_save_post(
client_auth_info.clone(),
uat.uuid.to_string(),
ATTR_DISPLAYNAME.to_string(),
vec![new_attrs.display_name],
vec![query.display_name],
filter.clone(),
kopid.eventid,
)
.map_err(|op_err| HtmxError::new(&kopid, op_err, domain_info.clone()))
.await?;
new_attrs
.emails
.sort_by_key(|sm| if sm.primary { 0 } else { 1 });
let email_addresses = new_attrs.emails.into_iter().map(|sm| sm.value).collect();
let mut emails = query.emails;
if let Some(primary) = query.new_primary_mail {
emails.insert(0, primary);
}
state
.qe_w_ref
.handle_setattribute(
client_auth_info.clone(),
uat.uuid.to_string(),
ATTR_MAIL.to_string(),
email_addresses,
emails,
filter.clone(),
kopid.eventid,
)
@ -266,9 +286,9 @@ pub(crate) async fn view_profile_diff_confirm_save_post(
VerifiedClientInformation(client_auth_info),
DomainInfo(domain_info),
)
.await
.await
{
Ok(pv) => Ok(pv.into_response()),
Ok(_) => Ok(Redirect::to(Urls::Profile.as_ref()).into_response()),
Err(e) => Ok(e.into_response()),
}
}
@ -331,5 +351,5 @@ pub(crate) async fn view_profile_unlock_get(
Urls::Profile.as_ref(),
display_ctx,
)
.await)
.await)
}

View file

@ -13,10 +13,15 @@ Profile Difference
<input type="hidden" name="display_name" value="(( new_attrs.display_name ))"/>
<!-- <input type="hidden" name="legal_name" value=" new_attrs.legal_name "/>-->
(% for email in new_attrs.emails %)
<input type="hidden" name="emails[]" value="(( email.value ))"/>
(% if !email.primary %)
<input type="hidden" name="emails[]" value="(( email.value ))"/>
(% endif %)
(% endfor %)
(% if let Some(new_primary_mail) = new_primary_mail %)
<input type="hidden" name="new_primary_mail" value="(( new_primary_mail ))"/>
(% endif %)
<table class="table table-bordered table-responsive">
<table class="table table-bordered overflow-x-scroll">
<thead>
<tr>
<th scope="col">Attribute</th>
@ -39,32 +44,44 @@ Profile Difference
<td class="text-break">(( new_attrs.display_name ))</td>
</tr>
(% endif %)
<!-- TODO: List new items with +, same items with . -->
<tr>
<th scope="row">Emails</th>
<td class="text-break">
<ul>
<!-- TODO: List new items with +, same items with . -->
<tr>
<th scope="row">Primary Emails</th>
<td class="text-nowrap">
(( primary_mail.clone().unwrap_or("none".to_string()) ))
</td>
<td class="text-nowrap">
(( new_primary_mail.clone().unwrap_or("none".to_string()) ))
</td>
</tr>
<tr>
<th scope="row">Secondary Emails</th>
<td class="text-break">
<ul class="ps-3">
(% for email in person.mails %)
<li>(( email.value ))</li>
(% if !email.primary %)
<li class="text-nowrap">(( email.value ))</li>
(% endif %)
(% endfor %)
</ul>
</td>
<td class="text-break">
<ul>
</ul>
</td>
<td class="text-break">
<ul class="ps-3">
(% for email in new_attrs.emails %)
<li>(( email.value ))</li>
(% if !email.primary %)
<li class="text-nowrap">(( email.value ))</li>
(% endif %)
(% endfor %)
</ul>
</td>
</tr>
</ul>
</td>
</tr>
</table>
<!-- Edit button -->
<div class="pt-4" hx-target="#user_settings_container" hx-swap="outerHTML">
(% if can_rw %)
<button class="btn btn-danger" type="button" hx-get="/ui/profile" hx-target="#user_settings_container" hx-swap="outerHTML">Discard Changes</button>
<button class="btn btn-primary" type="button" hx-post="/ui/api/user_settings/confirm_profile" hx-target="#user_settings_container" hx-swap="outerHTML">Confirm Changes</button>
<button class="btn btn-danger" type="button" hx-get="/ui/profile" hx-target="body" hx-swap="outerHTML">Discard Changes</button>
<button class="btn btn-primary" type="button" hx-post="/ui/api/user_settings/confirm_profile" hx-target="body" hx-swap="outerHTML">Confirm Changes</button>
(% else %)
<a href="/ui/profile/unlock" hx-boost="false">
<!-- TODO: at the moment, session expiring here means progress is lost. Do we just show an error screen ? We can't pass the update state through the reauth session, and we don't have profile update sessions like cred update. -->

View file

@ -23,7 +23,7 @@ Profile
<form id="user_settings_container" class="needs-validation"
hx-post="/ui/api/user_settings/edit_profile"
hx-target="#user_settings_container"
hx-target="#main"
hx-swap="outerHTML"
hx-validate="true"
hx-ext="bs-validation"