You've already forked AstralRinth
forked from didirus/AstralRinth
Technical review queue (#4775)
* chore: fix typo in status message * feat(labrinth): overhaul malware scanner report storage and routes * chore: address some review comments * feat: add Delphi to Docker Compose `with-delphi` profile * chore: fix unused import Clippy lint * feat(labrinth/delphi): use PAT token authorization with project read scopes * chore: expose file IDs in version queries * fix: accept null decompiled source payloads from Delphi * tweak(labrinth): expose base62 file IDs more consistently for Delphi * feat(labrinth/delphi): support new Delphi report severity field * chore(labrinth): run `cargo sqlx prepare` to fix Docker build errors * tweak: add route for fetching Delphi issue type schema, abstract Labrinth away from issue types * chore: run `cargo sqlx prepare` * chore: fix typo on frontend generated state file message * feat: update to use new Delphi issue schema * wip: tech review endpoints * wip: add ToSchema for dependent types * wip: report issues return * wip * wip: returning more data * wip * Fix up db query * Delphi configuration to talk to Labrinth * Get Delphi working with Labrinth * Add Delphi dummy fixture * Better Delphi logging * Improve utoipa for tech review routes * Add more sorting options for tech review queue * Oops join * New routes for fetching issues and reports * Fix which kind of ID is returned in tech review endpoints * Deduplicate tech review report rows * Reduce info sent for projects * Fetch more thread info * Address PR comments * fix ci * fix postgres version mismatch * fix version creation * Implement routes * fix up tech review * Allow adding a moderation comment to Delphi rejections * fix up rebase * exclude rejected projects from tech review * add status change msg to tech review thread * cargo sqlx prepare * also ignore withheld projects * More filtering on issue search * wip: report routes * Fix up for build * cargo sqlx prepare * fix thread message privacy * New tech review search route * submit route * details have statuses now * add default to drid status * dedup issue details * fix sqlx query on empty files * fixes * Dedupe issue detail statuses and message on entering tech rev * Fix qa issues * Fix qa issues * fix review comments * typos * fix ci * feat: tech review frontend (#4781) * chore: fix typo in status message * feat(labrinth): overhaul malware scanner report storage and routes * chore: address some review comments * feat: add Delphi to Docker Compose `with-delphi` profile * chore: fix unused import Clippy lint * feat(labrinth/delphi): use PAT token authorization with project read scopes * chore: expose file IDs in version queries * fix: accept null decompiled source payloads from Delphi * tweak(labrinth): expose base62 file IDs more consistently for Delphi * feat(labrinth/delphi): support new Delphi report severity field * chore(labrinth): run `cargo sqlx prepare` to fix Docker build errors * tweak: add route for fetching Delphi issue type schema, abstract Labrinth away from issue types * chore: run `cargo sqlx prepare` * chore: fix typo on frontend generated state file message * feat: update to use new Delphi issue schema * wip: tech review endpoints * wip: add ToSchema for dependent types * wip: report issues return * wip * wip: returning more data * wip * Fix up db query * Delphi configuration to talk to Labrinth * Get Delphi working with Labrinth * Add Delphi dummy fixture * Better Delphi logging * Improve utoipa for tech review routes * Add more sorting options for tech review queue * Oops join * New routes for fetching issues and reports * Fix which kind of ID is returned in tech review endpoints * Deduplicate tech review report rows * Reduce info sent for projects * Fetch more thread info * Address PR comments * fix ci * fix ci * fix postgres version mismatch * fix version creation * Implement routes * feat: batch scan alert * feat: layout * feat: introduce surface variables * fix: theme selector * feat: rough draft of tech review card * feat: tab switcher * feat: batch scan btn * feat: api-client module for tech review * draft: impl * feat: auto icons * fix: layout issues * feat: fixes to code blocks + flag labels * feat: temp remove mock data * fix: search sort types * fix: intl & lint * chore: re-enable mock data * fix: flag badges + auto open first issue in file tab * feat: update for new routes * fix: more qa issues * feat: lazy load sources * fix: re-enable auth middleware * feat: impl threads * fix: lint & severity * feat: download btn + switch to using NavTabs with new local mode option * feat: re-add toplevel btns * feat: reports page consistency * fix: consistency on project queue * fix: icons + sizing * fix: colors and gaps * fix: impl endpoints * feat: load all flags on file tab * feat: thread generics changes * feat: more qa * feat: fix collapse * fix: qa * feat: msg modal * fix: ISO import * feat: qa fixes * fix: empty state basic * fix: collapsible region * fix: collapse thread by default * feat: rough draft of new process/flow * fix labrinth build * fix thread message privacy * New tech review search route * feat: qa fixes * feat: QA changes * fix: verdict on detail not whole issue * fix: lint + intl * fix: lint * fix: thread message for tech rev verdict * feat: use anim frames * fix: exports + typecheck * polish: qa changes * feat: qa * feat: qa polish * feat: fix malic modal * fix: lint * fix: qa + lint * fix: pagination * fix: lint * fix: qa * intl extract * fix ci --------- Signed-off-by: Calum H. <contact@cal.engineer> Co-authored-by: Alejandro González <me@alegon.dev> Co-authored-by: aecsocket <aecsocket@tutanota.com> --------- Signed-off-by: Calum H. <contact@cal.engineer> Co-authored-by: Alejandro González <me@alegon.dev> Co-authored-by: Calum H. <contact@cal.engineer>
This commit is contained in:
@@ -12,6 +12,7 @@ import { LabrinthCollectionsModule } from './labrinth/collections'
|
||||
import { LabrinthProjectsV2Module } from './labrinth/projects/v2'
|
||||
import { LabrinthProjectsV3Module } from './labrinth/projects/v3'
|
||||
import { LabrinthStateModule } from './labrinth/state'
|
||||
import { LabrinthTechReviewInternalModule } from './labrinth/tech-review/internal'
|
||||
|
||||
type ModuleConstructor = new (client: AbstractModrinthClient) => AbstractModule
|
||||
|
||||
@@ -36,6 +37,7 @@ export const MODULE_REGISTRY = {
|
||||
labrinth_projects_v2: LabrinthProjectsV2Module,
|
||||
labrinth_projects_v3: LabrinthProjectsV3Module,
|
||||
labrinth_state: LabrinthStateModule,
|
||||
labrinth_tech_review_internal: LabrinthTechReviewInternalModule,
|
||||
labrinth_versions_v3: LabrinthVersionsV3Module,
|
||||
} as const satisfies Record<string, ModuleConstructor>
|
||||
|
||||
|
||||
@@ -3,4 +3,5 @@ export * from './collections'
|
||||
export * from './projects/v2'
|
||||
export * from './projects/v3'
|
||||
export * from './state'
|
||||
export * from './tech-review/internal'
|
||||
export * from './versions/v3'
|
||||
|
||||
124
packages/api-client/src/modules/labrinth/tech-review/internal.ts
Normal file
124
packages/api-client/src/modules/labrinth/tech-review/internal.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Labrinth } from '../types'
|
||||
|
||||
export class LabrinthTechReviewInternalModule extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'labrinth_tech_review_internal'
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for projects awaiting technical review.
|
||||
*
|
||||
* Returns a flat list of file reports with associated project data, ownership
|
||||
* information, and moderation threads provided as lookup maps.
|
||||
*
|
||||
* @param params - Search parameters including pagination, filters, and sorting
|
||||
* @returns Response object containing reports array and lookup maps for projects, threads, and ownership
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const response = await client.labrinth.tech_review_internal.searchProjects({
|
||||
* limit: 20,
|
||||
* page: 0,
|
||||
* sort_by: 'created_asc',
|
||||
* filter: {
|
||||
* project_type: ['mod', 'modpack']
|
||||
* }
|
||||
* })
|
||||
* // Access reports: response.reports
|
||||
* // Access project by ID: response.projects[projectId]
|
||||
* ```
|
||||
*/
|
||||
public async searchProjects(
|
||||
params: Labrinth.TechReview.Internal.SearchProjectsRequest,
|
||||
): Promise<Labrinth.TechReview.Internal.SearchResponse> {
|
||||
return this.client.request<Labrinth.TechReview.Internal.SearchResponse>(
|
||||
'/moderation/tech-review/search',
|
||||
{
|
||||
api: 'labrinth',
|
||||
version: 'internal',
|
||||
method: 'POST',
|
||||
body: params,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed information about a specific file report.
|
||||
*
|
||||
* @param reportId - The Delphi report ID
|
||||
* @returns Full report with all issues and details
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const report = await client.labrinth.tech_review_internal.getReport('report-123')
|
||||
* console.log(report.file_name, report.issues.length)
|
||||
* ```
|
||||
*/
|
||||
public async getReport(reportId: string): Promise<Labrinth.TechReview.Internal.FileReport> {
|
||||
return this.client.request<Labrinth.TechReview.Internal.FileReport>(
|
||||
`/moderation/tech-review/report/${reportId}`,
|
||||
{
|
||||
api: 'labrinth',
|
||||
version: 'internal',
|
||||
method: 'GET',
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed information about a specific issue.
|
||||
*
|
||||
* @param issueId - The issue ID
|
||||
* @returns Issue with all its details
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const issue = await client.labrinth.tech_review_internal.getIssue('issue-123')
|
||||
* console.log(issue.issue_type, issue.status)
|
||||
* ```
|
||||
*/
|
||||
public async getIssue(issueId: string): Promise<Labrinth.TechReview.Internal.FileIssue> {
|
||||
return this.client.request<Labrinth.TechReview.Internal.FileIssue>(
|
||||
`/moderation/tech-review/issue/${issueId}`,
|
||||
{
|
||||
api: 'labrinth',
|
||||
version: 'internal',
|
||||
method: 'GET',
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the status of a technical review issue detail.
|
||||
*
|
||||
* Allows moderators to mark an individual issue detail as safe (false positive) or unsafe (malicious).
|
||||
*
|
||||
* @param detailId - The ID of the issue detail to update
|
||||
* @param data - The verdict for the detail
|
||||
* @returns Promise that resolves when the update is complete
|
||||
*/
|
||||
public async updateIssueDetail(
|
||||
detailId: string,
|
||||
data: Labrinth.TechReview.Internal.UpdateIssueRequest,
|
||||
): Promise<void> {
|
||||
return this.client.request<void>(`/moderation/tech-review/issue-detail/${detailId}`, {
|
||||
api: 'labrinth',
|
||||
version: 'internal',
|
||||
method: 'PATCH',
|
||||
body: data,
|
||||
})
|
||||
}
|
||||
|
||||
public async submitProject(
|
||||
projectId: string,
|
||||
data: Labrinth.TechReview.Internal.SubmitProjectRequest,
|
||||
): Promise<void> {
|
||||
return this.client.request<void>(`/moderation/tech-review/submit/${projectId}`, {
|
||||
api: 'labrinth',
|
||||
version: 'internal',
|
||||
method: 'POST',
|
||||
body: data,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ export namespace Labrinth {
|
||||
price_id: string
|
||||
interval: PriceDuration
|
||||
status: SubscriptionStatus
|
||||
created: string // ISO datetime string
|
||||
created: string
|
||||
metadata?: SubscriptionMetadata
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ export namespace Labrinth {
|
||||
amount: number
|
||||
currency_code: string
|
||||
status: ChargeStatus
|
||||
due: string // ISO datetime string
|
||||
last_attempt: string | null // ISO datetime string
|
||||
due: string
|
||||
last_attempt: string | null
|
||||
type: ChargeType
|
||||
subscription_id: string | null
|
||||
subscription_interval: PriceDuration | null
|
||||
@@ -337,6 +337,10 @@ export namespace Labrinth {
|
||||
monetization_status: v2.MonetizationStatus
|
||||
side_types_migration_review_status: 'reviewed' | 'pending'
|
||||
environment?: Environment[]
|
||||
|
||||
/**
|
||||
* @deprecated Not recommended to use.
|
||||
**/
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
@@ -719,4 +723,181 @@ export namespace Labrinth {
|
||||
errors: unknown[]
|
||||
}
|
||||
}
|
||||
|
||||
export namespace TechReview {
|
||||
export namespace Internal {
|
||||
export type SearchProjectsRequest = {
|
||||
limit?: number
|
||||
page?: number
|
||||
filter?: SearchProjectsFilter
|
||||
sort_by?: SearchProjectsSort
|
||||
}
|
||||
|
||||
export type SearchProjectsFilter = {
|
||||
project_type?: string[]
|
||||
}
|
||||
|
||||
export type SearchProjectsSort =
|
||||
| 'created_asc'
|
||||
| 'created_desc'
|
||||
| 'severity_asc'
|
||||
| 'severity_desc'
|
||||
|
||||
export type UpdateIssueRequest = {
|
||||
verdict: 'safe' | 'unsafe'
|
||||
}
|
||||
|
||||
export type SubmitProjectRequest = {
|
||||
verdict: 'safe' | 'unsafe'
|
||||
message?: string
|
||||
}
|
||||
|
||||
export type SearchResponse = {
|
||||
project_reports: ProjectReport[]
|
||||
projects: Record<string, ProjectModerationInfo>
|
||||
threads: Record<string, Thread>
|
||||
ownership: Record<string, Ownership>
|
||||
}
|
||||
|
||||
export type ProjectModerationInfo = {
|
||||
id: string
|
||||
thread_id: string
|
||||
name: string
|
||||
project_types: string[]
|
||||
icon_url: string | null
|
||||
} & Projects.v3.Project
|
||||
|
||||
export type ProjectReport = {
|
||||
project_id: string
|
||||
max_severity: DelphiSeverity | null
|
||||
versions: VersionReport[]
|
||||
}
|
||||
|
||||
export type VersionReport = {
|
||||
version_id: string
|
||||
files: FileReport[]
|
||||
}
|
||||
|
||||
export type FileReport = {
|
||||
report_id: string
|
||||
file_id: string
|
||||
created: string
|
||||
flag_reason: FlagReason
|
||||
severity: DelphiSeverity
|
||||
file_name: string
|
||||
file_size: number
|
||||
download_url: string
|
||||
issues: FileIssue[]
|
||||
}
|
||||
|
||||
export type FileIssue = {
|
||||
id: string
|
||||
report_id: string
|
||||
issue_type: string
|
||||
details: ReportIssueDetail[]
|
||||
}
|
||||
|
||||
export type ReportIssueDetail = {
|
||||
id: string
|
||||
issue_id: string
|
||||
key: string
|
||||
file_path: string
|
||||
decompiled_source: string | null
|
||||
data: Record<string, unknown>
|
||||
severity: DelphiSeverity
|
||||
status: DelphiReportIssueStatus
|
||||
}
|
||||
|
||||
export type Ownership =
|
||||
| {
|
||||
kind: 'user'
|
||||
id: string
|
||||
name: string
|
||||
icon_url?: string
|
||||
}
|
||||
| {
|
||||
kind: 'organization'
|
||||
id: string
|
||||
name: string
|
||||
icon_url?: string
|
||||
}
|
||||
|
||||
export type DBThread = {
|
||||
id: string
|
||||
project_id?: string
|
||||
report_id?: string
|
||||
type_: ThreadType
|
||||
messages: DBThreadMessage[]
|
||||
members: string[]
|
||||
}
|
||||
|
||||
export type DBThreadMessage = {
|
||||
id: string
|
||||
thread_id: string
|
||||
author_id?: string
|
||||
body: MessageBody
|
||||
created: string
|
||||
hide_identity: boolean
|
||||
}
|
||||
|
||||
export type MessageBody =
|
||||
| {
|
||||
type: 'text'
|
||||
body: string
|
||||
private?: boolean
|
||||
replying_to?: string
|
||||
associated_images?: string[]
|
||||
}
|
||||
| {
|
||||
type: 'status_change'
|
||||
new_status: Projects.v2.ProjectStatus
|
||||
old_status: Projects.v2.ProjectStatus
|
||||
}
|
||||
| {
|
||||
type: 'thread_closure'
|
||||
}
|
||||
| {
|
||||
type: 'thread_reopen'
|
||||
}
|
||||
| {
|
||||
type: 'deleted'
|
||||
private?: boolean
|
||||
}
|
||||
|
||||
export type ThreadType = 'report' | 'project' | 'direct_message'
|
||||
|
||||
export type User = {
|
||||
id: string
|
||||
username: string
|
||||
avatar_url: string
|
||||
role: string
|
||||
badges: number
|
||||
created: string
|
||||
bio?: string
|
||||
}
|
||||
|
||||
export type ThreadMessage = {
|
||||
id: string | null
|
||||
author_id: string | null
|
||||
body: MessageBody
|
||||
created: string
|
||||
hide_identity: boolean
|
||||
}
|
||||
|
||||
export type Thread = {
|
||||
id: string
|
||||
type: ThreadType
|
||||
project_id: string | null
|
||||
report_id: string | null
|
||||
messages: ThreadMessage[]
|
||||
members: User[]
|
||||
}
|
||||
|
||||
export type FlagReason = 'delphi'
|
||||
|
||||
export type DelphiSeverity = 'low' | 'medium' | 'high' | 'severe'
|
||||
|
||||
export type DelphiReportIssueStatus = 'pending' | 'safe' | 'unsafe'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user