mirror of
https://github.com/captbaritone/webamp.git
synced 2026-07-24 02:27:37 +00:00
Allow skins to be marked as NSFW via API
This commit is contained in:
parent
929aef926b
commit
915ba85c8a
9 changed files with 86 additions and 25 deletions
3
packages/skin-database/__mocks__/algolia.ts
Normal file
3
packages/skin-database/__mocks__/algolia.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export const searchIndex = {
|
||||
partialUpdateObjects: jest.fn(),
|
||||
};
|
||||
|
|
@ -34,37 +34,44 @@ export default class DiscordEventHandler {
|
|||
await this.requestReview(action.md5, ctx);
|
||||
break;
|
||||
case "APPROVED_SKIN":
|
||||
await this.reportApproved(action.md5, ctx);
|
||||
await this.reportSkin(
|
||||
action.md5,
|
||||
ctx,
|
||||
(filename) => `Approved by ${ctx.username}: ${filename}`
|
||||
);
|
||||
break;
|
||||
case "REJECTED_SKIN":
|
||||
await this.reportRejected(action.md5, ctx);
|
||||
await this.reportSkin(
|
||||
action.md5,
|
||||
ctx,
|
||||
(filename) => `Rejected by ${ctx.username}: ${filename}`
|
||||
);
|
||||
break;
|
||||
case "MARKED_SKIN_NSFW":
|
||||
await this.reportSkin(
|
||||
action.md5,
|
||||
ctx,
|
||||
(filename) => `Marked NSFW by ${ctx.username}: ${filename}`,
|
||||
Config.NSFW_SKIN_CHANNEL_ID
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
async reportApproved(md5: string, ctx: UserContext) {
|
||||
async reportSkin(
|
||||
md5: string,
|
||||
ctx: UserContext,
|
||||
getFilename: (filename: string) => string,
|
||||
channelId = Config.SKIN_REVIEW_CHANNEL_ID
|
||||
) {
|
||||
const skin = await SkinModel.fromMd5(ctx, md5);
|
||||
if (skin == null) {
|
||||
return;
|
||||
}
|
||||
const dest = await this.getChannel(Config.SKIN_REVIEW_CHANNEL_ID);
|
||||
const dest = await this.getChannel(channelId);
|
||||
await DiscordUtils.postSkin({
|
||||
md5,
|
||||
title: (filename) => `Approved by ${ctx.username}: ${filename}`,
|
||||
dest,
|
||||
});
|
||||
}
|
||||
|
||||
async reportRejected(md5: string, ctx: UserContext) {
|
||||
console.log("Report rejected");
|
||||
const skin = await SkinModel.fromMd5(ctx, md5);
|
||||
if (skin == null) {
|
||||
return;
|
||||
}
|
||||
const dest = await this.getChannel(Config.SKIN_REVIEW_CHANNEL_ID);
|
||||
await DiscordUtils.postSkin({
|
||||
md5,
|
||||
title: (filename) => `Rejected by ${ctx.username}: ${filename}`,
|
||||
title: getFilename,
|
||||
dest,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ import * as S3 from "../../s3";
|
|||
import * as Auth from "../auth";
|
||||
import { processUserUploads } from "../processUserUploads";
|
||||
import UserContext from "../../data/UserContext";
|
||||
import { searchIndex } from "../../algolia";
|
||||
jest.mock("../../s3");
|
||||
jest.mock("../../algolia");
|
||||
jest.mock("../processUserUploads");
|
||||
jest.mock("../auth");
|
||||
|
||||
|
|
@ -155,7 +157,7 @@ test("/skins/a_fake_md5/approve", async () => {
|
|||
type: "APPROVED_SKIN",
|
||||
md5: "a_fake_md5",
|
||||
});
|
||||
expect(body).toEqual({}); // TODO: Where does the text response go?
|
||||
expect(body).toEqual({ message: "The skin has been approved." });
|
||||
const skin = await SkinModel.fromMd5(ctx, "a_fake_md5");
|
||||
|
||||
expect(await skin?.getTweetStatus()).toEqual("APPROVED");
|
||||
|
|
@ -195,7 +197,7 @@ test("/skins/a_fake_md5/reject", async () => {
|
|||
type: "REJECTED_SKIN",
|
||||
md5: "a_fake_md5",
|
||||
});
|
||||
expect(body).toEqual({}); // TODO: Where does the text response go?
|
||||
expect(body).toEqual({ message: "The skin has been rejected." }); // TODO: Where does the text response go?
|
||||
const skin = await SkinModel.fromMd5(ctx, "a_fake_md5");
|
||||
|
||||
expect(await skin?.getTweetStatus()).toEqual("REJECTED");
|
||||
|
|
@ -210,6 +212,24 @@ test("/skins/a_md5_that_does_not_exist/reject (404)", async () => {
|
|||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test.only("/skins/a_fake_md5/nsfw", async () => {
|
||||
const ctx = new UserContext();
|
||||
const { body } = await request(app)
|
||||
.post("/skins/a_fake_md5/nsfw")
|
||||
.expect(200);
|
||||
expect(handler).toHaveBeenCalledWith({
|
||||
type: "MARKED_SKIN_NSFW",
|
||||
md5: "a_fake_md5",
|
||||
});
|
||||
expect(searchIndex.partialUpdateObjects).toHaveBeenCalledWith([
|
||||
{ nsfw: true, objectID: "a_fake_md5" },
|
||||
]);
|
||||
expect(body).toEqual({ message: "The skin has been marked as NSFW." });
|
||||
const skin = await SkinModel.fromMd5(ctx, "a_fake_md5");
|
||||
|
||||
expect(await skin?.getTweetStatus()).toEqual("NSFW");
|
||||
});
|
||||
|
||||
// TODO: Actually upload some skins?
|
||||
test("/skins/status", async () => {
|
||||
const { body } = await request(app)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export type ApiAction =
|
|||
| { type: "REVIEW_REQUESTED"; md5: string }
|
||||
| { type: "REJECTED_SKIN"; md5: string }
|
||||
| { type: "APPROVED_SKIN"; md5: string }
|
||||
| { type: "MARKED_SKIN_NSFW"; md5: string }
|
||||
| { type: "SKIN_UPLOADED"; md5: string }
|
||||
| { type: "ERROR_PROCESSING_UPLOAD"; id: string; message: string };
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ router.post(
|
|||
}
|
||||
await Skins.reject(req.ctx, md5);
|
||||
req.notify({ type: "REJECTED_SKIN", md5 });
|
||||
res.send("The skin has been rejected.");
|
||||
res.send({ message: "The skin has been rejected." });
|
||||
})
|
||||
);
|
||||
|
||||
|
|
@ -182,7 +182,26 @@ router.post(
|
|||
}
|
||||
await Skins.approve(req.ctx, md5);
|
||||
req.notify({ type: "APPROVED_SKIN", md5 });
|
||||
res.send("The skin has been approved.");
|
||||
res.send({ message: "The skin has been approved." });
|
||||
})
|
||||
);
|
||||
|
||||
// Unlike /report, this marks the skin NSFW right away without sending to
|
||||
// Discord. Because of this, it requires auth.
|
||||
router.post(
|
||||
"/skins/:md5/nsfw",
|
||||
requireAuthed,
|
||||
asyncHandler(async (req, res) => {
|
||||
const { md5 } = req.params;
|
||||
req.log(`Approving skin with hash "${md5}"`);
|
||||
const skin = await SkinModel.fromMd5(req.ctx, md5);
|
||||
if (skin == null) {
|
||||
res.status(404).send("Skin not found");
|
||||
return;
|
||||
}
|
||||
await Skins.markAsNSFW(req.ctx, md5);
|
||||
req.notify({ type: "MARKED_SKIN_NSFW", md5 });
|
||||
res.send({ message: "The skin has been marked as NSFW." });
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ export default class SkinModel {
|
|||
}
|
||||
const reviewRows = await this.getReviews();
|
||||
const reviews = new Set(reviewRows.map((row) => row.review));
|
||||
if (reviews.has("NSFW")) {
|
||||
return "NSFW";
|
||||
}
|
||||
if (reviews.has("REJECTED")) {
|
||||
return "REJECTED";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ function getPrettyTwitterStatus(status: TweetStatus): string {
|
|||
switch (status) {
|
||||
case "APPROVED":
|
||||
return "Approved ✅";
|
||||
case "NSFW":
|
||||
return "Rejected (NSFW) ❌";
|
||||
case "REJECTED":
|
||||
return "Rejected ❌";
|
||||
case "UNREVIEWED":
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export async function tweet(discordClient: Client, anything: string | null) {
|
|||
await tweetBotChannel.send(`Oops! This skin has alraedy been tweeted.`);
|
||||
return;
|
||||
}
|
||||
if (tweetStatus == "REJECTED") {
|
||||
if (tweetStatus == "REJECTED" || tweetStatus == "NSFW") {
|
||||
// @ts-ignore
|
||||
await tweetBotChannel.send(`Oops! Can't tweet a rejected skin.`);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
export type TweetStatus = "APPROVED" | "REJECTED" | "TWEETED" | "UNREVIEWED";
|
||||
export type TweetStatus =
|
||||
| "APPROVED"
|
||||
| "REJECTED"
|
||||
| "TWEETED"
|
||||
| "UNREVIEWED"
|
||||
| "NSFW";
|
||||
|
||||
export type SkinType = "MODERN" | "CLASSIC";
|
||||
|
||||
export type SkinRow = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue