fix(backend): add project_name and invited_by_username to InvitationResponse
InvitationResponse was missing project_name and invited_by_username fields, causing /invitations accept to redirect to /project/undefined. Now populated via async from_model() with batch DB lookups.
This commit is contained in:
parent
5579e6c58e
commit
c4fb943e07
@ -1,8 +1,9 @@
|
|||||||
use crate::AppService;
|
use crate::AppService;
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
use futures::future::join_all;
|
||||||
use models::projects::{
|
use models::projects::{
|
||||||
MemberRole, project_audit_log, project_member_invitations, project_members,
|
project, MemberRole, project_audit_log, project_member_invitations, project_members,
|
||||||
};
|
};
|
||||||
use models::users::{user, user_email};
|
use models::users::{user, user_email};
|
||||||
use sea_orm::*;
|
use sea_orm::*;
|
||||||
@ -13,8 +14,10 @@ use uuid::Uuid;
|
|||||||
#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
|
#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
|
||||||
pub struct InvitationResponse {
|
pub struct InvitationResponse {
|
||||||
pub project_uid: Uuid,
|
pub project_uid: Uuid,
|
||||||
|
pub project_name: String,
|
||||||
pub user_uid: Uuid,
|
pub user_uid: Uuid,
|
||||||
pub invited_by: Uuid,
|
pub invited_by: Uuid,
|
||||||
|
pub invited_by_username: Option<String>,
|
||||||
pub scope: String,
|
pub scope: String,
|
||||||
pub accepted: bool,
|
pub accepted: bool,
|
||||||
pub accepted_at: Option<DateTime<Utc>>,
|
pub accepted_at: Option<DateTime<Utc>>,
|
||||||
@ -31,18 +34,36 @@ pub struct InvitationListResponse {
|
|||||||
pub per_page: u64,
|
pub per_page: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<project_member_invitations::Model> for InvitationResponse {
|
impl InvitationResponse {
|
||||||
fn from(invitation: project_member_invitations::Model) -> Self {
|
pub async fn from_model(
|
||||||
|
inv: project_member_invitations::Model,
|
||||||
|
db: &DatabaseConnection,
|
||||||
|
) -> Self {
|
||||||
|
let project_name = project::Entity::find_by_id(inv.project)
|
||||||
|
.one(db)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.map(|p| p.name)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let invited_by_username = user::Entity::find_by_id(inv.invited_by)
|
||||||
|
.one(db)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.map(|u| u.username);
|
||||||
InvitationResponse {
|
InvitationResponse {
|
||||||
project_uid: invitation.project,
|
project_uid: inv.project,
|
||||||
user_uid: invitation.user,
|
project_name,
|
||||||
invited_by: invitation.invited_by,
|
user_uid: inv.user,
|
||||||
scope: invitation.scope,
|
invited_by: inv.invited_by,
|
||||||
accepted: invitation.accepted,
|
invited_by_username,
|
||||||
accepted_at: invitation.accepted_at,
|
scope: inv.scope,
|
||||||
rejected: invitation.rejected,
|
accepted: inv.accepted,
|
||||||
rejected_at: invitation.rejected_at,
|
accepted_at: inv.accepted_at,
|
||||||
created_at: invitation.created_at,
|
rejected: inv.rejected,
|
||||||
|
rejected_at: inv.rejected_at,
|
||||||
|
created_at: inv.created_at,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,9 +103,31 @@ impl AppService {
|
|||||||
.count(&self.db)
|
.count(&self.db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let project_name = project.name.clone();
|
||||||
|
let inviter_ids: Vec<Uuid> = invitations.iter().map(|i| i.invited_by).collect();
|
||||||
|
let inviters: std::collections::HashMap<Uuid, Option<String>> = user::Entity::find()
|
||||||
|
.filter(user::Column::Uid.is_in(inviter_ids))
|
||||||
|
.all(&self.db)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(|u| (u.uid, Some(u.username)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let invitations = invitations
|
let invitations = invitations
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(InvitationResponse::from)
|
.map(|inv| InvitationResponse {
|
||||||
|
project_uid: inv.project,
|
||||||
|
project_name: project_name.clone(),
|
||||||
|
user_uid: inv.user,
|
||||||
|
invited_by: inv.invited_by,
|
||||||
|
invited_by_username: inviters.get(&inv.invited_by).cloned().flatten(),
|
||||||
|
scope: inv.scope,
|
||||||
|
accepted: inv.accepted,
|
||||||
|
accepted_at: inv.accepted_at,
|
||||||
|
rejected: inv.rejected,
|
||||||
|
rejected_at: inv.rejected_at,
|
||||||
|
created_at: inv.created_at,
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(InvitationListResponse {
|
Ok(InvitationListResponse {
|
||||||
@ -122,9 +165,12 @@ impl AppService {
|
|||||||
.count(&self.db)
|
.count(&self.db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let invitations = invitations
|
let invitations = join_all(
|
||||||
.into_iter()
|
invitations
|
||||||
.map(InvitationResponse::from)
|
.into_iter()
|
||||||
|
.map(|inv| InvitationResponse::from_model(inv, self.db.writer())),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(InvitationListResponse {
|
Ok(InvitationListResponse {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user