Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 62 additions & 0 deletions apps/labrinth/src/routes/internal/moderation/tech_review.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,34 @@ fn default_sort_by() -> SearchProjectsSort {

#[derive(Debug, Clone, Default, Serialize, Deserialize, utoipa::ToSchema)]
pub struct SearchProjectsFilter {
#[serde(default)]
pub project_type: Vec<ProjectTypeId>,
#[serde(default)]
pub replied_to: Option<RepliedTo>,
#[serde(default)]
pub project_status: Vec<ProjectStatus>,
}

/// Filter by whether a moderator has replied to the last message in the
/// project's moderation thread.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
utoipa::ToSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum RepliedTo {
/// Last message in the thread is from a moderator, indicating a moderator
/// has replied to it.
Replied,
/// Last message in the thread is not from a moderator.
Unreplied,
}

#[derive(
Expand Down Expand Up @@ -386,6 +413,11 @@ async fn search_projects(
let offset = i64::try_from(offset)
.wrap_request_err("offset cannot fit into `i64`")?;

let replied_to_filter = search_req.filter.replied_to.map(|r| match r {
RepliedTo::Replied => "replied",
RepliedTo::Unreplied => "unreplied",
});

let mut project_reports = Vec::<ProjectReport>::new();
let mut project_ids = Vec::<DBProjectId>::new();
let mut thread_ids = Vec::<DBThreadId>::new();
Expand Down Expand Up @@ -473,12 +505,35 @@ async fn search_projects(
ON didws.project_id = m.id AND didws.status = 'pending'

-- filtering

-- by project type
LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id
LEFT JOIN categories c ON c.id = mc.joining_category_id

-- get last message in thread for replied/unreplied filtering
LEFT JOIN threads_messages tm_last
ON tm_last.thread_id = t.id
AND tm_last.id = (
SELECT id FROM threads_messages
WHERE thread_id = t.id
ORDER BY created DESC
LIMIT 1
)
LEFT JOIN users u_last
ON u_last.id = tm_last.author_id

WHERE
-- project type
(cardinality($4::int[]) = 0 OR c.project_type = ANY($4::int[]))
AND m.status NOT IN ('draft', 'rejected', 'withheld')
-- project status
AND (cardinality($6::text[]) = 0 OR m.status = ANY($6::text[]))
-- replied/unreplied filter
AND (
$5::text IS NULL
OR ($5::text = 'unreplied' AND (tm_last.id IS NULL OR u_last.role IS NULL OR u_last.role NOT IN ('moderator', 'admin')))
OR ($5::text = 'replied' AND tm_last.id IS NOT NULL AND u_last.role IS NOT NULL AND u_last.role IN ('moderator', 'admin'))
)

GROUP BY m.id, t.id
) t
Expand All @@ -503,6 +558,13 @@ async fn search_projects(
.iter()
.map(|ty| ty.0)
.collect::<Vec<_>>(),
replied_to_filter.as_deref(),
&search_req
.filter
.project_status
.iter()
.map(|status| status.to_string())
.collect::<Vec<_>>()
)
.fetch(&**pool);

Expand Down
2 changes: 1 addition & 1 deletion scripts/i18n-import-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ function analyzeFile(filePath: string): FileIssue[] {
}
}
} catch {
// Silent fail for unparseable files
// Silent fail for unparsable files
}

return issues
Expand Down