Get skins by tweet id

This commit is contained in:
Jordan Eldredge 2020-12-01 18:45:24 -05:00
parent 986aecc708
commit afe22daee5
7 changed files with 119 additions and 16 deletions

View file

@ -82,7 +82,7 @@ describe("/skins/", () => {
const { body } = await request(app).get("/skins/");
expect(body).toMatchInlineSnapshot(`
Object {
"skinCount": 5,
"skinCount": 6,
"skins": Array [
Object {
"fileName": "Zelda_Amp_3.wsz",
@ -94,6 +94,11 @@ describe("/skins/", () => {
"md5": "a_fake_md5",
"nsfw": false,
},
Object {
"fileName": "tweeted.wsz",
"md5": "a_tweeted_md5",
"nsfw": false,
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
@ -119,7 +124,7 @@ describe("/skins/", () => {
.query({ first: 2, offset: 1 });
expect(body).toMatchInlineSnapshot(`
Object {
"skinCount": 5,
"skinCount": 6,
"skins": Array [
Object {
"fileName": "path.wsz",
@ -127,8 +132,8 @@ describe("/skins/", () => {
"nsfw": false,
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
"fileName": "tweeted.wsz",
"md5": "a_tweeted_md5",
"nsfw": false,
},
],
@ -212,7 +217,7 @@ test("/skins/a_md5_that_does_not_exist/reject (404)", async () => {
expect(handler).not.toHaveBeenCalled();
});
test.only("/skins/a_fake_md5/nsfw", async () => {
test("/skins/a_fake_md5/nsfw", async () => {
const ctx = new UserContext();
const { body } = await request(app)
.post("/skins/a_fake_md5/nsfw")
@ -338,6 +343,10 @@ test("/stylegan.json", async () => {
"fileName": "rejected.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_rejected_md5.png",
},
Object {
"fileName": "tweeted.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_tweeted_md5.png",
},
Object {
"fileName": "approved.wsz",
"url": "https://cdn.webampskins.org/screenshots/an_approved_md5.png",

View file

@ -4,7 +4,7 @@ import UserContext, { ctxWeakMapMemoize } from "./UserContext";
import TweetModel, { TweetDebugData } from "./TweetModel";
import IaItemModel from "./IaItemModel";
import FileModel, { FileDebugData } from "./FileModel";
import { MD5_REGEX } from "../utils";
import { MD5_REGEX, TWEET_ID_REGEX } from "../utils";
import DataLoader from "dataloader";
import { knex } from "../db";
@ -32,7 +32,14 @@ export default class SkinModel {
}
}
const iaItem = await IaItemModel.fromAnything(ctx, anything);
return iaItem?.getSkin() ?? null;
if (iaItem != null) {
return iaItem.getSkin();
}
const tweet = await TweetModel.fromAnything(ctx, anything);
if (tweet != null) {
return tweet.getSkin();
}
return null;
}
static async exists(ctx: UserContext, md5: string): Promise<boolean> {

View file

@ -2,6 +2,8 @@ import UserContext, { ctxWeakMapMemoize } from "./UserContext";
import { TweetRow } from "../types";
import DataLoader from "dataloader";
import { knex } from "../db";
import { TWEET_SNOWFLAKE_REGEX } from "../utils";
import SkinModel from "./SkinModel";
export type TweetDebugData = {
row: TweetRow;
@ -15,6 +17,37 @@ export default class TweetModel {
return rows.map((row) => new TweetModel(ctx, row));
}
static async fromUrl(
ctx: UserContext,
url: string
): Promise<TweetModel | null> {
const row = await getTweetByTweetUrlLoader(ctx).load(url);
if (row == null) {
return null;
}
return new TweetModel(ctx, row);
}
static async fromAnything(
ctx: UserContext,
anything: string
): Promise<TweetModel | null> {
const snowflakeMatch = anything.match(TWEET_SNOWFLAKE_REGEX);
if (snowflakeMatch == null) {
return null;
}
const snowflake = snowflakeMatch[1];
const found = await TweetModel.fromUrl(
ctx,
`https://twitter.com/winampskins/status/${snowflake}`
);
return found || null;
}
getMd5(): string {
return this.row.skin_md5;
}
getUrl(): string {
return this.row.url;
}
@ -25,6 +58,14 @@ export default class TweetModel {
return this.row.retweets;
}
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;
}
async debug(): Promise<TweetDebugData> {
return {
row: this.row,
@ -39,3 +80,13 @@ const getTweetsLoader = ctxWeakMapMemoize<DataLoader<string, TweetRow[]>>(
return md5s.map((md5) => rows.filter((x) => x.skin_md5 === md5));
})
);
const getTweetByTweetUrlLoader = ctxWeakMapMemoize<
DataLoader<string, TweetRow>
>(
() =>
new DataLoader(async (urls) => {
const rows = await knex("tweets").whereIn("url", urls).select();
return urls.map((url) => rows.find((x) => x.url === url));
})
);

View file

@ -51,4 +51,12 @@ describe("fromAnything", () => {
);
expect(skin?.getMd5()).toBe("a_fake_md5");
});
test("Tweet URL", async () => {
const ctx = new UserContext();
const skin = await SkinModel.fromAnything(
ctx,
"https://twitter.com/winampskins/status/1333893671326871552"
);
expect(skin?.getMd5()).toBe("a_tweeted_md5");
});
});

View file

@ -52,6 +52,10 @@ describe("seeded", () => {
"fileName": "rejected.wsz",
"md5": "a_rejected_md5",
},
Object {
"fileName": "tweeted.wsz",
"md5": "a_tweeted_md5",
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
@ -60,7 +64,7 @@ describe("seeded", () => {
`);
});
test("getClassicSkinCount", async () => {
expect(await Skins.getClassicSkinCount()).toBe(5);
expect(await Skins.getClassicSkinCount()).toBe(6);
});
test("getTweetableSkinCount", async () => {
expect(await Skins.getTweetableSkinCount()).toBe(1);
@ -84,6 +88,10 @@ describe("seeded", () => {
"fileName": "rejected.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_rejected_md5.png",
},
Object {
"fileName": "tweeted.wsz",
"url": "https://cdn.webampskins.org/screenshots/a_tweeted_md5.png",
},
Object {
"fileName": "approved.wsz",
"url": "https://cdn.webampskins.org/screenshots/an_approved_md5.png",
@ -105,6 +113,11 @@ describe("seeded", () => {
"md5": "a_fake_md5",
"nsfw": false,
},
Object {
"fileName": "tweeted.wsz",
"md5": "a_tweeted_md5",
"nsfw": false,
},
Object {
"fileName": "approved.wsz",
"md5": "an_approved_md5",
@ -124,14 +137,16 @@ describe("seeded", () => {
`);
});
test("getStats", async () => {
expect(await Skins.getStats()).toEqual({
approved: 1,
rejected: 1,
nsfw: 1,
tweeted: 0,
tweetable: 1,
webUploads: 0,
});
expect(await Skins.getStats()).toMatchInlineSnapshot(`
Object {
"approved": 2,
"nsfw": 1,
"rejected": 1,
"tweetable": 1,
"tweeted": 1,
"webUploads": 0,
}
`);
});
test("getSkinToTweet", async () => {
expect(await Skins.getSkinToTweet()).toEqual({

View file

@ -6,6 +6,7 @@ export async function seed(knex: Knex): Promise<any> {
await knex("files").del();
await knex("skin_reviews").del();
await knex("ia_items").del();
await knex("tweets").del();
// Inserts seed entries
await knex("skins").insert([
{ md5: "a_fake_md5", skin_type: 1, emails: "" },
@ -13,6 +14,7 @@ export async function seed(knex: Knex): Promise<any> {
{ md5: "an_approved_md5", skin_type: 1, emails: "" },
{ md5: "a_rejected_md5", skin_type: 1, emails: "" },
{ md5: "a_nsfw_md5", skin_type: 1, emails: "" },
{ md5: "a_tweeted_md5", skin_type: 1, emails: "" },
{ md5: "48bbdbbeb03d347e59b1eebda4d352d0", skin_type: 1, emails: "" },
]);
await knex("files").insert([
@ -21,6 +23,7 @@ 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: "a_tweeted_md5", file_path: "/a/fake/tweeted.wsz" },
{
skin_md5: "48bbdbbeb03d347e59b1eebda4d352d0",
file_path: "/a/fake/Zelda_Amp_3.wsz",
@ -29,10 +32,19 @@ export async function seed(knex: Knex): Promise<any> {
await knex("skin_reviews").insert([
{ skin_md5: "an_approved_md5", review: "APPROVED" },
{ skin_md5: "a_rejected_md5", review: "REJECTED" },
{ skin_md5: "a_tweeted_md5", review: "APPROVED" },
{ skin_md5: "a_nsfw_md5", review: "NSFW" },
]);
await knex("ia_items").insert([
{ skin_md5: "a_fake_md5", identifier: "a_fake_ia_identifier" },
]);
await knex("tweets").insert([
{
skin_md5: "a_tweeted_md5",
url: "https://twitter.com/winampskins/status/1333893671326871552",
tweet_id: "1333893671326871552",
},
]);
}

View file

@ -12,3 +12,4 @@ export function truncate(str: string, len: number): string {
}
export const MD5_REGEX = /([a-fA-F0-9]{32})/;
export const TWEET_SNOWFLAKE_REGEX = /([0-9]{19})/;