Moderation Checklist V1.5 (#3980)

* starting on new checklist implementation

Change default shouldShow behavior for stages.
add new messages and stages.
Change some existing stage logic.
Add placeholder var for the rules.

Co-Authored-By: @coolbot100s

* misc fixes + corrections

* Add clickable link previews to links stage

* Correct mislabeled title message and add new title messages

* Change message formatting, use rules variable, correct wip desc and title 1.8 messages, add tags buttons

* More applications of rules placeholder

* Add new status alerts stage

* change order of statusAlerts

* Update title related messages, add navigation based vars

* Overhaul Links stage and add new messages.

* Set message weights, add some disables

* message.mds now obey lint >:(

* fixed links text message formatting and changed an icon

* Combine title and slug stages

* Add more info to some stages and properly case stage ids

* tweak summary text formatting

* Improved tags stage info and more navigation placeholders

* redo reupload stage, more navigation placeholders, licensing stage improvements, versions stage improvements, status alerts stage improvements

* Allow modpack permissions stage to appear again by adding a dummy button.

* Update modpack permissions guidance

* fix: blog path issues

* fix: lint issues

* fix license stage text formatting

* Improve license stage

* feat: move links into one md file to be cleaner

* Update packages/moderation/data/stages/links.ts

Signed-off-by: IMB11 <hendersoncal117@gmail.com>

---------

Signed-off-by: IMB11 <hendersoncal117@gmail.com>
Co-authored-by: IMB11 <hendersoncal117@gmail.com>
Co-authored-by: IMB11 <calum@modrinth.com>
This commit is contained in:
coolbot 2025-07-16 10:48:26 -08:00 committed by GitHub
parent eb595cdc3e
commit 62f5a23fcb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
93 changed files with 954 additions and 366 deletions

View File

@ -464,7 +464,7 @@ const stageTextExpanded = computedAsync(async () => {
const stage = checklist[stageIndex]; const stage = checklist[stageIndex];
if (stage.text) { if (stage.text) {
return renderHighlightedString( return renderHighlightedString(
expandVariables(await stage.text(), props.project, variables.value), expandVariables(await stage.text(props.project), props.project, variables.value),
); );
} }
return null; return null;
@ -980,6 +980,18 @@ async function processAction(
} }
function shouldShowStage(stage: Stage): boolean { function shouldShowStage(stage: Stage): boolean {
let hasVisibleActions = false;
for (const a of stage.actions) {
if (shouldShowAction(a)) {
hasVisibleActions = true;
}
}
if (!hasVisibleActions) {
return false;
}
if (typeof stage.shouldShow === "function") { if (typeof stage.shouldShow === "function") {
return stage.shouldShow(props.project); return stage.shouldShow(props.project);
} }

View File

@ -98,13 +98,6 @@
"date": "2023-02-01T20:00:00.000Z", "date": "2023-02-01T20:00:00.000Z",
"link": "https://modrinth.com/news/article/accelerating-development" "link": "https://modrinth.com/news/article/accelerating-development"
}, },
{
"title": "Two years of Modrinth: a retrospective",
"summary": "The history of Modrinth as we know it from December 2020 to December 2022.",
"thumbnail": "https://modrinth.com/news/default.webp",
"date": "2023-01-07T00:00:00.000Z",
"link": "https://modrinth.com/news/article/two-years-of-modrinth-history"
},
{ {
"title": "Modrinth's Anniversary Update", "title": "Modrinth's Anniversary Update",
"summary": "Marking two years of Modrinth and discussing our New Year's Resolutions for 2023.", "summary": "Marking two years of Modrinth and discussing our New Year's Resolutions for 2023.",
@ -112,6 +105,13 @@
"date": "2023-01-07T00:00:00.000Z", "date": "2023-01-07T00:00:00.000Z",
"link": "https://modrinth.com/news/article/two-years-of-modrinth" "link": "https://modrinth.com/news/article/two-years-of-modrinth"
}, },
{
"title": "Two years of Modrinth: a retrospective",
"summary": "The history of Modrinth as we know it from December 2020 to December 2022.",
"thumbnail": "https://modrinth.com/news/default.webp",
"date": "2023-01-07T00:00:00.000Z",
"link": "https://modrinth.com/news/article/two-years-of-modrinth-history"
},
{ {
"title": "Creators can now make money on Modrinth!", "title": "Creators can now make money on Modrinth!",
"summary": "Introducing the Creator Monetization Program allowing creators to earn revenue from their projects.", "summary": "Introducing the Creator Monetization Program allowing creators to earn revenue from their projects.",

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,7 @@
"app:build": "turbo run build --filter=@modrinth/app", "app:build": "turbo run build --filter=@modrinth/app",
"app:fix": "turbo run fix --filter=@modrinth/app", "app:fix": "turbo run fix --filter=@modrinth/app",
"app:intl:extract": "pnpm run --filter=@modrinth/app-frontend intl:extract", "app:intl:extract": "pnpm run --filter=@modrinth/app-frontend intl:extract",
"blog:fix": "turbo run fix --filter=@modrinth/blog",
"pages:build": "NITRO_PRESET=cloudflare-pages pnpm --filter frontend run build", "pages:build": "NITRO_PRESET=cloudflare-pages pnpm --filter frontend run build",
"build": "turbo run build --continue", "build": "turbo run build --continue",
"lint": "turbo run lint --continue", "lint": "turbo run lint --continue",

View File

@ -1,16 +1,16 @@
import { promises as fs } from 'fs' import { promises as fs } from 'fs'
import * as path from 'path' import * as path from 'path'
import fastGlob from 'fast-glob'
import { repoPath, toVarName } from './utils' import { repoPath, toVarName } from './utils'
import { glob } from 'glob'
import { PUBLIC_SRC, PUBLIC_LOCATIONS, ARTICLES_GLOB, COMPILED_DIR } from './blog.config' import { PUBLIC_SRC, PUBLIC_LOCATIONS, ARTICLES_GLOB, COMPILED_DIR } from './blog.config'
async function checkPublicAssets() { async function checkPublicAssets() {
const srcFiles = await fastGlob(['**/*'], { cwd: PUBLIC_SRC, dot: true }) const srcFiles = await glob('**/*', { cwd: PUBLIC_SRC, dot: true })
let allOk = true let allOk = true
for (const target of PUBLIC_LOCATIONS) { for (const target of PUBLIC_LOCATIONS) {
for (const relativeFile of srcFiles) { for (const relativeFile of srcFiles) {
const shouldExist = path.join(target, relativeFile) const shouldExist = path.posix.join(target, relativeFile)
try { try {
await fs.access(shouldExist) await fs.access(shouldExist)
} catch { } catch {
@ -26,15 +26,15 @@ async function checkPublicAssets() {
} }
async function checkCompiledArticles() { async function checkCompiledArticles() {
const mdFiles = await fastGlob([ARTICLES_GLOB]) const mdFiles = await glob(ARTICLES_GLOB)
const compiledFiles = await fastGlob([`${COMPILED_DIR}/*.ts`]) const compiledFiles = await glob(`${COMPILED_DIR}/*.ts`)
const compiledVarNames = compiledFiles.map((f) => path.basename(f, '.ts')) const compiledVarNames = compiledFiles.map((f) => path.basename(f, '.ts'))
// Check all .md have compiled .ts and .content.ts and the proper public thumbnail // Check all .md have compiled .ts and .content.ts and the proper public thumbnail
for (const file of mdFiles) { for (const file of mdFiles) {
const varName = toVarName(path.basename(file, '.md')) const varName = toVarName(path.basename(file, '.md'))
const compiledPath = path.join(COMPILED_DIR, varName + '.ts') const compiledPath = path.posix.join(COMPILED_DIR, varName + '.ts')
const contentPath = path.join(COMPILED_DIR, varName + '.content.ts') const contentPath = path.posix.join(COMPILED_DIR, varName + '.content.ts')
if (!compiledVarNames.includes(varName)) { if (!compiledVarNames.includes(varName)) {
console.error(`⚠️ Missing compiled article for: ${file} (should be: ${compiledPath})`) console.error(`⚠️ Missing compiled article for: ${file} (should be: ${compiledPath})`)
process.exit(1) process.exit(1)
@ -59,7 +59,7 @@ async function checkCompiledArticles() {
if (varName === 'index' || varName.endsWith('.content')) continue if (varName === 'index' || varName.endsWith('.content')) continue
const mdPathGlob = repoPath(`packages/blog/articles/**/${varName.replace(/_/g, '*')}.md`) const mdPathGlob = repoPath(`packages/blog/articles/**/${varName.replace(/_/g, '*')}.md`)
const found = await fastGlob([mdPathGlob]) const found = await glob(mdPathGlob)
if (!found.length) { if (!found.length) {
console.error(`❌ Compiled article ${compiled} has no matching markdown source!`) console.error(`❌ Compiled article ${compiled} has no matching markdown source!`)
process.exit(1) process.exit(1)

View File

@ -1,12 +1,12 @@
import { promises as fs } from 'fs' import { promises as fs } from 'fs'
import * as path from 'path' import * as path from 'path'
import fg from 'fast-glob'
import matter from 'gray-matter' import matter from 'gray-matter'
import { md } from '@modrinth/utils' import { md } from '@modrinth/utils'
import { minify } from 'html-minifier-terser' import { minify } from 'html-minifier-terser'
import { copyDir, toVarName } from './utils' import { copyDir, toVarName } from './utils'
import RSS from 'rss' import RSS from 'rss'
import { parseStringPromise } from 'xml2js' import { parseStringPromise } from 'xml2js'
import { glob } from 'glob'
import { import {
ARTICLES_GLOB, ARTICLES_GLOB,
@ -24,7 +24,7 @@ async function ensureCompiledDir() {
} }
async function hasThumbnail(slug: string): Promise<boolean> { async function hasThumbnail(slug: string): Promise<boolean> {
const thumbnailPath = path.join(PUBLIC_SRC, slug, 'thumbnail.webp') const thumbnailPath = path.posix.join(PUBLIC_SRC, slug, 'thumbnail.webp')
try { try {
await fs.access(thumbnailPath) await fs.access(thumbnailPath)
return true return true
@ -48,7 +48,7 @@ function getThumbnailUrl(slug: string, hasThumb: boolean): string {
async function compileArticles() { async function compileArticles() {
await ensureCompiledDir() await ensureCompiledDir()
const files = await fg([ARTICLES_GLOB]) const files = await glob(ARTICLES_GLOB)
console.log(`🔎 Found ${files.length} markdown articles!`) console.log(`🔎 Found ${files.length} markdown articles!`)
const articleExports: string[] = [] const articleExports: string[] = []
const articlesArray: string[] = [] const articlesArray: string[] = []
@ -75,8 +75,8 @@ async function compileArticles() {
const slug = frontSlug || path.basename(file, '.md') const slug = frontSlug || path.basename(file, '.md')
const varName = toVarName(slug) const varName = toVarName(slug)
const exportFile = path.join(COMPILED_DIR, `${varName}.ts`) const exportFile = path.posix.join(COMPILED_DIR, `${varName}.ts`)
const contentFile = path.join(COMPILED_DIR, `${varName}.content.ts`) const contentFile = path.posix.join(COMPILED_DIR, `${varName}.content.ts`)
const thumbnailPresent = await hasThumbnail(slug) const thumbnailPresent = await hasThumbnail(slug)
const contentTs = ` const contentTs = `
@ -221,7 +221,7 @@ async function deleteDirContents(dir: string) {
const entries = await fs.readdir(dir, { withFileTypes: true }) const entries = await fs.readdir(dir, { withFileTypes: true })
await Promise.all( await Promise.all(
entries.map(async (entry) => { entries.map(async (entry) => {
const fullPath = path.join(dir, entry.name) const fullPath = path.posix.join(dir, entry.name)
if (entry.isDirectory()) { if (entry.isDirectory()) {
await fs.rm(fullPath, { recursive: true, force: true }) await fs.rm(fullPath, { recursive: true, force: true })
} else { } else {

View File

@ -1,56 +1,56 @@
// AUTO-GENERATED FILE - DO NOT EDIT // AUTO-GENERATED FILE - DO NOT EDIT
import { article as a_new_chapter_for_modrinth_servers } from './a_new_chapter_for_modrinth_servers'
import { article as accelerating_development } from './accelerating_development'
import { article as becoming_sustainable } from './becoming_sustainable'
import { article as capital_return } from './capital_return'
import { article as carbon_ads } from './carbon_ads'
import { article as creator_monetization } from './creator_monetization'
import { article as creator_update } from './creator_update'
import { article as creator_updates_july_2025 } from './creator_updates_july_2025'
import { article as design_refresh } from './design_refresh'
import { article as download_adjustment } from './download_adjustment'
import { article as knossos_v2_1_0 } from './knossos_v2_1_0'
import { article as licensing_guide } from './licensing_guide'
import { article as modpack_changes } from './modpack_changes'
import { article as modpacks_alpha } from './modpacks_alpha'
import { article as modrinth_app_beta } from './modrinth_app_beta'
import { article as modrinth_beta } from './modrinth_beta'
import { article as modrinth_servers_beta } from './modrinth_servers_beta'
import { article as new_site_beta } from './new_site_beta'
import { article as plugins_resource_packs } from './plugins_resource_packs'
import { article as pride_campaign_2025 } from './pride_campaign_2025'
import { article as redesign } from './redesign'
import { article as skins_now_in_modrinth_app } from './skins_now_in_modrinth_app'
import { article as two_years_of_modrinth_history } from './two_years_of_modrinth_history'
import { article as two_years_of_modrinth } from './two_years_of_modrinth'
import { article as whats_modrinth } from './whats_modrinth'
import { article as windows_borderless_malware_disclosure } from './windows_borderless_malware_disclosure' import { article as windows_borderless_malware_disclosure } from './windows_borderless_malware_disclosure'
import { article as whats_modrinth } from './whats_modrinth'
import { article as two_years_of_modrinth } from './two_years_of_modrinth'
import { article as two_years_of_modrinth_history } from './two_years_of_modrinth_history'
import { article as skins_now_in_modrinth_app } from './skins_now_in_modrinth_app'
import { article as redesign } from './redesign'
import { article as pride_campaign_2025 } from './pride_campaign_2025'
import { article as plugins_resource_packs } from './plugins_resource_packs'
import { article as new_site_beta } from './new_site_beta'
import { article as modrinth_servers_beta } from './modrinth_servers_beta'
import { article as modrinth_beta } from './modrinth_beta'
import { article as modrinth_app_beta } from './modrinth_app_beta'
import { article as modpacks_alpha } from './modpacks_alpha'
import { article as modpack_changes } from './modpack_changes'
import { article as licensing_guide } from './licensing_guide'
import { article as knossos_v2_1_0 } from './knossos_v2_1_0'
import { article as download_adjustment } from './download_adjustment'
import { article as design_refresh } from './design_refresh'
import { article as creator_updates_july_2025 } from './creator_updates_july_2025'
import { article as creator_update } from './creator_update'
import { article as creator_monetization } from './creator_monetization'
import { article as carbon_ads } from './carbon_ads'
import { article as capital_return } from './capital_return'
import { article as becoming_sustainable } from './becoming_sustainable'
import { article as accelerating_development } from './accelerating_development'
import { article as a_new_chapter_for_modrinth_servers } from './a_new_chapter_for_modrinth_servers'
export const articles = [ export const articles = [
a_new_chapter_for_modrinth_servers,
accelerating_development,
becoming_sustainable,
capital_return,
carbon_ads,
creator_monetization,
creator_update,
creator_updates_july_2025,
design_refresh,
download_adjustment,
knossos_v2_1_0,
licensing_guide,
modpack_changes,
modpacks_alpha,
modrinth_app_beta,
modrinth_beta,
modrinth_servers_beta,
new_site_beta,
plugins_resource_packs,
pride_campaign_2025,
redesign,
skins_now_in_modrinth_app,
two_years_of_modrinth_history,
two_years_of_modrinth,
whats_modrinth,
windows_borderless_malware_disclosure, windows_borderless_malware_disclosure,
whats_modrinth,
two_years_of_modrinth,
two_years_of_modrinth_history,
skins_now_in_modrinth_app,
redesign,
pride_campaign_2025,
plugins_resource_packs,
new_site_beta,
modrinth_servers_beta,
modrinth_beta,
modrinth_app_beta,
modpacks_alpha,
modpack_changes,
licensing_guide,
knossos_v2_1_0,
download_adjustment,
design_refresh,
creator_updates_july_2025,
creator_update,
creator_monetization,
carbon_ads,
capital_return,
becoming_sustainable,
accelerating_development,
a_new_chapter_for_modrinth_servers,
] ]

View File

@ -9,6 +9,7 @@
"fix": "jiti ./compile.ts && eslint . --fix && prettier --write ." "fix": "jiti ./compile.ts && eslint . --fix && prettier --write ."
}, },
"devDependencies": { "devDependencies": {
"@types/glob": "^9.0.0",
"@types/html-minifier-terser": "^7.0.2", "@types/html-minifier-terser": "^7.0.2",
"@types/rss": "^0.0.32", "@types/rss": "^0.0.32",
"@types/xml2js": "^0.4.14", "@types/xml2js": "^0.4.14",
@ -19,7 +20,7 @@
}, },
"dependencies": { "dependencies": {
"@modrinth/utils": "workspace:*", "@modrinth/utils": "workspace:*",
"fast-glob": "^3.3.3", "glob": "^10.2.7",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"html-minifier-terser": "^7.2.0", "html-minifier-terser": "^7.2.0",
"rss": "^1.2.2", "rss": "^1.2.2",

View File

@ -8,7 +8,7 @@ export function getRepoRoot(): string {
} }
export function repoPath(...segments: string[]): string { export function repoPath(...segments: string[]): string {
return path.join(getRepoRoot(), ...segments) return path.posix.join(getRepoRoot(), ...segments)
} }
export async function copyDir( export async function copyDir(
@ -20,8 +20,8 @@ export async function copyDir(
await fs.mkdir(dest, { recursive: true }) await fs.mkdir(dest, { recursive: true })
const entries = await fs.readdir(src, { withFileTypes: true }) const entries = await fs.readdir(src, { withFileTypes: true })
for (const entry of entries) { for (const entry of entries) {
const srcPath = path.join(src, entry.name) const srcPath = path.posix.join(src, entry.name)
const destPath = path.join(dest, entry.name) const destPath = path.posix.join(dest, entry.name)
if (entry.isDirectory()) { if (entry.isDirectory()) {
await copyDir(srcPath, destPath, logFn) await copyDir(srcPath, destPath, logFn)
} else if (entry.isFile()) { } else if (entry.isFile()) {

View File

@ -1,28 +1,32 @@
import type { Stage } from '../types/stage' import type { Stage } from '../types/stage'
import modpackPermissionsStage from './modpack-permissions-stage' import modpackPermissionsStage from './modpack-permissions-stage'
import categories from './stages/categories' import categories from './stages/categories'
import copyright from './stages/copyright' import reupload from './stages/reupload'
import description from './stages/description' import description from './stages/description'
import gallery from './stages/gallery' import gallery from './stages/gallery'
import links from './stages/links' import links from './stages/links'
import ruleFollowing from './stages/rule-following' import ruleFollowing from './stages/rule-following'
import sideTypes from './stages/side-types' import sideTypes from './stages/side-types'
import slug from './stages/slug'
import summary from './stages/summary' import summary from './stages/summary'
import title from './stages/title' import titleSlug from './stages/title-slug'
import versions from './stages/versions' import versions from './stages/versions'
import license from './stages/license'
import undefinedProject from './stages/undefined-project'
import statusAlerts from './stages/status-alerts'
export default [ export default [
title, titleSlug,
slug,
summary, summary,
description, description,
links, links,
license,
categories, categories,
sideTypes, sideTypes,
gallery, gallery,
versions, versions,
copyright, reupload,
ruleFollowing, ruleFollowing,
modpackPermissionsStage, modpackPermissionsStage,
statusAlerts,
undefinedProject,
] as ReadonlyArray<Stage> ] as ReadonlyArray<Stage>

View File

@ -1,3 +1,3 @@
## Misuse of Tags ## Misuse of Tags
Per section 5.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous), it is important that the metadata of your projects is accurate. Including that selected tags honestly represent your project. Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate. Including that selected tags honestly represent your project.

View File

@ -0,0 +1 @@
It looks like the Optimization tag is not accurate for this project.

View File

@ -0,0 +1,5 @@
Currently, your pack has multiple Resolutions selected, in most cases, this will misrepresent your project.
For a brief rundown of how this works:
Vanilla Minecraft textures like blocks and items have a width and height of 16 pixels.
This means that packs with textures the same size as the default are considered 16x.
Some packs make the resolution of textures smaller than the default, such as 8x, and some bigger, such as 32x.

View File

@ -0,0 +1,2 @@
**Featured Tags:** %PROJECT_CATEGORIES% \
**Additional Tags:** %PROJECT_ADDITIONAL_CATEGORIES%

View File

@ -0,0 +1 @@
**License id:** %PROJECT_LICENSE_ID% \

View File

@ -0,0 +1 @@
**License Link:** %PROJECT_LICENSE_URL%

View File

@ -0,0 +1,4 @@
**Discord:** %PROJECT_DISCORD_URL% \
**Issues:** %PROJECT_ISSUES_URL% \
**Source:** %PROJECT_SOURCE_URL% \
**Wiki:** %PROJECT_WIKI_URL%

View File

@ -0,0 +1 @@
> **{PLATFORM}:** {URL}

View File

@ -0,0 +1 @@
<u>**Donation Links:**</u>

View File

@ -0,0 +1 @@
**Applying for:** `%PROJECT_REQUESTED_STATUS%`

View File

@ -0,0 +1,2 @@
**Summary:**
`%PROJECT_SUMMARY%`

View File

@ -0,0 +1,4 @@
**Title:** %PROJECT_TITLE% \
**Slug:** `%PROJECT_SLUG%`
**Title issues?**

View File

@ -1,7 +1,6 @@
## Insufficient Description ## Insufficient Description
Per section 2.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#general-expectations) your project's Description should clearly inform the reader of the content, purpose, and appeal of your project. Per section 2.1 of %RULES% your project's Description should clearly inform the reader of the content, purpose, and appeal of your project.
Currently, it looks like there are some missing details. Currently, it looks like there are some missing details.
%EXPLAINER%
> %EXPLAINER%

View File

@ -1,5 +1,5 @@
## No English Description ## No English Description
Per section 2.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#accessibility) a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations. Per section 2.2 of %RULES% a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations.
You may include your non-English Description if you would like but we ask that you also add an English translation of the Description to your Description page, if you would like to use an online translator to do this, we recommend [DeepL](https://www.deepl.com/translator). You may include your non-English Description if you would like but we ask that you also add an English translation of the Description to your Description page, if you would like to use an online translator to do this, we recommend [DeepL](https://www.deepl.com/translator).

View File

@ -1,6 +1,6 @@
## Description Accessibility ## Description Accessibility
Per section 2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#clear-and-honest-function) your description must be plainly readable and accessible. Per section 2 of %RULES% your description must be plainly readable and accessible.
Using non-standard text characters like Zalgo or "fancy text" in place of text anywhere in your project, including the Description, Summary, or Title can make your project pages inaccessible. Using non-standard text characters like Zalgo or "fancy text" in place of text anywhere in your project, including the Description, Summary, or Title can make your project pages inaccessible.

View File

@ -1,7 +1,4 @@
## Unfinished Description ## Unfinished Description
It looks like your project Description is still a WIP (Work In Progress). It looks like your project Description is still a Work In Progress.
Please remember to submit only when ready, as it is important your project meets the requirements of Section 2.1 of %RULES%.
> %REASON%
Please remember to submit only when ready, as it is important your project meets the requirements of Section 2.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#general-expectations), if you have any questions on this feel free to reach out!

View File

@ -1,6 +1,6 @@
## Insufficient Gallery Images ## Insufficient Gallery Images
We ask that projects like yours show off their content using images in the Gallery, or optionally in the Description, in order to effectively and clearly inform users of its content per section 2.1 of [Modrinth's content rules](https://modrinth.com/legal/rules#general-expectations). We ask that projects like yours show off their content using images in the Gallery, or optionally in the Description, in order to effectively and clearly inform users of its content per section 2.1 of %RULES%.
Keep in mind that you should: Keep in mind that you should:
- Set a featured image that best represents your project. - Set a featured image that best represents your project.

View File

@ -1,3 +1,3 @@
## Unrelated Gallery Images ## Unrelated Gallery Images
Per section 5.5 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) any images in your project's Gallery must be relevant to the project and also include a Title. Per section 5.5 of %RULES% any images in your project's Gallery must be relevant to the project and also include a Title.

View File

@ -0,0 +1 @@
If this is a project-specific License you've written yourself, you must host the full License in a way that makes it publicly available, for instance, in a public source repository on a platform like GitHub.

View File

@ -0,0 +1,4 @@
## Invalid License Link
It's important that your project's License link is accurate and leads directly to a valid license for this content.
Your current link: `%PROJECT_LICENSE_URL%` does not appear to lead to a valid license for this project, or it is not publicly accessable.

View File

@ -0,0 +1,5 @@
## No Source Code Provided
Your project's license of `%PROJECT_LICENSE_NAME%`, requires source disclosure.
Consider adding a Source link to your project's repository, or including a Sources file for each version as an Additional File.
Keep in mind this may be a requirement of the source work's licensing, which must be abided per section 4 of %RULES%.

View File

@ -0,0 +1,4 @@
## No Source Code Provided
Your project's license of `%PROJECT_LICENSE_NAME%`, requires source disclosure.
Consider adding a Source link to your project's repository, or including a Sources file for each version as an Additional File. You may also want to refer to %LICENSING_GUIDE% if you wish to select a different License, remember to make sure your selected License is consistent with the license in your project's files as well.

View File

@ -1,3 +1,4 @@
## Misuse of External Resources ## Misuse of Links
Per section 5.4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) all links must lead to correctly labeled publicly available resources that are directly related to your project. Per section 5.4 of %RULES% all %PROJECT_LINKS_FLINK% must lead to correctly labeled publicly available resources that are directly related to your project.
Currently it looks like your %MISUSED_LINKS% link(s) are misused or incorrectly labeled.

View File

@ -1,5 +0,0 @@
## Unreachable Links
Per section 5.4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) all links must lead to correctly labeled publicly available resources that are directly related to your project.
Currently, your %LINK% link is inaccessible!

View File

@ -1,5 +0,0 @@
## Unreachable Links
Per section 5.4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) all links must lead to correctly labeled publicly available resources that are directly related to your project.
Currently, your Source link directs to a Page Not Found error, likely because your repository is private, make sure to make your repository public before resubmitting your project!

View File

@ -0,0 +1 @@
Currently, your Discord link directs to an invalid invite, likely because your invite has expired. Make sure to set your invite link to permanent with unlimited uses before resubmitting your project.

View File

@ -0,0 +1 @@
Currently, your Source link directs to a Page Not Found error, likely because your repository is private. Make sure to set your repository to public before resubmitting your project.

View File

@ -0,0 +1,3 @@
## Unreachable Links
Per section 5.4 of %RULES% all %PROJECT_LINKS_FLINK% must lead to correctly labeled publicly available resources that are directly related to your project.

View File

@ -0,0 +1,4 @@
## Forks and Reuploads
Per section 4 of %RULES%, please provide proof that this project is both license-abiding and significantly divergent from the source work.
Alternatively, please provide proof of your explicit permission from the author of the source work to distribute this content on Modrinth.

View File

@ -0,0 +1,4 @@
## Insufficient Fork
This project does not appear to significantly diverge from the source work, or does not abide by the license of the source work as required by section 4 of %RULES%.
Please provide proof of your explicit permission to distribute this project from the creator(s) of the source work.

View File

@ -0,0 +1,5 @@
## Proof of permissions
This project appears to contain content from other creators.
Per section 4 of %RULES%, we ask that you provide proof of your permission to distribute this content, or derivatives of this content in your project on Modrinth.
Either implicit permission abiding by the terms of the content's license(s) or explicit permission from the original creator of the content.

View File

@ -1,7 +1,5 @@
## Reuploads are forbidden ## Reuploads are forbidden
This project appears to contain content from %ORIGINAL_PROJECT% by %ORIGINAL_AUTHOR%. This project appears to contain content from %ORIGINAL_PROJECT% by %ORIGINAL_AUTHOR%.
Per section 4 of %RULES% this is strictly forbidden.
Per section 4 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) this is strictly forbidden. If you believe this is an error, or you can verify you are the creator and rightful owner of this content please let us know. Otherwise, we ask that you **do not resubmit this project**.
If you believe this is an error, or you can verify you are the creator and rightful owner of this content please let us know. Otherwise, we ask that you **do not resubmit this project**.`,

View File

@ -1,5 +1 @@
# Does not follow content rules
Our moderators have determined that your project does not follow Modrinth's Content Rules, and has been rejected.
%MESSAGE% %MESSAGE%

View File

@ -1,6 +1,6 @@
## Environment Information ## Environment Information
Per section 5.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous), it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side. Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side.
For a brief rundown of how this works: For a brief rundown of how this works:

View File

@ -1,6 +1,6 @@
## Incorrect Environment Information ## Incorrect Environment Information
Per section 5.1 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous), it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side. Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate, including whether the project runs on the client or server side.
For a brief rundown of how this works: For a brief rundown of how this works:

View File

@ -1,3 +1,3 @@
## Misuse of Slug ## Misuse of Slug
Per section 5.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your project slug (URL) must accurately represent your project. Per section 5.2 of %RULES% must accurately represent your project.

View File

@ -0,0 +1,6 @@
---
## Account Issues Indicated
We're sorry to hear you're having trouble accessing your accounts, unfortunately, our moderation team is unable to assist with account-related issues.
Before resubmitting your project, %SUPPORT%.

View File

@ -0,0 +1,5 @@
---
Unfortunately, our AutoMod cannot read your project's Description or your messages to moderation.
AutoMod will warn both you and our Moderation Staff about potential issues, but if you've already followed the necessary steps these warnings can safely be ignored.
Note that if your project is being rejected by AutoMod this means your project has content that can not be included in your modpack and must be removed before resubmission, including deleting versions of your modpack that include the content.

View File

@ -0,0 +1,5 @@
---
## Corrections Applied
I've gone ahead and corrected the issues listed above so your project can be Approved.

View File

@ -0,0 +1,8 @@
---
## Private Use
Under normal circumstances, your project would be rejected due to the issues listed above.
However, since your project is not intended for for public use, these requirements will be waived and your project will be unlisted. This means it will remain accessible through a direct link without appearing in public search results, allowing you to share it privately.
If you're okay with this, or submitted your project to be unlisted already, than no further action is necessary.
If you would like to publish your project publicly, please address all moderation concerns before resubmitting this project.

View File

@ -1,6 +1,6 @@
## Insufficient Summary ## Insufficient Summary
Per section 5.3 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your Summary can not include any extra formatting such as lists, or links. Per section 5.3 of %RULES% your Summary can not include any extra formatting such as lists, or links.
Your project summary should provide a brief overview of your project that informs and entices users. Your project summary should provide a brief overview of your project that informs and entices users.

View File

@ -1,5 +1,5 @@
## Insufficient Summary ## Insufficient Summary
Per section 5.3 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your project summary should provide a brief overview of your project that informs and entices users. Per section 5.3 of %RULES% your project summary should provide a brief overview of your project that informs and entices users.
This is the first thing most people will see about your mod other than the Logo, so it's important it be accurate, reasonably detailed, and exciting. This is the first thing most people will see about your mod other than the Logo, so it's important it be accurate, reasonably detailed, and exciting.

View File

@ -1,5 +1,5 @@
## No English Summary ## No English Summary
Per section 2.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#accessibility) a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations. Per section 2.2 of %RULES% a project's Summary and Description must be in English, unless meant exclusively for non-English use, such as translations.
You may include your non-English Summary but we ask that you also add an English translation. You may include your non-English Summary but we ask that you also add an English translation.

View File

@ -1,6 +1,6 @@
## Insufficient Summary ## Insufficient Summary
Per section 5.3 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) your Summary can not be the same as your project's Title. Per section 5.3 of %RULES% your Summary can not be the same as your project's Title.
Your project summary should provide a brief overview of your project that informs and entices users. Your project summary should provide a brief overview of your project that informs and entices users.

View File

@ -1,7 +1,6 @@
## Project Title ## Minecraft Project Names
Projects must not use Minecraft's branding or include "Minecraft" as a significant part of the title. Projects must not use Minecraft's branding or include "Minecraft" as a significant part of the title.
Your project's current Name of `%PROJECT_TITLE%` may be confusingly similar to, or imply association with, the game Minecraft. We encourage you to change your project's [Name](%PROJECT_SETTINGS_LINK%) to avoid a potential violation of Minecraft's Usage Guidelines.
The title of your project may be confusingly similar to the game, and we encourage you to change your title to avoid a potential violation of Minecraft's Usage Guidelines. Abbreviations like "MC" or elaborate titles that do not make the name Minecraft a significant portion of the name are okay.
When editing your project's Name, remember to update its [URL](%PROJECT_SETTINGS_LINK%) to match.
Abbreviations like "MC" or elaborate titles that do not make the name Minecraft a significant portion of the name are okay.

View File

@ -0,0 +1,2 @@
You may reference the source work in the Description of your fork, however, you must do so in a way that is unlikely to cause confusion or imply association with or endorsement from the author of the source work.
Additionally, per section 4 of %RULES%, we ask that you ensure your project's Name and Branding abide by the license of the source work.

View File

@ -0,0 +1 @@
You may reference the projects that make up the focus point of your modpack, however, you must do so in a way that is unlikely to cause confusion or imply association with or endorsement from the author of that content.

View File

@ -1,3 +1,5 @@
## Project Branding ## Project Branding
Per section 1.8 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) we ask that you change your project title and other relevant branding to avoid causing confusion or implying association with existing projects. Per section 1.8 of %RULES%, your project or its branding must not imply association or be easily confused with any other person or organization.
We ask that you change your project's [Name](%PROJECT_SETTINGS_LINK%) and other relevant branding to avoid causing confusion or implying association with existing projects or individuals.
When editing your project's Name, remember to update its [URL](%PROJECT_SETTINGS_LINK%) to match.

View File

@ -1,7 +1,6 @@
## Misuse of Title ## Misuse of Project Name
Per section 5.2 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) we ask that you limit the title to just the name of your project. Per section 5.2 of %RULES%, your project's [Name](%PROJECT_SETTINGS_LINK%) should not include unnecessary information such as loaders, themes, tags, or versions.
Your project's current Name of `%PROJECT_TITLE%` appears to contain extra information.
Additional information, such as themes, tags, supported versions or loaders, etc. should be saved for the Summary or Description. We ask that you remove all additional information from the [Name](%PROJECT_SETTINGS_LINK%). Instead, consider including this in your project's Summary or Description, or as a part of its relevant metadata.
When editing your project's Name, remember to update its [URL](%PROJECT_SETTINGS_LINK%) to match.
When changing your project title, remember to also ensure that your project slug (URL) matches and accurately represents your project.

View File

@ -0,0 +1,4 @@
## No Versions
It looks like all versions of your project have been deleted, meaning that our Moderation Team cannot finish reviewing your project.
Please resubmit your project once you've uploaded a new version.

View File

@ -0,0 +1,5 @@
## Unsupported Project
Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules), Modrinth does not support uploading multiple variations of your project as Additional files.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
We ask that you upload each alternate version of your project as a new project, ensuring that all users will be able to access and easily find your content.

View File

@ -0,0 +1,5 @@
## Unsupported Project
Modrinth does not support uploading projects that have unnecessary or extraneous installation steps.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
We ask that you upload each alternate version of your project as a new project, ensuring that all users will be able to access and easily find your content.

View File

@ -0,0 +1,6 @@
## Unsupported Project
Modrinth does not support uploading multiple variations of your project as separate versions.
New Versions of your project should strictly be a linear upgrade of the same content.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
We ask that you upload each alternate version of your project as a new project, ensuring that all users will be able to access and easily find your content.

View File

@ -0,0 +1,4 @@
## Incorrect Additional Files
Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) the additional files section should only be used for specific designated purposes such as a `Sources.jar`.
To ensure a smooth experience for you and your users, please upload each alternate version of your modpack as its own Modpack project, thank you.

View File

@ -0,0 +1,6 @@
## Unsupported Project
Modrinth does not support uploading multiple variations of your project as separate versions.
New Versions of your project should strictly be a linear upgrade of the same content.
Having alternate versions of your content on the same project will hurt the functionality of the Modrinth App and other supported launchers as it would prevent users from updating your content, and may make it harder for your users to find the content they want.
To ensure a smooth experience for you and your users, please upload each alternate version of your modpack as its own Modpack project, thank you.

View File

@ -0,0 +1,5 @@
## Incorrect Additional Files
Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules) the additional files section should only be used for specific designated purposes such as a `Sources.jar`.
Modrinth does not support the upload of modpacks in the `.zip` format, as this may cause issues for Modrinth users or distribute copyrighted content without the proper permissions.
If you would like to upload a server-specific version of your modpack, consider creating a separate Modpack project.

View File

@ -0,0 +1,5 @@
## Broken Version
It looks like you've uploaded multiple files with the same name to the same version. This triggers a bug that produces duplicate primary file entries.
This may cause issues for users and creators as it would prevent Modpacks that include this content from functioning in the Modrinth App and other launchers.
We ask that you delete and reupload all applicable versions. Be sure to only upload one file to each version before resubmission.

View File

@ -1,7 +0,0 @@
## Incorrect Use of Additional Files
It looks like you've uploaded multiple `mod.jar` files to one Version as Additional Files. Per section 5.7 of [Modrinth's Content Rules](https://modrinth.com/legal/rules#miscellaneous) each Version of your project must include only one `mod.jar` that corresponds to its respective Minecraft and loader versions.
This allows users to easily find and download the file they need for the version they're on with ease. The Additional Files feature can be used for things like a `Sources.jar`.
Please upload each version of your mod separately, thank you.

View File

@ -0,0 +1,5 @@
## Incorrect Use of Additional Files
It looks like you've uploaded multiple primary files to one Version as Additional Files. Per section 5.7 of %RULES% each Version of your project must include only one primary file that corresponds to its respective Minecraft and loader versions.
This allows users to easily find and download the content they need for their game profile with ease. The Additional Files feature can be used for things like a `Sources.jar`.
Please upload each version of your project separately, thank you.

View File

@ -0,0 +1,3 @@
## Data Packs on Modrinth
It looks like you've selected loaders for your Data Pack that are causing it to be marked as a different project type. Data Packs must only be uploaded with the "Data Pack" loader selected. Please re-upload all versions of your data pack and make sure to only select "Data Pack" as the loader.

View File

@ -1,3 +1,5 @@
## Modpacks on Modrinth ## Modpacks on Modrinth
It looks like you've uploaded your Modpack as a `.zip`, unfortunately, this is invalid and is why your project type is "Mod". I recommend taking a look at our support page about [Modrinth Modpacks](https://support.modrinth.com/en/articles/8802250-modpacks-on-modrinth), and once you're ready feel free to resubmit your project as a `.mrpack`. Don't forget to delete the old files from your Versions! It looks like you've uploaded your Modpack as a `.zip`, unfortunately, this is invalid and is why your project type is "Mod". Please refer to our support article to learn more about %MODPACKS_ON_MODRINTH%.
Once you're ready feel free to resubmit your project as a `.mrpack`.
Don't forget to delete the old files from your %PROJECT_VERSIONS_FLINK%!

View File

@ -0,0 +1,5 @@
## Excessive File Size
This project appears to include libs or dependencies, unnecessarily redistributing their entire contents.
This is often due to an error in project structure or compilation, and in some cases, may violate the copyrights or licensing agreements of these libraries.
We ask that you remove all unnecessary files, assets, and code from your project before resubmission.

View File

@ -0,0 +1,4 @@
## Vanilla Assets
Your resource pack currently includes an excessive amount of unmodified assets from vanilla Minecraft.
Please remove these from your pack and ensure your project only contains original assets created by you, thank you.

View File

@ -1,15 +1,22 @@
import type { ModerationModpackPermissionApprovalType, Project } from '@modrinth/utils' import type { ModerationModpackPermissionApprovalType, Project } from '@modrinth/utils'
import type { Stage } from '../types/stage' import type { Stage } from '../types/stage'
import { BoxIcon } from '@modrinth/assets' import { PackageOpenIcon } from '@modrinth/assets'
export default { export default {
id: 'modpack-permissions', id: 'modpack-permissions',
title: 'Modpack Permissions', title: 'Modpack Permissions',
icon: BoxIcon, icon: PackageOpenIcon,
// Replace me please. // Replace me please.
guidance_url: 'https://docs.modrinth.com/moderation/modpack-permissions', guidance_url:
'https://www.notion.so/Content-Moderation-Cheat-Sheets-22d5ee711bf081a4920ef08879fe6bf5?source=copy_link#22d5ee711bf08116bd8bc1186f357062',
shouldShow: (project: Project) => project.project_type === 'modpack', shouldShow: (project: Project) => project.project_type === 'modpack',
actions: [], actions: [
{
id: 'button',
type: 'button',
label: 'This dummy button must be present or the stage will not appear.',
},
],
} as Stage } as Stage
export const finalPermissionMessages: Record< export const finalPermissionMessages: Record<
@ -18,7 +25,7 @@ export const finalPermissionMessages: Record<
> = { > = {
yes: undefined, yes: undefined,
'with-attribution-and-source': undefined, 'with-attribution-and-source': undefined,
'with-attribution': `The following content has attribution requirements, meaning that you must link back to the page where you originally found this content in your modpack description or version changelog (e.g. linking a mod's CurseForge page if you got it from CurseForge):`, 'with-attribution': `The following content has attribution requirements, meaning that you must link back to the page where you originally found this content in your Modpack's description or version changelog (e.g. linking a mod's CurseForge page if you got it from CurseForge):`,
no: 'The following content is not allowed in Modrinth modpacks due to licensing restrictions. Please contact the author(s) directly for permission or remove the content from your modpack:', no: 'The following content is not allowed in Modrinth modpacks due to licensing restrictions. Please contact the author(s) directly for permission or remove the content from your modpack:',
'permanent-no': `The following content is not allowed in Modrinth modpacks, regardless of permission obtained. This may be because it breaks Modrinth's content rules or because the authors, upon being contacted for permission, have declined. Please remove the content from your modpack:`, 'permanent-no': `The following content is not allowed in Modrinth modpacks, regardless of permission obtained. This may be because it breaks Modrinth's content rules or because the authors, upon being contacted for permission, have declined. Please remove the content from your modpack:`,
unidentified: `The following content could not be identified. Please provide proof of its origin along with proof that you have permission to include it:`, unidentified: `The following content could not be identified. Please provide proof of its origin along with proof that you have permission to include it:`,

View File

@ -3,21 +3,53 @@ import type { ButtonAction } from '../../types/actions'
import { TagsIcon } from '@modrinth/assets' import { TagsIcon } from '@modrinth/assets'
const categories: Stage = { const categories: Stage = {
title: "Are the project's tags/categories accurate?", title: "Are the project's tags accurate?",
id: 'tags', id: 'tags',
icon: TagsIcon, icon: TagsIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous', guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
navigate: '/settings/tags', navigate: '/settings/tags',
shouldShow: (project) =>
project.categories.length > 0 || project.additional_categories.length > 0,
text: async () => {
return (await import('../messages/checklist-text/categories.md?raw')).default
},
actions: [ actions: [
{ {
id: 'categories_inaccurate', id: 'categories_inaccurate',
type: 'button', type: 'button',
label: 'Inaccurate', label: 'Inaccurate',
weight: 10, weight: 700,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
message: async () => (await import('../messages/categories/inaccurate.md?raw')).default, message: async () => (await import('../messages/categories/inaccurate.md?raw')).default,
disablesActions: ['categories_optimization_misused', 'categories_resolutions_misused'],
} as ButtonAction, } as ButtonAction,
{
id: 'categories_optimization_misused',
type: 'button',
label: 'Optimization',
weight: 701,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.categories.includes('optimization'),
message: async () =>
(await import('../messages/categories/inaccurate.md?raw')).default +
(await import('../messages/categories/optimization_misused.md?raw')).default,
disablesActions: ['categories_inaccurate', 'categories_resolutions_misused'],
} as ButtonAction,
{
id: 'categories_resolutions_misused',
type: 'button',
label: 'Resolutions',
weight: 702,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.project_type === 'resourcepack',
message: async () =>
(await import('../messages/categories/inaccurate.md?raw')).default +
(await import('../messages/categories/resolutions_misused.md?raw')).default,
disablesActions: ['categories_inaccurate', 'categories_optimization_misused'],
},
], ],
} }

View File

@ -1,37 +0,0 @@
import type { Stage } from '../../types/stage'
import type { ButtonAction } from '../../types/actions'
import { CopyrightIcon } from '@modrinth/assets'
const copyright: Stage = {
title: 'Does the author have proper permissions to post this project?',
id: 'copyright',
icon: CopyrightIcon,
guidance_url: 'https://modrinth.com/legal/rules',
actions: [
{
id: 'copyright_reupload',
type: 'button',
label: 'Re-upload',
weight: 10,
suggestedStatus: 'rejected',
severity: 'high',
message: async () => (await import('../messages/copyright/reupload.md?raw')).default,
relevantExtraInput: [
{
label: 'What is the title of the original project?',
variable: 'ORIGINAL_PROJECT',
required: true,
suggestions: ['Vanilla Tweaks'],
},
{
label: 'What is the author of the original project?',
variable: 'ORIGINAL_AUTHOR',
required: true,
suggestions: ['Vanilla Tweaks Team'],
},
],
} as ButtonAction,
],
}
export default copyright

View File

@ -3,7 +3,7 @@ import type { ButtonAction } from '../../types/actions'
import { LibraryIcon } from '@modrinth/assets' import { LibraryIcon } from '@modrinth/assets'
const description: Stage = { const description: Stage = {
title: "Is the project's description sufficient?", title: 'Is the description sufficient, accurate, and accessible?',
id: 'description', id: 'description',
icon: LibraryIcon, icon: LibraryIcon,
guidance_url: 'https://modrinth.com/legal/rules#general-expectations', guidance_url: 'https://modrinth.com/legal/rules#general-expectations',
@ -13,7 +13,7 @@ const description: Stage = {
id: 'description_insufficient', id: 'description_insufficient',
type: 'button', type: 'button',
label: 'Insufficient (custom)', label: 'Insufficient (custom)',
weight: 10, weight: 400,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
message: async () => (await import('../messages/description/insufficient.md?raw')).default, message: async () => (await import('../messages/description/insufficient.md?raw')).default,
@ -30,7 +30,7 @@ const description: Stage = {
id: 'description_insufficient_packs', id: 'description_insufficient_packs',
type: 'button', type: 'button',
label: 'Insufficient', label: 'Insufficient',
weight: 10, weight: 401,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
shouldShow: (project) => project.project_type === 'modpack', shouldShow: (project) => project.project_type === 'modpack',
@ -41,7 +41,7 @@ const description: Stage = {
id: 'description_insufficient_projects', id: 'description_insufficient_projects',
type: 'button', type: 'button',
label: 'Insufficient', label: 'Insufficient',
weight: 10, weight: 401,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
shouldShow: (project) => project.project_type !== 'modpack', shouldShow: (project) => project.project_type !== 'modpack',
@ -52,7 +52,7 @@ const description: Stage = {
id: 'description_non_english', id: 'description_non_english',
type: 'button', type: 'button',
label: 'Non-english', label: 'Non-english',
weight: 10, weight: 402,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
message: async () => (await import('../messages/description/non-english.md?raw')).default, message: async () => (await import('../messages/description/non-english.md?raw')).default,
@ -61,23 +61,16 @@ const description: Stage = {
id: 'description_unfinished', id: 'description_unfinished',
type: 'button', type: 'button',
label: 'Unfinished', label: 'Unfinished',
weight: 10, weight: 403,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
message: async () => (await import('../messages/description/unfinished.md?raw')).default, message: async () => (await import('../messages/description/unfinished.md?raw')).default,
relevantExtraInput: [
{
label: 'Please specify the reason the description appears unfinished.',
variable: 'REASON',
required: true,
},
],
} as ButtonAction, } as ButtonAction,
{ {
id: 'description_headers_as_body', id: 'description_headers_as_body',
type: 'button', type: 'button',
label: 'Headers as body text', label: 'Headers as body text',
weight: 10, weight: 404,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
message: async () => (await import('../messages/description/headers-as-body.md?raw')).default, message: async () => (await import('../messages/description/headers-as-body.md?raw')).default,
@ -86,7 +79,7 @@ const description: Stage = {
id: 'description_image_only', id: 'description_image_only',
type: 'button', type: 'button',
label: 'Image-only', label: 'Image-only',
weight: 10, weight: 405,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
message: async () => (await import('../messages/description/image-only.md?raw')).default, message: async () => (await import('../messages/description/image-only.md?raw')).default,
@ -95,7 +88,7 @@ const description: Stage = {
id: 'description_non_standard_text', id: 'description_non_standard_text',
type: 'button', type: 'button',
label: 'Non-standard text', label: 'Non-standard text',
weight: 10, weight: 406,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
message: async () => message: async () =>

View File

@ -13,7 +13,7 @@ const gallery: Stage = {
id: 'gallery_insufficient', id: 'gallery_insufficient',
type: 'button', type: 'button',
label: 'Insufficient', label: 'Insufficient',
weight: 10, weight: 900,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
message: async () => (await import('../messages/gallery/insufficient.md?raw')).default, message: async () => (await import('../messages/gallery/insufficient.md?raw')).default,
@ -22,7 +22,7 @@ const gallery: Stage = {
id: 'gallery_not_relevant', id: 'gallery_not_relevant',
type: 'button', type: 'button',
label: 'Not relevant', label: 'Not relevant',
weight: 10, weight: 901,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
message: async () => (await import('../messages/gallery/not-relevant.md?raw')).default, message: async () => (await import('../messages/gallery/not-relevant.md?raw')).default,

View File

@ -0,0 +1,100 @@
import { BookTextIcon } from '@modrinth/assets'
import type { Stage } from '../../types/stage'
const licensesNotRequiringSource: string[] = [
'LicenseRef-All-Rights-Reserved',
'Apache-2.0',
'BSD-2-Clause',
'BSD-3-Clause',
'CC0-1.0',
'CC-BY-4.0',
'CC-BY-SA-4.0',
'CC-BY-NC-4.0',
'CC-BY-NC-SA-4.0',
'CC-BY-ND-4.0',
'CC-BY-NC-ND-4.0',
'ISC',
'MIT',
'Zlib',
]
const licenseStage: Stage = {
title: 'Is this license and link valid?',
text: async (project) => {
let text = ''
text += (await import('../messages/checklist-text/license/id.md?raw')).default
if (project.license.url)
text += (await import('../messages/checklist-text/license/link.md?raw')).default
return text
},
id: 'license',
icon: BookTextIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
navigate: '/settings/license',
actions: [
{
id: 'license_invalid_link',
type: 'button',
label: 'Invalid Link',
weight: 600,
suggestedStatus: 'flagged',
severity: 'medium',
shouldShow: (project) => Boolean(project.license.url),
message: async () => (await import('../messages/license/invalid_link.md?raw')).default,
enablesActions: [
{
id: 'license_invalid_link-custom_license',
type: 'toggle',
label: 'Invalid Link: Custom License',
weight: 601,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () =>
(await import('../messages/license/invalid_link-custom_license.md?raw')).default,
},
],
},
// {
// id: 'license_no_source',
// type: 'conditional-button',
// label: 'No Source',
// fallbackWeight: 602,
// suggestedStatus: 'rejected',
// severity: 'medium',
// fallbackMessage: async () => (await import('../messages/license/no_source.md?raw')).default,
// messageVariants: [
// {
// conditions: {
// requiredActions: ['reupload_unclear_fork'],
// },
// weight: 602,
// message: async () => (await import('../messages/license/no_source-fork.md?raw')).default,
// },
// ],
// },
{
id: 'license_no_source',
type: 'button',
label: 'No Source',
weight: 602,
suggestedStatus: 'rejected',
severity: 'medium',
shouldShow: (project) => !licensesNotRequiringSource.includes(project.license.id),
message: async () => (await import('../messages/license/no_source.md?raw')).default,
enablesActions: [
{
id: 'license_no_source-fork',
type: 'toggle',
label: 'No Source: Fork',
weight: 602,
suggestedStatus: 'rejected',
severity: 'high',
message: async () => (await import('../messages/license/no_source-fork.md?raw')).default,
},
],
},
],
}
export default licenseStage

View File

@ -3,43 +3,81 @@ import type { ButtonAction } from '../../types/actions'
import { LinkIcon } from '@modrinth/assets' import { LinkIcon } from '@modrinth/assets'
const links: Stage = { const links: Stage = {
title: "Are the project's links accessible and not misleading?", title: "Are the project's links accurate and accessible?",
id: 'links', id: 'links',
icon: LinkIcon, icon: LinkIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous', guidance_url: 'https://modrinth.com/legal/rules',
navigate: '/settings/links', navigate: '/settings/links',
shouldShow: (project) =>
Boolean(
project.issues_url ||
project.source_url ||
project.wiki_url ||
project.discord_url ||
project.donation_urls.length > 0,
),
text: async (project) => {
let text = (await import('../messages/checklist-text/links/base.md?raw')).default
if (project.donation_urls.length > 0) {
text += (await import('../messages/checklist-text/links/donation/donations.md?raw')).default
for (const donation of project.donation_urls) {
text += (await import(`../messages/checklist-text/links/donation/donation.md?raw`)).default
.replace('{URL}', donation.url)
.replace('{PLATFORM}', donation.platform)
}
}
return text
},
actions: [ actions: [
{ {
id: 'links_misused', id: 'links_misused',
type: 'button', type: 'button',
label: 'Links are misused', label: 'Links are misused',
weight: 10, weight: 500,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
message: async () => (await import('../messages/links/misused.md?raw')).default, message: async () => (await import('../messages/links/misused.md?raw')).default,
} as ButtonAction,
{
id: 'links_not_accessible_source',
type: 'button',
label: 'Not accessible (source)',
weight: 10,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/links/not-accessible-source.md?raw')).default,
} as ButtonAction,
{
id: 'links_not_accessible_other',
type: 'button',
label: 'Not accessible (other)',
weight: 10,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/links/not-accessible-other.md?raw')).default,
relevantExtraInput: [ relevantExtraInput: [
{ {
label: 'Please specify the link type that is inaccessible.', label: 'What links are misused?',
variable: 'LINK', variable: 'MISUSED_LINKS',
required: true, required: false,
},
],
} as ButtonAction,
{
id: 'links_unaccessible',
type: 'button',
label: 'Links are inaccessible',
weight: 510,
suggestedStatus: 'flagged',
// Theoretically a conditional could go here to prevent overlap of misuse and unaccessible messages repeating while still allowing for a multi-select in each.
// if links_misused was selected, send nothing.
message: async () => (await import('../messages/links/not_accessible.md?raw')).default,
enablesActions: [
{
id: 'links_unaccessible_options',
type: 'multi-select-chips',
label: 'Warn of unaccessible link?',
options: [
{
label: 'Source',
weight: 511,
shouldShow: (project) => Boolean(project.source_url),
message: async () =>
(await import('../messages/links/not_accessible-source.md?raw')).default,
},
{
label: 'Discord',
weight: 512,
shouldShow: (project) => Boolean(project.discord_url),
message: async () =>
(await import('../messages/links/not_accessible-discord.md?raw')).default,
},
],
}, },
], ],
} as ButtonAction, } as ButtonAction,

View File

@ -0,0 +1,77 @@
import type { Stage } from '../../types/stage'
import type { ButtonAction } from '../../types/actions'
import { CopyrightIcon } from '@modrinth/assets'
const reupload: Stage = {
title: 'Does the author have proper permissions to post this project?',
id: 'reupload',
icon: CopyrightIcon,
guidance_url: 'https://modrinth.com/legal/rules',
actions: [
{
id: 'reupload_reupload',
type: 'button',
label: 'Re-upload',
weight: 1100,
suggestedStatus: 'rejected',
severity: 'high',
message: async () => (await import('../messages/reupload/reupload.md?raw')).default,
disablesActions: [
'reupload_unclear_fork',
'reupload_insufficient_fork',
'reupload_request_proof',
],
relevantExtraInput: [
{
label: 'What is the title of the original project?',
variable: 'ORIGINAL_PROJECT',
required: true,
suggestions: ['Vanilla Tweaks'],
},
{
label: 'What is the author of the original project?',
variable: 'ORIGINAL_AUTHOR',
required: true,
suggestions: ['Vanilla Tweaks Team'],
},
],
} as ButtonAction,
{
id: 'reupload_unclear_fork',
type: 'button',
label: 'Unclear Fork',
weight: 1100,
suggestedStatus: 'rejected',
severity: 'high',
message: async () => (await import('../messages/reupload/fork.md?raw')).default,
// disablesActions: [
// 'reupload_reupload',
// 'reupload_insufficient_fork',
// 'reupload_request_proof',
// ],
} as ButtonAction,
{
id: 'reupload_insufficient_fork',
type: 'button',
label: 'Insufficient Fork',
weight: 1100,
suggestedStatus: 'rejected',
severity: 'high',
message: async () => (await import('../messages/reupload/insufficient_fork.md?raw')).default,
// disablesActions: ['reupload_unclear_fork', 'reupload_reupload', 'reupload_request_proof'],
} as ButtonAction,
{
id: 'reupload_request_proof',
type: 'button',
label: 'Proof of permissions',
weight: 1100,
suggestedStatus: 'rejected',
severity: 'high',
message: async () =>
(await import('../messages/reupload/proof_of_permissions.md?raw')).default,
// disablesActions: ['reupload_reupload', 'reupload_unclear_fork', 'reupload_insufficient_fork'],
},
],
}
export default reupload

View File

@ -3,17 +3,18 @@ import type { ButtonAction } from '../../types/actions'
import { ListBulletedIcon } from '@modrinth/assets' import { ListBulletedIcon } from '@modrinth/assets'
const ruleFollowing: Stage = { const ruleFollowing: Stage = {
title: 'Does this project break our content rules?', title: 'Does this project violate the rules?',
id: 'rule-following', id: 'rule-following',
icon: ListBulletedIcon, icon: ListBulletedIcon,
guidance_url: 'https://modrinth.com/legal/rules', guidance_url:
navigate: '/', 'https://www.notion.so/Creator-Communication-Guide-1b65ee711bf080ec9337e3ccdded146c',
navigate: '/moderation',
actions: [ actions: [
{ {
id: 'rule_breaking_yes', id: 'rule_breaking_yes',
type: 'button', type: 'button',
label: 'Yes', label: 'Yes',
weight: 10, weight: 0,
suggestedStatus: 'rejected', suggestedStatus: 'rejected',
severity: 'critical', severity: 'critical',
message: async () => (await import('../messages/rule-breaking.md?raw')).default, message: async () => (await import('../messages/rule-breaking.md?raw')).default,

View File

@ -12,8 +12,8 @@ const sideTypes: Stage = {
{ {
id: 'side_types_inaccurate_modpack', id: 'side_types_inaccurate_modpack',
type: 'button', type: 'button',
label: 'Inaccurate (modpack)', label: 'Inaccurate',
weight: 10, weight: 800,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
shouldShow: (project) => project.project_type === 'modpack', shouldShow: (project) => project.project_type === 'modpack',
@ -23,8 +23,8 @@ const sideTypes: Stage = {
{ {
id: 'side_types_inaccurate_mod', id: 'side_types_inaccurate_mod',
type: 'button', type: 'button',
label: 'Inaccurate (mod)', label: 'Inaccurate',
weight: 10, weight: 800,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
shouldShow: (project) => project.project_type === 'mod', shouldShow: (project) => project.project_type === 'mod',

View File

@ -1,23 +0,0 @@
import { HashIcon } from '@modrinth/assets'
import type { Stage } from '../../types/stage'
const slugStage: Stage = {
title: 'Is the slug accurate and appropriate?',
id: 'slug',
icon: HashIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
navigate: '/settings',
actions: [
{
id: 'slug_misused',
type: 'button',
label: 'Misused',
weight: 100,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/slug/misused.md?raw')).default,
},
],
}
export default slugStage

View File

@ -0,0 +1,53 @@
import type { Stage } from '../../types/stage'
import type { ButtonAction } from '../../types/actions'
import { TriangleAlertIcon } from '@modrinth/assets'
const statusAlerts: Stage = {
title: `Is anything else affecting this project's status?`,
id: 'status-alerts',
icon: TriangleAlertIcon,
text: async () => (await import('../messages/checklist-text/status-alerts/text.md?raw')).default,
guidance_url:
'https://www.notion.so/Project-Modification-Guidelines-22e5ee711bf080628416f0471ba6af02',
navigate: '/moderation',
actions: [
{
id: 'status_corrections_applied',
type: 'button',
label: 'Corrections applied',
weight: 999999,
suggestedStatus: 'approved',
disablesActions: ['status_private_use', 'status_account_issues'],
message: async () => (await import('../messages/status-alerts/fixed.md?raw')).default,
} as ButtonAction,
{
id: 'status_private_use',
type: 'button',
label: 'Private use',
weight: 999999,
suggestedStatus: 'flagged',
disablesActions: ['status_corrections_applied', 'status_account_issues'],
message: async () => (await import('../messages/status-alerts/private.md?raw')).default,
} as ButtonAction,
{
id: 'status_account_issues',
type: 'button',
label: 'Account issues',
weight: 999999,
suggestedStatus: 'rejected',
disablesActions: ['status_corrections_applied', 'status_private_use'],
message: async () =>
(await import('../messages/status-alerts/account_issues.md?raw')).default,
} as ButtonAction,
{
id: 'status_automod_confusion',
type: 'button',
label: `Automod confusion`,
weight: 999999,
message: async () =>
(await import('../messages/status-alerts/automod_confusion.md?raw')).default,
} as ButtonAction,
],
}
export default statusAlerts

View File

@ -4,6 +4,7 @@ import { AlignLeftIcon } from '@modrinth/assets'
const summary: Stage = { const summary: Stage = {
title: "Is the project's summary sufficient?", title: "Is the project's summary sufficient?",
text: async () => (await import('../messages/checklist-text/summary/summary.md?raw')).default,
id: 'summary', id: 'summary',
icon: AlignLeftIcon, icon: AlignLeftIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous', guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
@ -12,25 +13,27 @@ const summary: Stage = {
id: 'summary_insufficient', id: 'summary_insufficient',
type: 'button', type: 'button',
label: 'Insufficient', label: 'Insufficient',
weight: 10, weight: 300,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
disablesActions: ['summary_repeat_title'],
message: async () => (await import('../messages/summary/insufficient.md?raw')).default, message: async () => (await import('../messages/summary/insufficient.md?raw')).default,
} as ButtonAction, } as ButtonAction,
{ {
id: 'summary_repeat_title', id: 'summary_repeat_title',
type: 'button', type: 'button',
label: 'Repeat of title', label: 'Repeat of title',
weight: 10, weight: 300,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
disablesActions: ['summary_insufficient'],
message: async () => (await import('../messages/summary/repeat-title.md?raw')).default, message: async () => (await import('../messages/summary/repeat-title.md?raw')).default,
} as ButtonAction, } as ButtonAction,
{ {
id: 'summary_formatting', id: 'summary_formatting',
type: 'button', type: 'button',
label: 'Formatting', label: 'Formatting',
weight: 10, weight: 301,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'low', severity: 'low',
message: async () => (await import('../messages/summary/formatting.md?raw')).default, message: async () => (await import('../messages/summary/formatting.md?raw')).default,
@ -39,7 +42,7 @@ const summary: Stage = {
id: 'summary_non_english', id: 'summary_non_english',
type: 'button', type: 'button',
label: 'Non-english', label: 'Non-english',
weight: 10, weight: 302,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
message: async () => (await import('../messages/summary/non-english.md?raw')).default, message: async () => (await import('../messages/summary/non-english.md?raw')).default,

View File

@ -0,0 +1,77 @@
import { BookOpenIcon } from '@modrinth/assets'
import type { Stage } from '../../types/stage'
const titleSlug: Stage = {
title: 'Are the Name and URL accurate and appropriate?',
id: 'title-&-slug',
text: async () => (await import('../messages/checklist-text/title-slug.md?raw')).default,
icon: BookOpenIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
actions: [
{
id: 'title_useless_info',
type: 'button',
label: 'Contains useless info',
weight: 100,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/title/useless-info.md?raw')).default,
},
{
id: 'title_minecraft_branding',
type: 'button',
label: 'Minecraft title',
weight: 100,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () => (await import('../messages/title/minecraft-branding.md?raw')).default,
},
{
id: 'title_similarities',
type: 'button',
label: 'Title similarities',
weight: 110,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () => (await import('../messages/title/similarities.md?raw')).default,
enablesActions: [
{
id: 'title_similarities_options',
type: 'multi-select-chips',
label: 'Similarities additional info',
options: [
{
label: 'Modpack named after mod',
weight: 111,
shouldShow: (project) => project.project_type === 'modpack',
message: async () =>
(await import('../messages/title/similarities-modpack.md?raw')).default,
},
{
label: 'Forked project',
weight: 112,
message: async () =>
(await import('../messages/title/similarities-fork.md?raw')).default,
},
],
},
],
},
{
id: 'slug_misused_options',
type: 'multi-select-chips',
label: 'Slug issues?',
suggestedStatus: 'rejected',
severity: 'low',
options: [
{
label: 'Misused',
weight: 200,
message: async () => (await import('../messages/slug/misused.md?raw')).default,
},
],
},
],
}
export default titleSlug

View File

@ -1,41 +0,0 @@
import { BookOpenIcon } from '@modrinth/assets'
import type { Stage } from '../../types/stage'
const titleStage: Stage = {
title: 'Is this title free of useless information?',
text: async () => '**Title:** `%PROJECT_TITLE%`',
id: 'title',
icon: BookOpenIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
actions: [
{
id: 'title_useless_info',
type: 'button',
label: 'Contains useless info',
weight: 100,
suggestedStatus: 'flagged',
severity: 'low',
message: async () => (await import('../messages/title/useless-info.md?raw')).default,
},
{
id: 'title_minecraft_branding',
type: 'button',
label: 'Minecraft title',
weight: 100,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () => (await import('../messages/title/minecraft-branding.md?raw')).default,
},
{
id: 'title_similarities',
type: 'button',
label: 'Title similarities',
weight: 100,
suggestedStatus: 'flagged',
severity: 'medium',
message: async () => (await import('../messages/title/similarities.md?raw')).default,
},
],
}
export default titleStage

View File

@ -0,0 +1,24 @@
import { XIcon } from '@modrinth/assets'
import type { Stage } from '../../types/stage'
const undefinedProjectStage: Stage = {
title: 'This project is undefined!',
id: 'undefined-project',
icon: XIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
navigate: '/versions',
shouldShow: (project) => project.versions.length === 0,
actions: [
{
id: 'undefined_no_versions',
type: 'button',
label: 'No Versions',
weight: -100,
suggestedStatus: 'rejected',
message: async () =>
(await import('../messages/undefined-project/no_versions.md?raw')).default,
},
],
}
export default undefinedProjectStage

View File

@ -1,9 +1,9 @@
import type { Stage } from '../../types/stage' import type { Stage } from '../../types/stage'
import type { ButtonAction } from '../../types/actions' import type { ButtonAction, DropdownAction, DropdownActionOption } from '../../types/actions'
import { VersionIcon } from '@modrinth/assets' import { VersionIcon } from '@modrinth/assets'
const versions: Stage = { const versions: Stage = {
title: "Are these project's files correct?", title: "Are this project's files correct?",
id: 'versions', id: 'versions',
icon: VersionIcon, icon: VersionIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous', guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
@ -13,33 +13,140 @@ const versions: Stage = {
id: 'versions_incorrect_additional', id: 'versions_incorrect_additional',
type: 'button', type: 'button',
label: 'Incorrect additional files', label: 'Incorrect additional files',
weight: 10, weight: 1000,
suggestedStatus: 'flagged', suggestedStatus: 'flagged',
severity: 'medium', severity: 'medium',
message: async () => message: async () =>
(await import('../messages/versions/incorrect-additional-files.md?raw')).default, (await import('../messages/versions/incorrect_additional_files.md?raw')).default,
} as ButtonAction, } as ButtonAction,
{ {
id: 'versions_invalid_modpacks', id: 'versions_incorrect_project_type',
type: 'button', type: 'button',
label: 'Invalid file type (modpacks)', label: 'Incorrect Project Type',
weight: 10,
suggestedStatus: 'rejected', suggestedStatus: 'rejected',
severity: 'medium', severity: 'medium',
shouldShow: (project) => project.project_type === 'modpack', enablesActions: [
message: async () => (await import('../messages/versions/invalid-modpacks.md?raw')).default, {
id: 'versions_incorrect_project_type_options',
type: 'dropdown',
label: 'What type should this project be?',
options: [
{
label: 'Modpack',
weight: 1001,
shouldShow: (project) => project.project_type !== 'modpack',
message: async () =>
(await import('../messages/versions/invalid-modpacks.md?raw')).default,
} as DropdownActionOption,
{
label: 'Resource Pack',
weight: 1001,
shouldShow: (project) => project.project_type !== 'resourcepack',
message: async () =>
(await import('../messages/versions/invalid-resourcepacks.md?raw')).default,
} as DropdownActionOption,
{
label: 'Data Pack',
weight: 1001,
shouldShow: (project) => !project.loaders.includes('datapack'),
message: async () =>
(await import('../messages/versions/invalid-datapacks.md?raw')).default,
} as DropdownActionOption,
],
} as DropdownAction,
],
} as ButtonAction, } as ButtonAction,
{ {
id: 'versions_invalid_resourcepacks', id: 'versions_alternate_versions',
type: 'button', type: 'button',
label: 'Invalid file type (resourcepacks)', label: 'Alternate Versions',
weight: 10, suggestedStatus: 'flagged',
suggestedStatus: 'rejected',
severity: 'medium', severity: 'medium',
enablesActions: [
{
id: 'versions_incorrect_project_type_options',
type: 'dropdown',
label: 'How are the alternate versions distributed?',
options: [
{
label: 'Primary Files',
weight: 1002,
message: async () =>
(await import('../messages/versions/alternate_versions-primary.md?raw')).default,
} as DropdownActionOption,
{
label: 'Additional Files',
weight: 1002,
message: async () =>
(await import('../messages/versions/alternate_versions-additional.md?raw')).default,
} as DropdownActionOption,
{
label: 'Monofile',
weight: 1002,
shouldShow: (project) =>
project.project_type === 'resourcepack' || project.loaders.includes('datapack'),
message: async () =>
(await import('../messages/versions/alternate_versions-mono.md?raw')).default,
} as DropdownActionOption,
{
label: 'Server Files (Primary Files)',
weight: 1002,
shouldShow: (project) => project.project_type === 'modpack',
message: async () =>
(await import('../messages/versions/alternate_versions-server.md?raw')).default,
} as DropdownActionOption,
{
label: 'Server Files (Additional Files)',
weight: 1002,
suggestedStatus: 'rejected',
severity: 'high',
shouldShow: (project) => project.project_type === 'modpack',
message: async () =>
(await import('../messages/versions/alternate_versions-server-additional.md?raw'))
.default,
} as DropdownActionOption,
{
label: 'mods.zip',
weight: 1002,
suggestedStatus: 'rejected',
severity: 'high',
shouldShow: (project) => project.project_type === `modpack`,
message: async () =>
(await import('../messages/versions/alternate_versions-zip.md?raw')).default,
} as DropdownActionOption,
],
} as DropdownAction,
],
} as ButtonAction,
{
id: 'versions_vanilla_assets',
type: 'button',
label: 'Vanilla Assets',
suggestedStatus: `rejected`,
severity: `medium`,
weight: 1003,
shouldShow: (project) => project.project_type === 'resourcepack', shouldShow: (project) => project.project_type === 'resourcepack',
message: async () => message: async () => (await import('../messages/versions/vanilla_assets.md?raw')).default,
(await import('../messages/versions/invalid-resourcepacks.md?raw')).default,
} as ButtonAction, } as ButtonAction,
{
id: 'versions_redist_libs',
type: 'button',
label: 'Oversized File',
suggestedStatus: `rejected`,
severity: `medium`,
weight: 1003,
shouldShow: (project) => project.project_type === 'mod',
message: async () => (await import('../messages/versions/redist_libs.md?raw')).default,
} as ButtonAction,
{
id: 'versions_duplicate_primary_files',
type: 'button',
label: 'Duplicate Primary Files',
suggestedStatus: 'flagged',
severity: `medium`,
weight: 1004,
message: async () => (await import('../messages/versions/broken_version.md?raw')).default,
},
], ],
} }

View File

@ -14,7 +14,7 @@ export interface Stage {
/** /**
* An optional description or additional text for the stage. * An optional description or additional text for the stage.
*/ */
text?: () => Promise<string> text?: (project: Project) => Promise<string>
/** /**
* Optional id for the stage, used for identification in the checklist. Will be used in the stage list as well instead of the title. * Optional id for the stage, used for identification in the checklist. Will be used in the stage list as well instead of the title.

View File

@ -229,6 +229,10 @@ export function kebabToTitleCase(input: string): string {
.join(' ') .join(' ')
} }
export function arrayOrNone(arr: string[]): string {
return arr.length > 0 ? arr.join(', ') : 'None'
}
export function flattenProjectVariables(project: Project): Record<string, string> { export function flattenProjectVariables(project: Project): Record<string, string> {
const vars: Record<string, string> = {} const vars: Record<string, string> = {}
@ -236,17 +240,17 @@ export function flattenProjectVariables(project: Project): Record<string, string
vars['PROJECT_TYPE'] = project.project_type vars['PROJECT_TYPE'] = project.project_type
vars['PROJECT_SLUG'] = project.slug vars['PROJECT_SLUG'] = project.slug
vars['PROJECT_TITLE'] = project.title vars['PROJECT_TITLE'] = project.title
vars['PROJECT_DESCRIPTION'] = project.description vars['PROJECT_SUMMARY'] = project.description
vars['PROJECT_STATUS'] = project.status vars['PROJECT_STATUS'] = project.status
vars['PROJECT_REQUESTED_STATUS'] = project.requested_status vars['PROJECT_REQUESTED_STATUS'] = project.requested_status
vars['PROJECT_MONETIZATION_STATUS'] = project.monetization_status vars['PROJECT_MONETIZATION_STATUS'] = project.monetization_status
vars['PROJECT_BODY'] = project.body vars['PROJECT_BODY'] = project.body
vars['PROJECT_ICON_URL'] = project.icon_url || '' vars['PROJECT_ICON_URL'] = project.icon_url || ''
vars['PROJECT_ISSUES_URL'] = project.issues_url || '' vars['PROJECT_ISSUES_URL'] = project.issues_url || 'None'
vars['PROJECT_SOURCE_URL'] = project.source_url || '' vars['PROJECT_SOURCE_URL'] = project.source_url || 'None'
vars['PROJECT_WIKI_URL'] = project.wiki_url || '' vars['PROJECT_WIKI_URL'] = project.wiki_url || 'None'
vars['PROJECT_DISCORD_URL'] = project.discord_url || '' vars['PROJECT_DISCORD_URL'] = project.discord_url || 'None'
vars['PROJECT_DOWNLOADS'] = project.downloads.toString() vars['PROJECT_DOWNLOADS'] = project.downloads.toString()
vars['PROJECT_FOLLOWERS'] = project.followers.toString() vars['PROJECT_FOLLOWERS'] = project.followers.toString()
@ -266,13 +270,13 @@ export function flattenProjectVariables(project: Project): Record<string, string
vars['PROJECT_LICENSE_ID'] = project.license.id vars['PROJECT_LICENSE_ID'] = project.license.id
vars['PROJECT_LICENSE_NAME'] = project.license.name vars['PROJECT_LICENSE_NAME'] = project.license.name
vars['PROJECT_LICENSE_URL'] = project.license.url || '' vars['PROJECT_LICENSE_URL'] = project.license.url || 'None'
vars['PROJECT_CATEGORIES'] = project.categories.join(', ') vars['PROJECT_CATEGORIES'] = arrayOrNone(project.categories)
vars['PROJECT_ADDITIONAL_CATEGORIES'] = project.additional_categories.join(', ') vars['PROJECT_ADDITIONAL_CATEGORIES'] = arrayOrNone(project.additional_categories)
vars['PROJECT_GAME_VERSIONS'] = project.game_versions.join(', ') vars['PROJECT_GAME_VERSIONS'] = arrayOrNone(project.game_versions)
vars['PROJECT_LOADERS'] = project.loaders.join(', ') vars['PROJECT_LOADERS'] = arrayOrNone(project.loaders)
vars['PROJECT_VERSIONS'] = project.versions.join(', ') vars['PROJECT_VERSIONS'] = arrayOrNone(project.versions)
vars['PROJECT_CATEGORIES_COUNT'] = project.categories.length.toString() vars['PROJECT_CATEGORIES_COUNT'] = project.categories.length.toString()
vars['PROJECT_GAME_VERSIONS_COUNT'] = project.game_versions.length.toString() vars['PROJECT_GAME_VERSIONS_COUNT'] = project.game_versions.length.toString()
@ -294,5 +298,42 @@ export function flattenProjectVariables(project: Project): Record<string, string
vars[`PROJECT_GALLERY_${index}_FEATURED`] = image.featured.toString() vars[`PROJECT_GALLERY_${index}_FEATURED`] = image.featured.toString()
}) })
// Static time saving stuff
vars[`RULES`] = `[Modrinth's Content Rules](https://modrinth.com/legal/rules)`
vars[`TOS`] = `[Terms of Use](https://modrinth.com/legal/terms)`
vars[`COPYRIGHT_POLICY`] = `[Copyright Policy](https://modrinth.com/legal/copyright)`
vars[`SUPPORT`] =
`please visit the [Modrinth Help Center](https://support.modrinth.com/) and click the green bubble to contact support.`
vars[`MODPACK_PERMISSIONS_GUIDE`] =
`our guide to [Obtaining Modpack Permissions](https://support.modrinth.com/en/articles/8797527-obtaining-modpack-permissions)`
vars[`MODPACKS_ON_MODRINTH`] =
`[Modpacks on Modrinth](https://support.modrinth.com/en/articles/8802250-modpacks-on-modrinth)`
vars[`ADVANCED_MARKDOWN`] =
`[Markdown Formatting Guide](https://support.modrinth.com/en/articles/8801962-advanced-markdown-formatting)`
vars[`LICENSING_GUIDE`] =
`our guide to [Guide to Licensing your Mods](https://modrinth.com/news/article/licensing-guide)`
// Navigation related variables
vars[`PROJECT_PERMANENT_LINK`] = `https://modrinth.com/project/${project.id}`
vars[`PROJECT_SETTINGS_LINK`] = `https://modrinth.com/project/${project.id}/settings`
vars[`PROJECT_SETTINGS_FLINK`] = `[Settings](https://modrinth.com/project/${project.id}/settings)`
vars[`PROJECT_TAGS_LINK`] = `https://modrinth.com/project/${project.id}/settings/tags`
vars[`PROJECT_TAGS_FLINK`] = `[Tags](https://modrinth.com/project/${project.id}/settings/tags)`
vars[`PROJECT_DESCRIPTION_LINK`] =
`https://modrinth.com/project/${project.id}/settings/description`
vars[`PROJECT_DESCRIPTION_FLINK`] =
`[Description](https://modrinth.com/project/${project.id}/settings/description)`
vars[`PROJECT_LICENSE_LINK`] = `https://modrinth.com/project/${project.id}/license`
vars[`PROJECT_LICENSE_FLINK`] = `[License](https://modrinth.com/project/${project.id}/license`
vars[`PROJECT_LINKS_LINK`] = `https://modrinth.com/project/${project.id}/settings/links`
vars[`PROJECT_LINKS_FLINK`] = `[Links](https://modrinth.com/project/${project.id}/settings/links)`
vars[`PROJECT_GALLERY_LINK`] = `https://modrinth.com/project/${project.id}/gallery`
vars[`PROJECT_GALLERY_FLINK`] = `[Gallery](https://modrinth.com/project/${project.id}/gallery)`
vars[`PROJECT_VERSIONS_LINK`] = `https://modrinth.com/project/${project.id}/versions`
vars[`PROJECT_VERSIONS_FLINK`] = `[Versions](https://modrinth.com/project/${project.id}/versions)`
vars[`PROJECT_MODERATION_LINK`] = `https://modrinth.com/project/${project.id}/moderation`
vars[`PROJECT_MODERATION_FLINK`] =
`[moderation tab](https://modrinth.com/project/${project.id}/moderation)`
return vars return vars
} }

39
pnpm-lock.yaml generated
View File

@ -394,9 +394,9 @@ importers:
'@modrinth/utils': '@modrinth/utils':
specifier: workspace:* specifier: workspace:*
version: link:../utils version: link:../utils
fast-glob: glob:
specifier: ^3.3.3 specifier: ^10.2.7
version: 3.3.3 version: 10.4.2
gray-matter: gray-matter:
specifier: ^4.0.3 specifier: ^4.0.3
version: 4.0.3 version: 4.0.3
@ -410,6 +410,9 @@ importers:
specifier: ^0.6.2 specifier: ^0.6.2
version: 0.6.2 version: 0.6.2
devDependencies: devDependencies:
'@types/glob':
specifier: ^9.0.0
version: 9.0.0
'@types/html-minifier-terser': '@types/html-minifier-terser':
specifier: ^7.0.2 specifier: ^7.0.2
version: 7.0.2 version: 7.0.2
@ -2643,6 +2646,10 @@ packages:
'@types/fs-extra@9.0.13': '@types/fs-extra@9.0.13':
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
'@types/glob@9.0.0':
resolution: {integrity: sha512-00UxlRaIUvYm4R4W9WYkN8/J+kV8fmOQ7okeH6YFtGWFMt3odD45tpG5yA5wnL7HE6lLgjaTW5n14ju2hl2NNA==}
deprecated: This is a stub types definition. glob provides its own type definitions, so you do not need this installed.
'@types/hast@3.0.4': '@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
@ -4626,10 +4633,6 @@ packages:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'} engines: {node: '>=8.6.0'}
fast-glob@3.3.3:
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
engines: {node: '>=8.6.0'}
fast-json-stable-stringify@2.1.0: fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
@ -9336,7 +9339,7 @@ snapshots:
'@eslint/eslintrc@2.1.4': '@eslint/eslintrc@2.1.4':
dependencies: dependencies:
ajv: 6.12.6 ajv: 6.12.6
debug: 4.4.0(supports-color@9.4.0) debug: 4.4.0
espree: 9.6.1 espree: 9.6.1
globals: 13.24.0 globals: 13.24.0
ignore: 5.3.1 ignore: 5.3.1
@ -9512,7 +9515,7 @@ snapshots:
'@humanwhocodes/config-array@0.11.14': '@humanwhocodes/config-array@0.11.14':
dependencies: dependencies:
'@humanwhocodes/object-schema': 2.0.3 '@humanwhocodes/object-schema': 2.0.3
debug: 4.4.0(supports-color@9.4.0) debug: 4.4.0
minimatch: 3.1.2 minimatch: 3.1.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -10659,6 +10662,10 @@ snapshots:
dependencies: dependencies:
'@types/node': 20.14.11 '@types/node': 20.14.11
'@types/glob@9.0.0':
dependencies:
glob: 10.4.2
'@types/hast@3.0.4': '@types/hast@3.0.4':
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
@ -12392,6 +12399,10 @@ snapshots:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
debug@4.4.0:
dependencies:
ms: 2.1.3
debug@4.4.0(supports-color@9.4.0): debug@4.4.0(supports-color@9.4.0):
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@ -13154,7 +13165,7 @@ snapshots:
ajv: 6.12.6 ajv: 6.12.6
chalk: 4.1.2 chalk: 4.1.2
cross-spawn: 7.0.3 cross-spawn: 7.0.3
debug: 4.4.0(supports-color@9.4.0) debug: 4.4.0
doctrine: 3.0.0 doctrine: 3.0.0
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
eslint-scope: 7.2.2 eslint-scope: 7.2.2
@ -13369,14 +13380,6 @@ snapshots:
merge2: 1.4.1 merge2: 1.4.1
micromatch: 4.0.8 micromatch: 4.0.8
fast-glob@3.3.3:
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.8
fast-json-stable-stringify@2.1.0: {} fast-json-stable-stringify@2.1.0: {}
fast-levenshtein@2.0.6: {} fast-levenshtein@2.0.6: {}