diff --git a/sqlx-data.json b/sqlx-data.json index ff61bd325..5a8ae78df 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -7186,6 +7186,26 @@ }, "query": "\n UPDATE mods\n SET status = $1\n WHERE (id = $2)\n " }, + "ea1525cbe7460d0d9e9da8f448c661f7209bc1a7a04e2ea0026fa69c3f550a14": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT tm.user_id id\n FROM team_members tm\n WHERE tm.team_id = $1 AND tm.accepted\n " + }, "ebef881a0dae70e990814e567ed3de9565bb29b772782bc974c953af195fd6d7": { "describe": { "columns": [ diff --git a/src/models/projects.rs b/src/models/projects.rs index 7f4efbca2..6b819006e 100644 --- a/src/models/projects.rs +++ b/src/models/projects.rs @@ -319,6 +319,20 @@ impl ProjectStatus { ProjectStatus::Private => "private", } } + pub fn as_friendly_str(&self) -> &'static str { + match self { + ProjectStatus::Approved => "Listed", + ProjectStatus::Rejected => "Rejected", + ProjectStatus::Draft => "Draft", + ProjectStatus::Unlisted => "Unlisted", + ProjectStatus::Processing => "Under review", + ProjectStatus::Unknown => "Unknown", + ProjectStatus::Archived => "Archived", + ProjectStatus::Withheld => "Withheld", + ProjectStatus::Scheduled => "Scheduled", + ProjectStatus::Private => "Private", + } + } pub fn iterator() -> impl Iterator { [ diff --git a/src/routes/projects.rs b/src/routes/projects.rs index ed1ad6ec9..5bb986af8 100644 --- a/src/routes/projects.rs +++ b/src/routes/projects.rs @@ -1,4 +1,5 @@ use crate::database; +use crate::database::models::notification_item::NotificationBuilder; use crate::file_hosting::FileHost; use crate::models; use crate::models::ids::UserId; @@ -13,7 +14,7 @@ use crate::util::routes::read_from_payload; use crate::util::validate::validation_errors_to_string; use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; -use futures::StreamExt; +use futures::{StreamExt, TryStreamExt}; use serde::{Deserialize, Serialize}; use serde_json::json; use sqlx::{PgPool, Row}; @@ -395,7 +396,7 @@ pub async fn project_edit( if user.role.is_admin() { permissions = Some(Permissions::ALL) - } else if let Some(member) = team_member { + } else if let Some(ref member) = team_member { permissions = Some(member.permissions) } else if user.role.is_mod() { permissions = @@ -551,6 +552,40 @@ pub async fn project_edit( } } + if team_member.map(|x| !x.accepted).unwrap_or(true) { + let notified_members = sqlx::query!( + " + SELECT tm.user_id id + FROM team_members tm + WHERE tm.team_id = $1 AND tm.accepted + ", + project_item.inner.team_id as database::models::ids::TeamId + ) + .fetch_many(&mut *transaction) + .try_filter_map(|e| async { Ok(e.right().map(|c| database::models::UserId(c.id))) }) + .try_collect::>() + .await?; + + NotificationBuilder { + notification_type: Some("status_update".to_string()), + title: format!("**{}**'s status has changed!", project_item.inner.title), + text: format!( + "The project {}'s status has changed from {} to {}", + project_item.inner.title, + project_item.inner.status.as_friendly_str(), + status.as_friendly_str() + ), + link: format!( + "/{}/{}", + project_item.project_type, + ProjectId::from(id) + ), + actions: vec![], + } + .insert_many(notified_members, &mut transaction) + .await?; + } + sqlx::query!( " UPDATE mods