New Creator Notifications (#4383)

* Some new notification types

* Fix error

* Use existing DB models rather than inline queries

* Fix template fillout

* Fix ModerationThreadMessageReceived

* Insert more notifications, fix some formatting

* chore: query cache, clippy, fmt

* chore: query cache, clippy, fmt

* Use outer transactions to insert notifications instead of creating a new one

* Join futures
This commit is contained in:
François-Xavier Talbot
2025-09-17 15:37:21 -04:00
committed by GitHub
parent 8149618187
commit 6da190ed01
25 changed files with 1211 additions and 77 deletions

View File

@@ -13,6 +13,8 @@ use rand::distributions::Alphanumeric;
use rand_chacha::ChaCha20Rng;
use rand_chacha::rand_core::SeedableRng;
use crate::database::models::notification_item::NotificationBuilder;
use crate::models::notifications::NotificationBody;
use crate::models::pats::{PersonalAccessToken, Scopes};
use crate::queue::session::AuthQueue;
use crate::util::validate::validation_errors_to_string;
@@ -129,7 +131,15 @@ pub async fn create_pat(
.insert(&mut transaction)
.await?;
NotificationBuilder {
body: NotificationBody::PatCreated {
token_name: name.clone(),
},
}
.insert(user.id.into(), &mut transaction, &redis)
.await?;
transaction.commit().await?;
database::models::pat_item::DBPersonalAccessToken::clear_cache(
vec![(None, None, Some(user.id.into()))],
&redis,

View File

@@ -476,6 +476,22 @@ pub async fn project_edit(
new_status: *status,
},
}
.insert_many(notified_members.clone(), &mut transaction, &redis)
.await?;
NotificationBuilder {
body: if status.is_approved() {
NotificationBody::ProjectStatusApproved {
project_id: project_item.inner.id.into(),
}
} else {
NotificationBody::ProjectStatusNeutral {
project_id: project_item.inner.id.into(),
old_status: project_item.inner.status,
new_status: *status,
}
},
}
.insert_many(notified_members, &mut transaction, &redis)
.await?;
}

View File

@@ -1,6 +1,7 @@
use crate::auth::{check_is_moderator_from_headers, get_user_from_headers};
use crate::database;
use crate::database::models::image_item;
use crate::database::models::notification_item::NotificationBuilder;
use crate::database::models::thread_item::{
ThreadBuilder, ThreadMessageBuilder,
};
@@ -8,6 +9,7 @@ use crate::database::redis::RedisPool;
use crate::models::ids::ImageId;
use crate::models::ids::{ProjectId, VersionId};
use crate::models::images::{Image, ImageContext};
use crate::models::notifications::NotificationBody;
use crate::models::pats::Scopes;
use crate::models::reports::{ItemType, Report};
use crate::models::threads::{MessageBody, ThreadType};
@@ -204,6 +206,15 @@ pub async fn report_create(
.insert(&mut transaction)
.await?;
// Notify the reporter that the report has been submitted
NotificationBuilder {
body: NotificationBody::ReportSubmitted {
report_id: id.into(),
},
}
.insert(current_user.id.into(), &mut transaction, &redis)
.await?;
transaction.commit().await?;
Ok(HttpResponse::Ok().json(Report {
@@ -455,6 +466,14 @@ pub async fn report_edit(
.insert(&mut transaction)
.await?;
NotificationBuilder {
body: NotificationBody::ReportStatusUpdated {
report_id: id.into(),
},
}
.insert(report.reporter, &mut transaction, &redis)
.await?;
sqlx::query!(
"
UPDATE reports

View File

@@ -878,7 +878,7 @@ pub async fn transfer_ownership(
// Forbid transferring ownership of a project team that is owned by an organization
// These are owned by the organization owner, and must be removed from the organization first
// There shouldnt be an ownr on these projects in these cases, but just in case.
// There shouldnt be an owner on these projects in these cases, but just in case.
let team_association_id =
DBTeam::get_association(id.into(), &**pool).await?;
if let Some(TeamAssociationId::Project(pid)) = team_association_id {
@@ -1018,7 +1018,21 @@ pub async fn transfer_ownership(
vec![]
};
// If this team is associated with a project, notify the new owner
if let Some(TeamAssociationId::Project(pid)) = team_association_id {
NotificationBuilder {
body: NotificationBody::ProjectTransferred {
project_id: pid.into(),
new_owner_user_id: Some(new_owner.user_id),
new_owner_organization_id: None,
},
}
.insert(new_owner.user_id.into(), &mut transaction, &redis)
.await?;
}
transaction.commit().await?;
DBTeamMember::clear_cache(id.into(), &redis).await?;
for team_id in project_teams_edited {
DBTeamMember::clear_cache(team_id, &redis).await?;

View File

@@ -477,7 +477,19 @@ pub async fn thread_send_message(
},
}
.insert_many(
members.into_iter().map(|x| x.user_id).collect(),
members.iter().map(|x| x.user_id).collect(),
&mut transaction,
&redis,
)
.await?;
NotificationBuilder {
body: NotificationBody::ModerationMessageReceived {
project_id: project.inner.id.into(),
},
}
.insert_many(
members.iter().map(|x| x.user_id).collect(),
&mut transaction,
&redis,
)