You've already forked AstralRinth
forked from didirus/AstralRinth
Queue Dates + Warnings, some cleanup (#549)
* Queue Dates + Warnings, some cleanup * Fix ping * Fix repeated discord messaging * Fix compile error + run fmt
This commit is contained in:
2
migrations/20230221212958_queue-date.sql
Normal file
2
migrations/20230221212958_queue-date.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- Add migration script here
|
||||
ALTER TABLE mods ADD COLUMN queued timestamptz NULL
|
||||
2084
sqlx-data.json
2084
sqlx-data.json
File diff suppressed because it is too large
Load Diff
@@ -121,45 +121,15 @@ impl Notification {
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, sqlx::error::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('id', na.id, 'notification_id', na.notification_id, 'title', na.title, 'action_route_method', na.action_route_method, 'action_route', na.action_route)) filter (where na.id is not null) actions
|
||||
FROM notifications n
|
||||
LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id
|
||||
WHERE n.id = $1
|
||||
GROUP BY n.id, n.user_id;
|
||||
",
|
||||
id as NotificationId,
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(row) = result {
|
||||
Ok(Some(Notification {
|
||||
id,
|
||||
user_id: UserId(row.user_id),
|
||||
notification_type: row.notification_type,
|
||||
title: row.title,
|
||||
text: row.text,
|
||||
link: row.link,
|
||||
read: row.read,
|
||||
created: row.created,
|
||||
actions: serde_json::from_value(
|
||||
row.actions.unwrap_or_default(),
|
||||
)
|
||||
.ok()
|
||||
.unwrap_or_default(),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Self::get_many(&[id], executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E>(
|
||||
notification_ids: Vec<NotificationId>,
|
||||
notification_ids: &[NotificationId],
|
||||
exec: E,
|
||||
) -> Result<Vec<Notification>, sqlx::Error>
|
||||
where
|
||||
@@ -168,7 +138,7 @@ impl Notification {
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let notification_ids_parsed: Vec<i64> =
|
||||
notification_ids.into_iter().map(|x| x.0).collect();
|
||||
notification_ids.iter().map(|x| x.0).collect();
|
||||
sqlx::query!(
|
||||
"
|
||||
SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,
|
||||
@@ -257,35 +227,15 @@ impl Notification {
|
||||
id: NotificationId,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<Option<()>, sqlx::error::Error> {
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM notifications_actions
|
||||
WHERE notification_id = $1
|
||||
",
|
||||
id as NotificationId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM notifications
|
||||
WHERE id = $1
|
||||
",
|
||||
id as NotificationId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
Ok(Some(()))
|
||||
Self::remove_many(&[id], transaction).await
|
||||
}
|
||||
|
||||
pub async fn remove_many(
|
||||
notification_ids: Vec<NotificationId>,
|
||||
notification_ids: &[NotificationId],
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<Option<()>, sqlx::error::Error> {
|
||||
let notification_ids_parsed: Vec<i64> =
|
||||
notification_ids.into_iter().map(|x| x.0).collect();
|
||||
notification_ids.iter().map(|x| x.0).collect();
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
|
||||
@@ -119,6 +119,11 @@ impl ProjectBuilder {
|
||||
published: Utc::now(),
|
||||
updated: Utc::now(),
|
||||
approved: None,
|
||||
queued: if self.status == ProjectStatus::Processing {
|
||||
Some(Utc::now())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
status: self.status,
|
||||
requested_status: self.requested_status,
|
||||
downloads: 0,
|
||||
@@ -202,6 +207,7 @@ pub struct Project {
|
||||
pub published: DateTime<Utc>,
|
||||
pub updated: DateTime<Utc>,
|
||||
pub approved: Option<DateTime<Utc>>,
|
||||
pub queued: Option<DateTime<Utc>>,
|
||||
pub status: ProjectStatus,
|
||||
pub requested_status: Option<ProjectStatus>,
|
||||
pub downloads: i32,
|
||||
@@ -281,69 +287,15 @@ impl Project {
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, sqlx::error::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT project_type, title, description, downloads, follows,
|
||||
icon_url, body, published,
|
||||
updated, approved, status, requested_status,
|
||||
issues_url, source_url, wiki_url, discord_url, license_url,
|
||||
team_id, client_side, server_side, license, slug,
|
||||
moderation_message, moderation_message_body, flame_anvil_project,
|
||||
flame_anvil_user, webhook_sent, color, loaders, game_versions
|
||||
FROM mods
|
||||
WHERE id = $1
|
||||
",
|
||||
id as ProjectId,
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(row) = result {
|
||||
Ok(Some(Project {
|
||||
id,
|
||||
project_type: ProjectTypeId(row.project_type),
|
||||
team_id: TeamId(row.team_id),
|
||||
title: row.title,
|
||||
description: row.description,
|
||||
downloads: row.downloads,
|
||||
body_url: None,
|
||||
icon_url: row.icon_url,
|
||||
published: row.published,
|
||||
updated: row.updated,
|
||||
issues_url: row.issues_url,
|
||||
source_url: row.source_url,
|
||||
wiki_url: row.wiki_url,
|
||||
license_url: row.license_url,
|
||||
discord_url: row.discord_url,
|
||||
client_side: SideTypeId(row.client_side),
|
||||
status: ProjectStatus::from_str(&row.status),
|
||||
requested_status: row
|
||||
.requested_status
|
||||
.map(|x| ProjectStatus::from_str(&x)),
|
||||
server_side: SideTypeId(row.server_side),
|
||||
license: row.license,
|
||||
slug: row.slug,
|
||||
body: row.body,
|
||||
follows: row.follows,
|
||||
moderation_message: row.moderation_message,
|
||||
moderation_message_body: row.moderation_message_body,
|
||||
approved: row.approved,
|
||||
flame_anvil_project: row.flame_anvil_project,
|
||||
flame_anvil_user: row.flame_anvil_user.map(UserId),
|
||||
webhook_sent: row.webhook_sent,
|
||||
color: row.color.map(|x| x as u32),
|
||||
loaders: row.loaders,
|
||||
game_versions: row.game_versions,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Project::get_many(&[id], executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E>(
|
||||
project_ids: Vec<ProjectId>,
|
||||
project_ids: &[ProjectId],
|
||||
exec: E,
|
||||
) -> Result<Vec<Project>, sqlx::Error>
|
||||
where
|
||||
@@ -352,12 +304,12 @@ impl Project {
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let project_ids_parsed: Vec<i64> =
|
||||
project_ids.into_iter().map(|x| x.0).collect();
|
||||
project_ids.iter().map(|x| x.0).collect();
|
||||
let projects = sqlx::query!(
|
||||
"
|
||||
SELECT id, project_type, title, description, downloads, follows,
|
||||
icon_url, body, published,
|
||||
updated, approved, status, requested_status,
|
||||
updated, approved, queued, status, requested_status,
|
||||
issues_url, source_url, wiki_url, discord_url, license_url,
|
||||
team_id, client_side, server_side, license, slug,
|
||||
moderation_message, moderation_message_body, flame_anvil_project,
|
||||
@@ -406,6 +358,7 @@ impl Project {
|
||||
color: m.color.map(|x| x as u32),
|
||||
loaders: m.loaders,
|
||||
game_versions: m.game_versions,
|
||||
queued: m.queued,
|
||||
}))
|
||||
})
|
||||
.try_collect::<Vec<Project>>()
|
||||
@@ -677,125 +630,9 @@ impl Project {
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,
|
||||
m.icon_url icon_url, m.body body, m.published published,
|
||||
m.updated updated, m.approved approved, m.status status, m.requested_status requested_status,
|
||||
m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,
|
||||
m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,
|
||||
cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent webhook_sent, m.color,
|
||||
m.loaders loaders, m.game_versions game_versions,
|
||||
ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is false) categories,
|
||||
ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is true) additional_categories,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('id', v.id, 'date_published', v.date_published)) filter (where v.id is not null) versions,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('image_url', mg.image_url, 'featured', mg.featured, 'title', mg.title, 'description', mg.description, 'created', mg.created, 'ordering', mg.ordering)) filter (where mg.image_url is not null) gallery,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('platform_id', md.joining_platform_id, 'platform_short', dp.short, 'platform_name', dp.name,'url', md.url)) filter (where md.joining_platform_id is not null) donations
|
||||
FROM mods m
|
||||
INNER JOIN project_types pt ON pt.id = m.project_type
|
||||
INNER JOIN side_types cs ON m.client_side = cs.id
|
||||
INNER JOIN side_types ss ON m.server_side = ss.id
|
||||
LEFT JOIN mods_donations md ON md.joining_mod_id = m.id
|
||||
LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id
|
||||
LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id
|
||||
LEFT JOIN categories c ON mc.joining_category_id = c.id
|
||||
LEFT JOIN versions v ON v.mod_id = m.id AND v.status = ANY($2)
|
||||
LEFT JOIN mods_gallery mg ON mg.mod_id = m.id
|
||||
WHERE m.id = $1
|
||||
GROUP BY pt.id, cs.id, ss.id, m.id;
|
||||
",
|
||||
id as ProjectId,
|
||||
&*crate::models::projects::VersionStatus::iterator().filter(|x| x.is_listed()).map(|x| x.to_string()).collect::<Vec<String>>()
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(m) = result {
|
||||
Ok(Some(QueryProject {
|
||||
inner: Project {
|
||||
id: ProjectId(m.id),
|
||||
project_type: ProjectTypeId(m.project_type),
|
||||
team_id: TeamId(m.team_id),
|
||||
title: m.title.clone(),
|
||||
description: m.description.clone(),
|
||||
downloads: m.downloads,
|
||||
body_url: None,
|
||||
icon_url: m.icon_url.clone(),
|
||||
published: m.published,
|
||||
updated: m.updated,
|
||||
issues_url: m.issues_url.clone(),
|
||||
source_url: m.source_url.clone(),
|
||||
wiki_url: m.wiki_url.clone(),
|
||||
license_url: m.license_url.clone(),
|
||||
discord_url: m.discord_url.clone(),
|
||||
client_side: SideTypeId(m.client_side),
|
||||
status: ProjectStatus::from_str(&m.status),
|
||||
requested_status: m
|
||||
.requested_status
|
||||
.map(|x| ProjectStatus::from_str(&x)),
|
||||
server_side: SideTypeId(m.server_side),
|
||||
license: m.license.clone(),
|
||||
slug: m.slug.clone(),
|
||||
body: m.body.clone(),
|
||||
follows: m.follows,
|
||||
moderation_message: m.moderation_message,
|
||||
moderation_message_body: m.moderation_message_body,
|
||||
approved: m.approved,
|
||||
flame_anvil_project: m.flame_anvil_project,
|
||||
flame_anvil_user: m.flame_anvil_user.map(UserId),
|
||||
webhook_sent: m.webhook_sent,
|
||||
color: m.color.map(|x| x as u32),
|
||||
loaders: m.loaders,
|
||||
game_versions: m.game_versions,
|
||||
},
|
||||
project_type: m.project_type_name,
|
||||
categories: m.categories.unwrap_or_default(),
|
||||
additional_categories: m
|
||||
.additional_categories
|
||||
.unwrap_or_default(),
|
||||
versions: {
|
||||
#[derive(Deserialize)]
|
||||
struct Version {
|
||||
pub id: VersionId,
|
||||
pub date_published: DateTime<Utc>,
|
||||
}
|
||||
|
||||
let mut versions: Vec<Version> =
|
||||
serde_json::from_value(m.versions.unwrap_or_default())
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
|
||||
versions.sort_by(|a, b| {
|
||||
a.date_published.cmp(&b.date_published)
|
||||
});
|
||||
|
||||
versions.into_iter().map(|x| x.id).collect()
|
||||
},
|
||||
gallery_items: {
|
||||
let mut gallery: Vec<GalleryItem> =
|
||||
serde_json::from_value(m.gallery.unwrap_or_default())
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
|
||||
gallery.sort_by(|a, b| a.ordering.cmp(&b.ordering));
|
||||
|
||||
gallery
|
||||
},
|
||||
donation_urls: serde_json::from_value(
|
||||
m.donations.unwrap_or_default(),
|
||||
)
|
||||
.ok()
|
||||
.unwrap_or_default(),
|
||||
client_side: crate::models::projects::SideType::from_str(
|
||||
&m.client_side_type,
|
||||
),
|
||||
server_side: crate::models::projects::SideType::from_str(
|
||||
&m.server_side_type,
|
||||
),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Project::get_many_full(&[id], executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many_full<'a, E>(
|
||||
@@ -813,7 +650,7 @@ impl Project {
|
||||
"
|
||||
SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,
|
||||
m.icon_url icon_url, m.body body, m.published published,
|
||||
m.updated updated, m.approved approved, m.status status, m.requested_status requested_status,
|
||||
m.updated updated, m.approved approved, m.queued, m.status status, m.requested_status requested_status,
|
||||
m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,
|
||||
m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,
|
||||
cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent, m.color,
|
||||
@@ -882,6 +719,7 @@ impl Project {
|
||||
color: m.color.map(|x| x as u32),
|
||||
loaders: m.loaders,
|
||||
game_versions: m.game_versions,
|
||||
queued: m.queued,
|
||||
},
|
||||
project_type: m.project_type_name,
|
||||
categories: m.categories.unwrap_or_default(),
|
||||
|
||||
@@ -60,36 +60,13 @@ impl Report {
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT rt.name, r.mod_id, r.version_id, r.user_id, r.body, r.reporter, r.created
|
||||
FROM reports r
|
||||
INNER JOIN report_types rt ON rt.id = r.report_type_id
|
||||
WHERE r.id = $1
|
||||
",
|
||||
id as ReportId,
|
||||
)
|
||||
.fetch_optional(exec)
|
||||
.await?;
|
||||
|
||||
if let Some(row) = result {
|
||||
Ok(Some(QueryReport {
|
||||
id,
|
||||
report_type: row.name,
|
||||
project_id: row.mod_id.map(ProjectId),
|
||||
version_id: row.version_id.map(VersionId),
|
||||
user_id: row.user_id.map(UserId),
|
||||
body: row.body,
|
||||
reporter: UserId(row.reporter),
|
||||
created: row.created,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Self::get_many(&[id], exec)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E>(
|
||||
report_ids: Vec<ReportId>,
|
||||
report_ids: &[ReportId],
|
||||
exec: E,
|
||||
) -> Result<Vec<QueryReport>, sqlx::Error>
|
||||
where
|
||||
@@ -98,7 +75,7 @@ impl Report {
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let report_ids_parsed: Vec<i64> =
|
||||
report_ids.into_iter().map(|x| x.0).collect();
|
||||
report_ids.iter().map(|x| x.0).collect();
|
||||
let reports = sqlx::query!(
|
||||
"
|
||||
SELECT r.id, rt.name, r.mod_id, r.version_id, r.user_id, r.body, r.reporter, r.created
|
||||
|
||||
@@ -157,71 +157,13 @@ impl TeamMember {
|
||||
executor: E,
|
||||
) -> Result<Vec<QueryTeamMember>, super::DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split, tm.ordering ordering,
|
||||
u.id user_id, u.github_id github_id, u.name user_name, u.email email,
|
||||
u.avatar_url avatar_url, u.username username, u.bio bio,
|
||||
u.created created, u.role user_role, u.badges badges, u.balance balance,
|
||||
u.payout_wallet payout_wallet, u.payout_wallet_type payout_wallet_type,
|
||||
u.payout_address payout_address, u.flame_anvil_key flame_anvil_key
|
||||
FROM team_members tm
|
||||
INNER JOIN users u ON u.id = tm.user_id
|
||||
WHERE tm.team_id = $1
|
||||
ORDER BY tm.ordering
|
||||
",
|
||||
id as TeamId,
|
||||
)
|
||||
.fetch_many(executor)
|
||||
.try_filter_map(|e| async {
|
||||
if let Some(m) = e.right() {
|
||||
|
||||
Ok(Some(Ok(QueryTeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: id,
|
||||
role: m.member_role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64).unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
user: User {
|
||||
id: UserId(m.user_id),
|
||||
github_id: m.github_id,
|
||||
name: m.user_name,
|
||||
email: m.email,
|
||||
avatar_url: m.avatar_url,
|
||||
username: m.username,
|
||||
bio: m.bio,
|
||||
created: m.created,
|
||||
role: m.user_role,
|
||||
badges: Badges::from_bits(m.badges as u64).unwrap_or_default(),
|
||||
balance: m.balance,
|
||||
payout_wallet: m.payout_wallet.map(|x| RecipientWallet::from_string(&x)),
|
||||
payout_wallet_type: m.payout_wallet_type.map(|x| RecipientType::from_string(&x)),
|
||||
payout_address: m.payout_address,
|
||||
flame_anvil_key: m.flame_anvil_key,
|
||||
},
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
})))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
.try_collect::<Vec<Result<QueryTeamMember, super::DatabaseError>>>()
|
||||
.await?;
|
||||
|
||||
let team_members = team_members
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<QueryTeamMember>, super::DatabaseError>>()?;
|
||||
|
||||
Ok(team_members)
|
||||
Self::get_from_team_full_many(&[id], executor).await
|
||||
}
|
||||
|
||||
pub async fn get_from_team_full_many<'a, E>(
|
||||
team_ids: Vec<TeamId>,
|
||||
team_ids: &[TeamId],
|
||||
exec: E,
|
||||
) -> Result<Vec<QueryTeamMember>, super::DatabaseError>
|
||||
where
|
||||
@@ -229,8 +171,7 @@ impl TeamMember {
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let team_ids_parsed: Vec<i64> =
|
||||
team_ids.into_iter().map(|x| x.0).collect();
|
||||
let team_ids_parsed: Vec<i64> = team_ids.iter().map(|x| x.0).collect();
|
||||
|
||||
let teams = sqlx::query!(
|
||||
"
|
||||
@@ -394,38 +335,14 @@ impl TeamMember {
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT id, user_id, role, permissions, accepted, payouts_split, ordering
|
||||
FROM team_members
|
||||
WHERE (team_id = $1 AND user_id = $2 AND accepted = TRUE)
|
||||
",
|
||||
id as TeamId,
|
||||
user_id as UserId
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(m) = result {
|
||||
Ok(Some(TeamMember {
|
||||
id: TeamMemberId(m.id),
|
||||
team_id: id,
|
||||
user_id,
|
||||
role: m.role,
|
||||
permissions: Permissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Self::get_from_user_id_many(&[id], user_id, executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
/// Gets team members from user ids and team ids. Does not return pending members.
|
||||
pub async fn get_from_user_id_many<'a, 'b, E>(
|
||||
team_ids: Vec<TeamId>,
|
||||
team_ids: &[TeamId],
|
||||
user_id: UserId,
|
||||
executor: E,
|
||||
) -> Result<Vec<Self>, super::DatabaseError>
|
||||
@@ -434,8 +351,7 @@ impl TeamMember {
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let team_ids_parsed: Vec<i64> =
|
||||
team_ids.into_iter().map(|x| x.0).collect();
|
||||
let team_ids_parsed: Vec<i64> = team_ids.iter().map(|x| x.0).collect();
|
||||
|
||||
let team_members = sqlx::query!(
|
||||
"
|
||||
|
||||
@@ -56,49 +56,11 @@ impl User {
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, sqlx::error::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT u.github_id, u.name, u.email,
|
||||
u.avatar_url, u.username, u.bio,
|
||||
u.created, u.role, u.badges,
|
||||
u.balance, u.payout_wallet, u.payout_wallet_type,
|
||||
u.payout_address, u.flame_anvil_key
|
||||
FROM users u
|
||||
WHERE u.id = $1
|
||||
",
|
||||
id as UserId,
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(row) = result {
|
||||
Ok(Some(User {
|
||||
id,
|
||||
github_id: row.github_id,
|
||||
name: row.name,
|
||||
email: row.email,
|
||||
avatar_url: row.avatar_url,
|
||||
username: row.username,
|
||||
bio: row.bio,
|
||||
created: row.created,
|
||||
role: row.role,
|
||||
badges: Badges::from_bits(row.badges as u64)
|
||||
.unwrap_or_default(),
|
||||
balance: row.balance,
|
||||
payout_wallet: row
|
||||
.payout_wallet
|
||||
.map(|x| RecipientWallet::from_string(&x)),
|
||||
payout_wallet_type: row
|
||||
.payout_wallet_type
|
||||
.map(|x| RecipientType::from_string(&x)),
|
||||
payout_address: row.payout_address,
|
||||
flame_anvil_key: row.flame_anvil_key,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Self::get_many(&[id], executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_from_github_id<'a, 'b, E>(
|
||||
@@ -202,7 +164,7 @@ impl User {
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E>(
|
||||
user_ids: Vec<UserId>,
|
||||
user_ids: &[UserId],
|
||||
exec: E,
|
||||
) -> Result<Vec<User>, sqlx::Error>
|
||||
where
|
||||
@@ -210,8 +172,7 @@ impl User {
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let user_ids_parsed: Vec<i64> =
|
||||
user_ids.into_iter().map(|x| x.0).collect();
|
||||
let user_ids_parsed: Vec<i64> = user_ids.iter().map(|x| x.0).collect();
|
||||
let users = sqlx::query!(
|
||||
"
|
||||
SELECT u.id, u.github_id, u.name, u.email,
|
||||
|
||||
@@ -573,46 +573,15 @@ impl Version {
|
||||
executor: E,
|
||||
) -> Result<Option<Self>, sqlx::error::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT v.mod_id, v.author_id, v.name, v.version_number,
|
||||
v.changelog, v.date_published, v.downloads,
|
||||
v.version_type, v.featured, v.status, v.requested_status
|
||||
FROM versions v
|
||||
WHERE v.id = $1
|
||||
",
|
||||
id as VersionId,
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(row) = result {
|
||||
Ok(Some(Version {
|
||||
id,
|
||||
project_id: ProjectId(row.mod_id),
|
||||
author_id: UserId(row.author_id),
|
||||
name: row.name,
|
||||
version_number: row.version_number,
|
||||
changelog: row.changelog,
|
||||
changelog_url: None,
|
||||
date_published: row.date_published,
|
||||
downloads: row.downloads,
|
||||
version_type: row.version_type,
|
||||
featured: row.featured,
|
||||
status: VersionStatus::from_str(&row.status),
|
||||
requested_status: row
|
||||
.requested_status
|
||||
.map(|x| VersionStatus::from_str(&x)),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Self::get_many(&[id], executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E>(
|
||||
version_ids: Vec<VersionId>,
|
||||
version_ids: &[VersionId],
|
||||
exec: E,
|
||||
) -> Result<Vec<Version>, sqlx::Error>
|
||||
where
|
||||
@@ -621,7 +590,7 @@ impl Version {
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let version_ids_parsed: Vec<i64> =
|
||||
version_ids.into_iter().map(|x| x.0).collect();
|
||||
version_ids.iter().map(|x| x.0).collect();
|
||||
let versions = sqlx::query!(
|
||||
"
|
||||
SELECT v.id, v.mod_id, v.author_id, v.name, v.version_number,
|
||||
@@ -664,151 +633,15 @@ impl Version {
|
||||
executor: E,
|
||||
) -> Result<Option<QueryVersion>, sqlx::error::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,
|
||||
v.changelog changelog, v.date_published date_published, v.downloads downloads,
|
||||
v.version_type version_type, v.featured featured, v.status status, v.requested_status requested_status,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('version', gv.version, 'created', gv.created)) filter (where gv.version is not null) game_versions,
|
||||
ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('id', f.id, 'url', f.url, 'filename', f.filename, 'primary', f.is_primary, 'size', f.size, 'file_type', f.file_type)) filter (where f.id is not null) files,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('algorithm', h.algorithm, 'hash', encode(h.hash, 'escape'), 'file_id', h.file_id)) filter (where h.hash is not null) hashes,
|
||||
JSONB_AGG(DISTINCT jsonb_build_object('project_id', d.mod_dependency_id, 'version_id', d.dependency_id, 'dependency_type', d.dependency_type,'file_name', dependency_file_name)) filter (where d.dependency_type is not null) dependencies
|
||||
FROM versions v
|
||||
LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id
|
||||
LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id
|
||||
LEFT OUTER JOIN loaders_versions lv on v.id = lv.version_id
|
||||
LEFT OUTER JOIN loaders l on lv.loader_id = l.id
|
||||
LEFT OUTER JOIN files f on v.id = f.version_id
|
||||
LEFT OUTER JOIN hashes h on f.id = h.file_id
|
||||
LEFT OUTER JOIN dependencies d on v.id = d.dependent_id
|
||||
WHERE v.id = $1
|
||||
GROUP BY v.id;
|
||||
",
|
||||
id as VersionId,
|
||||
)
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
|
||||
if let Some(v) = result {
|
||||
Ok(Some(QueryVersion {
|
||||
inner: Version {
|
||||
id: VersionId(v.id),
|
||||
project_id: ProjectId(v.mod_id),
|
||||
author_id: UserId(v.author_id),
|
||||
name: v.version_name,
|
||||
version_number: v.version_number,
|
||||
changelog: v.changelog,
|
||||
changelog_url: None,
|
||||
date_published: v.date_published,
|
||||
downloads: v.downloads,
|
||||
version_type: v.version_type,
|
||||
featured: v.featured,
|
||||
status: VersionStatus::from_str(&v.status),
|
||||
requested_status: v
|
||||
.requested_status
|
||||
.map(|x| VersionStatus::from_str(&x)),
|
||||
},
|
||||
files: {
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Hash {
|
||||
pub file_id: FileId,
|
||||
pub algorithm: String,
|
||||
pub hash: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct File {
|
||||
pub id: FileId,
|
||||
pub url: String,
|
||||
pub filename: String,
|
||||
pub primary: bool,
|
||||
pub size: u32,
|
||||
pub file_type: Option<FileType>,
|
||||
}
|
||||
|
||||
let hashes: Vec<Hash> =
|
||||
serde_json::from_value(v.hashes.unwrap_or_default())
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
|
||||
let files: Vec<File> =
|
||||
serde_json::from_value(v.files.unwrap_or_default())
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut files = files
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
let mut file_hashes = HashMap::new();
|
||||
|
||||
for hash in &hashes {
|
||||
if hash.file_id == x.id {
|
||||
file_hashes.insert(
|
||||
hash.algorithm.clone(),
|
||||
hash.hash.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
QueryFile {
|
||||
id: x.id,
|
||||
url: x.url,
|
||||
filename: x.filename,
|
||||
hashes: file_hashes,
|
||||
primary: x.primary,
|
||||
size: x.size,
|
||||
file_type: x.file_type,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
files.sort_by(|a, b| {
|
||||
if a.primary {
|
||||
Ordering::Less
|
||||
} else if b.primary {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
a.filename.cmp(&b.filename)
|
||||
}
|
||||
});
|
||||
|
||||
files
|
||||
},
|
||||
game_versions: {
|
||||
#[derive(Deserialize)]
|
||||
struct GameVersion {
|
||||
pub version: String,
|
||||
pub created: DateTime<Utc>,
|
||||
}
|
||||
|
||||
let mut game_versions: Vec<GameVersion> =
|
||||
serde_json::from_value(
|
||||
v.game_versions.unwrap_or_default(),
|
||||
)
|
||||
.ok()
|
||||
.unwrap_or_default();
|
||||
|
||||
game_versions.sort_by(|a, b| a.created.cmp(&b.created));
|
||||
|
||||
game_versions.into_iter().map(|x| x.version).collect()
|
||||
},
|
||||
loaders: v.loaders.unwrap_or_default(),
|
||||
dependencies: serde_json::from_value(
|
||||
v.dependencies.unwrap_or_default(),
|
||||
)
|
||||
.ok()
|
||||
.unwrap_or_default(),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Self::get_many_full(&[id], executor)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many_full<'a, E>(
|
||||
version_ids: Vec<VersionId>,
|
||||
version_ids: &[VersionId],
|
||||
exec: E,
|
||||
) -> Result<Vec<QueryVersion>, sqlx::Error>
|
||||
where
|
||||
@@ -817,7 +650,7 @@ impl Version {
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let version_ids_parsed: Vec<i64> =
|
||||
version_ids.into_iter().map(|x| x.0).collect();
|
||||
version_ids.iter().map(|x| x.0).collect();
|
||||
sqlx::query!(
|
||||
"
|
||||
SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,
|
||||
|
||||
69
src/main.rs
69
src/main.rs
@@ -7,6 +7,7 @@ use crate::ratelimit::middleware::RateLimiter;
|
||||
use crate::util::env::{parse_strings_from_var, parse_var};
|
||||
use actix_cors::Cors;
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use chrono::{DateTime, Utc};
|
||||
use env_logger::Env;
|
||||
use log::{error, info, warn};
|
||||
use search::indexing::index_projects;
|
||||
@@ -201,6 +202,74 @@ async fn main() -> std::io::Result<()> {
|
||||
}
|
||||
});
|
||||
|
||||
// Reminding moderators to review projects which have been in the queue longer than 24hr
|
||||
let pool_ref = pool.clone();
|
||||
let webhook_message_sent = Arc::new(Mutex::new(Vec::<(
|
||||
database::models::ProjectId,
|
||||
DateTime<Utc>,
|
||||
)>::new()));
|
||||
|
||||
scheduler.run(std::time::Duration::from_secs(10 * 60), move || {
|
||||
let pool_ref = pool_ref.clone();
|
||||
let webhook_message_sent_ref = webhook_message_sent.clone();
|
||||
info!("Checking reviewed projects submitted more than 24hrs ago");
|
||||
|
||||
async move {
|
||||
let do_steps = async {
|
||||
use futures::TryStreamExt;
|
||||
|
||||
let project_ids = sqlx::query!(
|
||||
"
|
||||
SELECT id FROM mods
|
||||
WHERE status = $1 AND queued < NOW() - INTERVAL '1 day'
|
||||
ORDER BY updated ASC
|
||||
",
|
||||
crate::models::projects::ProjectStatus::Processing.as_str(),
|
||||
)
|
||||
.fetch_many(&pool_ref)
|
||||
.try_filter_map(|e| async {
|
||||
Ok(e.right().map(|m| database::models::ProjectId(m.id)))
|
||||
})
|
||||
.try_collect::<Vec<database::models::ProjectId>>()
|
||||
.await?;
|
||||
|
||||
let mut webhook_message_sent_ref = webhook_message_sent_ref.lock().await;
|
||||
|
||||
webhook_message_sent_ref.retain(|x| Utc::now() - x.1 > chrono::Duration::hours(12));
|
||||
|
||||
for project in project_ids {
|
||||
if webhook_message_sent_ref.iter().any(|x| x.0 == project) { continue; }
|
||||
|
||||
if let Ok(webhook_url) =
|
||||
dotenvy::var("MODERATION_DISCORD_WEBHOOK")
|
||||
{
|
||||
util::webhook::send_discord_webhook(
|
||||
project.into(),
|
||||
&pool_ref,
|
||||
webhook_url,
|
||||
Some("<@&783155186491195394> This project has been in the queue for over 24 hours!".to_string()),
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
webhook_message_sent_ref.push((project, Utc::now()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok::<(), crate::routes::ApiError>(())
|
||||
};
|
||||
|
||||
if let Err(e) = do_steps.await {
|
||||
warn!(
|
||||
"Checking reviewed projects submitted more than 24hrs ago failed: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
info!("Finished checking reviewed projects submitted more than 24hrs ago");
|
||||
}
|
||||
});
|
||||
|
||||
scheduler::schedule_versions(&mut scheduler, pool.clone());
|
||||
|
||||
let download_queue = Arc::new(DownloadQueue::new());
|
||||
|
||||
@@ -48,6 +48,8 @@ pub struct Project {
|
||||
/// The date at which the project was first approved.
|
||||
//pub approved: Option<DateTime<Utc>>,
|
||||
pub approved: Option<DateTime<Utc>>,
|
||||
/// The date at which the project entered the moderation queue
|
||||
pub queued: Option<DateTime<Utc>>,
|
||||
|
||||
/// The status of the project
|
||||
pub status: ProjectStatus,
|
||||
@@ -122,6 +124,7 @@ impl From<QueryProject> for Project {
|
||||
published: m.published,
|
||||
updated: m.updated,
|
||||
approved: m.approved,
|
||||
queued: m.queued,
|
||||
status: m.status,
|
||||
requested_status: m.requested_status,
|
||||
moderator_message: if let Some(message) = m.moderation_message {
|
||||
|
||||
@@ -30,7 +30,7 @@ pub async fn get_projects(
|
||||
"
|
||||
SELECT id FROM mods
|
||||
WHERE status = $1
|
||||
ORDER BY updated ASC
|
||||
ORDER BY queued ASC
|
||||
LIMIT $2;
|
||||
",
|
||||
ProjectStatus::Processing.as_str(),
|
||||
|
||||
@@ -32,7 +32,7 @@ pub async fn notifications_get(
|
||||
|
||||
let notifications_data: Vec<DBNotification> =
|
||||
database::models::notification_item::Notification::get_many(
|
||||
notification_ids,
|
||||
¬ification_ids,
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
@@ -127,13 +127,13 @@ pub async fn notifications_delete(
|
||||
serde_json::from_str::<Vec<NotificationId>>(&ids.ids)?
|
||||
.into_iter()
|
||||
.map(|x| x.into())
|
||||
.collect();
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
|
||||
let notifications_data =
|
||||
database::models::notification_item::Notification::get_many(
|
||||
notification_ids,
|
||||
¬ification_ids,
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
@@ -148,7 +148,7 @@ pub async fn notifications_delete(
|
||||
}
|
||||
|
||||
database::models::notification_item::Notification::remove_many(
|
||||
notifications,
|
||||
¬ifications,
|
||||
&mut transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -802,6 +802,7 @@ async fn project_create_inner(
|
||||
published: now,
|
||||
updated: now,
|
||||
approved: None,
|
||||
queued: None,
|
||||
status,
|
||||
requested_status: project_builder.requested_status,
|
||||
moderator_message: None,
|
||||
@@ -844,6 +845,7 @@ async fn project_create_inner(
|
||||
response.id,
|
||||
pool,
|
||||
webhook_url,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
@@ -256,12 +256,13 @@ pub async fn dependency_list(
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let dep_version_ids = dependencies
|
||||
.iter()
|
||||
.filter_map(|x| x.0)
|
||||
.collect::<Vec<database::models::VersionId>>();
|
||||
let (projects_result, versions_result) = futures::future::try_join(
|
||||
database::Project::get_many_full(&project_ids, &**pool),
|
||||
database::Version::get_many_full(
|
||||
dependencies.iter().filter_map(|x| x.0).collect(),
|
||||
&**pool,
|
||||
),
|
||||
database::Version::get_many_full(&dep_version_ids, &**pool),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -502,18 +503,7 @@ pub async fn project_edit(
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE mods
|
||||
SET moderation_message = NULL
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as database::models::ids::ProjectId,
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
UPDATE mods
|
||||
SET moderation_message_body = NULL
|
||||
SET moderation_message = NULL, moderation_message_body = NULL, queued = NOW()
|
||||
WHERE (id = $1)
|
||||
",
|
||||
id as database::models::ids::ProjectId,
|
||||
@@ -528,6 +518,7 @@ pub async fn project_edit(
|
||||
project_item.inner.id.into(),
|
||||
&pool,
|
||||
webhook_url,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
@@ -557,6 +548,7 @@ pub async fn project_edit(
|
||||
project_item.inner.id.into(),
|
||||
&pool,
|
||||
webhook_url,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
@@ -1234,9 +1226,12 @@ pub async fn projects_edit(
|
||||
)));
|
||||
}
|
||||
|
||||
let team_ids = projects_data
|
||||
.iter()
|
||||
.map(|x| x.inner.team_id)
|
||||
.collect::<Vec<database::models::TeamId>>();
|
||||
let team_members = database::models::TeamMember::get_from_team_full_many(
|
||||
projects_data.iter().map(|x| x.inner.team_id).collect(),
|
||||
&**pool,
|
||||
&team_ids, &**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -184,7 +184,8 @@ pub async fn reports(
|
||||
.await?;
|
||||
|
||||
let query_reports = crate::database::models::report_item::Report::get_many(
|
||||
report_ids, &**pool,
|
||||
&report_ids,
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -121,11 +121,11 @@ pub async fn teams_get(
|
||||
.collect::<Vec<crate::database::models::ids::TeamId>>();
|
||||
|
||||
let teams_data =
|
||||
TeamMember::get_from_team_full_many(team_ids.clone(), &**pool).await?;
|
||||
TeamMember::get_from_team_full_many(&team_ids, &**pool).await?;
|
||||
|
||||
let current_user = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||
let accepted = if let Some(user) = current_user {
|
||||
TeamMember::get_from_user_id_many(team_ids, user.id.into(), &**pool)
|
||||
TeamMember::get_from_user_id_many(&team_ids, user.id.into(), &**pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|m| m.team_id.0)
|
||||
|
||||
@@ -45,7 +45,7 @@ pub async fn forge_updates(
|
||||
.await?;
|
||||
|
||||
let versions =
|
||||
database::models::Version::get_many_full(version_ids, &**pool).await?;
|
||||
database::models::Version::get_many_full(&version_ids, &**pool).await?;
|
||||
|
||||
let mut versions =
|
||||
filter_authorized_versions(versions, &user_option, &pool).await?;
|
||||
|
||||
@@ -44,9 +44,9 @@ pub async fn users_get(
|
||||
let user_ids = serde_json::from_str::<Vec<UserId>>(&ids.ids)?
|
||||
.into_iter()
|
||||
.map(|x| x.into())
|
||||
.collect();
|
||||
.collect::<Vec<crate::database::models::UserId>>();
|
||||
|
||||
let users_data = User::get_many(user_ids, &**pool).await?;
|
||||
let users_data = User::get_many(&user_ids, &**pool).await?;
|
||||
|
||||
let users: Vec<crate::models::users::User> =
|
||||
users_data.into_iter().map(From::from).collect();
|
||||
|
||||
@@ -31,7 +31,7 @@ pub async fn mods_list(
|
||||
let project_data = User::get_projects(id, &**pool).await?;
|
||||
|
||||
let response: Vec<_> =
|
||||
crate::database::Project::get_many(project_data, &**pool)
|
||||
crate::database::Project::get_many(&project_data, &**pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|x| can_view_private || x.status.is_approved())
|
||||
|
||||
@@ -84,7 +84,7 @@ pub async fn version_list(
|
||||
.await?;
|
||||
|
||||
let mut versions =
|
||||
database::models::Version::get_many_full(version_ids, &**pool)
|
||||
database::models::Version::get_many_full(&version_ids, &**pool)
|
||||
.await?;
|
||||
|
||||
let mut response = versions
|
||||
@@ -165,9 +165,9 @@ pub async fn versions_get(
|
||||
let version_ids = serde_json::from_str::<Vec<VersionId>>(&ids.ids)?
|
||||
.into_iter()
|
||||
.map(|x| x.into())
|
||||
.collect();
|
||||
.collect::<Vec<database::models::VersionId>>();
|
||||
let versions_data =
|
||||
database::models::Version::get_many_full(version_ids, &**pool).await?;
|
||||
database::models::Version::get_many_full(&version_ids, &**pool).await?;
|
||||
|
||||
let mut versions = Vec::new();
|
||||
|
||||
|
||||
@@ -63,14 +63,12 @@ pub async fn get_version_from_hash(
|
||||
.fetch_all(&**pool)
|
||||
.await?;
|
||||
|
||||
let versions_data = database::models::Version::get_many_full(
|
||||
result
|
||||
.iter()
|
||||
.map(|x| database::models::VersionId(x.version_id))
|
||||
.collect(),
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
let version_ids = result
|
||||
.iter()
|
||||
.map(|x| database::models::VersionId(x.version_id))
|
||||
.collect::<Vec<_>>();
|
||||
let versions_data =
|
||||
database::models::Version::get_many_full(&version_ids, &**pool).await?;
|
||||
|
||||
if let Some(first) = versions_data.first() {
|
||||
if hash_query.multiple {
|
||||
@@ -357,14 +355,12 @@ pub async fn get_versions_from_hashes(
|
||||
.fetch_all(&**pool)
|
||||
.await?;
|
||||
|
||||
let versions_data = database::models::Version::get_many_full(
|
||||
result
|
||||
.iter()
|
||||
.map(|x| database::models::VersionId(x.version_id))
|
||||
.collect(),
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
let version_ids = result
|
||||
.iter()
|
||||
.map(|x| database::models::VersionId(x.version_id))
|
||||
.collect::<Vec<_>>();
|
||||
let versions_data =
|
||||
database::models::Version::get_many_full(&version_ids, &**pool).await?;
|
||||
|
||||
let response: Result<HashMap<String, Version>, ApiError> = result
|
||||
.into_iter()
|
||||
@@ -518,11 +514,10 @@ pub async fn update_files(
|
||||
}
|
||||
}
|
||||
|
||||
let versions = database::models::Version::get_many_full(
|
||||
version_ids.keys().copied().collect(),
|
||||
&**pool,
|
||||
)
|
||||
.await?;
|
||||
let query_version_ids = version_ids.keys().copied().collect::<Vec<_>>();
|
||||
let versions =
|
||||
database::models::Version::get_many_full(&query_version_ids, &**pool)
|
||||
.await?;
|
||||
|
||||
let mut response = HashMap::new();
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ pub async fn version_list(
|
||||
.await?;
|
||||
|
||||
let mut versions =
|
||||
database::models::Version::get_many_full(version_ids, &**pool)
|
||||
database::models::Version::get_many_full(&version_ids, &**pool)
|
||||
.await?;
|
||||
|
||||
let mut response = versions
|
||||
@@ -179,9 +179,9 @@ pub async fn versions_get(
|
||||
serde_json::from_str::<Vec<models::ids::VersionId>>(&ids.ids)?
|
||||
.into_iter()
|
||||
.map(|x| x.into())
|
||||
.collect();
|
||||
.collect::<Vec<database::models::VersionId>>();
|
||||
let versions_data =
|
||||
database::models::Version::get_many_full(version_ids, &**pool).await?;
|
||||
database::models::Version::get_many_full(&version_ids, &**pool).await?;
|
||||
|
||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ struct DiscordWebhook {
|
||||
pub avatar_url: Option<String>,
|
||||
pub username: Option<String>,
|
||||
pub embeds: Vec<DiscordEmbed>,
|
||||
pub content: Option<String>,
|
||||
}
|
||||
|
||||
const PLUGIN_LOADERS: &[&str] = &[
|
||||
@@ -72,6 +73,7 @@ pub async fn send_discord_webhook(
|
||||
project_id: ProjectId,
|
||||
pool: &PgPool,
|
||||
webhook_url: String,
|
||||
message: Option<String>,
|
||||
) -> Result<(), ApiError> {
|
||||
let all_game_versions = GameVersion::list(pool).await?;
|
||||
|
||||
@@ -257,6 +259,7 @@ pub async fn send_discord_webhook(
|
||||
),
|
||||
username: Some("Modrinth Release".to_string()),
|
||||
embeds: vec![embed],
|
||||
content: message,
|
||||
})
|
||||
.send()
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user