mirror of
https://github.com/captbaritone/webamp.git
synced 2026-07-27 03:54:24 +00:00
Expose statistics in GraphQL
This commit is contained in:
parent
bfa7e87bd4
commit
a7173e8da5
4 changed files with 174 additions and 44 deletions
|
|
@ -0,0 +1,34 @@
|
|||
import * as Skins from "../../../data/Skins";
|
||||
|
||||
export default class DatabaseStatisticsResolver {
|
||||
unique_classic_skins_count(): Promise<number> {
|
||||
return Skins.getClassicSkinCount();
|
||||
}
|
||||
tweeted_skins_count(): Promise<number> {
|
||||
return Skins.getTweetedSkinCount();
|
||||
}
|
||||
approved_skins_count(): Promise<number> {
|
||||
return Skins.getApprovedSkinCount();
|
||||
}
|
||||
rejected_skins_count(): Promise<number> {
|
||||
return Skins.getRejectedSkinCount();
|
||||
}
|
||||
nsfw_skins_count(): Promise<number> {
|
||||
return Skins.getNsfwSkinCount();
|
||||
}
|
||||
unreviewed_skins_count(): Promise<number> {
|
||||
return Skins.getUnreviewedSkinCount();
|
||||
}
|
||||
tweetable_skins_count(): Promise<number> {
|
||||
return Skins.getTweetableSkinCount();
|
||||
}
|
||||
uploads_pending_processing_count(): Promise<number> {
|
||||
return Skins.getUploadsAwaitingProcessingCount();
|
||||
}
|
||||
uploads_in_error_state_count(): Promise<number> {
|
||||
return Skins.getUploadsErroredCount();
|
||||
}
|
||||
web_uploads_count(): Promise<number> {
|
||||
return Skins.getWebUploadsCount();
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import MutationResolver from "./MutationResolver";
|
|||
import { knex } from "../../../db";
|
||||
import ArchiveFileModel from "../../../data/ArchiveFileModel";
|
||||
import ArchiveFileResolver from "./ArchiveFileResolver";
|
||||
import DatabaseStatisticsResolver from "./DatabaseStatisticsResolver";
|
||||
|
||||
// These keys are already in the web client, so they are not secret at all.
|
||||
const client = algoliasearch("HQ9I5Z6IM5", "6466695ec3f624a5fccf46ec49680e51");
|
||||
|
|
@ -54,7 +55,7 @@ class RootResolver extends MutationResolver {
|
|||
throw new Error("Can only query 1000 records via search.");
|
||||
}
|
||||
|
||||
const results = await index.search(query, {
|
||||
const results: { hits: { md5: string }[] } = await index.search(query, {
|
||||
attributesToRetrieve: ["md5"],
|
||||
length: first,
|
||||
offset,
|
||||
|
|
@ -112,6 +113,10 @@ class RootResolver extends MutationResolver {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
statistics() {
|
||||
return new DatabaseStatisticsResolver();
|
||||
}
|
||||
}
|
||||
|
||||
export default RootResolver;
|
||||
|
|
|
|||
|
|
@ -426,6 +426,72 @@ type Mutation {
|
|||
request_nsfw_review_for_skin(md5: String): Boolean
|
||||
}
|
||||
|
||||
"""
|
||||
Statistics about the contents of the Museum's database.
|
||||
"""
|
||||
type DatabaseStatistics {
|
||||
"""
|
||||
The total number of classic skins in the Museum's database
|
||||
"""
|
||||
unique_classic_skins_count: Int
|
||||
|
||||
"""
|
||||
The number of skins in the Museum that have been tweeted by @winampskins
|
||||
"""
|
||||
tweeted_skins_count: Int
|
||||
|
||||
"""
|
||||
The number of skins that have been approved for tweeting. This includes both
|
||||
tweeted and untweeted skins.
|
||||
|
||||
**Note:** Skins can be both approved and rejected by different users.
|
||||
"""
|
||||
approved_skins_count: Int
|
||||
|
||||
"""
|
||||
The number of skins that have been rejected for tweeting.
|
||||
|
||||
**Note:** Skins can be both approved and rejected by different users.
|
||||
**Note:** Generally skins that have been marked NSFW are also marked as rejected.
|
||||
"""
|
||||
rejected_skins_count: Int
|
||||
|
||||
"""
|
||||
The number of skins that have been marked as NSFW.
|
||||
|
||||
**Note:** Skins can be approved and rejected by different users.
|
||||
**Note:** Generally skins that have been marked NSFW are also marked as rejected.
|
||||
"""
|
||||
nsfw_skins_count: Int
|
||||
|
||||
"""
|
||||
The number of skins that have never been reviewed.
|
||||
"""
|
||||
unreviewed_skins_count: Int
|
||||
|
||||
"""
|
||||
The number of skins that have been approved for tweeting, but not yet tweeted.
|
||||
"""
|
||||
tweetable_skins_count: Int
|
||||
|
||||
"""
|
||||
Skins uplaods awaiting processing. This can happen when there are a large
|
||||
number of skin uplaods at the same time, or when the skin uploading processing
|
||||
pipeline gets stuck.
|
||||
"""
|
||||
uploads_pending_processing_count: Int
|
||||
|
||||
"""
|
||||
Skins uploads that have errored during processing.
|
||||
"""
|
||||
uploads_in_error_state_count: Int
|
||||
|
||||
"""
|
||||
Number of skins that have been uploaded to the Museum via the web interface.
|
||||
"""
|
||||
web_uploads_count: Int
|
||||
}
|
||||
|
||||
type Query {
|
||||
"""
|
||||
The currently authenticated user, if any.
|
||||
|
|
@ -503,4 +569,9 @@ type Query {
|
|||
Get the status of a batch of uploads by ids
|
||||
"""
|
||||
upload_statuses(ids: [String!]!): [SkinUpload]
|
||||
|
||||
"""
|
||||
A namespace for statistics about the database
|
||||
"""
|
||||
statistics: DatabaseStatistics
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,6 +427,61 @@ export async function getSkinToPostToInstagram(): Promise<string | null> {
|
|||
return skin.md5;
|
||||
}
|
||||
|
||||
export async function getUnreviewedSkinCount(): Promise<number> {
|
||||
const rows = await knex("skins")
|
||||
.where({ skin_type: 1 })
|
||||
.whereNotIn("md5", knex("skin_reviews").select("skin_md5"))
|
||||
.count("*", { as: "unreviewed" });
|
||||
return Number(rows[0].unreviewed);
|
||||
}
|
||||
|
||||
export async function getApprovedSkinCount(): Promise<number> {
|
||||
const row = await knex("skin_reviews")
|
||||
.first(knex.raw(`COUNT(DISTINCT skin_md5) AS "approved_count"`))
|
||||
.where({ review: "APPROVED" });
|
||||
return Number(row.approved_count);
|
||||
}
|
||||
|
||||
export async function getRejectedSkinCount(): Promise<number> {
|
||||
const row = await knex("skin_reviews")
|
||||
.first(knex.raw(`COUNT(DISTINCT skin_md5) AS "rejected_count"`))
|
||||
.where({ review: "REJECTED" });
|
||||
return Number(row.rejected_count);
|
||||
}
|
||||
|
||||
export async function getNsfwSkinCount(): Promise<number> {
|
||||
const row = await knex("skin_reviews")
|
||||
.first(knex.raw(`COUNT(DISTINCT skin_md5) AS "nsfw_count"`))
|
||||
.where({ review: "NSFW" });
|
||||
return Number(row.nsfw_count);
|
||||
}
|
||||
|
||||
export async function getTweetedSkinCount(): Promise<number> {
|
||||
const rows = await knex("tweets").count("*", { as: "tweeted" });
|
||||
return Number(rows[0].tweeted);
|
||||
}
|
||||
|
||||
export async function getWebUploadsCount(): Promise<number> {
|
||||
const rows = await knex("files")
|
||||
.where("source_attribution", "Web API")
|
||||
.count("*", { as: "uploads" });
|
||||
return Number(rows[0].uploads);
|
||||
}
|
||||
|
||||
export async function getUploadsAwaitingProcessingCount(): Promise<number> {
|
||||
const rows = await knex("skin_uploads")
|
||||
.where("status", "UPLOAD_REPORTED")
|
||||
.count("*", { as: "uploads" });
|
||||
return Number(rows[0].uploads);
|
||||
}
|
||||
|
||||
export async function getUploadsErroredCount(): Promise<number> {
|
||||
const rows = await knex("skin_uploads")
|
||||
.where("status", "ERRORED")
|
||||
.count("*", { as: "uploads" });
|
||||
return Number(rows[0].uploads);
|
||||
}
|
||||
|
||||
export async function getStats(): Promise<{
|
||||
approved: number;
|
||||
rejected: number;
|
||||
|
|
@ -437,50 +492,15 @@ export async function getStats(): Promise<{
|
|||
uploadsAwaitingProcessing: number;
|
||||
uploadsErrored: number;
|
||||
}> {
|
||||
const approved = (
|
||||
await knex("skin_reviews")
|
||||
.first(knex.raw(`COUNT(DISTINCT skin_md5) AS "approved_count"`))
|
||||
.where({ review: "APPROVED" })
|
||||
).approved_count;
|
||||
const rejected = (
|
||||
await knex("skin_reviews")
|
||||
.first(knex.raw(`COUNT(DISTINCT skin_md5) AS "rejected_count"`))
|
||||
.where({ review: "REJECTED" })
|
||||
).rejected_count;
|
||||
const nsfw = (
|
||||
await knex("skin_reviews")
|
||||
.first(knex.raw(`COUNT(DISTINCT skin_md5) AS "nsfw_count"`))
|
||||
.where({ review: "NSFW" })
|
||||
).nsfw_count;
|
||||
const tweeted = (await knex("tweets").count("*", { as: "tweeted" }))[0]
|
||||
.tweeted;
|
||||
const webUploads = (
|
||||
await knex("files")
|
||||
.where("source_attribution", "Web API")
|
||||
.count("*", { as: "uploads" })
|
||||
)[0].uploads;
|
||||
|
||||
const uploadsAwaitingProcessing = (
|
||||
await knex("skin_uploads")
|
||||
.where("status", "UPLOAD_REPORTED")
|
||||
.count("*", { as: "uploads" })
|
||||
)[0].uploads;
|
||||
|
||||
const uploadsErrored = (
|
||||
await knex("skin_uploads")
|
||||
.where("status", "ERRORED")
|
||||
.count("*", { as: "uploads" })
|
||||
)[0].uploads;
|
||||
const tweetable = await getTweetableSkinCount();
|
||||
return {
|
||||
approved: Number(approved),
|
||||
rejected: Number(rejected),
|
||||
nsfw: Number(nsfw),
|
||||
tweeted: Number(tweeted),
|
||||
tweetable,
|
||||
webUploads: Number(webUploads),
|
||||
uploadsAwaitingProcessing: Number(uploadsAwaitingProcessing),
|
||||
uploadsErrored: Number(uploadsErrored),
|
||||
approved: await getApprovedSkinCount(),
|
||||
rejected: await getRejectedSkinCount(),
|
||||
nsfw: await getNsfwSkinCount(),
|
||||
tweeted: await getTweetedSkinCount(),
|
||||
tweetable: await getTweetableSkinCount(),
|
||||
webUploads: await getWebUploadsCount(),
|
||||
uploadsAwaitingProcessing: await getUploadsAwaitingProcessingCount(),
|
||||
uploadsErrored: await getUploadsErroredCount(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue