forked from didirus/AstralRinth
Fix reports creation (#580)
This commit is contained in:
2
migrations/20230421174120_remove-threads-ref.sql
Normal file
2
migrations/20230421174120_remove-threads-ref.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE threads DROP COLUMN project_id;
|
||||
ALTER TABLE threads DROP COLUMN report_id;
|
||||
206
sqlx-data.json
206
sqlx-data.json
@@ -130,6 +130,50 @@
|
||||
},
|
||||
"query": "\n UPDATE mods\n SET source_url = $1\n WHERE (id = $2)\n "
|
||||
},
|
||||
"04a6310fcc8183e6795a63a5017d607174a9a94587ce774e124613b184dfff43": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"name": "thread_type",
|
||||
"ordinal": 1,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "show_in_mod_inbox",
|
||||
"ordinal": 2,
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"name": "members",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int8Array"
|
||||
},
|
||||
{
|
||||
"name": "messages",
|
||||
"ordinal": 4,
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8Array"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "\n SELECT t.id, t.thread_type, t.show_in_mod_inbox,\n ARRAY_AGG(DISTINCT tm.user_id) filter (where tm.user_id is not null) members,\n 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\n FROM threads t\n LEFT OUTER JOIN threads_messages tmsg ON tmsg.thread_id = t.id\n LEFT OUTER JOIN threads_members tm ON tm.thread_id = t.id\n WHERE t.id = ANY($1)\n GROUP BY t.id\n "
|
||||
},
|
||||
"04e5ecb14c526000e9098efb65861f6125e6fcc88f39d6ad811ac8504d229de1": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@@ -775,6 +819,38 @@
|
||||
},
|
||||
"query": "\n UPDATE notifications\n SET read = TRUE\n WHERE id = ANY($1)\n "
|
||||
},
|
||||
"13e9d01d815b415eb8505e2362319cbdb7881f100f80671289f47886f3ed084e": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"ordinal": 1,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "team_id",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "SELECT m.id, m.status, m.team_id FROM mods m WHERE thread_id = $1"
|
||||
},
|
||||
"1411c9ae3af067679aa21d7f45937cd94d457e4eb17a108566776a9bd1ee77e2": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@@ -2062,6 +2138,19 @@
|
||||
},
|
||||
"query": "\n SELECT r.id, rt.name, r.mod_id, r.version_id, r.user_id, r.body, r.reporter, r.created, r.thread_id, r.closed\n FROM reports r\n INNER JOIN report_types rt ON rt.id = r.report_type_id\n WHERE r.id = ANY($1)\n ORDER BY r.created DESC\n "
|
||||
},
|
||||
"3ae7c4a29dab8bce0e84a9c47a4a4f50a3be4bcb86e5b13d7dd60975d62e9ea3": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Varchar"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "\n INSERT INTO threads (\n id, thread_type\n )\n VALUES (\n $1, $2\n )\n "
|
||||
},
|
||||
"3af747b5543a5a9b10dcce0a1eb9c2a1926dd5a507fe0d8b7f52d8ccc7fcd0af": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@@ -2284,62 +2373,6 @@
|
||||
},
|
||||
"query": "\n SELECT gv.id id, gv.version version_, gv.type type_, gv.created created, gv.major major FROM game_versions gv\n WHERE major = $1 AND type = $2\n ORDER BY created DESC\n "
|
||||
},
|
||||
"447c21dd66f9ac85f9f9d39402d2ceb8440d5951e2c7277d329b65412d330f4e": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"name": "thread_type",
|
||||
"ordinal": 1,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "show_in_mod_inbox",
|
||||
"ordinal": 2,
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"name": "project_id",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"name": "report_id",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"name": "members",
|
||||
"ordinal": 5,
|
||||
"type_info": "Int8Array"
|
||||
},
|
||||
{
|
||||
"name": "messages",
|
||||
"ordinal": 6,
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
null
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8Array"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "\n SELECT t.id, t.thread_type, t.show_in_mod_inbox, t.project_id, t.report_id,\n ARRAY_AGG(DISTINCT tm.user_id) filter (where tm.user_id is not null) members,\n 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\n FROM threads t\n LEFT OUTER JOIN threads_messages tmsg ON tmsg.thread_id = t.id\n LEFT OUTER JOIN threads_members tm ON tm.thread_id = t.id\n WHERE t.id = ANY($1)\n GROUP BY t.id\n "
|
||||
},
|
||||
"4567790f0dc98ff20b596a33161d1f6ac8af73da67fe8c54192724626c6bf670": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@@ -3353,6 +3386,26 @@
|
||||
},
|
||||
"query": "\n INSERT INTO threads_members (\n thread_id, user_id\n )\n VALUES (\n $1, $2\n )\n "
|
||||
},
|
||||
"71766ebbecc05c27ae368992f6ec1043661deb57ba62b7f2328016df9c055cba": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "SELECT r.id FROM reports r WHERE thread_id = $1"
|
||||
},
|
||||
"71abd207410d123f9a50345ddcddee335fea0d0cc6f28762713ee01a36aee8a0": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
@@ -3752,32 +3805,6 @@
|
||||
},
|
||||
"query": "\n INSERT INTO mods_categories (joining_mod_id, joining_category_id, is_additional)\n VALUES ($1, $2, FALSE)\n "
|
||||
},
|
||||
"7ee877b149288e53a14b5f0f3417806aee7a8954fa0fc17da80d59bebbe067d2": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "status",
|
||||
"ordinal": 0,
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"name": "team_id",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "SELECT m.status, m.team_id FROM mods m WHERE thread_id = $1"
|
||||
},
|
||||
"83d428e1c07d16e356ef26bdf1d707940b1683b5f631ded1f6674a081453d67b": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
@@ -5404,21 +5431,6 @@
|
||||
},
|
||||
"query": "\n SELECT v.id version_id, v.mod_id project_id, h.hash hash FROM hashes h\n INNER JOIN files f on h.file_id = f.id\n INNER JOIN versions v on f.version_id = v.id\n WHERE h.algorithm = 'sha1' AND h.hash = ANY($1)\n "
|
||||
},
|
||||
"d0a65443aef9d3781000d0a59d8d81d1a8e51613dfee343d079c233375cebd12": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Varchar",
|
||||
"Int8",
|
||||
"Int8"
|
||||
]
|
||||
}
|
||||
},
|
||||
"query": "\n INSERT INTO threads (\n id, thread_type, report_id, project_id\n )\n VALUES (\n $1, $2, $3, $4\n )\n "
|
||||
},
|
||||
"d12bc07adb4dc8147d0ddccd72a4f23ed38cd31d7db3d36ebbe2c9b627130f0b": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
|
||||
@@ -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>>()
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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?;
|
||||
|
||||
@@ -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?;
|
||||
|
||||
@@ -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(""))
|
||||
|
||||
Reference in New Issue
Block a user