Fix reports creation (#580)

This commit is contained in:
Geometrically
2023-04-21 11:10:57 -07:00
committed by GitHub
parent 59f24df294
commit 3a6b9f04f9
7 changed files with 185 additions and 188 deletions

View File

@@ -7,8 +7,6 @@ use serde::Deserialize;
pub struct ThreadBuilder {
pub type_: ThreadType,
pub members: Vec<UserId>,
pub project_id: Option<ProjectId>,
pub report_id: Option<ReportId>,
}
#[derive(Clone)]
@@ -18,8 +16,6 @@ pub struct Thread {
pub messages: Vec<ThreadMessage>,
pub members: Vec<UserId>,
pub show_in_mod_inbox: bool,
pub project_id: Option<ProjectId>,
pub report_id: Option<ReportId>,
}
pub struct ThreadMessageBuilder {
@@ -71,20 +67,17 @@ impl ThreadBuilder {
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<ThreadId, DatabaseError> {
let thread_id = generate_thread_id(&mut *transaction).await?;
sqlx::query!(
"
INSERT INTO threads (
id, thread_type, report_id, project_id
id, thread_type
)
VALUES (
$1, $2, $3, $4
$1, $2
)
",
thread_id as ThreadId,
self.type_.as_str(),
self.report_id.map(|x| x.0),
self.project_id.map(|x| x.0),
self.type_.as_str()
)
.execute(&mut *transaction)
.await?;
@@ -132,7 +125,7 @@ impl Thread {
let thread_ids_parsed: Vec<i64> = thread_ids.iter().map(|x| x.0).collect();
let threads = sqlx::query!(
"
SELECT t.id, t.thread_type, t.show_in_mod_inbox, t.project_id, t.report_id,
SELECT t.id, t.thread_type, t.show_in_mod_inbox,
ARRAY_AGG(DISTINCT tm.user_id) filter (where tm.user_id is not null) members,
JSONB_AGG(DISTINCT jsonb_build_object('id', tmsg.id, 'author_id', tmsg.author_id, 'thread_id', tmsg.thread_id, 'body', tmsg.body, 'created', tmsg.created)) filter (where tmsg.id is not null) messages
FROM threads t
@@ -159,8 +152,6 @@ impl Thread {
},
members: x.members.unwrap_or_default().into_iter().map(UserId).collect(),
show_in_mod_inbox: x.show_in_mod_inbox,
project_id: x.project_id.map(ProjectId),
report_id: x.report_id.map(ReportId),
}))
})
.try_collect::<Vec<Thread>>()

View File

@@ -1,5 +1,4 @@
use super::ids::Base62Id;
use crate::models::ids::{ProjectId, ReportId};
use crate::models::projects::ProjectStatus;
use crate::models::users::{User, UserId};
use chrono::{DateTime, Utc};
@@ -22,9 +21,6 @@ pub struct Thread {
pub type_: ThreadType,
pub messages: Vec<ThreadMessage>,
pub members: Vec<User>,
pub project_id: Option<ProjectId>,
pub report_id: Option<ReportId>,
}
#[derive(Serialize, Deserialize)]

View File

@@ -721,8 +721,6 @@ async fn project_create_inner(
let thread_id = ThreadBuilder {
type_: ThreadType::Project,
members: vec![],
project_id: Some(project_id.into()),
report_id: None,
}
.insert(&mut *transaction)
.await?;

View File

@@ -58,8 +58,6 @@ pub async fn report_create(
let thread_id = ThreadBuilder {
type_: ThreadType::Report,
members: vec![],
project_id: None,
report_id: Some(id),
}
.insert(&mut transaction)
.await?;

View File

@@ -1,9 +1,9 @@
use crate::database;
use crate::database::models::notification_item::NotificationBuilder;
use crate::database::models::thread_item::ThreadMessageBuilder;
use crate::models::ids::{ReportId, ThreadMessageId};
use crate::models::ids::ThreadMessageId;
use crate::models::notifications::NotificationBody;
use crate::models::projects::{ProjectId, ProjectStatus};
use crate::models::projects::ProjectStatus;
use crate::models::threads::{MessageBody, Thread, ThreadId, ThreadMessage, ThreadType};
use crate::models::users::User;
use crate::routes::ApiError;
@@ -240,8 +240,6 @@ fn convert_thread(data: database::models::Thread, users: Vec<User>, user: &User)
.into_iter()
.filter(|x| !x.role.is_mod() || user.role.is_mod())
.collect(),
project_id: data.project_id.map(ProjectId::from),
report_id: data.report_id.map(ReportId::from),
}
}
@@ -370,21 +368,19 @@ pub async fn thread_send_message(
return Ok(HttpResponse::NotFound().body(""));
}
let report = if let Some(report) = thread.report_id {
database::models::report_item::Report::get(report, &**pool).await?
} else {
None
};
let mut transaction = pool.begin().await?;
if report.as_ref().map(|x| x.closed).unwrap_or(false) && !user.role.is_mod() {
return Err(ApiError::InvalidInput(
"You may not reply to a closed report".to_string(),
));
let id = ThreadMessageBuilder {
author_id: Some(user.id.into()),
body: new_message.body.clone(),
thread_id: thread.id,
}
.insert(&mut transaction)
.await?;
let (mod_notif, (user_notif, team_id)) = if thread.type_ == ThreadType::Project {
let mod_notif = if thread.type_ == ThreadType::Project {
let record = sqlx::query!(
"SELECT m.status, m.team_id FROM mods m WHERE thread_id = $1",
"SELECT m.id, m.status, m.team_id FROM mods m WHERE thread_id = $1",
thread.id as database::models::ids::ThreadId,
)
.fetch_one(&**pool)
@@ -392,28 +388,69 @@ pub async fn thread_send_message(
let status = ProjectStatus::from_str(&record.status);
(
status == ProjectStatus::Processing && !user.role.is_mod(),
(
status != ProjectStatus::Processing && user.role.is_mod(),
Some(record.team_id),
),
if status != ProjectStatus::Processing && user.role.is_mod() {
let members = database::models::TeamMember::get_from_team_full(
database::models::TeamId(record.team_id),
&**pool,
)
.await?;
NotificationBuilder {
body: NotificationBody::ModeratorMessage {
thread_id: thread.id.into(),
message_id: id.into(),
project_id: Some(database::models::ProjectId(record.id).into()),
report_id: None,
},
}
.insert_many(
members.into_iter().map(|x| x.user.id).collect(),
&mut transaction,
)
.await?;
}
status == ProjectStatus::Processing && !user.role.is_mod()
} else if thread.type_ == ThreadType::Report {
let record = sqlx::query!(
"SELECT r.id FROM reports r WHERE thread_id = $1",
thread.id as database::models::ids::ThreadId,
)
.fetch_one(&**pool)
.await?;
let report = database::models::report_item::Report::get(
database::models::ReportId(record.id),
&**pool,
)
.await?;
if let Some(report) = report {
if report.closed && !user.role.is_mod() {
return Err(ApiError::InvalidInput(
"You may not reply to a closed report".to_string(),
));
}
if user.id != report.reporter.into() {
NotificationBuilder {
body: NotificationBody::ModeratorMessage {
thread_id: thread.id.into(),
message_id: id.into(),
project_id: None,
report_id: Some(report.id.into()),
},
}
.insert(report.reporter, &mut transaction)
.await?;
}
}
!user.role.is_mod()
} else {
(
!user.role.is_mod(),
(
thread.type_ == ThreadType::Report
&& !report
.as_ref()
.map(|x| x.reporter == user.id.into())
.unwrap_or(false),
None,
),
)
false
};
let mut transaction = pool.begin().await?;
sqlx::query!(
"
UPDATE threads
@@ -426,43 +463,6 @@ pub async fn thread_send_message(
.execute(&mut *transaction)
.await?;
let id = ThreadMessageBuilder {
author_id: Some(user.id.into()),
body: new_message.body.clone(),
thread_id: thread.id,
}
.insert(&mut transaction)
.await?;
if user_notif {
let users_to_notify = if let Some(team_id) = team_id {
let members = database::models::TeamMember::get_from_team_full(
database::models::TeamId(team_id),
&**pool,
)
.await?;
members.into_iter().map(|x| x.user.id).collect()
} else if let Some(report) = report {
vec![report.reporter]
} else {
vec![]
};
if !users_to_notify.is_empty() {
NotificationBuilder {
body: NotificationBody::ModeratorMessage {
thread_id: thread.id.into(),
message_id: id.into(),
project_id: thread.project_id.map(ProjectId::from),
report_id: thread.report_id.map(ReportId::from),
},
}
.insert_many(users_to_notify, &mut transaction)
.await?;
}
}
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))