Extract fromAnything logic into models

This commit is contained in:
Jordan Eldredge 2020-11-19 19:02:21 -05:00
parent e7005dba72
commit e1d29222a5
9 changed files with 279 additions and 153 deletions

View file

@ -17,27 +17,60 @@ beforeEach(async () => {
describe("/skins/", () => {
test("no query params", async () => {
const { body } = await request(app).get("/skins/");
expect(body).toEqual({
skinCount: 4,
skins: [
{ fileName: "path.wsz", md5: "a_fake_md5", nsfw: false },
{ fileName: "approved.wsz", md5: "an_approved_md5", nsfw: false },
{ fileName: "rejected.wsz", md5: "a_rejected_md5", nsfw: false },
{ fileName: "nsfw.wsz", md5: "a_nsfw_md5", nsfw: true },
],
});
expect(body).toMatchInlineSnapshot(`
Object {
"skinCount": 5,
"skins": Array [
Object {
"fileName": "Zelda_Amp_3.wsz",
"md5": "48bbdbbeb03d347e59b1eebda4d352d0",
"nsfw": false,
},
Object {
"fileName": "path.wsz",
"md5": "a_fake_md5",
"nsfw": false,
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
"nsfw": false,
},
Object {
"fileName": "rejected.wsz",
"md5": "a_rejected_md5",
"nsfw": false,
},
Object {
"fileName": "nsfw.wsz",
"md5": "a_nsfw_md5",
"nsfw": true,
},
],
}
`);
});
test("first and offset", async () => {
const { body } = await request(app)
.get("/skins/")
.query({ first: 2, offset: 1 });
expect(body).toEqual({
skinCount: 4,
skins: [
{ fileName: "approved.wsz", md5: "an_approved_md5", nsfw: false },
{ fileName: "rejected.wsz", md5: "a_rejected_md5", nsfw: false },
],
});
expect(body).toMatchInlineSnapshot(`
Object {
"skinCount": 5,
"skins": Array [
Object {
"fileName": "path.wsz",
"md5": "a_fake_md5",
"nsfw": false,
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
"nsfw": false,
},
],
}
`);
});
});
@ -76,22 +109,28 @@ test("/skins/a_fake_md5", async () => {
test("/stylegan.json", async () => {
let response = await request(app).get("/stylegan.json");
expect(response.body).toEqual([
{
fileName: "path.wsz",
url: "https://cdn.webampskins.org/screenshots/a_fake_md5.png",
},
{
fileName: "nsfw.wsz",
url: "https://cdn.webampskins.org/screenshots/a_nsfw_md5.png",
},
{
fileName: "rejected.wsz",
url: "https://cdn.webampskins.org/screenshots/a_rejected_md5.png",
},
{
fileName: "approved.wsz",
url: "https://cdn.webampskins.org/screenshots/an_approved_md5.png",
},
]);
expect(response.body).toMatchInlineSnapshot(`
Array [
Object {
"fileName": "Zelda_Amp_3.wsz",
"url": "https://cdn.webampskins.org/screenshots/48bbdbbeb03d347e59b1eebda4d352d0.png",
},
Object {
"fileName": "path.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_fake_md5.png",
},
Object {
"fileName": "nsfw.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_nsfw_md5.png",
},
Object {
"fileName": "rejected.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_rejected_md5.png",
},
Object {
"fileName": "approved.wsz",
"url": "https://cdn.webampskins.org/screenshots/an_approved_md5.png",
},
]
`);
});

View file

@ -1,5 +1,8 @@
import UserContext from "./UserContext";
import { IaItemRow } from "../types";
import SkinModel from "./SkinModel";
const IA_URL = /^(https:\/\/)?archive.org\/details\/([^\/]+)\/?/;
export default class IaItemModel {
constructor(readonly ctx: UserContext, readonly row: IaItemRow) {}
@ -20,6 +23,29 @@ export default class IaItemModel {
return row == null ? null : new IaItemModel(ctx, row);
}
static async fromAnything(
ctx: UserContext,
anything: string
): Promise<IaItemModel | null> {
const itemMatchResult = anything.match(IA_URL);
if (itemMatchResult != null) {
const itemName = itemMatchResult[2];
const item = await IaItemModel.fromIdentifier(ctx, itemName);
if (item != null) {
return item;
}
}
return IaItemModel.fromIdentifier(ctx, anything);
}
async getSkin(): Promise<SkinModel> {
const skin = await SkinModel.fromMd5(this.ctx, this.getMd5());
if (skin == null) {
throw new Error(`Could not find skin for md5 "${this.getMd5()}"`);
}
return skin;
}
getMd5(): string {
return this.row.skin_md5;
}

View file

@ -1,10 +1,11 @@
import path from "path";
import { getScreenshotUrl, getSkinUrl } from "./skins";
import { TweetStatus, SkinRow, TweetRow, ReviewRow, FileRow } from "../types";
import { TweetStatus, SkinRow, ReviewRow } from "../types";
import UserContext from "./UserContext";
import TweetModel, { TweetDebugData } from "./TweetModel";
import IaItemModel from "./IaItemModel";
import FileModel, { FileDebugData } from "./FileModel";
import { MD5_REGEX } from "../utils";
export default class SkinModel {
constructor(readonly ctx: UserContext, readonly row: SkinRow) {}
@ -17,6 +18,22 @@ export default class SkinModel {
return row == null ? null : new SkinModel(ctx, row);
}
static async fromAnything(
ctx: UserContext,
anything: string
): Promise<SkinModel | null> {
const md5Match = anything.match(MD5_REGEX);
if (md5Match != null) {
const md5 = md5Match[1];
const found = await SkinModel.fromMd5(ctx, md5);
if (found != null) {
return found;
}
}
const iaItem = await IaItemModel.fromAnything(ctx, anything);
return iaItem?.getSkin() ?? null;
}
static async exists(ctx: UserContext, md5: string): Promise<boolean> {
const row = await ctx.skin.load(md5);
return row != null;

View file

@ -0,0 +1,25 @@
import { knex } from "../../db";
import SkinModel from "../SkinModel";
import UserContext from "../UserContext";
beforeEach(async () => {
await knex.migrate.latest();
await knex.seed.run();
});
test("fromMd5", async () => {
const ctx = new UserContext();
const skin = await SkinModel.fromMd5(ctx, "a_fake_md5");
expect(skin?.getMd5()).toBe("a_fake_md5");
});
describe("fromAnything", () => {
test("md5", async () => {
const ctx = new UserContext();
const skin = await SkinModel.fromAnything(
ctx,
"48bbdbbeb03d347e59b1eebda4d352d0"
);
expect(skin?.getMd5()).toBe("48bbdbbeb03d347e59b1eebda4d352d0");
});
});

View file

@ -5,85 +5,125 @@ beforeEach(async () => {
await knex.migrate.latest();
});
describe("empty", () => {
test("empty", async () => {
expect(await Skins.getAllClassicSkins()).toEqual([]);
expect(await Skins.getClassicSkinCount()).toBe(0);
expect(await Skins.getTweetableSkinCount()).toBe(0);
expect(await Skins.getAllClassicScreenshotUrls()).toEqual([]);
expect(await Skins.getMuseumPage({ offset: 0, first: 10 })).toEqual([]);
expect(await Skins.getStats()).toEqual({
approved: 0,
rejected: 0,
nsfw: 0,
tweeted: 0,
tweetable: 0,
webUploads: 0,
});
expect(await Skins.getSkinToTweet()).toBe(null);
expect(Skins.getSkinToReview()).rejects.toThrow(
"Could not find any skins to review"
);
expect(await Skins.getReportedUpload()).toBe(null);
expect(await Skins.getSkinToShoot()).toBe(null);
expect(await Skins.getUploadStatuses([])).toEqual({});
test("empty", async () => {
expect(await Skins.getAllClassicSkins()).toEqual([]);
expect(await Skins.getClassicSkinCount()).toBe(0);
expect(await Skins.getTweetableSkinCount()).toBe(0);
expect(await Skins.getAllClassicScreenshotUrls()).toEqual([]);
expect(await Skins.getMuseumPage({ offset: 0, first: 10 })).toEqual([]);
expect(await Skins.getStats()).toEqual({
approved: 0,
rejected: 0,
nsfw: 0,
tweeted: 0,
tweetable: 0,
webUploads: 0,
});
expect(await Skins.getSkinToTweet()).toBe(null);
expect(Skins.getSkinToReview()).rejects.toThrow(
"Could not find any skins to review"
);
expect(await Skins.getReportedUpload()).toBe(null);
expect(await Skins.getSkinToShoot()).toBe(null);
expect(await Skins.getUploadStatuses([])).toEqual({});
});
describe("seeded", () => {
beforeEach(async () => {
await knex.seed.run();
});
test("empty", async () => {
expect(await Skins.getAllClassicSkins()).toEqual([
{ fileName: "path.wsz", md5: "a_fake_md5" },
{ fileName: "nsfw.wsz", md5: "a_nsfw_md5" },
{ fileName: "rejected.wsz", md5: "a_rejected_md5" },
{ fileName: "approved.wsz", md5: "an_approved_md5" },
]);
expect(await Skins.getClassicSkinCount()).toBe(4);
test("getAllClassicSkins", async () => {
expect(await Skins.getAllClassicSkins()).toMatchInlineSnapshot(`
Array [
Object {
"fileName": "Zelda_Amp_3.wsz",
"md5": "48bbdbbeb03d347e59b1eebda4d352d0",
},
Object {
"fileName": "path.wsz",
"md5": "a_fake_md5",
},
Object {
"fileName": "nsfw.wsz",
"md5": "a_nsfw_md5",
},
Object {
"fileName": "rejected.wsz",
"md5": "a_rejected_md5",
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
},
]
`);
});
test("getClassicSkinCount", async () => {
expect(await Skins.getClassicSkinCount()).toBe(5);
});
test("getTweetableSkinCount", async () => {
expect(await Skins.getTweetableSkinCount()).toBe(1);
expect(await Skins.getAllClassicScreenshotUrls()).toEqual([
{
fileName: "path.wsz",
url: "https://cdn.webampskins.org/screenshots/a_fake_md5.png",
},
{
fileName: "nsfw.wsz",
url: "https://cdn.webampskins.org/screenshots/a_nsfw_md5.png",
},
{
fileName: "rejected.wsz",
url: "https://cdn.webampskins.org/screenshots/a_rejected_md5.png",
},
{
fileName: "approved.wsz",
url: "https://cdn.webampskins.org/screenshots/an_approved_md5.png",
},
]);
expect(await Skins.getMuseumPage({ offset: 0, first: 10 })).toEqual([
{
fileName: "path.wsz",
md5: "a_fake_md5",
nsfw: false,
},
{
fileName: "approved.wsz",
md5: "an_approved_md5",
nsfw: false,
},
{
fileName: "rejected.wsz",
md5: "a_rejected_md5",
nsfw: false,
},
{
fileName: "nsfw.wsz",
md5: "a_nsfw_md5",
nsfw: true,
},
]);
});
test("getAllClassicScreenshotUrls", async () => {
expect(await Skins.getAllClassicScreenshotUrls()).toMatchInlineSnapshot(`
Array [
Object {
"fileName": "Zelda_Amp_3.wsz",
"url": "https://cdn.webampskins.org/screenshots/48bbdbbeb03d347e59b1eebda4d352d0.png",
},
Object {
"fileName": "path.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_fake_md5.png",
},
Object {
"fileName": "nsfw.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_nsfw_md5.png",
},
Object {
"fileName": "rejected.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_rejected_md5.png",
},
Object {
"fileName": "approved.wsz",
"url": "https://cdn.webampskins.org/screenshots/an_approved_md5.png",
},
]
`);
});
test("getMuseumPage", async () => {
expect(await Skins.getMuseumPage({ offset: 0, first: 10 }))
.toMatchInlineSnapshot(`
Array [
Object {
"fileName": "Zelda_Amp_3.wsz",
"md5": "48bbdbbeb03d347e59b1eebda4d352d0",
"nsfw": false,
},
Object {
"fileName": "path.wsz",
"md5": "a_fake_md5",
"nsfw": false,
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
"nsfw": false,
},
Object {
"fileName": "rejected.wsz",
"md5": "a_rejected_md5",
"nsfw": false,
},
Object {
"fileName": "nsfw.wsz",
"md5": "a_nsfw_md5",
"nsfw": true,
},
]
`);
});
test("getStats", async () => {
expect(await Skins.getStats()).toEqual({
approved: 1,
rejected: 1,
@ -92,16 +132,27 @@ describe("seeded", () => {
tweetable: 1,
webUploads: 0,
});
});
test("getSkinToTweet", async () => {
expect(await Skins.getSkinToTweet()).toEqual({
canonicalFilename: "approved.wsz",
md5: "an_approved_md5",
});
});
test("getSkinToReview", async () => {
expect(Skins.getSkinToReview()).rejects.toThrow(
"Could not find any skins to review"
);
});
test("getReportedUpload", async () => {
expect(await Skins.getReportedUpload()).toBe(null);
expect(await Skins.getSkinToShoot()).toBe("a_fake_md5");
});
test("getSkinToShoot", async () => {
expect(await Skins.getSkinToShoot()).toBe(
"48bbdbbeb03d347e59b1eebda4d352d0"
);
});
test("getUploadStatuses", async () => {
expect(await Skins.getUploadStatuses([])).toEqual({});
});
});

View file

@ -55,8 +55,6 @@ export async function addSkin({
);
}
const IA_URL = /^(https:\/\/)?archive.org\/details\/([^\/]+)\/?/;
const CRUFT_FILENAME = /winampskins\.info\.(html)|(txt)$/;
export async function setContentHash(md5: string): Promise<string | null> {
@ -77,28 +75,6 @@ export async function setContentHash(md5: string): Promise<string | null> {
return contentHash;
}
export async function getMd5ByAnything(
anything: string
): Promise<string | null> {
const md5Match = anything.match(MD5_REGEX);
if (md5Match != null) {
const md5 = md5Match[1];
const found = await knex("skins").where({ md5, skin_type: 1 }).first();
if (found != null) {
return md5;
}
}
const itemMatchResult = anything.match(IA_URL);
if (itemMatchResult != null) {
const itemName = itemMatchResult[2];
const md5 = await getMd5FromInternetArchvieItemName(itemName);
if (md5 != null) {
return md5;
}
}
return (await getMd5FromInternetArchvieItemName(anything)) ?? null;
}
export async function getSkinDebugData(md5: string): Promise<any | null> {
const skin = await knex("skins").where({ md5 }).select();
const searchIndexUpdates = await knex("algolia_field_updates")
@ -126,12 +102,6 @@ export async function getSkinDebugData(md5: string): Promise<any | null> {
};
}
async function getMd5FromInternetArchvieItemName(itemName: string) {
const ctx = new UserContext();
const item = await IaItemModel.fromIdentifier(ctx, itemName);
return item?.getMd5();
}
export async function getTweetableSkinCount(): Promise<number> {
const tweetable = await knex("skins")
.leftJoin("skin_reviews", "skin_reviews.skin_md5", "=", "skins.md5")

View file

@ -1,21 +1,23 @@
import { Message } from "discord.js";
import * as Utils from "../utils";
import * as Skins from "../../data/skins";
import UserContext from "../../data/UserContext";
import SkinModel from "../../data/SkinModel";
async function handler(message: Message, args: [string]) {
const ctx = new UserContext();
const [anything] = args;
if (anything == null) {
message.channel.send(`<md5-skin> is required.`);
return;
}
const md5 = await Skins.getMd5ByAnything(anything);
if (md5 == null) {
const skin = await SkinModel.fromAnything(ctx, anything);
if (skin == null) {
message.channel.send(`Could not find a skin matching ${anything}`);
return;
}
await Utils.postSkin({
md5,
md5: skin.getMd5(),
dest: message.channel,
});
}

View file

@ -12,6 +12,7 @@ export async function seed(knex: Knex): Promise<any> {
{ md5: "an_approved_md5", skin_type: 1 },
{ md5: "a_rejected_md5", skin_type: 1 },
{ md5: "a_nsfw_md5", skin_type: 1 },
{ md5: "48bbdbbeb03d347e59b1eebda4d352d0", skin_type: 1 },
]);
await knex("files").insert([
{ skin_md5: "a_fake_md5", file_path: "/a/fake/path.wsz" },
@ -19,6 +20,10 @@ export async function seed(knex: Knex): Promise<any> {
{ skin_md5: "an_approved_md5", file_path: "/a/fake/approved.wsz" },
{ skin_md5: "a_rejected_md5", file_path: "/a/fake/rejected.wsz" },
{ skin_md5: "a_nsfw_md5", file_path: "/a/fake/nsfw.wsz" },
{
skin_md5: "48bbdbbeb03d347e59b1eebda4d352d0",
file_path: "/a/fake/Zelda_Amp_3.wsz",
},
]);
await knex("skin_reviews").insert([
{ skin_md5: "an_approved_md5", review: "APPROVED" },

View file

@ -18,23 +18,14 @@ export async function tweet(discordClient: Client, anything: string | null) {
}
let tweetableSkin: null | SkinModel = null;
if (anything != null) {
const _md5 = await Skins.getMd5ByAnything(anything);
if (_md5 == null) {
tweetableSkin = await SkinModel.fromAnything(ctx, anything);
if (tweetableSkin == null) {
// @ts-ignore
await tweetBotChannel.send(
`Oops! Could not find a skin matching ${anything}`
);
return;
}
tweetableSkin = await SkinModel.fromMd5(ctx, _md5);
if (tweetableSkin == null) {
// @ts-ignore
await tweetBotChannel.send(
`Oops! Could not find a skin matching the md5 hash ${_md5}`
);
logger.info(`Could not find a skin matching hash ${_md5}`);
return;
}
const tweetStatus = await tweetableSkin.getTweetStatus();
if (tweetStatus == "TWEETED") {
// @ts-ignore