diff --git a/apps/labrinth/.sqlx/query-03e377401b1a9bab44f3ff6451d3c1474a73fbce86ee25a3dab2320d59fc72b9.json b/apps/labrinth/.sqlx/query-03e377401b1a9bab44f3ff6451d3c1474a73fbce86ee25a3dab2320d59fc72b9.json
new file mode 100644
index 0000000000..e929d42e00
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-03e377401b1a9bab44f3ff6451d3c1474a73fbce86ee25a3dab2320d59fc72b9.json
@@ -0,0 +1,28 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n WITH project_membership AS (\n SELECT\n detail.project_id,\n BOOL_OR(\n detail.status IN ('pending', 'unsafe')\n AND detail.severity != 'hidden'\n ) AS old_needs_review,\n BOOL_OR(\n detail.status IN ('pending', 'unsafe')\n AND COALESCE(\n new_effect.severity,\n detail.original_severity\n ) != 'hidden'\n ) AS new_needs_review\n FROM delphi_issue_details_with_statuses detail\n LEFT JOIN delphi_rule_effects new_effect\n ON new_effect.revision = $1\n AND new_effect.detail_id = detail.id\n GROUP BY detail.project_id\n )\n SELECT\n project_id AS \"project_id!: DBProjectId\",\n new_needs_review AS \"new_needs_review!\"\n FROM project_membership\n WHERE old_needs_review IS DISTINCT FROM new_needs_review\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id!: DBProjectId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "new_needs_review!",
+ "type_info": "Bool"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": [
+ true,
+ null
+ ]
+ },
+ "hash": "03e377401b1a9bab44f3ff6451d3c1474a73fbce86ee25a3dab2320d59fc72b9"
+}
diff --git a/apps/labrinth/.sqlx/query-87d30e8802ebe69858141d0d918cafb5286f984cfe55ad1a7ac2219ec50539a4.json b/apps/labrinth/.sqlx/query-06384971752b20c04d7a747777bf03a765ab60c2b029a47fcd3fe97c02ee5b2a.json
similarity index 78%
rename from apps/labrinth/.sqlx/query-87d30e8802ebe69858141d0d918cafb5286f984cfe55ad1a7ac2219ec50539a4.json
rename to apps/labrinth/.sqlx/query-06384971752b20c04d7a747777bf03a765ab60c2b029a47fcd3fe97c02ee5b2a.json
index eabfd4299d..deece44e8e 100644
--- a/apps/labrinth/.sqlx/query-87d30e8802ebe69858141d0d918cafb5286f984cfe55ad1a7ac2219ec50539a4.json
+++ b/apps/labrinth/.sqlx/query-06384971752b20c04d7a747777bf03a765ab60c2b029a47fcd3fe97c02ee5b2a.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n WITH ranked_local_traces AS (\n SELECT\n didws.key AS detail_key,\n didws.id AS detail_id,\n didws.issue_id,\n dri.issue_type,\n m.id AS project_id,\n m.slug AS project_slug,\n m.name AS project_name,\n v.id AS version_id,\n v.version_number,\n f.id AS file_id,\n f.filename AS file_name,\n didws.jar,\n didws.file_path,\n didws.severity,\n COALESCE(didv.verdict, 'pending'::delphi_report_issue_status)\n AS local_status,\n didws.status AS effective_status,\n ROW_NUMBER() OVER (\n PARTITION BY didws.key\n ORDER BY didws.id\n ) AS row_num\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n INNER JOIN delphi_reports dr ON dr.id = dri.report_id\n INNER JOIN files f ON f.id = dr.file_id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m ON m.id = v.mod_id\n LEFT JOIN delphi_issue_detail_verdicts didv\n ON didv.project_id = didws.project_id\n AND didv.detail_key = didws.key\n WHERE\n didws.key = ANY($1::text[])\n AND dri.issue_type != '__dummy'\n )\n SELECT\n detail_key AS \"detail_key!\",\n detail_id AS \"detail_id!: DelphiReportIssueDetailsId\",\n issue_id AS \"issue_id!: DelphiReportIssueId\",\n issue_type,\n project_id AS \"project_id!: DBProjectId\",\n project_slug AS \"project_slug?\",\n project_name AS \"project_name!\",\n version_id AS \"version_id!: DBVersionId\",\n v.version_number,\n file_id AS \"file_id!: DBFileId\",\n file_name AS \"file_name!\",\n jar AS \"jar?\",\n file_path AS \"file_path!\",\n severity AS \"severity!: DelphiSeverity\",\n local_status AS \"local_status!: DelphiStatus\",\n effective_status AS \"effective_status!: DelphiStatus\"\n FROM ranked_local_traces v\n WHERE row_num <= $2\n ORDER BY detail_key, detail_id\n ",
+ "query": "\n WITH ranked_local_traces AS (\n SELECT\n didws.key AS detail_key,\n didws.id AS detail_id,\n didws.issue_id,\n dri.issue_type,\n m.id AS project_id,\n m.slug AS project_slug,\n m.name AS project_name,\n v.id AS version_id,\n v.version_number,\n f.id AS file_id,\n f.filename AS file_name,\n didws.jar,\n didws.file_path,\n didws.severity,\n COALESCE(didv.verdict, 'pending'::delphi_report_issue_status)\n AS local_status,\n didws.status AS effective_status,\n ROW_NUMBER() OVER (\n PARTITION BY didws.key\n ORDER BY didws.id\n ) AS row_num\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n INNER JOIN delphi_reports dr ON dr.id = dri.report_id\n INNER JOIN files f ON f.id = dr.file_id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m ON m.id = v.mod_id\n LEFT JOIN delphi_issue_detail_verdicts didv\n ON didv.project_id = didws.project_id\n AND didv.detail_key = didws.key\n WHERE\n didws.key = ANY($1::text[])\n AND didws.severity != 'hidden'\n )\n SELECT\n detail_key AS \"detail_key!\",\n detail_id AS \"detail_id!: DelphiReportIssueDetailsId\",\n issue_id AS \"issue_id!: DelphiReportIssueId\",\n issue_type,\n project_id AS \"project_id!: DBProjectId\",\n project_slug AS \"project_slug?\",\n project_name AS \"project_name!\",\n version_id AS \"version_id!: DBVersionId\",\n v.version_number,\n file_id AS \"file_id!: DBFileId\",\n file_name AS \"file_name!\",\n jar AS \"jar?\",\n file_path AS \"file_path!\",\n severity AS \"severity!: DelphiSeverity\",\n local_status AS \"local_status!: DelphiStatus\",\n effective_status AS \"effective_status!: DelphiStatus\"\n FROM ranked_local_traces v\n WHERE row_num <= $2\n ORDER BY detail_key, detail_id\n ",
"describe": {
"columns": [
{
@@ -76,10 +76,12 @@
"name": "delphi_severity",
"kind": {
"Enum": [
+ "hidden",
"low",
"medium",
"high",
- "severe"
+ "severe",
+ "malware"
]
}
}
@@ -143,5 +145,5 @@
true
]
},
- "hash": "87d30e8802ebe69858141d0d918cafb5286f984cfe55ad1a7ac2219ec50539a4"
+ "hash": "06384971752b20c04d7a747777bf03a765ab60c2b029a47fcd3fe97c02ee5b2a"
}
diff --git a/apps/labrinth/.sqlx/query-080e2f0068c0c1c248dcfacf39798aefed70d9a61610fc7f4f1c8f291706fa4a.json b/apps/labrinth/.sqlx/query-080e2f0068c0c1c248dcfacf39798aefed70d9a61610fc7f4f1c8f291706fa4a.json
deleted file mode 100644
index a80d2649ca..0000000000
--- a/apps/labrinth/.sqlx/query-080e2f0068c0c1c248dcfacf39798aefed70d9a61610fc7f4f1c8f291706fa4a.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n SELECT\n (\n SELECT t.id\n FROM threads t\n WHERE t.mod_id = $1\n ORDER BY t.id\n LIMIT 1\n ) AS \"thread_id: DBThreadId\",\n (\n SELECT tm.body->>'type'\n FROM threads t\n INNER JOIN threads_messages tm ON tm.thread_id = t.id\n WHERE\n t.mod_id = $1\n AND tm.body->>'type' = ANY($2::text[])\n ORDER BY tm.created DESC, tm.id DESC\n LIMIT 1\n ) AS \"last_tech_review_message_type\"\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "thread_id: DBThreadId",
- "type_info": "Int8"
- },
- {
- "ordinal": 1,
- "name": "last_tech_review_message_type",
- "type_info": "Text"
- }
- ],
- "parameters": {
- "Left": [
- "Int8",
- "TextArray"
- ]
- },
- "nullable": [
- null,
- null
- ]
- },
- "hash": "080e2f0068c0c1c248dcfacf39798aefed70d9a61610fc7f4f1c8f291706fa4a"
-}
diff --git a/apps/labrinth/.sqlx/query-0a541871989f0139a7f6f52e8cbae110b88a9cc05985c6cddc325ab913c9731a.json b/apps/labrinth/.sqlx/query-0a541871989f0139a7f6f52e8cbae110b88a9cc05985c6cddc325ab913c9731a.json
new file mode 100644
index 0000000000..20e84c3874
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-0a541871989f0139a7f6f52e8cbae110b88a9cc05985c6cddc325ab913c9731a.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT revision FROM delphi_rule_revisions LIMIT 1 FOR UPDATE",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "revision",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "0a541871989f0139a7f6f52e8cbae110b88a9cc05985c6cddc325ab913c9731a"
+}
diff --git a/apps/labrinth/.sqlx/query-0b94bdb7bf42fdfd0fb1b015fe582bfe8c43582acd17e726616da863e35742c5.json b/apps/labrinth/.sqlx/query-0b94bdb7bf42fdfd0fb1b015fe582bfe8c43582acd17e726616da863e35742c5.json
new file mode 100644
index 0000000000..3263182843
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-0b94bdb7bf42fdfd0fb1b015fe582bfe8c43582acd17e726616da863e35742c5.json
@@ -0,0 +1,28 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n WITH inserted AS (\n INSERT INTO delphi_tech_review_queue (project_id)\n SELECT unnest($1::bigint[])\n ON CONFLICT (project_id) DO NOTHING\n RETURNING project_id\n )\n SELECT\n inserted.project_id AS \"project_id!: DBProjectId\",\n (\n SELECT thread.id\n FROM threads thread\n WHERE thread.mod_id = inserted.project_id\n ORDER BY thread.id\n LIMIT 1\n ) AS \"thread_id!: DBThreadId\"\n FROM inserted\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id!: DBProjectId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "thread_id!: DBThreadId",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8Array"
+ ]
+ },
+ "nullable": [
+ false,
+ null
+ ]
+ },
+ "hash": "0b94bdb7bf42fdfd0fb1b015fe582bfe8c43582acd17e726616da863e35742c5"
+}
diff --git a/apps/labrinth/.sqlx/query-63a9a89443566baa880ddbe05f741e2a83b50d89f5954ab8d951a090e702de73.json b/apps/labrinth/.sqlx/query-15d8434ef325e21959ef8ab0541f78f647125717e2d157e0769e80aeae2cdc90.json
similarity index 90%
rename from apps/labrinth/.sqlx/query-63a9a89443566baa880ddbe05f741e2a83b50d89f5954ab8d951a090e702de73.json
rename to apps/labrinth/.sqlx/query-15d8434ef325e21959ef8ab0541f78f647125717e2d157e0769e80aeae2cdc90.json
index b9c6d3543c..0905114ade 100644
--- a/apps/labrinth/.sqlx/query-63a9a89443566baa880ddbe05f741e2a83b50d89f5954ab8d951a090e702de73.json
+++ b/apps/labrinth/.sqlx/query-15d8434ef325e21959ef8ab0541f78f647125717e2d157e0769e80aeae2cdc90.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT\n didws.id AS \"id!: DelphiReportIssueDetailsId\",\n didws.issue_id AS \"issue_id!: DelphiReportIssueId\",\n didws.key AS \"key!: String\",\n didws.jar AS \"jar?: String\",\n didws.file_path AS \"file_path!: String\",\n didws.data AS \"data!: sqlx::types::Json
>\",\n didws.severity AS \"severity!: DelphiSeverity\",\n didws.local_status AS \"local_status?: DelphiStatus\",\n didws.global_status AS \"global_status?: DelphiStatus\",\n didws.status AS \"status!: DelphiStatus\"\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.issue_id = ANY($1::bigint[])\n ORDER BY didws.issue_id, didws.id\n ",
+ "query": "\n SELECT\n didws.id AS \"id!: DelphiReportIssueDetailsId\",\n didws.issue_id AS \"issue_id!: DelphiReportIssueId\",\n didws.key AS \"key!: String\",\n didws.jar AS \"jar?: String\",\n didws.file_path AS \"file_path!: String\",\n didws.data AS \"data!: sqlx::types::Json>\",\n didws.severity AS \"severity!: DelphiSeverity\",\n didws.local_status AS \"local_status?: DelphiStatus\",\n didws.global_status AS \"global_status?: DelphiStatus\",\n didws.status AS \"status!: DelphiStatus\"\n FROM delphi_issue_details_with_statuses didws\n WHERE\n didws.issue_id = ANY($1::bigint[])\n AND didws.severity != 'hidden'\n ORDER BY didws.issue_id, didws.id\n ",
"describe": {
"columns": [
{
@@ -41,10 +41,12 @@
"name": "delphi_severity",
"kind": {
"Enum": [
+ "hidden",
"low",
"medium",
"high",
- "severe"
+ "severe",
+ "malware"
]
}
}
@@ -117,5 +119,5 @@
true
]
},
- "hash": "63a9a89443566baa880ddbe05f741e2a83b50d89f5954ab8d951a090e702de73"
+ "hash": "15d8434ef325e21959ef8ab0541f78f647125717e2d157e0769e80aeae2cdc90"
}
diff --git a/apps/labrinth/.sqlx/query-1697315d3414e911c9be30fa16164f884d1941120499ba076c7393c942131848.json b/apps/labrinth/.sqlx/query-1697315d3414e911c9be30fa16164f884d1941120499ba076c7393c942131848.json
new file mode 100644
index 0000000000..f643ed3d22
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-1697315d3414e911c9be30fa16164f884d1941120499ba076c7393c942131848.json
@@ -0,0 +1,14 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "UPDATE delphi_rules SET revision = $1 WHERE NOT delete_on_next_revision",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "1697315d3414e911c9be30fa16164f884d1941120499ba076c7393c942131848"
+}
diff --git a/apps/labrinth/.sqlx/query-182be4110f45b6be6a9174200a07a887cebbaeab0a8c1da8b008e0c5e94fbc4e.json b/apps/labrinth/.sqlx/query-182be4110f45b6be6a9174200a07a887cebbaeab0a8c1da8b008e0c5e94fbc4e.json
new file mode 100644
index 0000000000..5e057dc995
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-182be4110f45b6be6a9174200a07a887cebbaeab0a8c1da8b008e0c5e94fbc4e.json
@@ -0,0 +1,32 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT id AS \"id!: DelphiRuleId\", name, rule\n FROM delphi_rules\n WHERE NOT delete_on_next_revision\n ORDER BY priority DESC, id\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id!: DelphiRuleId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "name",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 2,
+ "name": "rule",
+ "type_info": "Varchar"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false,
+ false,
+ false
+ ]
+ },
+ "hash": "182be4110f45b6be6a9174200a07a887cebbaeab0a8c1da8b008e0c5e94fbc4e"
+}
diff --git a/apps/labrinth/.sqlx/query-1a6d4ac11af078439cff5c772f4dc2392729f99ba1f8c7892831235f341fb276.json b/apps/labrinth/.sqlx/query-1a6d4ac11af078439cff5c772f4dc2392729f99ba1f8c7892831235f341fb276.json
deleted file mode 100644
index 4db30b1153..0000000000
--- a/apps/labrinth/.sqlx/query-1a6d4ac11af078439cff5c772f4dc2392729f99ba1f8c7892831235f341fb276.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n SELECT\n m.id AS \"project_id: DBProjectId\",\n MIN(t.id) AS \"thread_id!: DBThreadId\"\n FROM mods m\n INNER JOIN threads t ON t.mod_id = m.id\n INNER JOIN versions v ON v.mod_id = m.id\n INNER JOIN files f ON f.version_id = v.id\n INNER JOIN delphi_reports dr ON dr.file_id = f.id\n INNER JOIN delphi_report_issues dri ON dri.report_id = dr.id\n INNER JOIN delphi_issue_details_with_statuses didws\n ON didws.issue_id = dri.id\n LEFT JOIN threads_messages tm_last\n ON tm_last.thread_id = t.id\n AND tm_last.id = (\n SELECT id FROM threads_messages\n WHERE thread_id = t.id\n ORDER BY created DESC\n LIMIT 1\n )\n LEFT JOIN users u_last\n ON u_last.id = tm_last.author_id\n WHERE\n (\n cardinality($4::text[]) = 0\n OR (\n 'minecraft_java_server' = ANY($4::text[])\n AND (\n m.components ? 'minecraft_server'\n OR m.components ? 'minecraft_java_server'\n )\n )\n OR EXISTS (\n SELECT 1\n FROM versions type_v\n INNER JOIN loaders_versions type_lv\n ON type_lv.version_id = type_v.id\n INNER JOIN loaders_project_types type_lpt\n ON type_lpt.joining_loader_id = type_lv.loader_id\n INNER JOIN project_types type_pt\n ON type_pt.id = type_lpt.joining_project_type_id\n WHERE\n type_v.mod_id = m.id\n AND type_pt.name = ANY($4::text[])\n AND (\n type_pt.name != 'modpack'\n OR NOT (\n m.components ? 'minecraft_server'\n OR m.components ? 'minecraft_java_server'\n )\n )\n )\n )\n AND m.status NOT IN ('draft', 'rejected', 'withheld')\n AND (cardinality($6::text[]) = 0 OR m.status = ANY($6::text[]))\n AND (cardinality($7::text[]) = 0 OR dri.issue_type = ANY($7::text[]))\n AND didws.status = 'pending'\n AND (\n $5::text IS NULL\n OR ($5::text = 'unreplied' AND (tm_last.id IS NULL OR u_last.role IS NULL OR u_last.role NOT IN ('moderator', 'admin')))\n 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'))\n )\n GROUP BY m.id\n ORDER BY\n CASE WHEN $3 = 'created_asc' THEN MIN(dr.created) ELSE TO_TIMESTAMP(0) END ASC,\n CASE WHEN $3 = 'created_desc' THEN MIN(dr.created) ELSE TO_TIMESTAMP(0) END DESC,\n CASE WHEN $3 = 'severity_asc' THEN MAX(dr.severity) ELSE 'low'::delphi_severity END ASC,\n CASE WHEN $3 = 'severity_desc' THEN MAX(dr.severity) ELSE 'low'::delphi_severity END DESC,\n -- tie-breaker: oldest reports\n MIN(dr.created) ASC\n LIMIT $1 OFFSET $2\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "project_id: DBProjectId",
- "type_info": "Int8"
- },
- {
- "ordinal": 1,
- "name": "thread_id!: DBThreadId",
- "type_info": "Int8"
- }
- ],
- "parameters": {
- "Left": [
- "Int8",
- "Int8",
- "Text",
- "TextArray",
- "Text",
- "TextArray",
- "TextArray"
- ]
- },
- "nullable": [
- false,
- null
- ]
- },
- "hash": "1a6d4ac11af078439cff5c772f4dc2392729f99ba1f8c7892831235f341fb276"
-}
diff --git a/apps/labrinth/.sqlx/query-20a88febcaf673264ff7f00a11848f97f334779cd871caa93a6de25c6c871e61.json b/apps/labrinth/.sqlx/query-20a88febcaf673264ff7f00a11848f97f334779cd871caa93a6de25c6c871e61.json
new file mode 100644
index 0000000000..f918bf11f0
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-20a88febcaf673264ff7f00a11848f97f334779cd871caa93a6de25c6c871e61.json
@@ -0,0 +1,12 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "DELETE FROM delphi_rules WHERE delete_on_next_revision",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": []
+ },
+ "hash": "20a88febcaf673264ff7f00a11848f97f334779cd871caa93a6de25c6c871e61"
+}
diff --git a/apps/labrinth/.sqlx/query-26618d64eb4ca9f14ed5cb5f143b593c4b16a3cfcff82a4ce93604f5448e5781.json b/apps/labrinth/.sqlx/query-26618d64eb4ca9f14ed5cb5f143b593c4b16a3cfcff82a4ce93604f5448e5781.json
new file mode 100644
index 0000000000..ecfdfc77f1
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-26618d64eb4ca9f14ed5cb5f143b593c4b16a3cfcff82a4ce93604f5448e5781.json
@@ -0,0 +1,186 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n\t\tSELECT\n\t\t\tdelphi_rule.id AS \"id!: DelphiRuleId\",\n\t\t\tdelphi_rule.name,\n\t\t\tdelphi_rule.rule,\n\t\t\tdelphi_rule.priority,\n\t\t\tdelphi_rule.revision,\n\t\t\tdelphi_rule.created_at,\n\t\t\tdelphi_rule.updated_at,\n\t\t\tdelphi_rule.created_by,\n\t\t\tdelphi_rule.updated_by,\n\t\t\tCOALESCE(preview.affected_details_count, 0)\n\t\t\t\tAS \"affected_details_count!\",\n\t\t\tpreview.detail_id AS \"detail_id?: DelphiReportIssueDetailsId\",\n\t\t\tpreview.issue_id AS \"issue_id?: DelphiReportIssueId\",\n\t\t\tpreview.project_id AS \"project_id?: DBProjectId\",\n\t\t\tpreview.project_name AS \"project_name?\",\n\t\t\tpreview.project_icon_url AS \"project_icon_url?\",\n\t\t\tpreview.version_id AS \"version_id?: DBVersionId\",\n\t\t\tpreview.version_name AS \"version_name?\",\n\t\t\tpreview.version_number AS \"version_number?\",\n\t\t\tpreview.issue_type AS \"issue_type?\",\n\t\t\tpreview.key AS \"key?\",\n\t\t\tpreview.jar AS \"jar?\",\n\t\t\tpreview.file_path AS \"file_path?\",\n\t\t\tpreview.original_severity AS \"original_severity?: DelphiSeverity\",\n\t\t\tpreview.severity AS \"effect_severity?: DelphiSeverity\"\n\t\tFROM delphi_rules delphi_rule\n\t\tLEFT JOIN LATERAL (\n\t\t\tSELECT\n\t\t\t\teffect.detail_id,\n\t\t\t\tdetail.issue_id,\n\t\t\t\tversion.mod_id AS project_id,\n\t\t\t\tproject.name AS project_name,\n\t\t\t\tproject.icon_url AS project_icon_url,\n\t\t\t\tversion.id AS version_id,\n\t\t\t\tversion.name AS version_name,\n\t\t\t\tversion.version_number,\n\t\t\t\tissue.issue_type,\n\t\t\t\tdetail.key,\n\t\t\t\tdetail.jar,\n\t\t\t\tdetail.file_path,\n\t\t\t\tdetail.severity AS original_severity,\n\t\t\t\teffect.severity,\n\t\t\t\tCOUNT(*) OVER () AS affected_details_count\n\t\t\tFROM delphi_rule_effects effect\n\t\t\tINNER JOIN delphi_rule_revisions published\n\t\t\t\tON published.revision = effect.revision\n\t\t\tINNER JOIN delphi_report_issue_details detail\n\t\t\t\tON detail.id = effect.detail_id\n\t\t\tINNER JOIN delphi_report_issues issue\n\t\t\t\tON issue.id = detail.issue_id\n\t\t\tINNER JOIN delphi_reports report\n\t\t\t\tON report.id = issue.report_id\n\t\t\tLEFT JOIN files file ON file.id = report.file_id\n\t\t\tLEFT JOIN versions version ON version.id = file.version_id\n\t\t\tLEFT JOIN mods project ON project.id = version.mod_id\n\t\t\tWHERE effect.rule_id = delphi_rule.id\n\t\t\tORDER BY effect.detail_id DESC\n\t\t\tLIMIT 3\n\t\t) preview ON TRUE\n\t\tWHERE NOT delphi_rule.delete_on_next_revision\n\t\tORDER BY\n\t\t\tdelphi_rule.priority DESC,\n\t\t\tdelphi_rule.id,\n\t\t\tpreview.detail_id DESC\n\t\t",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id!: DelphiRuleId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "name",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 2,
+ "name": "rule",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 3,
+ "name": "priority",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 4,
+ "name": "revision",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 5,
+ "name": "created_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 6,
+ "name": "updated_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 7,
+ "name": "created_by",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 8,
+ "name": "updated_by",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 9,
+ "name": "affected_details_count!",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 10,
+ "name": "detail_id?: DelphiReportIssueDetailsId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 11,
+ "name": "issue_id?: DelphiReportIssueId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 12,
+ "name": "project_id?: DBProjectId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 13,
+ "name": "project_name?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 14,
+ "name": "project_icon_url?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 15,
+ "name": "version_id?: DBVersionId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 16,
+ "name": "version_name?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 17,
+ "name": "version_number?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 18,
+ "name": "issue_type?",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 19,
+ "name": "key?",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 20,
+ "name": "jar?",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 21,
+ "name": "file_path?",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 22,
+ "name": "original_severity?: DelphiSeverity",
+ "type_info": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ordinal": 23,
+ "name": "effect_severity?: DelphiSeverity",
+ "type_info": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true,
+ null,
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false
+ ]
+ },
+ "hash": "26618d64eb4ca9f14ed5cb5f143b593c4b16a3cfcff82a4ce93604f5448e5781"
+}
diff --git a/apps/labrinth/.sqlx/query-285c66152a506e79c3c8996b4f44b8f63dcf79a2d02dcfeac9655d89bdb2750e.json b/apps/labrinth/.sqlx/query-285c66152a506e79c3c8996b4f44b8f63dcf79a2d02dcfeac9655d89bdb2750e.json
new file mode 100644
index 0000000000..5d0c482906
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-285c66152a506e79c3c8996b4f44b8f63dcf79a2d02dcfeac9655d89bdb2750e.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n DELETE FROM delphi_tech_review_queue\n WHERE project_id = $1\n RETURNING project_id AS \"project_id: DBProjectId\"\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id: DBProjectId",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "285c66152a506e79c3c8996b4f44b8f63dcf79a2d02dcfeac9655d89bdb2750e"
+}
diff --git a/apps/labrinth/.sqlx/query-055f71ec6d193c5f5259cafc989a04f3f791205e6c2df15c5bf9d5afcf71a76a.json b/apps/labrinth/.sqlx/query-36ffcc9010d1f70deba53483cc2bcbc274f4b55db499bf83b990634b9a805575.json
similarity index 94%
rename from apps/labrinth/.sqlx/query-055f71ec6d193c5f5259cafc989a04f3f791205e6c2df15c5bf9d5afcf71a76a.json
rename to apps/labrinth/.sqlx/query-36ffcc9010d1f70deba53483cc2bcbc274f4b55db499bf83b990634b9a805575.json
index cf686ee65a..8e9078348f 100644
--- a/apps/labrinth/.sqlx/query-055f71ec6d193c5f5259cafc989a04f3f791205e6c2df15c5bf9d5afcf71a76a.json
+++ b/apps/labrinth/.sqlx/query-36ffcc9010d1f70deba53483cc2bcbc274f4b55db499bf83b990634b9a805575.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT\n didws.key AS \"detail_key!\",\n didws.id AS \"detail_id!: DelphiReportIssueDetailsId\",\n didws.issue_id AS \"issue_id!: DelphiReportIssueId\",\n dri.issue_type,\n m.id AS \"project_id!: DBProjectId\",\n m.slug AS \"project_slug?\",\n m.name AS \"project_name!\",\n v.id AS \"version_id!: DBVersionId\",\n v.version_number,\n f.id AS \"file_id!: DBFileId\",\n f.filename AS \"file_name!\",\n didws.jar AS \"jar?\",\n didws.file_path AS \"file_path!\",\n didws.severity AS \"severity!: DelphiSeverity\",\n COALESCE(didv.verdict, 'pending'::delphi_report_issue_status)\n AS \"local_status!: DelphiStatus\",\n didws.status AS \"effective_status!: DelphiStatus\"\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n INNER JOIN delphi_reports dr ON dr.id = dri.report_id\n INNER JOIN files f ON f.id = dr.file_id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m ON m.id = v.mod_id\n LEFT JOIN delphi_issue_detail_verdicts didv\n ON didv.project_id = didws.project_id\n AND didv.detail_key = didws.key\n WHERE\n didws.key = $1\n AND ($2::bigint IS NULL OR didws.id > $2)\n AND dri.issue_type != '__dummy'\n ORDER BY didws.id\n LIMIT $3\n ",
+ "query": "\n SELECT\n didws.key AS \"detail_key!\",\n didws.id AS \"detail_id!: DelphiReportIssueDetailsId\",\n didws.issue_id AS \"issue_id!: DelphiReportIssueId\",\n dri.issue_type,\n m.id AS \"project_id!: DBProjectId\",\n m.slug AS \"project_slug?\",\n m.name AS \"project_name!\",\n v.id AS \"version_id!: DBVersionId\",\n v.version_number,\n f.id AS \"file_id!: DBFileId\",\n f.filename AS \"file_name!\",\n didws.jar AS \"jar?\",\n didws.file_path AS \"file_path!\",\n didws.severity AS \"severity!: DelphiSeverity\",\n COALESCE(didv.verdict, 'pending'::delphi_report_issue_status)\n AS \"local_status!: DelphiStatus\",\n didws.status AS \"effective_status!: DelphiStatus\"\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n INNER JOIN delphi_reports dr ON dr.id = dri.report_id\n INNER JOIN files f ON f.id = dr.file_id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m ON m.id = v.mod_id\n LEFT JOIN delphi_issue_detail_verdicts didv\n ON didv.project_id = didws.project_id\n AND didv.detail_key = didws.key\n WHERE\n didws.key = $1\n AND ($2::bigint IS NULL OR didws.id > $2)\n AND didws.severity != 'hidden'\n ORDER BY didws.id\n LIMIT $3\n ",
"describe": {
"columns": [
{
@@ -76,10 +76,12 @@
"name": "delphi_severity",
"kind": {
"Enum": [
+ "hidden",
"low",
"medium",
"high",
- "severe"
+ "severe",
+ "malware"
]
}
}
@@ -144,5 +146,5 @@
true
]
},
- "hash": "055f71ec6d193c5f5259cafc989a04f3f791205e6c2df15c5bf9d5afcf71a76a"
+ "hash": "36ffcc9010d1f70deba53483cc2bcbc274f4b55db499bf83b990634b9a805575"
}
diff --git a/apps/labrinth/.sqlx/query-42579ab8ccb58b9b2553787327115af8dbb2a85db0affc67eac74cfb48fbaa3e.json b/apps/labrinth/.sqlx/query-42579ab8ccb58b9b2553787327115af8dbb2a85db0affc67eac74cfb48fbaa3e.json
new file mode 100644
index 0000000000..c04d8b8fea
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-42579ab8ccb58b9b2553787327115af8dbb2a85db0affc67eac74cfb48fbaa3e.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT COUNT(*) AS \"count!\"\n FROM delphi_report_issue_details\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "count!",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "42579ab8ccb58b9b2553787327115af8dbb2a85db0affc67eac74cfb48fbaa3e"
+}
diff --git a/apps/labrinth/.sqlx/query-48dfc2f2bcf8917f110b7b2b142167f1525cdea2ace9e6165e5c5f596cbd9fb3.json b/apps/labrinth/.sqlx/query-48dfc2f2bcf8917f110b7b2b142167f1525cdea2ace9e6165e5c5f596cbd9fb3.json
deleted file mode 100644
index fa0165cc60..0000000000
--- a/apps/labrinth/.sqlx/query-48dfc2f2bcf8917f110b7b2b142167f1525cdea2ace9e6165e5c5f596cbd9fb3.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n SELECT DISTINCT ON (dr.id)\n to_jsonb(dr)\n || jsonb_build_object(\n 'report_id', dr.id,\n 'file_id', to_base62(f.id),\n 'version_id', to_base62(v.id),\n 'project_id', to_base62(v.mod_id),\n 'file_name', f.filename,\n 'file_size', f.size,\n 'flag_reason', 'delphi',\n 'download_url', f.url,\n -- TODO: replace with `json_array` in Postgres 16\n\t\t\t\t'issues', (\n\t\t\t\t\tSELECT coalesce(json_agg(\n\t\t\t\t\t\tto_jsonb(dri)\n\t\t\t\t\t\t|| jsonb_build_object(\n\t\t\t\t\t\t\t-- TODO: replace with `json_array` in Postgres 16\n\t\t\t\t\t\t\t'details', (\n\t\t\t\t\t\t\t\tSELECT coalesce(jsonb_agg(\n jsonb_build_object(\n 'id', didws.id,\n 'issue_id', didws.issue_id,\n 'key', didws.key,\n 'file_path', didws.file_path,\n 'decompiled_source', didws.decompiled_source,\n 'data', didws.data,\n 'severity', didws.severity,\n 'local_status', didws.local_status,\n 'global_status', didws.global_status,\n 'status', didws.status\n )\n ), '[]'::jsonb)\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.issue_id = dri.id\n )\n\t\t\t\t\t\t)\n\t\t\t\t\t), '[]'::json)\n\t\t\t\t\tFROM delphi_report_issues dri\n\t\t\t\t\tWHERE\n\t\t\t\t\t\tdri.report_id = dr.id\n -- see delphi.rs todo comment\n AND dri.issue_type != '__dummy'\n )\n ) AS \"data!: sqlx::types::Json\"\n FROM delphi_reports dr\n INNER JOIN files f ON f.id = dr.file_id\n INNER JOIN versions v ON v.id = f.version_id\n WHERE dr.id = $1\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "data!: sqlx::types::Json",
- "type_info": "Jsonb"
- }
- ],
- "parameters": {
- "Left": [
- "Int8"
- ]
- },
- "nullable": [
- null
- ]
- },
- "hash": "48dfc2f2bcf8917f110b7b2b142167f1525cdea2ace9e6165e5c5f596cbd9fb3"
-}
diff --git a/apps/labrinth/.sqlx/query-4e30093d30c2ee3c39e6e3f2d9ffdc2ba5455d2213e06bc3e273f250ef97a525.json b/apps/labrinth/.sqlx/query-4e30093d30c2ee3c39e6e3f2d9ffdc2ba5455d2213e06bc3e273f250ef97a525.json
new file mode 100644
index 0000000000..fcafa64eb2
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-4e30093d30c2ee3c39e6e3f2d9ffdc2ba5455d2213e06bc3e273f250ef97a525.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT requested.project_id AS \"project_id!: DBProjectId\"\n FROM unnest($1::bigint[]) AS requested(project_id)\n WHERE NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses detail\n WHERE detail.project_id = requested.project_id\n )\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id!: DBProjectId",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8Array"
+ ]
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "4e30093d30c2ee3c39e6e3f2d9ffdc2ba5455d2213e06bc3e273f250ef97a525"
+}
diff --git a/apps/labrinth/.sqlx/query-50a5f3a116ebe5cf88452a9aac89f73135491f170e3d619a93144b36ef429705.json b/apps/labrinth/.sqlx/query-50a5f3a116ebe5cf88452a9aac89f73135491f170e3d619a93144b36ef429705.json
new file mode 100644
index 0000000000..ec24566ebe
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-50a5f3a116ebe5cf88452a9aac89f73135491f170e3d619a93144b36ef429705.json
@@ -0,0 +1,14 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "DELETE FROM delphi_rule_effects WHERE revision <> $1",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "50a5f3a116ebe5cf88452a9aac89f73135491f170e3d619a93144b36ef429705"
+}
diff --git a/apps/labrinth/.sqlx/query-52ef6d02f8d533fc4e4ceb141d07a2eb115dc88da24735fffeca3eb1c269ad53.json b/apps/labrinth/.sqlx/query-563d4d8ff958b3a915e6e20b0654c9f189f1c34a94c27a2b894e7eade286b8a3.json
similarity index 76%
rename from apps/labrinth/.sqlx/query-52ef6d02f8d533fc4e4ceb141d07a2eb115dc88da24735fffeca3eb1c269ad53.json
rename to apps/labrinth/.sqlx/query-563d4d8ff958b3a915e6e20b0654c9f189f1c34a94c27a2b894e7eade286b8a3.json
index a0657d3e6d..d9091ae767 100644
--- a/apps/labrinth/.sqlx/query-52ef6d02f8d533fc4e4ceb141d07a2eb115dc88da24735fffeca3eb1c269ad53.json
+++ b/apps/labrinth/.sqlx/query-563d4d8ff958b3a915e6e20b0654c9f189f1c34a94c27a2b894e7eade286b8a3.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT\n didws.id AS \"issue_detail_id!\"\n FROM mods m\n INNER JOIN versions v ON v.mod_id = m.id\n INNER JOIN files f ON f.version_id = v.id\n INNER JOIN delphi_reports dr ON dr.file_id = f.id\n INNER JOIN delphi_report_issues dri ON dri.report_id = dr.id\n INNER JOIN delphi_issue_details_with_statuses didws ON didws.issue_id = dri.id\n WHERE\n m.id = $1\n AND didws.status = 'pending'\n -- see delphi.rs todo comment\n AND dri.issue_type != '__dummy'\n ",
+ "query": "\n SELECT\n didws.id AS \"issue_detail_id!\"\n FROM mods m\n INNER JOIN versions v ON v.mod_id = m.id\n INNER JOIN files f ON f.version_id = v.id\n INNER JOIN delphi_reports dr ON dr.file_id = f.id\n INNER JOIN delphi_report_issues dri ON dri.report_id = dr.id\n INNER JOIN delphi_issue_details_with_statuses didws ON didws.issue_id = dri.id\n WHERE\n m.id = $1\n AND didws.status = 'pending'\n AND didws.severity != 'hidden'\n ",
"describe": {
"columns": [
{
@@ -18,5 +18,5 @@
true
]
},
- "hash": "52ef6d02f8d533fc4e4ceb141d07a2eb115dc88da24735fffeca3eb1c269ad53"
+ "hash": "563d4d8ff958b3a915e6e20b0654c9f189f1c34a94c27a2b894e7eade286b8a3"
}
diff --git a/apps/labrinth/.sqlx/query-1bff1c5714dd039814d7a9d9f25f4ceca0e84a42b3a4c414210739fec6308e2d.json b/apps/labrinth/.sqlx/query-5d5024681546a90c9fb18dae934a0f99a63c3f075cbad8545000a03a5a030323.json
similarity index 64%
rename from apps/labrinth/.sqlx/query-1bff1c5714dd039814d7a9d9f25f4ceca0e84a42b3a4c414210739fec6308e2d.json
rename to apps/labrinth/.sqlx/query-5d5024681546a90c9fb18dae934a0f99a63c3f075cbad8545000a03a5a030323.json
index c55b8c6c7c..b1341067bb 100644
--- a/apps/labrinth/.sqlx/query-1bff1c5714dd039814d7a9d9f25f4ceca0e84a42b3a4c414210739fec6308e2d.json
+++ b/apps/labrinth/.sqlx/query-5d5024681546a90c9fb18dae934a0f99a63c3f075cbad8545000a03a5a030323.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT id\n FROM mods\n WHERE\n status = $1\n AND (\n $3::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = mods.id\n AND didws.status = 'pending'\n )\n )\n ORDER BY\n CASE WHEN $2 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $2 = 'oldest' THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n ",
+ "query": "\n SELECT id\n FROM mods\n WHERE\n status = $1\n AND (\n $3::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = mods.id\n AND didws.status = 'pending'\n AND didws.severity != 'hidden'\n )\n )\n ORDER BY\n CASE WHEN $2 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $2 = 'oldest' THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n ",
"describe": {
"columns": [
{
@@ -20,5 +20,5 @@
false
]
},
- "hash": "1bff1c5714dd039814d7a9d9f25f4ceca0e84a42b3a4c414210739fec6308e2d"
+ "hash": "5d5024681546a90c9fb18dae934a0f99a63c3f075cbad8545000a03a5a030323"
}
diff --git a/apps/labrinth/.sqlx/query-628d178e568998627de7e7cdba3b5c83300b5649f2ccc215f20fd82e258e76f4.json b/apps/labrinth/.sqlx/query-628d178e568998627de7e7cdba3b5c83300b5649f2ccc215f20fd82e258e76f4.json
new file mode 100644
index 0000000000..05ff0c342a
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-628d178e568998627de7e7cdba3b5c83300b5649f2ccc215f20fd82e258e76f4.json
@@ -0,0 +1,34 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n m.id AS \"project_id: DBProjectId\",\n MIN(t.id) AS \"thread_id!: DBThreadId\"\n FROM mods m\n INNER JOIN delphi_tech_review_queue trq ON trq.project_id = m.id\n INNER JOIN threads t ON t.mod_id = m.id\n LEFT JOIN versions v ON v.mod_id = m.id\n LEFT JOIN files f ON f.version_id = v.id\n LEFT JOIN delphi_reports dr ON dr.file_id = f.id\n LEFT JOIN delphi_report_issues dri ON dri.report_id = dr.id\n LEFT JOIN delphi_issue_details_with_statuses didws\n ON didws.issue_id = dri.id\n AND didws.severity != 'hidden'\n LEFT JOIN threads_messages tm_last\n ON tm_last.thread_id = t.id\n AND tm_last.id = (\n SELECT id FROM threads_messages\n WHERE thread_id = t.id\n ORDER BY created DESC\n LIMIT 1\n )\n LEFT JOIN users u_last\n ON u_last.id = tm_last.author_id\n WHERE\n (\n cardinality($4::text[]) = 0\n OR (\n 'minecraft_java_server' = ANY($4::text[])\n AND (\n m.components ? 'minecraft_server'\n OR m.components ? 'minecraft_java_server'\n )\n )\n OR EXISTS (\n SELECT 1\n FROM versions type_v\n INNER JOIN loaders_versions type_lv\n ON type_lv.version_id = type_v.id\n INNER JOIN loaders_project_types type_lpt\n ON type_lpt.joining_loader_id = type_lv.loader_id\n INNER JOIN project_types type_pt\n ON type_pt.id = type_lpt.joining_project_type_id\n WHERE\n type_v.mod_id = m.id\n AND type_pt.name = ANY($4::text[])\n AND (\n type_pt.name != 'modpack'\n OR NOT (\n m.components ? 'minecraft_server'\n OR m.components ? 'minecraft_java_server'\n )\n )\n )\n )\n AND m.status NOT IN ('draft', 'rejected', 'withheld')\n AND (cardinality($6::text[]) = 0 OR m.status = ANY($6::text[]))\n AND (\n cardinality($7::text[]) = 0\n OR EXISTS (\n SELECT 1\n FROM versions issue_version\n INNER JOIN files issue_file\n ON issue_file.version_id = issue_version.id\n INNER JOIN delphi_reports issue_report\n ON issue_report.file_id = issue_file.id\n INNER JOIN delphi_report_issues issue\n ON issue.report_id = issue_report.id\n INNER JOIN delphi_issue_details_with_statuses detail\n ON detail.issue_id = issue.id\n WHERE\n issue_version.mod_id = m.id\n AND issue.issue_type = ANY($7::text[])\n AND detail.severity != 'hidden'\n )\n )\n AND (\n $5::text IS NULL\n OR ($5::text = 'unreplied' AND (tm_last.id IS NULL OR u_last.role IS NULL OR u_last.role NOT IN ('moderator', 'admin')))\n 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'))\n )\n GROUP BY m.id\n ORDER BY\n CASE WHEN $3 = 'created_asc' THEN MIN(dr.created) ELSE TO_TIMESTAMP(0) END ASC,\n CASE WHEN $3 = 'created_desc' THEN MIN(dr.created) ELSE TO_TIMESTAMP(0) END DESC,\n CASE WHEN $3 = 'severity_asc' THEN COALESCE(MAX(didws.severity), 'low'::delphi_severity) ELSE 'low'::delphi_severity END ASC,\n CASE WHEN $3 = 'severity_desc' THEN COALESCE(MAX(didws.severity), 'low'::delphi_severity) ELSE 'low'::delphi_severity END DESC,\n -- tie-breaker: oldest reports\n MIN(dr.created) ASC\n LIMIT $1 OFFSET $2\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id: DBProjectId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "thread_id!: DBThreadId",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8",
+ "Int8",
+ "Text",
+ "TextArray",
+ "Text",
+ "TextArray",
+ "TextArray"
+ ]
+ },
+ "nullable": [
+ false,
+ null
+ ]
+ },
+ "hash": "628d178e568998627de7e7cdba3b5c83300b5649f2ccc215f20fd82e258e76f4"
+}
diff --git a/apps/labrinth/.sqlx/query-62d548639ed397f3619a8c3a4503f472fceb6ee0e120b511c1ed64cb200e0e9c.json b/apps/labrinth/.sqlx/query-62d548639ed397f3619a8c3a4503f472fceb6ee0e120b511c1ed64cb200e0e9c.json
new file mode 100644
index 0000000000..e2a4cfb50f
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-62d548639ed397f3619a8c3a4503f472fceb6ee0e120b511c1ed64cb200e0e9c.json
@@ -0,0 +1,12 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "LOCK TABLE delphi_report_issue_details IN SHARE MODE",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": []
+ },
+ "hash": "62d548639ed397f3619a8c3a4503f472fceb6ee0e120b511c1ed64cb200e0e9c"
+}
diff --git a/apps/labrinth/.sqlx/query-6776dc50f184188756ad7fe263b0304333536768527525a43bdd45aedffa3c4f.json b/apps/labrinth/.sqlx/query-6776dc50f184188756ad7fe263b0304333536768527525a43bdd45aedffa3c4f.json
new file mode 100644
index 0000000000..4187b628b7
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-6776dc50f184188756ad7fe263b0304333536768527525a43bdd45aedffa3c4f.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT pg_try_advisory_xact_lock($1)",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "pg_try_advisory_xact_lock",
+ "type_info": "Bool"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "6776dc50f184188756ad7fe263b0304333536768527525a43bdd45aedffa3c4f"
+}
diff --git a/apps/labrinth/.sqlx/query-ba7585f55df2a4596caae265ac956eb23268f26aef664234b898b17d13c09f91.json b/apps/labrinth/.sqlx/query-6fa83172261e64445f2fa18d2c98eb68f2617f6f57a31edda36c2f861e7da7f7.json
similarity index 70%
rename from apps/labrinth/.sqlx/query-ba7585f55df2a4596caae265ac956eb23268f26aef664234b898b17d13c09f91.json
rename to apps/labrinth/.sqlx/query-6fa83172261e64445f2fa18d2c98eb68f2617f6f57a31edda36c2f861e7da7f7.json
index 20a2667bb3..34f1afab32 100644
--- a/apps/labrinth/.sqlx/query-ba7585f55df2a4596caae265ac956eb23268f26aef664234b898b17d13c09f91.json
+++ b/apps/labrinth/.sqlx/query-6fa83172261e64445f2fa18d2c98eb68f2617f6f57a31edda36c2f861e7da7f7.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT DISTINCT didws.project_id AS \"project_id!: DBProjectId\"\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.key = ANY($1::text[])\n ",
+ "query": "\n SELECT DISTINCT didws.project_id AS \"project_id!: DBProjectId\"\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.id = ANY($1::bigint[])\n ",
"describe": {
"columns": [
{
@@ -11,12 +11,12 @@
],
"parameters": {
"Left": [
- "TextArray"
+ "Int8Array"
]
},
"nullable": [
true
]
},
- "hash": "ba7585f55df2a4596caae265ac956eb23268f26aef664234b898b17d13c09f91"
+ "hash": "6fa83172261e64445f2fa18d2c98eb68f2617f6f57a31edda36c2f861e7da7f7"
}
diff --git a/apps/labrinth/.sqlx/query-73e3646a21e4acb1299f0b183b92beda18c30564fc90e5213e5237f505504558.json b/apps/labrinth/.sqlx/query-73e3646a21e4acb1299f0b183b92beda18c30564fc90e5213e5237f505504558.json
new file mode 100644
index 0000000000..f0a4d22896
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-73e3646a21e4acb1299f0b183b92beda18c30564fc90e5213e5237f505504558.json
@@ -0,0 +1,29 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n WITH incoming AS (\n SELECT *\n FROM unnest($1::bigint[], $2::text[]) WITH ORDINALITY\n AS u(detail_id, verdict, ord)\n ),\n resolved AS (\n SELECT\n i.ord,\n didws.project_id,\n didws.key AS detail_key,\n i.verdict\n FROM incoming i\n INNER JOIN delphi_issue_details_with_statuses didws ON didws.id = i.detail_id\n ),\n validated AS (\n SELECT\n (SELECT COUNT(*) FROM incoming) AS incoming_count,\n (SELECT COUNT(*) FROM resolved) AS resolved_count\n ),\n latest AS (\n SELECT DISTINCT ON (project_id, detail_key)\n project_id,\n detail_key,\n verdict\n FROM resolved\n ORDER BY project_id, detail_key, ord DESC\n ),\n deleted AS (\n DELETE FROM delphi_issue_detail_verdicts didv\n USING latest\n WHERE\n didv.project_id = latest.project_id\n AND didv.detail_key = latest.detail_key\n AND latest.verdict = 'pending'\n RETURNING 1\n ),\n upserted AS (\n INSERT INTO delphi_issue_detail_verdicts (\n project_id,\n detail_key,\n verdict\n )\n SELECT\n project_id,\n detail_key,\n verdict::delphi_report_issue_status\n FROM latest\n WHERE verdict != 'pending'\n ON CONFLICT (project_id, detail_key)\n DO UPDATE SET verdict = EXCLUDED.verdict\n RETURNING 1\n )\n SELECT\n (v.incoming_count = v.resolved_count) AS \"all_found!\",\n (SELECT COUNT(*) FROM upserted) AS \"upserted_count!\"\n FROM validated v\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "all_found!",
+ "type_info": "Bool"
+ },
+ {
+ "ordinal": 1,
+ "name": "upserted_count!",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8Array",
+ "TextArray"
+ ]
+ },
+ "nullable": [
+ null,
+ null
+ ]
+ },
+ "hash": "73e3646a21e4acb1299f0b183b92beda18c30564fc90e5213e5237f505504558"
+}
diff --git a/apps/labrinth/.sqlx/query-7e7e2e9f67158b94eb62834cbfd65fd5165d02ebcc0f8454554cbd870e4ddb42.json b/apps/labrinth/.sqlx/query-7e7e2e9f67158b94eb62834cbfd65fd5165d02ebcc0f8454554cbd870e4ddb42.json
new file mode 100644
index 0000000000..14a9377c81
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-7e7e2e9f67158b94eb62834cbfd65fd5165d02ebcc0f8454554cbd870e4ddb42.json
@@ -0,0 +1,120 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n detail.id,\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(version_metadata.project_types, ARRAY[]::text[])\n AS \"project_types!: Vec\",\n COALESCE(version_metadata.loaders, ARRAY[]::text[])\n AS \"loaders!: Vec\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN LATERAL (\n SELECT\n ARRAY_AGG(\n DISTINCT project_type.name::text\n ORDER BY project_type.name::text\n ) FILTER (WHERE project_type.name IS NOT NULL)\n AS project_types,\n ARRAY_AGG(\n DISTINCT loader.loader\n ORDER BY loader.loader\n ) AS loaders\n FROM loaders_versions loader_version\n INNER JOIN loaders loader\n ON loader.id = loader_version.loader_id\n LEFT JOIN loaders_project_types loader_project_type\n ON loader_project_type.joining_loader_id = loader_version.loader_id\n LEFT JOIN project_types project_type\n ON project_type.id = loader_project_type.joining_project_type_id\n WHERE loader_version.version_id = version.id\n ) version_metadata ON TRUE\n LEFT JOIN LATERAL (\n SELECT\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n WHERE hashes.file_id = file.id\n ) file_hashes ON TRUE\n WHERE detail.id = ANY($1::bigint[])\n ORDER BY detail.id\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "key",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 2,
+ "name": "issue_type",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 3,
+ "name": "severity: DelphiSeverity",
+ "type_info": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ordinal": 4,
+ "name": "jar",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 5,
+ "name": "file_path",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 6,
+ "name": "data: Json>",
+ "type_info": "Jsonb"
+ },
+ {
+ "ordinal": 7,
+ "name": "delphi_version",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 8,
+ "name": "size?",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 9,
+ "name": "file_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 10,
+ "name": "version_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 11,
+ "name": "project_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 12,
+ "name": "project_types!: Vec",
+ "type_info": "TextArray"
+ },
+ {
+ "ordinal": 13,
+ "name": "loaders!: Vec",
+ "type_info": "VarcharArray"
+ },
+ {
+ "ordinal": 14,
+ "name": "hashes!: Json>",
+ "type_info": "Jsonb"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8Array"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ true,
+ true,
+ true,
+ true,
+ null,
+ null,
+ null
+ ]
+ },
+ "hash": "7e7e2e9f67158b94eb62834cbfd65fd5165d02ebcc0f8454554cbd870e4ddb42"
+}
diff --git a/apps/labrinth/.sqlx/query-820810b83ce47f32bf5b0dc20e5fc3223f66e83a2b5f6efbf10eec3a927f31b2.json b/apps/labrinth/.sqlx/query-820810b83ce47f32bf5b0dc20e5fc3223f66e83a2b5f6efbf10eec3a927f31b2.json
new file mode 100644
index 0000000000..24b8b0d507
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-820810b83ce47f32bf5b0dc20e5fc3223f66e83a2b5f6efbf10eec3a927f31b2.json
@@ -0,0 +1,12 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "LOCK TABLE delphi_rules IN SHARE MODE",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": []
+ },
+ "hash": "820810b83ce47f32bf5b0dc20e5fc3223f66e83a2b5f6efbf10eec3a927f31b2"
+}
diff --git a/apps/labrinth/.sqlx/query-852eff37ff36e1e87fcbc6c50f27bab003a40537c191eb6cb64a01d92b57e25f.json b/apps/labrinth/.sqlx/query-852eff37ff36e1e87fcbc6c50f27bab003a40537c191eb6cb64a01d92b57e25f.json
new file mode 100644
index 0000000000..374b61603c
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-852eff37ff36e1e87fcbc6c50f27bab003a40537c191eb6cb64a01d92b57e25f.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT DISTINCT ON (dr.id)\n to_jsonb(dr)\n || jsonb_build_object(\n 'report_id', dr.id,\n 'file_id', to_base62(f.id),\n 'version_id', to_base62(v.id),\n 'project_id', to_base62(v.mod_id),\n 'file_name', f.filename,\n 'file_size', f.size,\n 'flag_reason', 'delphi',\n 'download_url', f.url,\n 'severity', COALESCE((\n SELECT MAX(didws.severity)\n FROM delphi_report_issues severity_issue\n INNER JOIN delphi_issue_details_with_statuses didws\n ON didws.issue_id = severity_issue.id\n WHERE\n severity_issue.report_id = dr.id\n AND didws.severity != 'hidden'\n ), 'low'::delphi_severity),\n -- TODO: replace with `json_array` in Postgres 16\n\t\t\t\t'issues', (\n\t\t\t\t\tSELECT coalesce(json_agg(\n\t\t\t\t\t\tto_jsonb(dri)\n\t\t\t\t\t\t|| jsonb_build_object(\n\t\t\t\t\t\t\t-- TODO: replace with `json_array` in Postgres 16\n\t\t\t\t\t\t\t'details', (\n\t\t\t\t\t\t\t\tSELECT coalesce(jsonb_agg(\n jsonb_build_object(\n 'id', didws.id,\n 'issue_id', didws.issue_id,\n 'key', didws.key,\n 'file_path', didws.file_path,\n 'decompiled_source', didws.decompiled_source,\n 'data', didws.data,\n 'severity', didws.severity,\n 'local_status', didws.local_status,\n 'global_status', didws.global_status,\n 'status', didws.status\n )\n ), '[]'::jsonb)\n FROM delphi_issue_details_with_statuses didws\n WHERE\n didws.issue_id = dri.id\n AND didws.severity != 'hidden'\n )\n\t\t\t\t\t\t)\n\t\t\t\t\t), '[]'::json)\n\t\t\t\t\tFROM delphi_report_issues dri\n\t\t\t\t\tWHERE\n dri.report_id = dr.id\n AND EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses visible_detail\n WHERE\n visible_detail.issue_id = dri.id\n AND visible_detail.severity != 'hidden'\n )\n )\n ) AS \"data!: sqlx::types::Json\"\n FROM delphi_reports dr\n INNER JOIN files f ON f.id = dr.file_id\n INNER JOIN versions v ON v.id = f.version_id\n WHERE dr.id = $1\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "data!: sqlx::types::Json",
+ "type_info": "Jsonb"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": [
+ null
+ ]
+ },
+ "hash": "852eff37ff36e1e87fcbc6c50f27bab003a40537c191eb6cb64a01d92b57e25f"
+}
diff --git a/apps/labrinth/.sqlx/query-8537362d9c11e437ada9ce97bb604666378d1d24981ab8113badded16fb63413.json b/apps/labrinth/.sqlx/query-8537362d9c11e437ada9ce97bb604666378d1d24981ab8113badded16fb63413.json
new file mode 100644
index 0000000000..1102be54f7
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-8537362d9c11e437ada9ce97bb604666378d1d24981ab8113badded16fb63413.json
@@ -0,0 +1,118 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n detail.id,\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(version_metadata.project_types, ARRAY[]::text[])\n AS \"project_types!: Vec\",\n COALESCE(version_metadata.loaders, ARRAY[]::text[])\n AS \"loaders!: Vec\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN (\n SELECT\n loader_version.version_id,\n ARRAY_AGG(\n DISTINCT project_type.name::text\n ORDER BY project_type.name::text\n ) FILTER (WHERE project_type.name IS NOT NULL)\n AS project_types,\n ARRAY_AGG(\n DISTINCT loader.loader\n ORDER BY loader.loader\n ) AS loaders\n FROM loaders_versions loader_version\n INNER JOIN loaders loader\n ON loader.id = loader_version.loader_id\n LEFT JOIN loaders_project_types loader_project_type\n ON loader_project_type.joining_loader_id = loader_version.loader_id\n LEFT JOIN project_types project_type\n ON project_type.id = loader_project_type.joining_project_type_id\n GROUP BY loader_version.version_id\n ) version_metadata\n ON version_metadata.version_id = version.id\n LEFT JOIN (\n SELECT\n file_id,\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n GROUP BY file_id\n ) file_hashes ON file_hashes.file_id = file.id\n ORDER BY detail.id\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "key",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 2,
+ "name": "issue_type",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 3,
+ "name": "severity: DelphiSeverity",
+ "type_info": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ordinal": 4,
+ "name": "jar",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 5,
+ "name": "file_path",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 6,
+ "name": "data: Json>",
+ "type_info": "Jsonb"
+ },
+ {
+ "ordinal": 7,
+ "name": "delphi_version",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 8,
+ "name": "size?",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 9,
+ "name": "file_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 10,
+ "name": "version_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 11,
+ "name": "project_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 12,
+ "name": "project_types!: Vec",
+ "type_info": "TextArray"
+ },
+ {
+ "ordinal": 13,
+ "name": "loaders!: Vec",
+ "type_info": "VarcharArray"
+ },
+ {
+ "ordinal": 14,
+ "name": "hashes!: Json>",
+ "type_info": "Jsonb"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ null,
+ null,
+ null
+ ]
+ },
+ "hash": "8537362d9c11e437ada9ce97bb604666378d1d24981ab8113badded16fb63413"
+}
diff --git a/apps/labrinth/.sqlx/query-8c7f17ad005b42b4c6cac5ddb6a1f2d13592cc6995d1b87e79397ab592ad7675.json b/apps/labrinth/.sqlx/query-8c7f17ad005b42b4c6cac5ddb6a1f2d13592cc6995d1b87e79397ab592ad7675.json
new file mode 100644
index 0000000000..4ed9dbbf05
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-8c7f17ad005b42b4c6cac5ddb6a1f2d13592cc6995d1b87e79397ab592ad7675.json
@@ -0,0 +1,38 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n INSERT INTO delphi_rule_effects (\n revision,\n detail_id,\n rule_id,\n severity\n )\n SELECT $1, effect.*\n FROM UNNEST(\n $2::BIGINT[],\n $3::BIGINT[],\n $4::delphi_severity[]\n ) AS effect(detail_id, rule_id, severity)\n ",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Int8",
+ "Int8Array",
+ "Int8Array",
+ {
+ "Custom": {
+ "name": "delphi_severity[]",
+ "kind": {
+ "Array": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "8c7f17ad005b42b4c6cac5ddb6a1f2d13592cc6995d1b87e79397ab592ad7675"
+}
diff --git a/apps/labrinth/.sqlx/query-8d37c8c2633b7d601c7ba74d63608ff40af3b6b56f43540ec3798ef30e5c0b9d.json b/apps/labrinth/.sqlx/query-8d37c8c2633b7d601c7ba74d63608ff40af3b6b56f43540ec3798ef30e5c0b9d.json
index 475dba1b98..cf1d9b23c6 100644
--- a/apps/labrinth/.sqlx/query-8d37c8c2633b7d601c7ba74d63608ff40af3b6b56f43540ec3798ef30e5c0b9d.json
+++ b/apps/labrinth/.sqlx/query-8d37c8c2633b7d601c7ba74d63608ff40af3b6b56f43540ec3798ef30e5c0b9d.json
@@ -26,10 +26,12 @@
"name": "delphi_severity",
"kind": {
"Enum": [
+ "hidden",
"low",
"medium",
"high",
- "severe"
+ "severe",
+ "malware"
]
}
}
diff --git a/apps/labrinth/.sqlx/query-9369f0659c5fbd08463923a9b2bba49f4963315fd7667c6db96e6153e54a2fd2.json b/apps/labrinth/.sqlx/query-9369f0659c5fbd08463923a9b2bba49f4963315fd7667c6db96e6153e54a2fd2.json
index 8ca4b69491..f3609a305c 100644
--- a/apps/labrinth/.sqlx/query-9369f0659c5fbd08463923a9b2bba49f4963315fd7667c6db96e6153e54a2fd2.json
+++ b/apps/labrinth/.sqlx/query-9369f0659c5fbd08463923a9b2bba49f4963315fd7667c6db96e6153e54a2fd2.json
@@ -22,10 +22,12 @@
"name": "delphi_severity",
"kind": {
"Enum": [
+ "hidden",
"low",
"medium",
"high",
- "severe"
+ "severe",
+ "malware"
]
}
}
diff --git a/apps/labrinth/.sqlx/query-9ab1f07c2968b5d445752c1480345c1fa3af3a899b232482aab9cc44b9336063.json b/apps/labrinth/.sqlx/query-9ab1f07c2968b5d445752c1480345c1fa3af3a899b232482aab9cc44b9336063.json
deleted file mode 100644
index 83806baae2..0000000000
--- a/apps/labrinth/.sqlx/query-9ab1f07c2968b5d445752c1480345c1fa3af3a899b232482aab9cc44b9336063.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n DELETE FROM delphi_report_issue_details drid\n WHERE issue_id IN (\n SELECT dri.id\n FROM mods m\n INNER JOIN versions v ON v.mod_id = m.id\n INNER JOIN files f ON f.version_id = v.id\n INNER JOIN delphi_reports dr ON dr.file_id = f.id\n INNER JOIN delphi_report_issues dri ON dri.report_id = dr.id\n WHERE m.id = $1 AND dri.issue_type = '__dummy'\n )\n ",
- "describe": {
- "columns": [],
- "parameters": {
- "Left": [
- "Int8"
- ]
- },
- "nullable": []
- },
- "hash": "9ab1f07c2968b5d445752c1480345c1fa3af3a899b232482aab9cc44b9336063"
-}
diff --git a/apps/labrinth/.sqlx/query-9b0edb6399bc5f38ee96677cb2539476ecf08549b914f96f0c23fbfbe3f17f2e.json b/apps/labrinth/.sqlx/query-9b0edb6399bc5f38ee96677cb2539476ecf08549b914f96f0c23fbfbe3f17f2e.json
deleted file mode 100644
index c8aad7deda..0000000000
--- a/apps/labrinth/.sqlx/query-9b0edb6399bc5f38ee96677cb2539476ecf08549b914f96f0c23fbfbe3f17f2e.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n SELECT DISTINCT m.id\n FROM mods m\n WHERE\n EXISTS(\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n WHERE\n didws.project_id = m.id\n AND didws.status = 'pending'\n -- see delphi.rs todo comment\n AND dri.issue_type != '__dummy'\n )\n AND NOT EXISTS(\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n WHERE\n didws.project_id = m.id\n AND didws.status IN ('safe', 'unsafe')\n -- see delphi.rs todo comment\n AND dri.issue_type != '__dummy'\n )\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "id",
- "type_info": "Int8"
- }
- ],
- "parameters": {
- "Left": []
- },
- "nullable": [
- false
- ]
- },
- "hash": "9b0edb6399bc5f38ee96677cb2539476ecf08549b914f96f0c23fbfbe3f17f2e"
-}
diff --git a/apps/labrinth/.sqlx/query-c3598ed9f64f7151b83d47a15fabfdcf015bda1b3c0a7f2358c7f284feb532c3.json b/apps/labrinth/.sqlx/query-9d044826831bd15b1e0772e8a5db312189b48fcafaaf1b8c4c9f483c97b694ed.json
similarity index 76%
rename from apps/labrinth/.sqlx/query-c3598ed9f64f7151b83d47a15fabfdcf015bda1b3c0a7f2358c7f284feb532c3.json
rename to apps/labrinth/.sqlx/query-9d044826831bd15b1e0772e8a5db312189b48fcafaaf1b8c4c9f483c97b694ed.json
index c27569000b..077a894dfb 100644
--- a/apps/labrinth/.sqlx/query-c3598ed9f64f7151b83d47a15fabfdcf015bda1b3c0a7f2358c7f284feb532c3.json
+++ b/apps/labrinth/.sqlx/query-9d044826831bd15b1e0772e8a5db312189b48fcafaaf1b8c4c9f483c97b694ed.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT\n to_jsonb(dri)\n || jsonb_build_object(\n -- TODO: replace with `json_array` in Postgres 16\n 'details', (\n SELECT coalesce(jsonb_agg(\n jsonb_build_object(\n 'id', didws.id,\n 'issue_id', didws.issue_id,\n 'key', didws.key,\n 'file_path', didws.file_path,\n 'decompiled_source', didws.decompiled_source,\n 'data', didws.data,\n 'severity', didws.severity,\n 'local_status', didws.local_status,\n 'global_status', didws.global_status,\n 'status', didws.status\n )\n ), '[]'::jsonb)\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.issue_id = dri.id\n )\n ) AS \"data!: sqlx::types::Json\"\n FROM delphi_report_issues dri\n WHERE dri.id = $1\n ",
+ "query": "\n SELECT\n to_jsonb(dri)\n || jsonb_build_object(\n -- TODO: replace with `json_array` in Postgres 16\n 'details', (\n SELECT coalesce(jsonb_agg(\n jsonb_build_object(\n 'id', didws.id,\n 'issue_id', didws.issue_id,\n 'key', didws.key,\n 'file_path', didws.file_path,\n 'decompiled_source', didws.decompiled_source,\n 'data', didws.data,\n 'severity', didws.severity,\n 'local_status', didws.local_status,\n 'global_status', didws.global_status,\n 'status', didws.status\n )\n ), '[]'::jsonb)\n FROM delphi_issue_details_with_statuses didws\n WHERE\n didws.issue_id = dri.id\n AND didws.severity != 'hidden'\n )\n ) AS \"data!: sqlx::types::Json\"\n FROM delphi_report_issues dri\n WHERE dri.id = $1\n ",
"describe": {
"columns": [
{
@@ -18,5 +18,5 @@
null
]
},
- "hash": "c3598ed9f64f7151b83d47a15fabfdcf015bda1b3c0a7f2358c7f284feb532c3"
+ "hash": "9d044826831bd15b1e0772e8a5db312189b48fcafaaf1b8c4c9f483c97b694ed"
}
diff --git a/apps/labrinth/.sqlx/query-a1f38a33cc3159108dd7deda48a60ebdae8d60a6d555a625ee2ec5780ab78fc3.json b/apps/labrinth/.sqlx/query-a1f38a33cc3159108dd7deda48a60ebdae8d60a6d555a625ee2ec5780ab78fc3.json
new file mode 100644
index 0000000000..d43d795d65
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-a1f38a33cc3159108dd7deda48a60ebdae8d60a6d555a625ee2ec5780ab78fc3.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT DISTINCT detail.project_id AS \"project_id!: DBProjectId\"\n FROM delphi_issue_details_with_statuses detail\n WHERE detail.key = ANY($1::text[])\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id!: DBProjectId",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "TextArray"
+ ]
+ },
+ "nullable": [
+ true
+ ]
+ },
+ "hash": "a1f38a33cc3159108dd7deda48a60ebdae8d60a6d555a625ee2ec5780ab78fc3"
+}
diff --git a/apps/labrinth/.sqlx/query-a58e701218270abb1c5b177d7ab12a8d3fce511a3d03e883de8ce925f3332957.json b/apps/labrinth/.sqlx/query-a58e701218270abb1c5b177d7ab12a8d3fce511a3d03e883de8ce925f3332957.json
new file mode 100644
index 0000000000..d747bd944a
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-a58e701218270abb1c5b177d7ab12a8d3fce511a3d03e883de8ce925f3332957.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT DISTINCT m.id\n FROM mods m\n INNER JOIN delphi_tech_review_queue queue ON queue.project_id = m.id\n WHERE\n EXISTS(\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE\n didws.project_id = m.id\n AND didws.status = 'pending'\n AND didws.severity != 'hidden'\n )\n AND NOT EXISTS(\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE\n didws.project_id = m.id\n AND didws.status IN ('safe', 'unsafe')\n AND didws.severity != 'hidden'\n )\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "a58e701218270abb1c5b177d7ab12a8d3fce511a3d03e883de8ce925f3332957"
+}
diff --git a/apps/labrinth/.sqlx/query-ab87c1771628979a051e4b30cd6afa32576d95e5861cc857276e099b18a5e1f4.json b/apps/labrinth/.sqlx/query-ab87c1771628979a051e4b30cd6afa32576d95e5861cc857276e099b18a5e1f4.json
new file mode 100644
index 0000000000..b8322723a3
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-ab87c1771628979a051e4b30cd6afa32576d95e5861cc857276e099b18a5e1f4.json
@@ -0,0 +1,14 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "UPDATE delphi_rule_revisions SET revision = $1",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": []
+ },
+ "hash": "ab87c1771628979a051e4b30cd6afa32576d95e5861cc857276e099b18a5e1f4"
+}
diff --git a/apps/labrinth/.sqlx/query-abef4603febf18dae62ca424b0433f2bacc2555433277ee195ed6fbedb7be537.json b/apps/labrinth/.sqlx/query-abef4603febf18dae62ca424b0433f2bacc2555433277ee195ed6fbedb7be537.json
new file mode 100644
index 0000000000..155fd19fbd
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-abef4603febf18dae62ca424b0433f2bacc2555433277ee195ed6fbedb7be537.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SELECT revision FROM delphi_rule_revisions LIMIT 1",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "revision",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "abef4603febf18dae62ca424b0433f2bacc2555433277ee195ed6fbedb7be537"
+}
diff --git a/apps/labrinth/.sqlx/query-4680c4a59c6679f90e3b9e1a33ed1cb1fb60b93ffb79ba5b99e01ee0c14c991a.json b/apps/labrinth/.sqlx/query-aedd5d9fe052a9fa70e585f389c3b4915a88cb9c3ec54493a2a29582c80b5c76.json
similarity index 71%
rename from apps/labrinth/.sqlx/query-4680c4a59c6679f90e3b9e1a33ed1cb1fb60b93ffb79ba5b99e01ee0c14c991a.json
rename to apps/labrinth/.sqlx/query-aedd5d9fe052a9fa70e585f389c3b4915a88cb9c3ec54493a2a29582c80b5c76.json
index 21c5f042e6..1b0fcfb6dc 100644
--- a/apps/labrinth/.sqlx/query-4680c4a59c6679f90e3b9e1a33ed1cb1fb60b93ffb79ba5b99e01ee0c14c991a.json
+++ b/apps/labrinth/.sqlx/query-aedd5d9fe052a9fa70e585f389c3b4915a88cb9c3ec54493a2a29582c80b5c76.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT\n dgdv.detail_key,\n dgdv.verdict AS \"verdict!: DelphiStatus\",\n COUNT(dri.id) AS \"local_trace_count!\"\n FROM delphi_global_detail_verdicts dgdv\n LEFT JOIN delphi_issue_details_with_statuses didws\n ON didws.key = dgdv.detail_key\n LEFT JOIN delphi_report_issues dri\n ON dri.id = didws.issue_id\n AND dri.issue_type != '__dummy'\n WHERE (\n $1::text IS NULL\n OR dgdv.detail_key ILIKE '%' || $1 || '%'\n )\n GROUP BY dgdv.detail_key, dgdv.verdict\n ORDER BY dgdv.detail_key\n LIMIT $2 OFFSET $3\n ",
+ "query": "\n SELECT\n dgdv.detail_key,\n dgdv.verdict AS \"verdict!: DelphiStatus\",\n COUNT(dri.id) AS \"local_trace_count!\"\n FROM delphi_global_detail_verdicts dgdv\n LEFT JOIN delphi_issue_details_with_statuses didws\n ON didws.key = dgdv.detail_key\n AND didws.severity != 'hidden'\n LEFT JOIN delphi_report_issues dri\n ON dri.id = didws.issue_id\n WHERE (\n $1::text IS NULL\n OR dgdv.detail_key ILIKE '%' || $1 || '%'\n )\n GROUP BY dgdv.detail_key, dgdv.verdict\n ORDER BY dgdv.detail_key\n LIMIT $2 OFFSET $3\n ",
"describe": {
"columns": [
{
@@ -43,5 +43,5 @@
null
]
},
- "hash": "4680c4a59c6679f90e3b9e1a33ed1cb1fb60b93ffb79ba5b99e01ee0c14c991a"
+ "hash": "aedd5d9fe052a9fa70e585f389c3b4915a88cb9c3ec54493a2a29582c80b5c76"
}
diff --git a/apps/labrinth/.sqlx/query-b0004df8d3b1c5f9193a21f981452ce4ae56f608ec698f6f1ebb4c470bb2f0f5.json b/apps/labrinth/.sqlx/query-b0004df8d3b1c5f9193a21f981452ce4ae56f608ec698f6f1ebb4c470bb2f0f5.json
new file mode 100644
index 0000000000..b7d3810c3e
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-b0004df8d3b1c5f9193a21f981452ce4ae56f608ec698f6f1ebb4c470bb2f0f5.json
@@ -0,0 +1,73 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n\t\tINSERT INTO delphi_rules (\n\t\t\tname,\n\t\t\trule,\n\t\t\tpriority,\n\t\t\trevision,\n\t\t\tcreated_by,\n\t\t\tupdated_by\n\t\t)\n\t\tVALUES (\n\t\t\t$1,\n\t\t\t$2,\n\t\t\t$3,\n\t\t\t(SELECT revision + 1 FROM delphi_rule_revisions LIMIT 1),\n\t\t\t$4,\n\t\t\t$4\n\t\t)\n\t\tRETURNING\n\t\t\tid AS \"id!: DelphiRuleId\",\n\t\t\tname,\n\t\t\trule,\n\t\t\tpriority,\n\t\t\trevision,\n\t\t\tcreated_at,\n\t\t\tupdated_at,\n\t\t\tcreated_by,\n\t\t\tupdated_by\n\t\t",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id!: DelphiRuleId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "name",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 2,
+ "name": "rule",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 3,
+ "name": "priority",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 4,
+ "name": "revision",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 5,
+ "name": "created_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 6,
+ "name": "updated_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 7,
+ "name": "created_by",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 8,
+ "name": "updated_by",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Varchar",
+ "Varchar",
+ "Int4",
+ "Int8"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true
+ ]
+ },
+ "hash": "b0004df8d3b1c5f9193a21f981452ce4ae56f608ec698f6f1ebb4c470bb2f0f5"
+}
diff --git a/apps/labrinth/.sqlx/query-b5233d5b729fae87fdf24e7d5f9ee6c96fe5a33015ba94bc2c606c31f87af9c9.json b/apps/labrinth/.sqlx/query-b5233d5b729fae87fdf24e7d5f9ee6c96fe5a33015ba94bc2c606c31f87af9c9.json
new file mode 100644
index 0000000000..c26c415abd
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-b5233d5b729fae87fdf24e7d5f9ee6c96fe5a33015ba94bc2c606c31f87af9c9.json
@@ -0,0 +1,23 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n\t\tUPDATE delphi_rules\n\t\tSET\n\t\t\tdelete_on_next_revision = TRUE,\n\t\t\trevision = (\n\t\t\t\tSELECT revision + 1 FROM delphi_rule_revisions LIMIT 1\n\t\t\t),\n\t\t\tupdated_at = CURRENT_TIMESTAMP,\n\t\t\tupdated_by = $2\n\t\tWHERE id = $1 AND NOT delete_on_next_revision\n\t\tRETURNING id\n\t\t",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8",
+ "Int8"
+ ]
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "b5233d5b729fae87fdf24e7d5f9ee6c96fe5a33015ba94bc2c606c31f87af9c9"
+}
diff --git a/apps/labrinth/.sqlx/query-b536d7870ba77ace55e309938c3ba93c7016b2a6f18aa4f22ea57f604d82c1da.json b/apps/labrinth/.sqlx/query-b536d7870ba77ace55e309938c3ba93c7016b2a6f18aa4f22ea57f604d82c1da.json
new file mode 100644
index 0000000000..1d7013755a
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-b536d7870ba77ace55e309938c3ba93c7016b2a6f18aa4f22ea57f604d82c1da.json
@@ -0,0 +1,114 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT\n detail.key,\n issue.issue_type,\n detail.severity AS \"severity: DelphiSeverity\",\n detail.jar,\n detail.file_path,\n detail.data AS \"data: Json>\",\n report.delphi_version,\n file.size AS \"size?\",\n file.id AS \"file_id?\",\n version.id AS \"version_id?\",\n version.mod_id AS \"project_id?\",\n COALESCE(version_metadata.project_types, ARRAY[]::text[])\n AS \"project_types!: Vec\",\n COALESCE(version_metadata.loaders, ARRAY[]::text[])\n AS \"loaders!: Vec\",\n COALESCE(file_hashes.hashes, '{}'::jsonb)\n AS \"hashes!: Json>\"\n FROM delphi_report_issue_details detail\n INNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n INNER JOIN delphi_reports report ON report.id = issue.report_id\n LEFT JOIN files file ON file.id = report.file_id\n LEFT JOIN versions version ON version.id = file.version_id\n LEFT JOIN LATERAL (\n SELECT\n ARRAY_AGG(\n DISTINCT project_type.name::text\n ORDER BY project_type.name::text\n ) FILTER (WHERE project_type.name IS NOT NULL)\n AS project_types,\n ARRAY_AGG(\n DISTINCT loader.loader\n ORDER BY loader.loader\n ) AS loaders\n FROM loaders_versions loader_version\n INNER JOIN loaders loader\n ON loader.id = loader_version.loader_id\n LEFT JOIN loaders_project_types loader_project_type\n ON loader_project_type.joining_loader_id = loader_version.loader_id\n LEFT JOIN project_types project_type\n ON project_type.id = loader_project_type.joining_project_type_id\n WHERE loader_version.version_id = version.id\n ) version_metadata ON TRUE\n LEFT JOIN LATERAL (\n SELECT\n jsonb_object_agg(algorithm, encode(hash, 'hex')) AS hashes\n FROM hashes\n WHERE hashes.file_id = file.id\n ) file_hashes ON TRUE\n WHERE detail.id = $1\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "key",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 1,
+ "name": "issue_type",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 2,
+ "name": "severity: DelphiSeverity",
+ "type_info": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ordinal": 3,
+ "name": "jar",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 4,
+ "name": "file_path",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 5,
+ "name": "data: Json>",
+ "type_info": "Jsonb"
+ },
+ {
+ "ordinal": 6,
+ "name": "delphi_version",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 7,
+ "name": "size?",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 8,
+ "name": "file_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 9,
+ "name": "version_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 10,
+ "name": "project_id?",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 11,
+ "name": "project_types!: Vec",
+ "type_info": "TextArray"
+ },
+ {
+ "ordinal": 12,
+ "name": "loaders!: Vec",
+ "type_info": "VarcharArray"
+ },
+ {
+ "ordinal": 13,
+ "name": "hashes!: Json>",
+ "type_info": "Jsonb"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ null,
+ null,
+ null
+ ]
+ },
+ "hash": "b536d7870ba77ace55e309938c3ba93c7016b2a6f18aa4f22ea57f604d82c1da"
+}
diff --git a/apps/labrinth/.sqlx/query-bb94018c84f3809b9ad89f35ff08501addc8f203a0a152346aaebd32db52be30.json b/apps/labrinth/.sqlx/query-bb94018c84f3809b9ad89f35ff08501addc8f203a0a152346aaebd32db52be30.json
deleted file mode 100644
index 247c99cd89..0000000000
--- a/apps/labrinth/.sqlx/query-bb94018c84f3809b9ad89f35ff08501addc8f203a0a152346aaebd32db52be30.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n WITH project_ids AS (\n SELECT unnest($1::bigint[]) AS project_id\n )\n SELECT\n p.project_id AS \"project_id!: DBProjectId\",\n EXISTS(\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n WHERE\n didws.project_id = p.project_id\n AND didws.status = 'pending'\n AND dri.issue_type != $3\n ) AS \"has_pending_detail!\",\n EXISTS(\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n WHERE\n didws.project_id = p.project_id\n AND didws.status = 'unsafe'\n AND dri.issue_type != $3\n ) AS \"has_unsafe_detail!\",\n EXISTS(\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n WHERE\n didws.project_id = p.project_id\n AND didws.status = 'pending'\n AND dri.issue_type = $3\n ) AS \"has_dummy!\",\n (\n SELECT t.id\n FROM threads t\n WHERE t.mod_id = p.project_id\n ORDER BY t.id\n LIMIT 1\n ) AS \"thread_id: DBThreadId\",\n (\n SELECT tm.body->>'type'\n FROM threads t\n INNER JOIN threads_messages tm ON tm.thread_id = t.id\n WHERE\n t.mod_id = p.project_id\n AND tm.body->>'type' = ANY($2::text[])\n ORDER BY tm.created DESC, tm.id DESC\n LIMIT 1\n ) AS \"last_tech_review_message_type\",\n (\n SELECT dr.id\n FROM versions v\n INNER JOIN files f ON f.version_id = v.id\n INNER JOIN delphi_reports dr ON dr.file_id = f.id\n WHERE v.mod_id = p.project_id\n ORDER BY dr.created DESC, dr.id DESC\n LIMIT 1\n ) AS \"report_id: DelphiReportId\"\n FROM project_ids p\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "project_id!: DBProjectId",
- "type_info": "Int8"
- },
- {
- "ordinal": 1,
- "name": "has_pending_detail!",
- "type_info": "Bool"
- },
- {
- "ordinal": 2,
- "name": "has_unsafe_detail!",
- "type_info": "Bool"
- },
- {
- "ordinal": 3,
- "name": "has_dummy!",
- "type_info": "Bool"
- },
- {
- "ordinal": 4,
- "name": "thread_id: DBThreadId",
- "type_info": "Int8"
- },
- {
- "ordinal": 5,
- "name": "last_tech_review_message_type",
- "type_info": "Text"
- },
- {
- "ordinal": 6,
- "name": "report_id: DelphiReportId",
- "type_info": "Int8"
- }
- ],
- "parameters": {
- "Left": [
- "Int8Array",
- "TextArray",
- "Text"
- ]
- },
- "nullable": [
- null,
- null,
- null,
- null,
- null,
- null,
- null
- ]
- },
- "hash": "bb94018c84f3809b9ad89f35ff08501addc8f203a0a152346aaebd32db52be30"
-}
diff --git a/apps/labrinth/.sqlx/query-22fbd4bf1c2088903842b2c0070fd08431fc3f984263faed7aaeb311fa6ac2a9.json b/apps/labrinth/.sqlx/query-befd8c75e7ed4621f5e99d88719c0fde9d617b6603b99b75cc18d1a02387bac4.json
similarity index 96%
rename from apps/labrinth/.sqlx/query-22fbd4bf1c2088903842b2c0070fd08431fc3f984263faed7aaeb311fa6ac2a9.json
rename to apps/labrinth/.sqlx/query-befd8c75e7ed4621f5e99d88719c0fde9d617b6603b99b75cc18d1a02387bac4.json
index 38d43c6043..d90f24169d 100644
--- a/apps/labrinth/.sqlx/query-22fbd4bf1c2088903842b2c0070fd08431fc3f984263faed7aaeb311fa6ac2a9.json
+++ b/apps/labrinth/.sqlx/query-befd8c75e7ed4621f5e99d88719c0fde9d617b6603b99b75cc18d1a02387bac4.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n WITH moderation_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.description,\n m.queued,\n m.published,\n m.organization_id,\n m.team_id,\n m.components\n FROM mods m\n WHERE\n m.status = $1\n AND (\n $7::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = m.id\n AND didws.status = 'pending'\n )\n )\n ),\n external_dependencies AS (\n SELECT\n v.mod_id,\n COUNT(*) AS external_dependencies_count\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN dependencies d ON d.dependent_id = v.id\n WHERE d.dependency_file_name IS NOT NULL\n GROUP BY v.mod_id\n ),\n version_project_types AS (\n SELECT\n v.mod_id,\n ARRAY_AGG(DISTINCT pt.name::text) FILTER (WHERE pt.name IS NOT NULL) AS project_types\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN loaders_versions lv ON v.id = lv.version_id\n INNER JOIN loaders l ON lv.loader_id = l.id\n INNER JOIN loaders_project_types lpt ON lpt.joining_loader_id = l.id\n INNER JOIN project_types pt ON pt.id = lpt.joining_project_type_id\n WHERE v.status = ANY($2)\n GROUP BY v.mod_id\n ),\n queue_projects AS (\n SELECT\n mp.id,\n mp.slug,\n mp.name,\n mp.summary,\n mp.description,\n mp.queued,\n mp.published,\n search_organization.name AS organization_name,\n search_owner.username AS owner_name,\n CASE\n WHEN mp.components ? 'minecraft_server'\n THEN ARRAY_APPEND(\n ARRAY_REMOVE(\n COALESCE(vpt.project_types::text[], ARRAY[]::text[]),\n 'modpack'\n ),\n 'minecraft_java_server'\n )\n ELSE COALESCE(vpt.project_types::text[], ARRAY[]::text[])\n END AS project_types,\n COALESCE(ed.external_dependencies_count, 0) AS external_dependencies_count\n FROM moderation_projects mp\n LEFT JOIN organizations search_organization\n ON search_organization.id = mp.organization_id\n AND $3::text IS NOT NULL\n LEFT JOIN LATERAL (\n SELECT\n u.username\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = mp.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) search_owner ON $3::text IS NOT NULL\n AND mp.organization_id IS NULL\n LEFT JOIN external_dependencies ed ON ed.mod_id = mp.id\n LEFT JOIN version_project_types vpt ON vpt.mod_id = mp.id\n )\n SELECT id\n FROM queue_projects\n WHERE\n (\n $3::text IS NULL\n OR name ILIKE '%' || $3 || '%'\n OR slug ILIKE '%' || $3 || '%'\n OR summary ILIKE '%' || $3 || '%'\n OR description ILIKE '%' || $3 || '%'\n OR owner_name ILIKE '%' || $3 || '%'\n OR organization_name ILIKE '%' || $3 || '%'\n OR EXISTS (\n SELECT 1\n FROM UNNEST(project_types) AS searched_project_type(project_type)\n WHERE searched_project_type.project_type ILIKE '%' || $3 || '%'\n )\n )\n AND (\n $4::text IS NULL\n OR ($4 = 'none' AND CARDINALITY(project_types) = 0)\n OR ($4 = 'minecraft_java_server' AND project_types @> ARRAY['minecraft_java_server']::text[])\n OR ($4 <> 'none' AND $4 <> 'minecraft_java_server' AND project_types[1] = $4)\n )\n AND ($5::boolean IS NULL OR (external_dependencies_count > 0) = $5)\n ORDER BY\n CASE WHEN $6 = 'most_external_deps' THEN external_dependencies_count END DESC,\n CASE WHEN $6 = 'least_external_deps' THEN external_dependencies_count END ASC,\n CASE WHEN $6 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $6 IN ('oldest', 'most_external_deps', 'least_external_deps') THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n ",
+ "query": "\n WITH moderation_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.description,\n m.queued,\n m.published,\n m.organization_id,\n m.team_id,\n m.components\n FROM mods m\n WHERE\n m.status = $1\n AND (\n $7::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = m.id\n AND didws.status = 'pending'\n AND didws.severity != 'hidden'\n )\n )\n ),\n external_dependencies AS (\n SELECT\n v.mod_id,\n COUNT(*) AS external_dependencies_count\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN dependencies d ON d.dependent_id = v.id\n WHERE d.dependency_file_name IS NOT NULL\n GROUP BY v.mod_id\n ),\n version_project_types AS (\n SELECT\n v.mod_id,\n ARRAY_AGG(DISTINCT pt.name::text) FILTER (WHERE pt.name IS NOT NULL) AS project_types\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN loaders_versions lv ON v.id = lv.version_id\n INNER JOIN loaders l ON lv.loader_id = l.id\n INNER JOIN loaders_project_types lpt ON lpt.joining_loader_id = l.id\n INNER JOIN project_types pt ON pt.id = lpt.joining_project_type_id\n WHERE v.status = ANY($2)\n GROUP BY v.mod_id\n ),\n queue_projects AS (\n SELECT\n mp.id,\n mp.slug,\n mp.name,\n mp.summary,\n mp.description,\n mp.queued,\n mp.published,\n search_organization.name AS organization_name,\n search_owner.username AS owner_name,\n CASE\n WHEN mp.components ? 'minecraft_server'\n THEN ARRAY_APPEND(\n ARRAY_REMOVE(\n COALESCE(vpt.project_types::text[], ARRAY[]::text[]),\n 'modpack'\n ),\n 'minecraft_java_server'\n )\n ELSE COALESCE(vpt.project_types::text[], ARRAY[]::text[])\n END AS project_types,\n COALESCE(ed.external_dependencies_count, 0) AS external_dependencies_count\n FROM moderation_projects mp\n LEFT JOIN organizations search_organization\n ON search_organization.id = mp.organization_id\n AND $3::text IS NOT NULL\n LEFT JOIN LATERAL (\n SELECT\n u.username\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = mp.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) search_owner ON $3::text IS NOT NULL\n AND mp.organization_id IS NULL\n LEFT JOIN external_dependencies ed ON ed.mod_id = mp.id\n LEFT JOIN version_project_types vpt ON vpt.mod_id = mp.id\n )\n SELECT id\n FROM queue_projects\n WHERE\n (\n $3::text IS NULL\n OR name ILIKE '%' || $3 || '%'\n OR slug ILIKE '%' || $3 || '%'\n OR summary ILIKE '%' || $3 || '%'\n OR description ILIKE '%' || $3 || '%'\n OR owner_name ILIKE '%' || $3 || '%'\n OR organization_name ILIKE '%' || $3 || '%'\n OR EXISTS (\n SELECT 1\n FROM UNNEST(project_types) AS searched_project_type(project_type)\n WHERE searched_project_type.project_type ILIKE '%' || $3 || '%'\n )\n )\n AND (\n $4::text IS NULL\n OR ($4 = 'none' AND CARDINALITY(project_types) = 0)\n OR ($4 = 'minecraft_java_server' AND project_types @> ARRAY['minecraft_java_server']::text[])\n OR ($4 <> 'none' AND $4 <> 'minecraft_java_server' AND project_types[1] = $4)\n )\n AND ($5::boolean IS NULL OR (external_dependencies_count > 0) = $5)\n ORDER BY\n CASE WHEN $6 = 'most_external_deps' THEN external_dependencies_count END DESC,\n CASE WHEN $6 = 'least_external_deps' THEN external_dependencies_count END ASC,\n CASE WHEN $6 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $6 IN ('oldest', 'most_external_deps', 'least_external_deps') THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n ",
"describe": {
"columns": [
{
@@ -24,5 +24,5 @@
false
]
},
- "hash": "22fbd4bf1c2088903842b2c0070fd08431fc3f984263faed7aaeb311fa6ac2a9"
+ "hash": "befd8c75e7ed4621f5e99d88719c0fde9d617b6603b99b75cc18d1a02387bac4"
}
diff --git a/apps/labrinth/.sqlx/query-cb983aed301378550831204ff7f88e95e5db9cabd8e1fc177cdfdaf0951e58e4.json b/apps/labrinth/.sqlx/query-cb983aed301378550831204ff7f88e95e5db9cabd8e1fc177cdfdaf0951e58e4.json
new file mode 100644
index 0000000000..16a0b80bde
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-cb983aed301378550831204ff7f88e95e5db9cabd8e1fc177cdfdaf0951e58e4.json
@@ -0,0 +1,22 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n SELECT DISTINCT detail.project_id AS \"project_id!: DBProjectId\"\n FROM delphi_issue_details_with_statuses detail\n WHERE\n detail.project_id = ANY($1::bigint[])\n AND detail.status IN ('pending', 'unsafe')\n AND detail.severity != 'hidden'\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id!: DBProjectId",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8Array"
+ ]
+ },
+ "nullable": [
+ true
+ ]
+ },
+ "hash": "cb983aed301378550831204ff7f88e95e5db9cabd8e1fc177cdfdaf0951e58e4"
+}
diff --git a/apps/labrinth/.sqlx/query-5a68c53bd00c08edf9dfb9ffdabc28f86cdd77cd06bbb10c9a8e5199509f9c4b.json b/apps/labrinth/.sqlx/query-d37041da5452ecb82da506a83154cd66b78ebb9a1dbf0bb46e5bd6bb2b3a9bb9.json
similarity index 97%
rename from apps/labrinth/.sqlx/query-5a68c53bd00c08edf9dfb9ffdabc28f86cdd77cd06bbb10c9a8e5199509f9c4b.json
rename to apps/labrinth/.sqlx/query-d37041da5452ecb82da506a83154cd66b78ebb9a1dbf0bb46e5bd6bb2b3a9bb9.json
index 450ec6ad79..45ac66fbf6 100644
--- a/apps/labrinth/.sqlx/query-5a68c53bd00c08edf9dfb9ffdabc28f86cdd77cd06bbb10c9a8e5199509f9c4b.json
+++ b/apps/labrinth/.sqlx/query-d37041da5452ecb82da506a83154cd66b78ebb9a1dbf0bb46e5bd6bb2b3a9bb9.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n WITH filtered_projects AS (\n SELECT\n m.id,\n m.queued,\n m.published\n FROM mods m\n WHERE\n m.status = $1\n AND (\n $6::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = m.id\n AND didws.status = 'pending'\n )\n )\n ),\n total AS (\n SELECT COUNT(*) AS total_count FROM filtered_projects\n ),\n page_ids AS (\n SELECT\n id,\n queued,\n published\n FROM filtered_projects\n ORDER BY\n CASE WHEN $5 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $5 = 'oldest' THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n OFFSET $4\n LIMIT $3\n ),\n page_project_types AS (\n SELECT\n v.mod_id,\n ARRAY_AGG(DISTINCT pt.name::text) FILTER (WHERE pt.name IS NOT NULL) AS project_types\n FROM versions v\n INNER JOIN page_ids page ON page.id = v.mod_id\n INNER JOIN loaders_versions lv ON v.id = lv.version_id\n INNER JOIN loaders l ON lv.loader_id = l.id\n INNER JOIN loaders_project_types lpt ON lpt.joining_loader_id = l.id\n INNER JOIN project_types pt ON pt.id = lpt.joining_project_type_id\n WHERE v.status = ANY($2)\n GROUP BY v.mod_id\n ),\n page_external_dependencies AS (\n SELECT\n v.mod_id,\n COUNT(*) AS external_dependencies_count\n FROM versions v\n INNER JOIN page_ids page ON page.id = v.mod_id\n INNER JOIN dependencies d ON d.dependent_id = v.id\n WHERE d.dependency_file_name IS NOT NULL\n GROUP BY v.mod_id\n ),\n page_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.icon_url,\n m.status,\n m.requested_status,\n m.queued,\n m.published,\n m.updated,\n m.organization_id,\n o.name AS organization_name,\n o.icon_url AS organization_icon_url,\n owner.user_id AS owner_id,\n owner.username AS owner_name,\n owner.avatar_url AS owner_icon_url,\n CASE\n WHEN m.components ? 'minecraft_server'\n THEN ARRAY_APPEND(\n ARRAY_REMOVE(\n COALESCE(ppt.project_types::text[], ARRAY[]::text[]),\n 'modpack'\n ),\n 'minecraft_java_server'\n )\n ELSE COALESCE(ppt.project_types::text[], ARRAY[]::text[])\n END AS project_types,\n COALESCE(ped.external_dependencies_count, 0) AS external_dependencies_count\n FROM page_ids page\n INNER JOIN mods m ON m.id = page.id\n LEFT JOIN organizations o ON o.id = m.organization_id\n LEFT JOIN LATERAL (\n SELECT\n tm.user_id,\n u.username,\n u.avatar_url\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = m.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) owner ON m.organization_id IS NULL\n LEFT JOIN page_project_types ppt ON ppt.mod_id = m.id\n LEFT JOIN page_external_dependencies ped ON ped.mod_id = m.id\n )\n SELECT\n total.total_count AS \"total_count!\",\n page_projects.id AS \"id?\",\n page_projects.slug AS \"slug?\",\n page_projects.name AS \"name?\",\n page_projects.summary AS \"summary?\",\n page_projects.icon_url AS \"icon_url?\",\n page_projects.status AS \"status?\",\n page_projects.requested_status AS \"requested_status?\",\n page_projects.queued AS \"queued?\",\n page_projects.published AS \"published?\",\n page_projects.updated AS \"updated?\",\n page_projects.organization_id AS \"organization_id?\",\n page_projects.organization_name AS \"organization_name?\",\n page_projects.organization_icon_url AS \"organization_icon_url?\",\n page_projects.owner_id AS \"owner_id?\",\n page_projects.owner_name AS \"owner_name?\",\n page_projects.owner_icon_url AS \"owner_icon_url?\",\n page_projects.project_types AS \"project_types?: Vec\",\n page_projects.external_dependencies_count AS \"external_dependencies_count?\"\n FROM total\n LEFT JOIN page_projects ON true\n ORDER BY\n CASE WHEN $5 = 'newest' THEN COALESCE(page_projects.queued, page_projects.published) END DESC NULLS LAST,\n CASE WHEN $5 = 'oldest' THEN COALESCE(page_projects.queued, page_projects.published) END ASC NULLS LAST,\n page_projects.id ASC\n ",
+ "query": "\n WITH filtered_projects AS (\n SELECT\n m.id,\n m.queued,\n m.published\n FROM mods m\n WHERE\n m.status = $1\n AND (\n $6::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = m.id\n AND didws.status = 'pending'\n AND didws.severity != 'hidden'\n )\n )\n ),\n total AS (\n SELECT COUNT(*) AS total_count FROM filtered_projects\n ),\n page_ids AS (\n SELECT\n id,\n queued,\n published\n FROM filtered_projects\n ORDER BY\n CASE WHEN $5 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $5 = 'oldest' THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n OFFSET $4\n LIMIT $3\n ),\n page_project_types AS (\n SELECT\n v.mod_id,\n ARRAY_AGG(DISTINCT pt.name::text) FILTER (WHERE pt.name IS NOT NULL) AS project_types\n FROM versions v\n INNER JOIN page_ids page ON page.id = v.mod_id\n INNER JOIN loaders_versions lv ON v.id = lv.version_id\n INNER JOIN loaders l ON lv.loader_id = l.id\n INNER JOIN loaders_project_types lpt ON lpt.joining_loader_id = l.id\n INNER JOIN project_types pt ON pt.id = lpt.joining_project_type_id\n WHERE v.status = ANY($2)\n GROUP BY v.mod_id\n ),\n page_external_dependencies AS (\n SELECT\n v.mod_id,\n COUNT(*) AS external_dependencies_count\n FROM versions v\n INNER JOIN page_ids page ON page.id = v.mod_id\n INNER JOIN dependencies d ON d.dependent_id = v.id\n WHERE d.dependency_file_name IS NOT NULL\n GROUP BY v.mod_id\n ),\n page_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.icon_url,\n m.status,\n m.requested_status,\n m.queued,\n m.published,\n m.updated,\n m.organization_id,\n o.name AS organization_name,\n o.icon_url AS organization_icon_url,\n owner.user_id AS owner_id,\n owner.username AS owner_name,\n owner.avatar_url AS owner_icon_url,\n CASE\n WHEN m.components ? 'minecraft_server'\n THEN ARRAY_APPEND(\n ARRAY_REMOVE(\n COALESCE(ppt.project_types::text[], ARRAY[]::text[]),\n 'modpack'\n ),\n 'minecraft_java_server'\n )\n ELSE COALESCE(ppt.project_types::text[], ARRAY[]::text[])\n END AS project_types,\n COALESCE(ped.external_dependencies_count, 0) AS external_dependencies_count\n FROM page_ids page\n INNER JOIN mods m ON m.id = page.id\n LEFT JOIN organizations o ON o.id = m.organization_id\n LEFT JOIN LATERAL (\n SELECT\n tm.user_id,\n u.username,\n u.avatar_url\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = m.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) owner ON m.organization_id IS NULL\n LEFT JOIN page_project_types ppt ON ppt.mod_id = m.id\n LEFT JOIN page_external_dependencies ped ON ped.mod_id = m.id\n )\n SELECT\n total.total_count AS \"total_count!\",\n page_projects.id AS \"id?\",\n page_projects.slug AS \"slug?\",\n page_projects.name AS \"name?\",\n page_projects.summary AS \"summary?\",\n page_projects.icon_url AS \"icon_url?\",\n page_projects.status AS \"status?\",\n page_projects.requested_status AS \"requested_status?\",\n page_projects.queued AS \"queued?\",\n page_projects.published AS \"published?\",\n page_projects.updated AS \"updated?\",\n page_projects.organization_id AS \"organization_id?\",\n page_projects.organization_name AS \"organization_name?\",\n page_projects.organization_icon_url AS \"organization_icon_url?\",\n page_projects.owner_id AS \"owner_id?\",\n page_projects.owner_name AS \"owner_name?\",\n page_projects.owner_icon_url AS \"owner_icon_url?\",\n page_projects.project_types AS \"project_types?: Vec\",\n page_projects.external_dependencies_count AS \"external_dependencies_count?\"\n FROM total\n LEFT JOIN page_projects ON true\n ORDER BY\n CASE WHEN $5 = 'newest' THEN COALESCE(page_projects.queued, page_projects.published) END DESC NULLS LAST,\n CASE WHEN $5 = 'oldest' THEN COALESCE(page_projects.queued, page_projects.published) END ASC NULLS LAST,\n page_projects.id ASC\n ",
"describe": {
"columns": [
{
@@ -131,5 +131,5 @@
null
]
},
- "hash": "5a68c53bd00c08edf9dfb9ffdabc28f86cdd77cd06bbb10c9a8e5199509f9c4b"
+ "hash": "d37041da5452ecb82da506a83154cd66b78ebb9a1dbf0bb46e5bd6bb2b3a9bb9"
}
diff --git a/apps/labrinth/.sqlx/query-ca8493b59004511e8d26200638951d55a61c2b6466db69a81be975e150b3ef41.json b/apps/labrinth/.sqlx/query-d3d320af2786bf7908e65f5b7a35ade08110fb341d694ca0f25eecca2f5ad5bf.json
similarity index 98%
rename from apps/labrinth/.sqlx/query-ca8493b59004511e8d26200638951d55a61c2b6466db69a81be975e150b3ef41.json
rename to apps/labrinth/.sqlx/query-d3d320af2786bf7908e65f5b7a35ade08110fb341d694ca0f25eecca2f5ad5bf.json
index 91c2728ad9..a99323dc54 100644
--- a/apps/labrinth/.sqlx/query-ca8493b59004511e8d26200638951d55a61c2b6466db69a81be975e150b3ef41.json
+++ b/apps/labrinth/.sqlx/query-d3d320af2786bf7908e65f5b7a35ade08110fb341d694ca0f25eecca2f5ad5bf.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n WITH moderation_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.description,\n m.queued,\n m.published,\n m.organization_id,\n m.team_id,\n m.components\n FROM mods m\n WHERE\n m.status = $1\n AND (\n $9::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = m.id\n AND didws.status = 'pending'\n )\n )\n ),\n external_dependencies AS (\n SELECT\n v.mod_id,\n COUNT(*) AS external_dependencies_count\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN dependencies d ON d.dependent_id = v.id\n WHERE d.dependency_file_name IS NOT NULL\n GROUP BY v.mod_id\n ),\n version_project_types AS (\n SELECT\n v.mod_id,\n ARRAY_AGG(DISTINCT pt.name::text) FILTER (WHERE pt.name IS NOT NULL) AS project_types\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN loaders_versions lv ON v.id = lv.version_id\n INNER JOIN loaders l ON lv.loader_id = l.id\n INNER JOIN loaders_project_types lpt ON lpt.joining_loader_id = l.id\n INNER JOIN project_types pt ON pt.id = lpt.joining_project_type_id\n WHERE v.status = ANY($2)\n GROUP BY v.mod_id\n ),\n queue_projects AS (\n SELECT\n mp.id,\n mp.slug,\n mp.name,\n mp.summary,\n mp.description,\n mp.queued,\n mp.published,\n search_organization.name AS organization_name,\n search_owner.username AS owner_name,\n CASE\n WHEN mp.components ? 'minecraft_server'\n THEN ARRAY_APPEND(\n ARRAY_REMOVE(\n COALESCE(vpt.project_types::text[], ARRAY[]::text[]),\n 'modpack'\n ),\n 'minecraft_java_server'\n )\n ELSE COALESCE(vpt.project_types::text[], ARRAY[]::text[])\n END AS project_types,\n COALESCE(ed.external_dependencies_count, 0) AS external_dependencies_count\n FROM moderation_projects mp\n LEFT JOIN organizations search_organization\n ON search_organization.id = mp.organization_id\n AND $3::text IS NOT NULL\n LEFT JOIN LATERAL (\n SELECT\n u.username\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = mp.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) search_owner ON $3::text IS NOT NULL\n AND mp.organization_id IS NULL\n LEFT JOIN external_dependencies ed ON ed.mod_id = mp.id\n LEFT JOIN version_project_types vpt ON vpt.mod_id = mp.id\n ),\n filtered_projects AS (\n SELECT\n id,\n queued,\n published,\n project_types,\n external_dependencies_count\n FROM queue_projects\n WHERE\n (\n $3::text IS NULL\n OR name ILIKE '%' || $3 || '%'\n OR slug ILIKE '%' || $3 || '%'\n OR summary ILIKE '%' || $3 || '%'\n OR description ILIKE '%' || $3 || '%'\n OR owner_name ILIKE '%' || $3 || '%'\n OR organization_name ILIKE '%' || $3 || '%'\n OR EXISTS (\n SELECT 1\n FROM UNNEST(project_types) AS searched_project_type(project_type)\n WHERE searched_project_type.project_type ILIKE '%' || $3 || '%'\n )\n )\n AND (\n $4::text IS NULL\n OR ($4 = 'none' AND CARDINALITY(project_types) = 0)\n OR ($4 = 'minecraft_java_server' AND project_types @> ARRAY['minecraft_java_server']::text[])\n OR ($4 <> 'none' AND $4 <> 'minecraft_java_server' AND\n project_types[1] = $4\n )\n )\n AND ($5::boolean IS NULL OR (external_dependencies_count > 0) = $5)\n ),\n total AS (\n SELECT COUNT(*) AS total_count FROM filtered_projects\n ),\n page_ids AS (\n SELECT\n id,\n queued,\n published,\n project_types,\n external_dependencies_count\n FROM filtered_projects\n ORDER BY\n CASE WHEN $8 = 'most_external_deps' THEN external_dependencies_count END DESC,\n CASE WHEN $8 = 'least_external_deps' THEN external_dependencies_count END ASC,\n CASE WHEN $8 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $8 IN ('oldest', 'most_external_deps', 'least_external_deps') THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n OFFSET $7\n LIMIT $6\n ),\n page_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.icon_url,\n m.status,\n m.requested_status,\n m.queued,\n m.published,\n m.updated,\n m.organization_id,\n m.team_id,\n o.name AS organization_name,\n o.icon_url AS organization_icon_url,\n owner.user_id AS owner_id,\n owner.username AS owner_name,\n owner.avatar_url AS owner_icon_url,\n page_ids.project_types,\n page_ids.external_dependencies_count\n FROM page_ids\n INNER JOIN mods m ON m.id = page_ids.id\n LEFT JOIN organizations o ON o.id = m.organization_id\n LEFT JOIN LATERAL (\n SELECT\n tm.user_id,\n u.username,\n u.avatar_url\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = m.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) owner ON m.organization_id IS NULL\n )\n SELECT\n total.total_count AS \"total_count!\",\n page_projects.id AS \"id?\",\n page_projects.slug AS \"slug?\",\n page_projects.name AS \"name?\",\n page_projects.summary AS \"summary?\",\n page_projects.icon_url AS \"icon_url?\",\n page_projects.status AS \"status?\",\n page_projects.requested_status AS \"requested_status?\",\n page_projects.queued AS \"queued?\",\n page_projects.published AS \"published?\",\n page_projects.updated AS \"updated?\",\n page_projects.organization_id AS \"organization_id?\",\n page_projects.organization_name AS \"organization_name?\",\n page_projects.organization_icon_url AS \"organization_icon_url?\",\n page_projects.owner_id AS \"owner_id?\",\n page_projects.owner_name AS \"owner_name?\",\n page_projects.owner_icon_url AS \"owner_icon_url?\",\n page_projects.project_types AS \"project_types?: Vec\",\n page_projects.external_dependencies_count AS \"external_dependencies_count?\"\n FROM total\n LEFT JOIN page_projects ON true\n ORDER BY\n CASE WHEN $8 = 'most_external_deps' THEN page_projects.external_dependencies_count END DESC,\n CASE WHEN $8 = 'least_external_deps' THEN page_projects.external_dependencies_count END ASC,\n CASE WHEN $8 = 'newest' THEN COALESCE(page_projects.queued, page_projects.published) END DESC NULLS LAST,\n CASE WHEN $8 IN ('oldest', 'most_external_deps', 'least_external_deps') THEN COALESCE(page_projects.queued, page_projects.published) END ASC NULLS LAST,\n page_projects.id ASC\n ",
+ "query": "\n WITH moderation_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.description,\n m.queued,\n m.published,\n m.organization_id,\n m.team_id,\n m.components\n FROM mods m\n WHERE\n m.status = $1\n AND (\n $9::boolean = false\n OR NOT EXISTS (\n SELECT 1\n FROM delphi_issue_details_with_statuses didws\n WHERE didws.project_id = m.id\n AND didws.status = 'pending'\n AND didws.severity != 'hidden'\n )\n )\n ),\n external_dependencies AS (\n SELECT\n v.mod_id,\n COUNT(*) AS external_dependencies_count\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN dependencies d ON d.dependent_id = v.id\n WHERE d.dependency_file_name IS NOT NULL\n GROUP BY v.mod_id\n ),\n version_project_types AS (\n SELECT\n v.mod_id,\n ARRAY_AGG(DISTINCT pt.name::text) FILTER (WHERE pt.name IS NOT NULL) AS project_types\n FROM versions v\n INNER JOIN moderation_projects mp ON mp.id = v.mod_id\n INNER JOIN loaders_versions lv ON v.id = lv.version_id\n INNER JOIN loaders l ON lv.loader_id = l.id\n INNER JOIN loaders_project_types lpt ON lpt.joining_loader_id = l.id\n INNER JOIN project_types pt ON pt.id = lpt.joining_project_type_id\n WHERE v.status = ANY($2)\n GROUP BY v.mod_id\n ),\n queue_projects AS (\n SELECT\n mp.id,\n mp.slug,\n mp.name,\n mp.summary,\n mp.description,\n mp.queued,\n mp.published,\n search_organization.name AS organization_name,\n search_owner.username AS owner_name,\n CASE\n WHEN mp.components ? 'minecraft_server'\n THEN ARRAY_APPEND(\n ARRAY_REMOVE(\n COALESCE(vpt.project_types::text[], ARRAY[]::text[]),\n 'modpack'\n ),\n 'minecraft_java_server'\n )\n ELSE COALESCE(vpt.project_types::text[], ARRAY[]::text[])\n END AS project_types,\n COALESCE(ed.external_dependencies_count, 0) AS external_dependencies_count\n FROM moderation_projects mp\n LEFT JOIN organizations search_organization\n ON search_organization.id = mp.organization_id\n AND $3::text IS NOT NULL\n LEFT JOIN LATERAL (\n SELECT\n u.username\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = mp.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) search_owner ON $3::text IS NOT NULL\n AND mp.organization_id IS NULL\n LEFT JOIN external_dependencies ed ON ed.mod_id = mp.id\n LEFT JOIN version_project_types vpt ON vpt.mod_id = mp.id\n ),\n filtered_projects AS (\n SELECT\n id,\n queued,\n published,\n project_types,\n external_dependencies_count\n FROM queue_projects\n WHERE\n (\n $3::text IS NULL\n OR name ILIKE '%' || $3 || '%'\n OR slug ILIKE '%' || $3 || '%'\n OR summary ILIKE '%' || $3 || '%'\n OR description ILIKE '%' || $3 || '%'\n OR owner_name ILIKE '%' || $3 || '%'\n OR organization_name ILIKE '%' || $3 || '%'\n OR EXISTS (\n SELECT 1\n FROM UNNEST(project_types) AS searched_project_type(project_type)\n WHERE searched_project_type.project_type ILIKE '%' || $3 || '%'\n )\n )\n AND (\n $4::text IS NULL\n OR ($4 = 'none' AND CARDINALITY(project_types) = 0)\n OR ($4 = 'minecraft_java_server' AND project_types @> ARRAY['minecraft_java_server']::text[])\n OR ($4 <> 'none' AND $4 <> 'minecraft_java_server' AND\n project_types[1] = $4\n )\n )\n AND ($5::boolean IS NULL OR (external_dependencies_count > 0) = $5)\n ),\n total AS (\n SELECT COUNT(*) AS total_count FROM filtered_projects\n ),\n page_ids AS (\n SELECT\n id,\n queued,\n published,\n project_types,\n external_dependencies_count\n FROM filtered_projects\n ORDER BY\n CASE WHEN $8 = 'most_external_deps' THEN external_dependencies_count END DESC,\n CASE WHEN $8 = 'least_external_deps' THEN external_dependencies_count END ASC,\n CASE WHEN $8 = 'newest' THEN COALESCE(queued, published) END DESC NULLS LAST,\n CASE WHEN $8 IN ('oldest', 'most_external_deps', 'least_external_deps') THEN COALESCE(queued, published) END ASC NULLS LAST,\n id ASC\n OFFSET $7\n LIMIT $6\n ),\n page_projects AS (\n SELECT\n m.id,\n m.slug,\n m.name,\n m.summary,\n m.icon_url,\n m.status,\n m.requested_status,\n m.queued,\n m.published,\n m.updated,\n m.organization_id,\n m.team_id,\n o.name AS organization_name,\n o.icon_url AS organization_icon_url,\n owner.user_id AS owner_id,\n owner.username AS owner_name,\n owner.avatar_url AS owner_icon_url,\n page_ids.project_types,\n page_ids.external_dependencies_count\n FROM page_ids\n INNER JOIN mods m ON m.id = page_ids.id\n LEFT JOIN organizations o ON o.id = m.organization_id\n LEFT JOIN LATERAL (\n SELECT\n tm.user_id,\n u.username,\n u.avatar_url\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = m.team_id\n AND tm.is_owner\n ORDER BY tm.ordering ASC\n LIMIT 1\n ) owner ON m.organization_id IS NULL\n )\n SELECT\n total.total_count AS \"total_count!\",\n page_projects.id AS \"id?\",\n page_projects.slug AS \"slug?\",\n page_projects.name AS \"name?\",\n page_projects.summary AS \"summary?\",\n page_projects.icon_url AS \"icon_url?\",\n page_projects.status AS \"status?\",\n page_projects.requested_status AS \"requested_status?\",\n page_projects.queued AS \"queued?\",\n page_projects.published AS \"published?\",\n page_projects.updated AS \"updated?\",\n page_projects.organization_id AS \"organization_id?\",\n page_projects.organization_name AS \"organization_name?\",\n page_projects.organization_icon_url AS \"organization_icon_url?\",\n page_projects.owner_id AS \"owner_id?\",\n page_projects.owner_name AS \"owner_name?\",\n page_projects.owner_icon_url AS \"owner_icon_url?\",\n page_projects.project_types AS \"project_types?: Vec\",\n page_projects.external_dependencies_count AS \"external_dependencies_count?\"\n FROM total\n LEFT JOIN page_projects ON true\n ORDER BY\n CASE WHEN $8 = 'most_external_deps' THEN page_projects.external_dependencies_count END DESC,\n CASE WHEN $8 = 'least_external_deps' THEN page_projects.external_dependencies_count END ASC,\n CASE WHEN $8 = 'newest' THEN COALESCE(page_projects.queued, page_projects.published) END DESC NULLS LAST,\n CASE WHEN $8 IN ('oldest', 'most_external_deps', 'least_external_deps') THEN COALESCE(page_projects.queued, page_projects.published) END ASC NULLS LAST,\n page_projects.id ASC\n ",
"describe": {
"columns": [
{
@@ -134,5 +134,5 @@
null
]
},
- "hash": "ca8493b59004511e8d26200638951d55a61c2b6466db69a81be975e150b3ef41"
+ "hash": "d3d320af2786bf7908e65f5b7a35ade08110fb341d694ca0f25eecca2f5ad5bf"
}
diff --git a/apps/labrinth/.sqlx/query-d4d04f7cfd6efa582970ec0636f16df646df14ec647f7f2017d59fe786b9ad5b.json b/apps/labrinth/.sqlx/query-d4d04f7cfd6efa582970ec0636f16df646df14ec647f7f2017d59fe786b9ad5b.json
new file mode 100644
index 0000000000..1760686240
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-d4d04f7cfd6efa582970ec0636f16df646df14ec647f7f2017d59fe786b9ad5b.json
@@ -0,0 +1,28 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n WITH removed AS (\n DELETE FROM delphi_tech_review_queue\n WHERE project_id = ANY($1::bigint[])\n RETURNING project_id\n )\n SELECT\n removed.project_id AS \"project_id!: DBProjectId\",\n (\n SELECT thread.id\n FROM threads thread\n WHERE thread.mod_id = removed.project_id\n ORDER BY thread.id\n LIMIT 1\n ) AS \"thread_id!: DBThreadId\"\n FROM removed\n ",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "project_id!: DBProjectId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "thread_id!: DBThreadId",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8Array"
+ ]
+ },
+ "nullable": [
+ false,
+ null
+ ]
+ },
+ "hash": "d4d04f7cfd6efa582970ec0636f16df646df14ec647f7f2017d59fe786b9ad5b"
+}
diff --git a/apps/labrinth/.sqlx/query-d973a1edd200b4cd68ec30556a1e12240885f2372265597efa6e0361831d1318.json b/apps/labrinth/.sqlx/query-d973a1edd200b4cd68ec30556a1e12240885f2372265597efa6e0361831d1318.json
new file mode 100644
index 0000000000..5b5d207a52
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-d973a1edd200b4cd68ec30556a1e12240885f2372265597efa6e0361831d1318.json
@@ -0,0 +1,74 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n\t\tUPDATE delphi_rules\n\t\tSET\n\t\t\tname = $2,\n\t\t\trule = $3,\n\t\t\tpriority = $4,\n\t\t\trevision = (\n\t\t\t\tSELECT revision + 1 FROM delphi_rule_revisions LIMIT 1\n\t\t\t),\n\t\t\tupdated_at = CURRENT_TIMESTAMP,\n\t\t\tupdated_by = $5\n\t\tWHERE id = $1 AND NOT delete_on_next_revision\n\t\tRETURNING\n\t\t\tid AS \"id!: DelphiRuleId\",\n\t\t\tname,\n\t\t\trule,\n\t\t\tpriority,\n\t\t\trevision,\n\t\t\tcreated_at,\n\t\t\tupdated_at,\n\t\t\tcreated_by,\n\t\t\tupdated_by\n\t\t",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "id!: DelphiRuleId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "name",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 2,
+ "name": "rule",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 3,
+ "name": "priority",
+ "type_info": "Int4"
+ },
+ {
+ "ordinal": 4,
+ "name": "revision",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 5,
+ "name": "created_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 6,
+ "name": "updated_at",
+ "type_info": "Timestamptz"
+ },
+ {
+ "ordinal": 7,
+ "name": "created_by",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 8,
+ "name": "updated_by",
+ "type_info": "Int8"
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8",
+ "Varchar",
+ "Varchar",
+ "Int4",
+ "Int8"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true
+ ]
+ },
+ "hash": "d973a1edd200b4cd68ec30556a1e12240885f2372265597efa6e0361831d1318"
+}
diff --git a/apps/labrinth/.sqlx/query-e07b7f513dd5d2a0e06cc1880746cd8d7d4c27896cbfcb3e26085f99e3552c98.json b/apps/labrinth/.sqlx/query-e07b7f513dd5d2a0e06cc1880746cd8d7d4c27896cbfcb3e26085f99e3552c98.json
new file mode 100644
index 0000000000..eee5100504
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-e07b7f513dd5d2a0e06cc1880746cd8d7d4c27896cbfcb3e26085f99e3552c98.json
@@ -0,0 +1,128 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "\n\t\tSELECT\n\t\t\teffect.detail_id AS \"detail_id!: DelphiReportIssueDetailsId\",\n\t\t\tdetail.issue_id AS \"issue_id!: DelphiReportIssueId\",\n\t\t\tversion.mod_id AS \"project_id?: DBProjectId\",\n\t\t\tproject.name AS \"project_name?\",\n\t\t\tproject.icon_url AS \"project_icon_url?\",\n\t\t\tversion.id AS \"version_id?: DBVersionId\",\n\t\t\tversion.name AS \"version_name?\",\n\t\t\tversion.version_number AS \"version_number?\",\n\t\t\tissue.issue_type,\n\t\t\tdetail.key,\n\t\t\tdetail.jar,\n\t\t\tdetail.file_path,\n\t\t\tdetail.severity AS \"original_severity!: DelphiSeverity\",\n\t\t\teffect.severity AS \"effect_severity!: DelphiSeverity\"\n\t\tFROM delphi_rule_effects effect\n\t\tINNER JOIN delphi_rule_revisions published\n\t\t\tON published.revision = effect.revision\n\t\tINNER JOIN delphi_report_issue_details detail\n\t\t\tON detail.id = effect.detail_id\n\t\tINNER JOIN delphi_report_issues issue ON issue.id = detail.issue_id\n\t\tINNER JOIN delphi_reports report ON report.id = issue.report_id\n\t\tLEFT JOIN files file ON file.id = report.file_id\n\t\tLEFT JOIN versions version ON version.id = file.version_id\n\t\tLEFT JOIN mods project ON project.id = version.mod_id\n\t\tWHERE effect.rule_id = $1\n\t\tORDER BY effect.detail_id DESC\n\t\t",
+ "describe": {
+ "columns": [
+ {
+ "ordinal": 0,
+ "name": "detail_id!: DelphiReportIssueDetailsId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 1,
+ "name": "issue_id!: DelphiReportIssueId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 2,
+ "name": "project_id?: DBProjectId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 3,
+ "name": "project_name?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 4,
+ "name": "project_icon_url?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 5,
+ "name": "version_id?: DBVersionId",
+ "type_info": "Int8"
+ },
+ {
+ "ordinal": 6,
+ "name": "version_name?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 7,
+ "name": "version_number?",
+ "type_info": "Varchar"
+ },
+ {
+ "ordinal": 8,
+ "name": "issue_type",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 9,
+ "name": "key",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 10,
+ "name": "jar",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 11,
+ "name": "file_path",
+ "type_info": "Text"
+ },
+ {
+ "ordinal": 12,
+ "name": "original_severity!: DelphiSeverity",
+ "type_info": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ },
+ {
+ "ordinal": 13,
+ "name": "effect_severity!: DelphiSeverity",
+ "type_info": {
+ "Custom": {
+ "name": "delphi_severity",
+ "kind": {
+ "Enum": [
+ "hidden",
+ "low",
+ "medium",
+ "high",
+ "severe",
+ "malware"
+ ]
+ }
+ }
+ }
+ }
+ ],
+ "parameters": {
+ "Left": [
+ "Int8"
+ ]
+ },
+ "nullable": [
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false
+ ]
+ },
+ "hash": "e07b7f513dd5d2a0e06cc1880746cd8d7d4c27896cbfcb3e26085f99e3552c98"
+}
diff --git a/apps/labrinth/.sqlx/query-e3c356bd41074ba4b3474dfab5cc0349636abea5b21faf5fc18d9f69fd21db1d.json b/apps/labrinth/.sqlx/query-e3c356bd41074ba4b3474dfab5cc0349636abea5b21faf5fc18d9f69fd21db1d.json
deleted file mode 100644
index cfb283ab10..0000000000
--- a/apps/labrinth/.sqlx/query-e3c356bd41074ba4b3474dfab5cc0349636abea5b21faf5fc18d9f69fd21db1d.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n SELECT DISTINCT didws.project_id AS \"project_id!: DBProjectId\"\n FROM delphi_issue_details_with_statuses didws\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n WHERE\n didws.id = ANY($1::bigint[])\n AND dri.issue_type != '__dummy'\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "project_id!: DBProjectId",
- "type_info": "Int8"
- }
- ],
- "parameters": {
- "Left": [
- "Int8Array"
- ]
- },
- "nullable": [
- true
- ]
- },
- "hash": "e3c356bd41074ba4b3474dfab5cc0349636abea5b21faf5fc18d9f69fd21db1d"
-}
diff --git a/apps/labrinth/.sqlx/query-e67fda05dacea7a0b6290e8b69932ad27e5a0dd128af9273d1d6179e60f9ea0b.json b/apps/labrinth/.sqlx/query-e67fda05dacea7a0b6290e8b69932ad27e5a0dd128af9273d1d6179e60f9ea0b.json
new file mode 100644
index 0000000000..82f38da2f6
--- /dev/null
+++ b/apps/labrinth/.sqlx/query-e67fda05dacea7a0b6290e8b69932ad27e5a0dd128af9273d1d6179e60f9ea0b.json
@@ -0,0 +1,12 @@
+{
+ "db_name": "PostgreSQL",
+ "query": "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ",
+ "describe": {
+ "columns": [],
+ "parameters": {
+ "Left": []
+ },
+ "nullable": []
+ },
+ "hash": "e67fda05dacea7a0b6290e8b69932ad27e5a0dd128af9273d1d6179e60f9ea0b"
+}
diff --git a/apps/labrinth/.sqlx/query-e8b6e423aaf62046afd19fb1e177a3ef1f18f4814df8924926c47d4b0c7145c7.json b/apps/labrinth/.sqlx/query-e8b6e423aaf62046afd19fb1e177a3ef1f18f4814df8924926c47d4b0c7145c7.json
deleted file mode 100644
index 1e3e8c4d7f..0000000000
--- a/apps/labrinth/.sqlx/query-e8b6e423aaf62046afd19fb1e177a3ef1f18f4814df8924926c47d4b0c7145c7.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n WITH incoming AS (\n SELECT *\n FROM unnest($1::bigint[], $2::text[]) WITH ORDINALITY\n AS u(detail_id, verdict, ord)\n ),\n resolved AS (\n SELECT\n i.ord,\n didws.project_id,\n didws.key AS detail_key,\n i.verdict\n FROM incoming i\n INNER JOIN delphi_issue_details_with_statuses didws ON didws.id = i.detail_id\n INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id\n WHERE\n -- see delphi.rs todo comment\n dri.issue_type != '__dummy'\n ),\n validated AS (\n SELECT\n (SELECT COUNT(*) FROM incoming) AS incoming_count,\n (SELECT COUNT(*) FROM resolved) AS resolved_count\n ),\n latest AS (\n SELECT DISTINCT ON (project_id, detail_key)\n project_id,\n detail_key,\n verdict\n FROM resolved\n ORDER BY project_id, detail_key, ord DESC\n ),\n deleted AS (\n DELETE FROM delphi_issue_detail_verdicts didv\n USING latest\n WHERE\n didv.project_id = latest.project_id\n AND didv.detail_key = latest.detail_key\n AND latest.verdict = 'pending'\n RETURNING 1\n ),\n upserted AS (\n INSERT INTO delphi_issue_detail_verdicts (\n project_id,\n detail_key,\n verdict\n )\n SELECT\n project_id,\n detail_key,\n verdict::delphi_report_issue_status\n FROM latest\n WHERE verdict != 'pending'\n ON CONFLICT (project_id, detail_key)\n DO UPDATE SET verdict = EXCLUDED.verdict\n RETURNING 1\n )\n SELECT\n (v.incoming_count = v.resolved_count) AS \"all_found!\",\n (SELECT COUNT(*) FROM upserted) AS \"upserted_count!\"\n FROM validated v\n ",
- "describe": {
- "columns": [
- {
- "ordinal": 0,
- "name": "all_found!",
- "type_info": "Bool"
- },
- {
- "ordinal": 1,
- "name": "upserted_count!",
- "type_info": "Int8"
- }
- ],
- "parameters": {
- "Left": [
- "Int8Array",
- "TextArray"
- ]
- },
- "nullable": [
- null,
- null
- ]
- },
- "hash": "e8b6e423aaf62046afd19fb1e177a3ef1f18f4814df8924926c47d4b0c7145c7"
-}
diff --git a/apps/labrinth/.sqlx/query-f2054ae7dcc89b21ed6b2f04526de1e7cddd68ac956143bef994104280a8dc07.json b/apps/labrinth/.sqlx/query-f2054ae7dcc89b21ed6b2f04526de1e7cddd68ac956143bef994104280a8dc07.json
index 8cbe94abd5..1e2ab737e9 100644
--- a/apps/labrinth/.sqlx/query-f2054ae7dcc89b21ed6b2f04526de1e7cddd68ac956143bef994104280a8dc07.json
+++ b/apps/labrinth/.sqlx/query-f2054ae7dcc89b21ed6b2f04526de1e7cddd68ac956143bef994104280a8dc07.json
@@ -19,10 +19,12 @@
"name": "delphi_severity",
"kind": {
"Enum": [
+ "hidden",
"low",
"medium",
"high",
- "severe"
+ "severe",
+ "malware"
]
}
}
diff --git a/apps/labrinth/.sqlx/query-5e5fcfa6ac68f296ba5238e8211f8e206473f11fe1796fc2feda15f8d0ee7f41.json b/apps/labrinth/.sqlx/query-f952ab269d0aa1b98bb86b58debfd4ab14cea8575e4a15cf8c1c57e9c1e367a1.json
similarity index 77%
rename from apps/labrinth/.sqlx/query-5e5fcfa6ac68f296ba5238e8211f8e206473f11fe1796fc2feda15f8d0ee7f41.json
rename to apps/labrinth/.sqlx/query-f952ab269d0aa1b98bb86b58debfd4ab14cea8575e4a15cf8c1c57e9c1e367a1.json
index 99e2d4391d..06674db8d5 100644
--- a/apps/labrinth/.sqlx/query-5e5fcfa6ac68f296ba5238e8211f8e206473f11fe1796fc2feda15f8d0ee7f41.json
+++ b/apps/labrinth/.sqlx/query-f952ab269d0aa1b98bb86b58debfd4ab14cea8575e4a15cf8c1c57e9c1e367a1.json
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
- "query": "\n SELECT\n dgdv.detail_key,\n dgdv.verdict AS \"verdict!: DelphiStatus\",\n COUNT(dri.id) AS \"local_trace_count!\"\n FROM delphi_global_detail_verdicts dgdv\n LEFT JOIN delphi_issue_details_with_statuses didws\n ON didws.key = dgdv.detail_key\n LEFT JOIN delphi_report_issues dri\n ON dri.id = didws.issue_id\n AND dri.issue_type != '__dummy'\n WHERE dgdv.detail_key = $1\n GROUP BY dgdv.detail_key, dgdv.verdict\n ",
+ "query": "\n SELECT\n dgdv.detail_key,\n dgdv.verdict AS \"verdict!: DelphiStatus\",\n COUNT(dri.id) AS \"local_trace_count!\"\n FROM delphi_global_detail_verdicts dgdv\n LEFT JOIN delphi_issue_details_with_statuses didws\n ON didws.key = dgdv.detail_key\n AND didws.severity != 'hidden'\n LEFT JOIN delphi_report_issues dri\n ON dri.id = didws.issue_id\n WHERE dgdv.detail_key = $1\n GROUP BY dgdv.detail_key, dgdv.verdict\n ",
"describe": {
"columns": [
{
@@ -41,5 +41,5 @@
null
]
},
- "hash": "5e5fcfa6ac68f296ba5238e8211f8e206473f11fe1796fc2feda15f8d0ee7f41"
+ "hash": "f952ab269d0aa1b98bb86b58debfd4ab14cea8575e4a15cf8c1c57e9c1e367a1"
}
diff --git a/apps/labrinth/.sqlx/query-fc6c20348de487e4039ee7d53212ecd1856bde7aa4be6e366c98cef1321a7279.json b/apps/labrinth/.sqlx/query-fc6c20348de487e4039ee7d53212ecd1856bde7aa4be6e366c98cef1321a7279.json
deleted file mode 100644
index 16a500d5ac..0000000000
--- a/apps/labrinth/.sqlx/query-fc6c20348de487e4039ee7d53212ecd1856bde7aa4be6e366c98cef1321a7279.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "db_name": "PostgreSQL",
- "query": "\n WITH dummy_issue AS (\n INSERT INTO delphi_report_issues (report_id, issue_type)\n VALUES ($1, $2)\n ON CONFLICT (report_id, issue_type)\n DO UPDATE SET issue_type = EXCLUDED.issue_type\n RETURNING id\n )\n INSERT INTO delphi_report_issue_details (\n issue_id,\n key,\n jar,\n file_path,\n decompiled_source,\n data,\n severity\n )\n SELECT\n id,\n '',\n NULL,\n '',\n NULL,\n '{}'::jsonb,\n 'low'::delphi_severity\n FROM dummy_issue\n WHERE NOT EXISTS (\n SELECT 1\n FROM delphi_report_issue_details drid\n WHERE drid.issue_id = dummy_issue.id\n )\n ",
- "describe": {
- "columns": [],
- "parameters": {
- "Left": [
- "Int8",
- "Text"
- ]
- },
- "nullable": []
- },
- "hash": "fc6c20348de487e4039ee7d53212ecd1856bde7aa4be6e366c98cef1321a7279"
-}
diff --git a/apps/labrinth/Cargo.toml b/apps/labrinth/Cargo.toml
index 1081074d9a..068331ff85 100644
--- a/apps/labrinth/Cargo.toml
+++ b/apps/labrinth/Cargo.toml
@@ -33,6 +33,7 @@ aws-sdk-s3 = { workspace = true }
base64 = { workspace = true }
bitflags = { workspace = true }
bytes = { workspace = true }
+cel = { workspace = true }
censor = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
chumsky = { workspace = true }
diff --git a/apps/labrinth/migrations/20260720105358_delphi_trace_rules.sql b/apps/labrinth/migrations/20260720105358_delphi_trace_rules.sql
new file mode 100644
index 0000000000..666a8863d9
--- /dev/null
+++ b/apps/labrinth/migrations/20260720105358_delphi_trace_rules.sql
@@ -0,0 +1,103 @@
+ALTER TYPE delphi_severity ADD VALUE IF NOT EXISTS 'hidden' BEFORE 'low';
+ALTER TYPE delphi_severity ADD VALUE IF NOT EXISTS 'malware' AFTER 'severe';
+
+CREATE TABLE delphi_rules (
+ id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ created_by BIGINT REFERENCES users(id)
+ ON DELETE SET NULL,
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_by BIGINT REFERENCES users(id)
+ ON DELETE SET NULL,
+ name VARCHAR(256) NOT NULL,
+ rule VARCHAR(65536) NOT NULL,
+ priority INTEGER NOT NULL DEFAULT 0,
+ revision BIGINT NOT NULL DEFAULT 0,
+ delete_on_next_revision BOOL NOT NULL DEFAULT FALSE
+);
+
+CREATE TABLE delphi_rule_revisions (
+ revision BIGINT PRIMARY KEY
+);
+
+INSERT INTO delphi_rule_revisions (revision)
+VALUES (1);
+
+CREATE TABLE delphi_rule_effects (
+ revision BIGINT NOT NULL,
+ detail_id BIGINT NOT NULL REFERENCES delphi_report_issue_details(id)
+ ON DELETE CASCADE
+ ON UPDATE CASCADE,
+ rule_id BIGINT NOT NULL REFERENCES delphi_rules(id)
+ ON UPDATE CASCADE,
+ severity delphi_severity NOT NULL,
+ PRIMARY KEY (revision, detail_id)
+);
+
+CREATE INDEX delphi_rule_effects_rule_id ON delphi_rule_effects(rule_id);
+
+DROP VIEW delphi_issue_details_with_statuses;
+
+CREATE VIEW delphi_issue_details_with_statuses AS
+SELECT
+ drid.id,
+ drid.issue_id,
+ drid.key,
+ drid.jar,
+ drid.file_path,
+ drid.decompiled_source,
+ drid.data,
+ drid.severity AS original_severity,
+ COALESCE(dre.severity, drid.severity) AS severity,
+ m.id AS project_id,
+ didv.verdict AS local_status,
+ dgdv.verdict AS global_status,
+ COALESCE(dgdv.verdict, didv.verdict, 'pending') AS status
+FROM delphi_report_issue_details drid
+INNER JOIN delphi_report_issues dri ON dri.id = drid.issue_id
+INNER JOIN delphi_reports dr ON dr.id = dri.report_id
+INNER JOIN files f ON f.id = dr.file_id
+INNER JOIN versions v ON v.id = f.version_id
+INNER JOIN mods m ON m.id = v.mod_id
+LEFT JOIN delphi_global_detail_verdicts dgdv
+ ON drid.key = dgdv.detail_key
+LEFT JOIN delphi_issue_detail_verdicts didv
+ ON m.id = didv.project_id
+ AND drid.key = didv.detail_key
+LEFT JOIN (
+ SELECT revision
+ FROM delphi_rule_revisions
+ LIMIT 1
+) drr ON TRUE
+LEFT JOIN delphi_rule_effects dre
+ ON dre.revision = drr.revision
+ AND dre.detail_id = drid.id;
+
+CREATE TABLE delphi_tech_review_queue (
+ project_id BIGINT PRIMARY KEY REFERENCES mods(id)
+ ON DELETE CASCADE
+);
+
+INSERT INTO delphi_tech_review_queue (project_id)
+SELECT DISTINCT didws.project_id
+FROM delphi_issue_details_with_statuses didws
+INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
+WHERE
+ (
+ dri.issue_type = '__dummy'
+ AND didws.status = 'pending'
+ )
+ OR (
+ dri.issue_type != '__dummy'
+ AND didws.status IN ('pending', 'unsafe')
+ AND didws.severity::text != 'hidden'
+ );
+
+DELETE FROM delphi_report_issue_details detail
+USING delphi_report_issues issue
+WHERE
+ detail.issue_id = issue.id
+ AND issue.issue_type = '__dummy';
+
+DELETE FROM delphi_report_issues
+WHERE issue_type = '__dummy';
diff --git a/apps/labrinth/src/database/models/delphi_report_item.rs b/apps/labrinth/src/database/models/delphi_report_item.rs
index 4ae71749b4..92cf1000aa 100644
--- a/apps/labrinth/src/database/models/delphi_report_item.rs
+++ b/apps/labrinth/src/database/models/delphi_report_item.rs
@@ -55,7 +55,7 @@ impl DBDelphiReport {
}
}
-/// A severity level reported by Delphi.
+/// A severity level for a Delphi report or transformed issue detail.
#[derive(
Deserialize,
Serialize,
@@ -76,6 +76,8 @@ impl DBDelphiReport {
#[serde(rename_all = "snake_case")]
#[sqlx(type_name = "delphi_severity", rename_all = "snake_case")]
pub enum DelphiSeverity {
+ #[serde(alias = "HIDDEN")]
+ Hidden,
#[serde(alias = "LOW")]
Low,
#[serde(alias = "MEDIUM")]
@@ -84,6 +86,8 @@ pub enum DelphiSeverity {
High,
#[serde(alias = "SEVERE")]
Severe,
+ #[serde(alias = "MALWARE")]
+ Malware,
}
/// An issue found in a Delphi report. Every issue belongs to a report,
diff --git a/apps/labrinth/src/database/models/ids.rs b/apps/labrinth/src/database/models/ids.rs
index 5f92ece21d..bd953e7e2d 100644
--- a/apps/labrinth/src/database/models/ids.rs
+++ b/apps/labrinth/src/database/models/ids.rs
@@ -292,4 +292,5 @@ id_type!(StatusId as i32);
id_type!(DelphiReportId as i64);
id_type!(DelphiReportIssueId as i64);
id_type!(DelphiReportIssueDetailsId as i64);
+id_type!(DelphiRuleId as i64);
id_type!(SharedInstanceId as i64);
diff --git a/apps/labrinth/src/routes/internal/delphi/mod.rs b/apps/labrinth/src/routes/internal/delphi/mod.rs
index 1a5d9e55fb..ce0fa3da9d 100644
--- a/apps/labrinth/src/routes/internal/delphi/mod.rs
+++ b/apps/labrinth/src/routes/internal/delphi/mod.rs
@@ -30,7 +30,7 @@ use crate::{
};
pub mod rescan;
-pub mod tech_review_sync;
+pub mod tech_review_queue;
pub fn config(cfg: &mut actix_web::web::ServiceConfig) {
cfg.service(
@@ -208,6 +208,7 @@ async fn ingest_report_deserialized(
"Delphi found issues in file",
);
+ let mut inserted_detail_ids = Vec::new();
for (issue_type, issue_details) in report.issues {
let issue_id = DBDelphiReportIssue {
id: DelphiReportIssueId(0), // This will be set by the database
@@ -227,7 +228,7 @@ async fn ingest_report_deserialized(
let decompiled_source =
report.decompiled_sources.get(&issue_detail.file);
- ReportIssueDetail {
+ let detail_id = ReportIssueDetail {
id: DelphiReportIssueDetailsId(0), // This will be set by the database
issue_id,
key: issue_detail.key.0,
@@ -243,12 +244,19 @@ async fn ingest_report_deserialized(
.insert(&mut transaction)
.await
.wrap_internal_err("failed to insert Delphi issue detail")?;
+ inserted_detail_ids.push(detail_id);
}
}
- tech_review_sync::sync_project_tech_review_state(
+ crate::routes::internal::moderation::tech_review::rules_scan::materialize_current_rule_effects(
+ &inserted_detail_ids,
+ &mut transaction,
+ )
+ .await
+ .wrap_internal_err("failed to apply delphi rules to new issue details")?;
+
+ tech_review_queue::add_projects_with_review_details(
&[DBProjectId::from(report.project_id)],
- tech_review_sync::TechReviewExitReason::Resolved,
&mut transaction,
)
.await?;
diff --git a/apps/labrinth/src/routes/internal/delphi/rescan.rs b/apps/labrinth/src/routes/internal/delphi/rescan.rs
index c7d7fa297b..71b47d9cee 100644
--- a/apps/labrinth/src/routes/internal/delphi/rescan.rs
+++ b/apps/labrinth/src/routes/internal/delphi/rescan.rs
@@ -97,26 +97,23 @@ async fn fetch_unreviewed_tech_review_project_ids(
r#"
SELECT DISTINCT m.id
FROM mods m
+ INNER JOIN delphi_tech_review_queue queue ON queue.project_id = m.id
WHERE
EXISTS(
SELECT 1
FROM delphi_issue_details_with_statuses didws
- INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
WHERE
didws.project_id = m.id
AND didws.status = 'pending'
- -- see delphi.rs todo comment
- AND dri.issue_type != '__dummy'
+ AND didws.severity != 'hidden'
)
AND NOT EXISTS(
SELECT 1
FROM delphi_issue_details_with_statuses didws
- INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
WHERE
didws.project_id = m.id
AND didws.status IN ('safe', 'unsafe')
- -- see delphi.rs todo comment
- AND dri.issue_type != '__dummy'
+ AND didws.severity != 'hidden'
)
"#,
)
diff --git a/apps/labrinth/src/routes/internal/delphi/tech_review_queue.rs b/apps/labrinth/src/routes/internal/delphi/tech_review_queue.rs
new file mode 100644
index 0000000000..de55b758df
--- /dev/null
+++ b/apps/labrinth/src/routes/internal/delphi/tech_review_queue.rs
@@ -0,0 +1,203 @@
+//! Maintains explicit project membership in the technical review queue.
+//!
+//! Queue membership is represented by a row in `delphi_tech_review_queue`.
+//! Enter and exit thread messages are emitted only when an insert or delete
+//! actually changes that membership, in the same transaction.
+
+use itertools::Itertools;
+
+use crate::{
+ database::{
+ PgTransaction,
+ models::{DBProjectId, DBThreadId, thread_item::ThreadMessageBuilder},
+ },
+ models::threads::MessageBody,
+ routes::ApiError,
+ util::error::Context,
+};
+
+#[derive(Debug, Clone, Copy)]
+pub enum TechReviewRemovalReason {
+ RulesChanged,
+ FileDeleted,
+}
+
+pub async fn add_projects(
+ project_ids: &[DBProjectId],
+ txn: &mut PgTransaction<'_>,
+) -> Result<(), ApiError> {
+ let project_ids = project_ids.iter().copied().unique().collect::>();
+ if project_ids.is_empty() {
+ return Ok(());
+ }
+
+ let rows = sqlx::query!(
+ r#"
+ WITH inserted AS (
+ INSERT INTO delphi_tech_review_queue (project_id)
+ SELECT unnest($1::bigint[])
+ ON CONFLICT (project_id) DO NOTHING
+ RETURNING project_id
+ )
+ SELECT
+ inserted.project_id AS "project_id!: DBProjectId",
+ (
+ SELECT thread.id
+ FROM threads thread
+ WHERE thread.mod_id = inserted.project_id
+ ORDER BY thread.id
+ LIMIT 1
+ ) AS "thread_id!: DBThreadId"
+ FROM inserted
+ "#,
+ &project_ids.iter().map(|id| id.0).collect::>(),
+ )
+ .fetch_all(&mut *txn)
+ .await
+ .wrap_internal_err("failed to add projects to technical review queue")?;
+
+ for row in rows {
+ ThreadMessageBuilder {
+ author_id: None,
+ body: MessageBody::TechReviewEntered,
+ thread_id: row.thread_id,
+ hide_identity: false,
+ }
+ .insert(txn)
+ .await
+ .wrap_internal_err("failed to add entering technical review message")?;
+ }
+
+ Ok(())
+}
+
+pub async fn remove_projects(
+ project_ids: &[DBProjectId],
+ reason: TechReviewRemovalReason,
+ txn: &mut PgTransaction<'_>,
+) -> Result<(), ApiError> {
+ let project_ids = project_ids.iter().copied().unique().collect::>();
+ if project_ids.is_empty() {
+ return Ok(());
+ }
+
+ let rows = sqlx::query!(
+ r#"
+ WITH removed AS (
+ DELETE FROM delphi_tech_review_queue
+ WHERE project_id = ANY($1::bigint[])
+ RETURNING project_id
+ )
+ SELECT
+ removed.project_id AS "project_id!: DBProjectId",
+ (
+ SELECT thread.id
+ FROM threads thread
+ WHERE thread.mod_id = removed.project_id
+ ORDER BY thread.id
+ LIMIT 1
+ ) AS "thread_id!: DBThreadId"
+ FROM removed
+ "#,
+ &project_ids.iter().map(|id| id.0).collect::>(),
+ )
+ .fetch_all(&mut *txn)
+ .await
+ .wrap_internal_err(
+ "failed to remove projects from technical review queue",
+ )?;
+
+ let body = match reason {
+ TechReviewRemovalReason::RulesChanged => MessageBody::TechReviewExited,
+ TechReviewRemovalReason::FileDeleted => {
+ MessageBody::TechReviewExitFileDeleted
+ }
+ };
+
+ for row in rows {
+ ThreadMessageBuilder {
+ author_id: None,
+ body: body.clone(),
+ thread_id: row.thread_id,
+ hide_identity: false,
+ }
+ .insert(txn)
+ .await
+ .wrap_internal_err("failed to add exiting technical review message")?;
+ }
+
+ Ok(())
+}
+
+pub async fn add_projects_with_review_details(
+ project_ids: &[DBProjectId],
+ txn: &mut PgTransaction<'_>,
+) -> Result<(), ApiError> {
+ let project_ids = project_ids.iter().copied().unique().collect::>();
+ if project_ids.is_empty() {
+ return Ok(());
+ }
+
+ let rows = sqlx::query!(
+ r#"
+ SELECT DISTINCT detail.project_id AS "project_id!: DBProjectId"
+ FROM delphi_issue_details_with_statuses detail
+ WHERE
+ detail.project_id = ANY($1::bigint[])
+ AND detail.status IN ('pending', 'unsafe')
+ AND detail.severity != 'hidden'
+ "#,
+ &project_ids.iter().map(|id| id.0).collect::>(),
+ )
+ .fetch_all(&mut *txn)
+ .await
+ .wrap_internal_err("failed to find projects requiring technical review")?;
+
+ add_projects(
+ &rows
+ .into_iter()
+ .map(|row| row.project_id)
+ .collect::>(),
+ txn,
+ )
+ .await
+}
+
+pub async fn remove_projects_without_details(
+ project_ids: &[DBProjectId],
+ reason: TechReviewRemovalReason,
+ txn: &mut PgTransaction<'_>,
+) -> Result<(), ApiError> {
+ let project_ids = project_ids.iter().copied().unique().collect::>();
+ if project_ids.is_empty() {
+ return Ok(());
+ }
+
+ let rows = sqlx::query!(
+ r#"
+ SELECT requested.project_id AS "project_id!: DBProjectId"
+ FROM unnest($1::bigint[]) AS requested(project_id)
+ WHERE NOT EXISTS (
+ SELECT 1
+ FROM delphi_issue_details_with_statuses detail
+ WHERE detail.project_id = requested.project_id
+ )
+ "#,
+ &project_ids.iter().map(|id| id.0).collect::>(),
+ )
+ .fetch_all(&mut *txn)
+ .await
+ .wrap_internal_err(
+ "failed to find projects without technical review details",
+ )?;
+
+ remove_projects(
+ &rows
+ .into_iter()
+ .map(|row| row.project_id)
+ .collect::>(),
+ reason,
+ txn,
+ )
+ .await
+}
diff --git a/apps/labrinth/src/routes/internal/delphi/tech_review_sync.rs b/apps/labrinth/src/routes/internal/delphi/tech_review_sync.rs
deleted file mode 100644
index 23a45d218a..0000000000
--- a/apps/labrinth/src/routes/internal/delphi/tech_review_sync.rs
+++ /dev/null
@@ -1,411 +0,0 @@
-//! Synchronizes moderation thread messages and dummy queue blockers with the
-//! current computed tech review state of affected projects.
-//!
-//! When a project has a Delphi report submitted for it, or when a moderator
-//! updates one of its issue details' rows (like flagging a detail as *globally*
-//! safe or unsafe), we will need to recheck if the project still belongs in the
-//! tech review queue or if it needs to exit now.
-//!
-//! Side-note: "entering the queue" or "exiting the queue" right now just means
-//! adding a new message to the project's moderation thread which indicates if
-//! it entered/exited. In the future this should be replaced with a more proper
-//! audit log table, or "is project currently in tech review" table.
-//!
-//! A project is considered to need tech review when it has at least one
-//! non-dummy issue detail whose effective status is pending or unsafe, or when
-//! it already has a dummy pending detail blocking the final review submission.
-//! Effective status is just the local detail's verdict (from
-//! `delphi_issue_detail_verdicts`), or if it's null then the global verdict for
-//! the same `drid.key` (from `delphi_global_detail_verdicts`).
-//!
-//! Some examples of how this behavior manifests: let's assume you have projects
-//! _A_ and _B_ currently in tech review. They each have one (unresolved) issue
-//! detail with key _K_.
-//! - If you mark _K_ on _A_ as locally safe/unsafe, then _A_ is fully resolved,
-//! but we still have the `__dummy` detail, which means it's still in the
-//! queue until the moderator submits the actual report. _B_ is entirely
-//! unaffected.
-//! - If you mark _K_ on _A_ as globally safe, then _A_ and _B_ both get fully
-//! resolved, but both still have the `__dummy` detail, so they also still
-//! need the final report to be submitted by the moderator.
-//!
-//! In practice, this means that some projects may have e.g. "100/100 traces
-//! are safe" reported, but they will just be waiting for final moderator
-//! approval.
-//!
-//! The logic for checking whether a project is now in tech review or not, and
-//! sending the appropriate message, is complex! That's why this module exists:
-//! to act as a single chokepoint which (correctly) syncs all the state, instead
-//! of having each mutation run its own ad-hoc update logic.
-
-use itertools::Itertools;
-
-use crate::{
- database::{
- PgTransaction,
- models::{
- DBProjectId, DBThreadId, DelphiReportId,
- delphi_report_item::DelphiVerdict,
- thread_item::ThreadMessageBuilder,
- },
- },
- models::threads::MessageBody,
- routes::ApiError,
- util::error::Context,
-};
-
-const DUMMY_ISSUE_TYPE: &str = "__dummy";
-
-#[derive(Debug, Clone, Copy)]
-pub enum TechReviewExitReason {
- Resolved,
- FileDeleted,
-}
-
-struct ProjectTechReviewState {
- has_pending_detail: bool,
- has_unsafe_detail: bool,
- has_dummy: bool,
- thread_id: Option,
- report_id: Option,
- last_tech_review_message_type: Option,
-}
-
-pub async fn sync_project_tech_review_state(
- project_ids: &[DBProjectId],
- exit_reason: TechReviewExitReason,
- txn: &mut PgTransaction<'_>,
-) -> Result<(), ApiError> {
- let project_ids = project_ids.iter().copied().unique().collect::>();
- if project_ids.is_empty() {
- return Ok(());
- }
-
- let project_ids_raw = project_ids.iter().map(|id| id.0).collect::>();
- let tech_review_message_types = tech_review_message_types();
-
- let rows = sqlx::query!(
- r#"
- WITH project_ids AS (
- SELECT unnest($1::bigint[]) AS project_id
- )
- SELECT
- p.project_id AS "project_id!: DBProjectId",
- EXISTS(
- SELECT 1
- FROM delphi_issue_details_with_statuses didws
- INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
- WHERE
- didws.project_id = p.project_id
- AND didws.status = 'pending'
- AND dri.issue_type != $3
- ) AS "has_pending_detail!",
- EXISTS(
- SELECT 1
- FROM delphi_issue_details_with_statuses didws
- INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
- WHERE
- didws.project_id = p.project_id
- AND didws.status = 'unsafe'
- AND dri.issue_type != $3
- ) AS "has_unsafe_detail!",
- EXISTS(
- SELECT 1
- FROM delphi_issue_details_with_statuses didws
- INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
- WHERE
- didws.project_id = p.project_id
- AND didws.status = 'pending'
- AND dri.issue_type = $3
- ) AS "has_dummy!",
- (
- SELECT t.id
- FROM threads t
- WHERE t.mod_id = p.project_id
- ORDER BY t.id
- LIMIT 1
- ) AS "thread_id: DBThreadId",
- (
- SELECT tm.body->>'type'
- FROM threads t
- INNER JOIN threads_messages tm ON tm.thread_id = t.id
- WHERE
- t.mod_id = p.project_id
- AND tm.body->>'type' = ANY($2::text[])
- ORDER BY tm.created DESC, tm.id DESC
- LIMIT 1
- ) AS "last_tech_review_message_type",
- (
- SELECT dr.id
- FROM versions v
- INNER JOIN files f ON f.version_id = v.id
- INNER JOIN delphi_reports dr ON dr.file_id = f.id
- WHERE v.mod_id = p.project_id
- ORDER BY dr.created DESC, dr.id DESC
- LIMIT 1
- ) AS "report_id: DelphiReportId"
- FROM project_ids p
- "#,
- &project_ids_raw,
- &tech_review_message_types,
- DUMMY_ISSUE_TYPE,
- )
- .fetch_all(&mut *txn)
- .await
- .wrap_internal_err("failed to fetch project tech review state")?;
-
- for row in rows {
- let state = ProjectTechReviewState {
- has_pending_detail: row.has_pending_detail,
- has_unsafe_detail: row.has_unsafe_detail,
- has_dummy: row.has_dummy,
- thread_id: row.thread_id,
- report_id: row.report_id,
- last_tech_review_message_type: row.last_tech_review_message_type,
- };
-
- sync_one_project_tech_review_state(state, exit_reason, txn).await?;
- }
-
- Ok(())
-}
-
-pub async fn sync_detail_key_tech_review_state(
- detail_keys: &[String],
- exit_reason: TechReviewExitReason,
- txn: &mut PgTransaction<'_>,
-) -> Result<(), ApiError> {
- let detail_keys = detail_keys.iter().cloned().unique().collect::>();
-
- if detail_keys.is_empty() {
- return Ok(());
- }
-
- let rows = sqlx::query!(
- r#"
- SELECT DISTINCT didws.project_id AS "project_id!: DBProjectId"
- FROM delphi_issue_details_with_statuses didws
- WHERE didws.key = ANY($1::text[])
- "#,
- &detail_keys,
- )
- .fetch_all(&mut *txn)
- .await
- .wrap_internal_err("failed to fetch projects affected by detail keys")?;
-
- let project_ids = rows
- .into_iter()
- .map(|row| row.project_id)
- .collect::>();
-
- sync_project_tech_review_state(&project_ids, exit_reason, txn).await
-}
-
-pub async fn sync_deleted_project_tech_review_exit(
- project_id: DBProjectId,
- txn: &mut PgTransaction<'_>,
-) -> Result<(), ApiError> {
- let tech_review_message_types = tech_review_message_types();
-
- let row = sqlx::query!(
- r#"
- SELECT
- (
- SELECT t.id
- FROM threads t
- WHERE t.mod_id = $1
- ORDER BY t.id
- LIMIT 1
- ) AS "thread_id: DBThreadId",
- (
- SELECT tm.body->>'type'
- FROM threads t
- INNER JOIN threads_messages tm ON tm.thread_id = t.id
- WHERE
- t.mod_id = $1
- AND tm.body->>'type' = ANY($2::text[])
- ORDER BY tm.created DESC, tm.id DESC
- LIMIT 1
- ) AS "last_tech_review_message_type"
- "#,
- project_id as DBProjectId,
- &tech_review_message_types,
- )
- .fetch_one(&mut *txn)
- .await
- .wrap_internal_err("failed to fetch deleted project tech review state")?;
-
- if let Some(thread_id) = row.thread_id
- && should_send_exit(row.last_tech_review_message_type.as_deref())
- {
- insert_exit_message(thread_id, TechReviewExitReason::FileDeleted, txn)
- .await?;
- }
-
- Ok(())
-}
-
-async fn sync_one_project_tech_review_state(
- state: ProjectTechReviewState,
- exit_reason: TechReviewExitReason,
- txn: &mut PgTransaction<'_>,
-) -> Result<(), ApiError> {
- let needs_tech_review =
- state.has_pending_detail || state.has_unsafe_detail || state.has_dummy;
-
- if needs_tech_review {
- if (state.has_pending_detail || state.has_unsafe_detail)
- && !state.has_dummy
- && let Some(report_id) = state.report_id
- {
- // TODO: Currently, the queue query determines whether a project is
- // in tech review by checking whether it has any pending issue
- // details. If all visible issue details are marked safe or unsafe
- // before the final report is submitted, the project would otherwise
- // leave the tech review queue without a final tech review verdict
- // message.
- //
- // This should be replaced with explicit tech review state, such as
- // an append-only project tech review event table where the latest
- // enter/exit event is the current state. Until then, this dummy
- // issue detail acts as the pending queue blocker.
- ensure_dummy_issue_detail(report_id, txn).await?;
- }
-
- if let Some(thread_id) = state.thread_id
- && state.last_tech_review_message_type.as_deref()
- != Some(MessageBody::TechReviewEntered.as_ref())
- {
- ThreadMessageBuilder {
- author_id: None,
- body: MessageBody::TechReviewEntered,
- thread_id,
- hide_identity: false,
- }
- .insert(txn)
- .await
- .wrap_internal_err("failed to add entering tech review message")?;
- }
-
- return Ok(());
- }
-
- if matches!(exit_reason, TechReviewExitReason::Resolved)
- && state.last_tech_review_message_type.as_deref()
- == Some(MessageBody::TechReviewEntered.as_ref())
- {
- if let Some(report_id) = state.report_id {
- ensure_dummy_issue_detail(report_id, txn).await?;
- }
-
- return Ok(());
- }
-
- if let Some(thread_id) = state.thread_id
- && should_send_exit(state.last_tech_review_message_type.as_deref())
- {
- insert_exit_message(thread_id, exit_reason, txn).await?;
- }
-
- Ok(())
-}
-
-fn should_send_exit(last_tech_review_message_type: Option<&str>) -> bool {
- matches!(last_tech_review_message_type, Some(message_type) if !matches!(
- message_type,
- message_type if message_type == MessageBody::TechReviewExited.as_ref()
- || message_type == MessageBody::TechReviewExitFileDeleted.as_ref()
- || message_type == tech_review_completed_message_type()
- ))
-}
-
-async fn insert_exit_message(
- thread_id: DBThreadId,
- exit_reason: TechReviewExitReason,
- txn: &mut PgTransaction<'_>,
-) -> Result<(), ApiError> {
- let body = match exit_reason {
- TechReviewExitReason::Resolved => MessageBody::TechReviewExited,
- TechReviewExitReason::FileDeleted => {
- MessageBody::TechReviewExitFileDeleted
- }
- };
-
- ThreadMessageBuilder {
- author_id: None,
- body,
- thread_id,
- hide_identity: false,
- }
- .insert(txn)
- .await
- .wrap_internal_err("failed to add exiting tech review message")?;
-
- Ok(())
-}
-
-async fn ensure_dummy_issue_detail(
- report_id: DelphiReportId,
- txn: &mut PgTransaction<'_>,
-) -> Result<(), ApiError> {
- sqlx::query!(
- r#"
- WITH dummy_issue AS (
- INSERT INTO delphi_report_issues (report_id, issue_type)
- VALUES ($1, $2)
- ON CONFLICT (report_id, issue_type)
- DO UPDATE SET issue_type = EXCLUDED.issue_type
- RETURNING id
- )
- INSERT INTO delphi_report_issue_details (
- issue_id,
- key,
- jar,
- file_path,
- decompiled_source,
- data,
- severity
- )
- SELECT
- id,
- '',
- NULL,
- '',
- NULL,
- '{}'::jsonb,
- 'low'::delphi_severity
- FROM dummy_issue
- WHERE NOT EXISTS (
- SELECT 1
- FROM delphi_report_issue_details drid
- WHERE drid.issue_id = dummy_issue.id
- )
- "#,
- report_id as DelphiReportId,
- DUMMY_ISSUE_TYPE,
- )
- .execute(&mut *txn)
- .await
- .wrap_internal_err("failed to ensure dummy Delphi report issue detail")?;
-
- Ok(())
-}
-
-fn tech_review_message_types() -> Vec {
- [
- MessageBody::TechReviewEntered.as_ref(),
- MessageBody::TechReviewExited.as_ref(),
- MessageBody::TechReviewExitFileDeleted.as_ref(),
- tech_review_completed_message_type(),
- ]
- .into_iter()
- .map(|message_type| message_type.to_string())
- .collect()
-}
-
-fn tech_review_completed_message_type() -> &'static str {
- MessageBody::TechReview {
- verdict: DelphiVerdict::Safe,
- }
- .as_ref()
-}
diff --git a/apps/labrinth/src/routes/internal/mod.rs b/apps/labrinth/src/routes/internal/mod.rs
index 272ac2de8b..fba588db64 100644
--- a/apps/labrinth/src/routes/internal/mod.rs
+++ b/apps/labrinth/src/routes/internal/mod.rs
@@ -118,6 +118,15 @@ pub fn config(cfg: &mut web::ServiceConfig) {
moderation::tech_review::search_projects,
moderation::tech_review::global::search_global_issue_details,
moderation::tech_review::global::get_global_issue_detail,
+ moderation::tech_review::rules::get_rules,
+ moderation::tech_review::rules::test_rule,
+ moderation::tech_review::rules::get_rule_affected_details,
+ moderation::tech_review::rules::create_rule,
+ moderation::tech_review::rules::update_rule,
+ moderation::tech_review::rules::delete_rule,
+ moderation::tech_review::rules_scan::get_rule_schema,
+ moderation::tech_review::rules_scan::get_detail_rule_input,
+ moderation::tech_review::rules_scan::scan_rules,
moderation::tech_review::get_project_report,
moderation::tech_review::submit_report,
moderation::tech_review::update_issue_details,
diff --git a/apps/labrinth/src/routes/internal/moderation/mod.rs b/apps/labrinth/src/routes/internal/moderation/mod.rs
index e66f0e0f84..468fca061c 100644
--- a/apps/labrinth/src/routes/internal/moderation/mod.rs
+++ b/apps/labrinth/src/routes/internal/moderation/mod.rs
@@ -295,6 +295,7 @@ pub async fn get_projects_internal(
FROM delphi_issue_details_with_statuses didws
WHERE didws.project_id = m.id
AND didws.status = 'pending'
+ AND didws.severity != 'hidden'
)
)
),
@@ -542,6 +543,7 @@ pub async fn get_projects_internal(
FROM delphi_issue_details_with_statuses didws
WHERE didws.project_id = m.id
AND didws.status = 'pending'
+ AND didws.severity != 'hidden'
)
)
),
@@ -770,6 +772,7 @@ pub async fn get_project_ids(
FROM delphi_issue_details_with_statuses didws
WHERE didws.project_id = m.id
AND didws.status = 'pending'
+ AND didws.severity != 'hidden'
)
)
),
@@ -898,6 +901,7 @@ pub async fn get_project_ids(
FROM delphi_issue_details_with_statuses didws
WHERE didws.project_id = mods.id
AND didws.status = 'pending'
+ AND didws.severity != 'hidden'
)
)
ORDER BY
diff --git a/apps/labrinth/src/routes/internal/moderation/tech_review.rs b/apps/labrinth/src/routes/internal/moderation/tech_review.rs
index 2cb592533b..e912746b7b 100644
--- a/apps/labrinth/src/routes/internal/moderation/tech_review.rs
+++ b/apps/labrinth/src/routes/internal/moderation/tech_review.rs
@@ -33,10 +33,7 @@ use crate::{
queue::session::AuthQueue,
routes::{
ApiError,
- internal::{
- delphi::tech_review_sync::{self, TechReviewExitReason},
- moderation::Ownership,
- },
+ internal::{delphi::tech_review_queue, moderation::Ownership},
},
search::SearchState,
util::error::Context,
@@ -44,10 +41,14 @@ use crate::{
use eyre::eyre;
pub mod global;
+pub mod rules;
+pub mod rules_scan;
pub fn config(cfg: &mut actix_web::web::ServiceConfig) {
cfg.service(search_projects)
.configure(global::config)
+ .configure(rules::config)
+ .configure(rules_scan::config)
.service(get_project_report)
.service(get_report)
.service(get_issue)
@@ -250,7 +251,9 @@ pub async fn get_issue(
)
), '[]'::jsonb)
FROM delphi_issue_details_with_statuses didws
- WHERE didws.issue_id = dri.id
+ WHERE
+ didws.issue_id = dri.id
+ AND didws.severity != 'hidden'
)
) AS "data!: sqlx::types::Json"
FROM delphi_report_issues dri
@@ -305,6 +308,15 @@ pub async fn get_report(
'file_size', f.size,
'flag_reason', 'delphi',
'download_url', f.url,
+ 'severity', COALESCE((
+ SELECT MAX(didws.severity)
+ FROM delphi_report_issues severity_issue
+ INNER JOIN delphi_issue_details_with_statuses didws
+ ON didws.issue_id = severity_issue.id
+ WHERE
+ severity_issue.report_id = dr.id
+ AND didws.severity != 'hidden'
+ ), 'low'::delphi_severity),
-- TODO: replace with `json_array` in Postgres 16
'issues', (
SELECT coalesce(json_agg(
@@ -327,15 +339,22 @@ pub async fn get_report(
)
), '[]'::jsonb)
FROM delphi_issue_details_with_statuses didws
- WHERE didws.issue_id = dri.id
+ WHERE
+ didws.issue_id = dri.id
+ AND didws.severity != 'hidden'
)
)
), '[]'::json)
FROM delphi_report_issues dri
WHERE
- dri.report_id = dr.id
- -- see delphi.rs todo comment
- AND dri.issue_type != '__dummy'
+ dri.report_id = dr.id
+ AND EXISTS (
+ SELECT 1
+ FROM delphi_issue_details_with_statuses visible_detail
+ WHERE
+ visible_detail.issue_id = dri.id
+ AND visible_detail.severity != 'hidden'
+ )
)
) AS "data!: sqlx::types::Json"
FROM delphi_reports dr
@@ -530,7 +549,9 @@ async fn fetch_project_reports(
didws.global_status AS "global_status?: DelphiStatus",
didws.status AS "status!: DelphiStatus"
FROM delphi_issue_details_with_statuses didws
- WHERE didws.issue_id = ANY($1::bigint[])
+ WHERE
+ didws.issue_id = ANY($1::bigint[])
+ AND didws.severity != 'hidden'
ORDER BY didws.issue_id, didws.id
"#,
&issue_ids.iter().map(|i| i.0).collect::>()
@@ -628,14 +649,14 @@ async fn fetch_project_reports(
let mut file_issues = Vec::new();
for issue_row in report_issues {
- if issue_row.issue_type == "__dummy" {
- continue;
- }
-
let issue_details = details_by_issue
.get(&issue_row.id)
.unwrap_or(&empty_details);
+ if issue_details.is_empty() {
+ continue;
+ }
+
file_issues.push(FileIssue {
id: issue_row.id,
report_id: issue_row.report_id,
@@ -644,12 +665,23 @@ async fn fetch_project_reports(
});
}
+ if file_issues.is_empty() {
+ continue;
+ }
+
+ let severity = file_issues
+ .iter()
+ .flat_map(|issue| issue.details.iter())
+ .map(|detail| detail.severity)
+ .max()
+ .unwrap_or(report_row.severity);
+
file_reports.push(FileReport {
report_id: report_row.report_id,
file_id: FileId::from(file_row.file_id),
created: report_row.created,
flag_reason: FlagReason::Delphi,
- severity: report_row.severity,
+ severity,
file_name: file_row.filename.clone(),
file_size: file_row.size,
download_url: file_row.url.clone(),
@@ -728,13 +760,15 @@ pub async fn search_projects(
m.id AS "project_id: DBProjectId",
MIN(t.id) AS "thread_id!: DBThreadId"
FROM mods m
+ INNER JOIN delphi_tech_review_queue trq ON trq.project_id = m.id
INNER JOIN threads t ON t.mod_id = m.id
- INNER JOIN versions v ON v.mod_id = m.id
- INNER JOIN files f ON f.version_id = v.id
- INNER JOIN delphi_reports dr ON dr.file_id = f.id
- INNER JOIN delphi_report_issues dri ON dri.report_id = dr.id
- INNER JOIN delphi_issue_details_with_statuses didws
+ LEFT JOIN versions v ON v.mod_id = m.id
+ LEFT JOIN files f ON f.version_id = v.id
+ LEFT JOIN delphi_reports dr ON dr.file_id = f.id
+ LEFT JOIN delphi_report_issues dri ON dri.report_id = dr.id
+ LEFT JOIN delphi_issue_details_with_statuses didws
ON didws.issue_id = dri.id
+ AND didws.severity != 'hidden'
LEFT JOIN threads_messages tm_last
ON tm_last.thread_id = t.id
AND tm_last.id = (
@@ -778,8 +812,25 @@ pub async fn search_projects(
)
AND m.status NOT IN ('draft', 'rejected', 'withheld')
AND (cardinality($6::text[]) = 0 OR m.status = ANY($6::text[]))
- AND (cardinality($7::text[]) = 0 OR dri.issue_type = ANY($7::text[]))
- AND didws.status = 'pending'
+ AND (
+ cardinality($7::text[]) = 0
+ OR EXISTS (
+ SELECT 1
+ FROM versions issue_version
+ INNER JOIN files issue_file
+ ON issue_file.version_id = issue_version.id
+ INNER JOIN delphi_reports issue_report
+ ON issue_report.file_id = issue_file.id
+ INNER JOIN delphi_report_issues issue
+ ON issue.report_id = issue_report.id
+ INNER JOIN delphi_issue_details_with_statuses detail
+ ON detail.issue_id = issue.id
+ WHERE
+ issue_version.mod_id = m.id
+ AND issue.issue_type = ANY($7::text[])
+ AND detail.severity != 'hidden'
+ )
+ )
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')))
@@ -789,8 +840,8 @@ pub async fn search_projects(
ORDER BY
CASE WHEN $3 = 'created_asc' THEN MIN(dr.created) ELSE TO_TIMESTAMP(0) END ASC,
CASE WHEN $3 = 'created_desc' THEN MIN(dr.created) ELSE TO_TIMESTAMP(0) END DESC,
- CASE WHEN $3 = 'severity_asc' THEN MAX(dr.severity) ELSE 'low'::delphi_severity END ASC,
- CASE WHEN $3 = 'severity_desc' THEN MAX(dr.severity) ELSE 'low'::delphi_severity END DESC,
+ CASE WHEN $3 = 'severity_asc' THEN COALESCE(MAX(didws.severity), 'low'::delphi_severity) ELSE 'low'::delphi_severity END ASC,
+ CASE WHEN $3 = 'severity_desc' THEN COALESCE(MAX(didws.severity), 'low'::delphi_severity) ELSE 'low'::delphi_severity END DESC,
-- tie-breaker: oldest reports
MIN(dr.created) ASC
LIMIT $1 OFFSET $2
@@ -1035,8 +1086,7 @@ pub async fn submit_report(
WHERE
m.id = $1
AND didws.status = 'pending'
- -- see delphi.rs todo comment
- AND dri.issue_type != '__dummy'
+ AND didws.severity != 'hidden'
"#,
project_id as _,
)
@@ -1055,24 +1105,18 @@ pub async fn submit_report(
});
}
- sqlx::query!(
- "
- DELETE FROM delphi_report_issue_details drid
- WHERE issue_id IN (
- SELECT dri.id
- FROM mods m
- INNER JOIN versions v ON v.mod_id = m.id
- INNER JOIN files f ON f.version_id = v.id
- INNER JOIN delphi_reports dr ON dr.file_id = f.id
- INNER JOIN delphi_report_issues dri ON dri.report_id = dr.id
- WHERE m.id = $1 AND dri.issue_type = '__dummy'
- )
- ",
- project_id as _,
+ sqlx::query_scalar!(
+ r#"
+ DELETE FROM delphi_tech_review_queue
+ WHERE project_id = $1
+ RETURNING project_id AS "project_id: DBProjectId"
+ "#,
+ project_id as DBProjectId,
)
- .execute(&mut txn)
+ .fetch_optional(&mut txn)
.await
- .wrap_internal_err("failed to delete dummy issue")?;
+ .wrap_internal_err("failed to remove project from technical review queue")?
+ .ok_or(ApiError::NotFound)?;
let record = sqlx::query!(
r#"
@@ -1257,10 +1301,6 @@ pub async fn update_issue_details(
i.verdict
FROM incoming i
INNER JOIN delphi_issue_details_with_statuses didws ON didws.id = i.detail_id
- INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
- WHERE
- -- see delphi.rs todo comment
- dri.issue_type != '__dummy'
),
validated AS (
SELECT
@@ -1320,10 +1360,7 @@ pub async fn update_issue_details(
r#"
SELECT DISTINCT didws.project_id AS "project_id!: DBProjectId"
FROM delphi_issue_details_with_statuses didws
- INNER JOIN delphi_report_issues dri ON dri.id = didws.issue_id
- WHERE
- didws.id = ANY($1::bigint[])
- AND dri.issue_type != '__dummy'
+ WHERE didws.id = ANY($1::bigint[])
"#,
&detail_ids,
)
@@ -1338,9 +1375,8 @@ pub async fn update_issue_details(
.map(|row| row.project_id)
.collect::>();
- tech_review_sync::sync_project_tech_review_state(
+ tech_review_queue::add_projects_with_review_details(
&affected_project_ids,
- TechReviewExitReason::Resolved,
&mut txn,
)
.await?;
@@ -1448,9 +1484,25 @@ pub async fn update_global_issue_details(
.await
.wrap_internal_err("failed to update global issue details")?;
- tech_review_sync::sync_detail_key_tech_review_state(
+ let affected_projects = sqlx::query!(
+ r#"
+ SELECT DISTINCT detail.project_id AS "project_id!: DBProjectId"
+ FROM delphi_issue_details_with_statuses detail
+ WHERE detail.key = ANY($1::text[])
+ "#,
&detail_keys,
- TechReviewExitReason::Resolved,
+ )
+ .fetch_all(&mut txn)
+ .await
+ .wrap_internal_err(
+ "failed to fetch projects affected by global detail updates",
+ )?;
+
+ tech_review_queue::add_projects_with_review_details(
+ &affected_projects
+ .into_iter()
+ .map(|row| row.project_id)
+ .collect::>(),
&mut txn,
)
.await?;
diff --git a/apps/labrinth/src/routes/internal/moderation/tech_review/global.rs b/apps/labrinth/src/routes/internal/moderation/tech_review/global.rs
index 6b69125466..269d4eac3e 100644
--- a/apps/labrinth/src/routes/internal/moderation/tech_review/global.rs
+++ b/apps/labrinth/src/routes/internal/moderation/tech_review/global.rs
@@ -188,9 +188,9 @@ pub async fn search_global_issue_details(
FROM delphi_global_detail_verdicts dgdv
LEFT JOIN delphi_issue_details_with_statuses didws
ON didws.key = dgdv.detail_key
+ AND didws.severity != 'hidden'
LEFT JOIN delphi_report_issues dri
ON dri.id = didws.issue_id
- AND dri.issue_type != '__dummy'
WHERE (
$1::text IS NULL
OR dgdv.detail_key ILIKE '%' || $1 || '%'
@@ -248,7 +248,7 @@ pub async fn search_global_issue_details(
AND didv.detail_key = didws.key
WHERE
didws.key = ANY($1::text[])
- AND dri.issue_type != '__dummy'
+ AND didws.severity != 'hidden'
)
SELECT
detail_key AS "detail_key!",
@@ -367,9 +367,9 @@ pub async fn get_global_issue_detail(
FROM delphi_global_detail_verdicts dgdv
LEFT JOIN delphi_issue_details_with_statuses didws
ON didws.key = dgdv.detail_key
+ AND didws.severity != 'hidden'
LEFT JOIN delphi_report_issues dri
ON dri.id = didws.issue_id
- AND dri.issue_type != '__dummy'
WHERE dgdv.detail_key = $1
GROUP BY dgdv.detail_key, dgdv.verdict
"#,
@@ -412,7 +412,7 @@ pub async fn get_global_issue_detail(
WHERE
didws.key = $1
AND ($2::bigint IS NULL OR didws.id > $2)
- AND dri.issue_type != '__dummy'
+ AND didws.severity != 'hidden'
ORDER BY didws.id
LIMIT $3
"#,
diff --git a/apps/labrinth/src/routes/internal/moderation/tech_review/rules.rs b/apps/labrinth/src/routes/internal/moderation/tech_review/rules.rs
new file mode 100644
index 0000000000..a721937b1e
--- /dev/null
+++ b/apps/labrinth/src/routes/internal/moderation/tech_review/rules.rs
@@ -0,0 +1,640 @@
+use actix_web::{HttpRequest, delete, get, post, put, web};
+use chrono::{DateTime, Utc};
+use eyre::eyre;
+use serde::{Deserialize, Serialize};
+use validator::Validate;
+use xredis::RedisPool;
+
+use super::rules_scan::RuleInput;
+use crate::{
+ auth::check_is_moderator_from_headers,
+ database::{
+ PgPool, ReadOnlyPgPool,
+ models::{
+ DBProjectId, DBVersionId, DelphiReportIssueDetailsId,
+ DelphiReportIssueId, DelphiRuleId,
+ delphi_report_item::DelphiSeverity,
+ },
+ },
+ models::{
+ ids::{ProjectId, VersionId},
+ pats::Scopes,
+ },
+ queue::session::AuthQueue,
+ routes::ApiError,
+ util::{error::Context, validate::validation_errors_to_string},
+};
+
+pub fn config(cfg: &mut actix_web::web::ServiceConfig) {
+ cfg.service(get_rules)
+ .service(test_rule)
+ .service(get_rule_affected_details)
+ .service(create_rule)
+ .service(update_rule)
+ .service(delete_rule);
+}
+
+#[derive(Debug, Serialize, utoipa::ToSchema)]
+pub struct DelphiRule {
+ pub id: DelphiRuleId,
+ pub name: String,
+ pub rule: String,
+ pub priority: i32,
+ pub revision: i64,
+ pub created_at: DateTime,
+ pub updated_at: DateTime,
+ pub created_by: Option,
+ pub updated_by: Option,
+ pub affected_details_count: i64,
+ pub affected_details: Vec,
+}
+
+#[derive(Debug, Serialize, utoipa::ToSchema)]
+pub struct DelphiRuleAffectedDetail {
+ pub detail_id: DelphiReportIssueDetailsId,
+ pub issue_id: DelphiReportIssueId,
+ pub project_id: Option,
+ pub project_name: Option,
+ pub project_icon_url: Option,
+ pub version_id: Option,
+ pub version_name: Option,
+ pub version_number: Option,
+ pub issue_type: String,
+ pub key: String,
+ pub jar: Option,
+ pub file_path: String,
+ pub original_severity: DelphiSeverity,
+ pub severity: DelphiSeverity,
+}
+
+#[derive(Debug, Deserialize, Validate, utoipa::ToSchema)]
+pub struct WriteDelphiRule {
+ #[validate(length(min = 1, max = 256))]
+ pub name: String,
+ #[validate(length(min = 1, max = 65536))]
+ pub rule: String,
+ #[serde(default)]
+ pub priority: i32,
+}
+
+#[derive(Deserialize, Validate, utoipa::ToSchema)]
+pub struct TestDelphiRule {
+ #[validate(length(min = 1, max = 65536))]
+ pub rule: String,
+ #[validate(length(max = 10))]
+ pub inputs: Vec,
+}
+
+#[derive(Debug, Serialize, utoipa::ToSchema)]
+pub struct TestDelphiRuleResponse {
+ pub effects: Vec