Spaces:
Running
Running
File size: 44,874 Bytes
5c2ed06 |
1 2 3 4 5 6 7 8 |
{
"version": 3,
"sources": ["../../../../server/chat-plugins/trivia/database.ts"],
"sourcesContent": ["/**\n * Manages the Trivia database.\n *\n * @author Annika\n */\n\nimport type {\n\tTriviaGame, TriviaHistory, TriviaLeaderboardData, TriviaLeaderboardScore, TriviaQuestion,\n} from \"./trivia\";\nimport { FS } from \"../../../lib\";\nimport { formatSQLArray } from \"../../../lib/utils\";\nimport type { Statement } from \"../../../lib/sql\";\n\nexport type Leaderboard = 'alltime' | 'nonAlltime' | 'cycle';\n/**\n * Keys are different Trivia leaderboards.\n * Values are the corresponding integer values of the SQLite `leaderboard` column.\n */\nexport const LEADERBOARD_ENUM: Record<Leaderboard, number> = {\n\talltime: 1,\n\tnonAlltime: 0,\n\tcycle: 2,\n};\n\ntype TriviaLeaderboards = Record<Leaderboard, TriviaLeaderboardData>;\n\nexport interface TriviaDatabase {\n\tupdateLeaderboardForUser(\n\t\tuserid: ID,\n\t\tadditions: Record<Leaderboard, TriviaLeaderboardScore>\n\t): Promise<void> | void;\n\taddHistory(history: Iterable<TriviaHistory>): Promise<void> | void;\n\taddQuestions(questions: Iterable<TriviaQuestion>): Promise<void> | void;\n\taddQuestionSubmissions(questions: Iterable<TriviaQuestion>): Promise<void> | void;\n\tsetShouldMoveEventQuestions(shouldMove: boolean): Promise<void> | void;\n\tmergeLeaderboardEntries(from: ID, to: ID): Promise<void> | void;\n\n\tshouldMoveEventQuestions(): Promise<boolean> | boolean;\n\tmoveQuestionToCategory(question: string, newCategory: string): Promise<void> | void;\n\tmigrateCategory(sourceCategory: string, targetCategory: string): Promise<number> | number;\n\tacceptSubmissions(submissions: string[]): Promise<void> | void;\n\teditQuestion(oldQuestionText: string, newQuestionText?: string, newAnswers?: string[]): Promise<void>;\n\n\tgetHistory(numberOfLines: number): Promise<TriviaGame[]> | TriviaGame[];\n\tgetScoresForLastGame(): Promise<{ [k: string]: number }> | { [k: string]: number };\n\tgetQuestions(\n\t\tcategories: string[] | 'all',\n\t\tlimit: number,\n\t\toptions: { order: 'newestfirst' | 'oldestfirst' | 'random' }\n\t): Promise<TriviaQuestion[]> | TriviaQuestion[];\n\tgetLeaderboardEntry(\n\t\tid: ID,\n\t\tleaderboard: Leaderboard\n\t): Promise<TriviaLeaderboardScore | null> | TriviaLeaderboardScore | null;\n\tgetLeaderboards(): Promise<TriviaLeaderboards> | TriviaLeaderboards;\n\n\tgetQuestion(questionText: string): Promise<TriviaQuestion | null> | TriviaQuestion | null;\n\tensureQuestionExists(questionText: string): Promise<TriviaQuestion> | TriviaQuestion;\n\tensureQuestionDoesNotExist(questionText: string): Promise<void> | void;\n\tgetSubmissions(): Promise<TriviaQuestion[]> | TriviaQuestion[];\n\tgetQuestionCounts(): Promise<{ [k: string]: number, total: number }> | { [k: string]: number, total: number };\n\tsearchQuestions(\n\t\tsearch: string,\n\t\toptions: { searchSubmissions: boolean, caseSensitive?: boolean }\n\t): Promise<TriviaQuestion[]> | TriviaQuestion[];\n\n\tclearSubmissions(): Promise<void> | void;\n\tclearCategory(category: string): Promise<void> | void;\n\tclearCycleLeaderboard(): Promise<void> | void;\n\tdeleteQuestion(questionText: string): Promise<void> | void;\n\tdeleteLeaderboardEntry(userid: ID, leaderboard: Leaderboard): Promise<void> | void;\n\tdeleteSubmissions(submissions: string[]): Promise<void> | void;\n}\n\nexport class TriviaSQLiteDatabase implements TriviaDatabase {\n\treadyPromise: Promise<void> | null;\n\n\tprivate legacyJSONPath?: string;\n\n\t// adding data\n\tprivate leaderboardInsertion: Statement | null;\n\tprivate questionInsertion: Statement | null;\n\tprivate answerInsertion: Statement | null;\n\tprivate gameHistoryInsertion: Statement | null;\n\tprivate scoreHistoryInsertion: Statement | null;\n\tprivate updateMoveEventQuestions: Statement | null;\n\n\t// modifying data\n\tprivate categoryChangeQuery: Statement | null;\n\tprivate leaderboardChangeQuery: Statement | null;\n\tprivate migrateCategoryQuery: Statement | null;\n\n\t// fetching data\n\tprivate historyQuery: Statement | null;\n\tprivate historyScoresQuery: Statement | null;\n\tprivate allQuestionsRandomOrderQuery: Statement | null;\n\tprivate allQuestionsNewestFirstQuery: Statement | null;\n\tprivate allQuestionsOldestFirstQuery: Statement | null;\n\tprivate answersQuery: Statement | null;\n\tprivate submissionsQuery: Statement | null;\n\tprivate leaderboardQuery: Statement | null;\n\tprivate leaderboardByUserQuery: Statement | null;\n\tprivate scoreAndPointsByUser: Statement | null;\n\tprivate eventQuestionQuery: Statement | null;\n\tprivate categoriesQuery: Statement | null;\n\tprivate questionCountQuery: Statement | null;\n\tprivate categoryQuestionCountQuery: Statement | null;\n\tprivate questionSearchQuery: Statement | null;\n\tprivate questionExistsQuery: Statement | null;\n\n\t// deleting data\n\tprivate clearAllSubmissionsQuery: Statement | null;\n\tprivate clearCategoryQuery: Statement | null;\n\tprivate clearCycleLeaderboardQuery: Statement | null;\n\tprivate deleteQuestionQuery: Statement | null;\n\tprivate leaderboardDeletionQuery: Statement | null;\n\n\tconstructor(legacyJSONPath?: string) {\n\t\tthis.legacyJSONPath = legacyJSONPath;\n\n\t\tthis.leaderboardInsertion = null;\n\t\tthis.questionInsertion = null;\n\t\tthis.answerInsertion = null;\n\t\tthis.gameHistoryInsertion = null;\n\t\tthis.scoreHistoryInsertion = null;\n\t\tthis.updateMoveEventQuestions = null;\n\n\t\tthis.categoryChangeQuery = null;\n\t\tthis.leaderboardChangeQuery = null;\n\t\tthis.migrateCategoryQuery = null;\n\n\t\tthis.historyQuery = null;\n\t\tthis.historyScoresQuery = null;\n\t\tthis.allQuestionsRandomOrderQuery = null;\n\t\tthis.allQuestionsNewestFirstQuery = null;\n\t\tthis.allQuestionsOldestFirstQuery = null;\n\t\tthis.answersQuery = null;\n\t\tthis.submissionsQuery = null;\n\t\tthis.leaderboardQuery = null;\n\t\tthis.leaderboardByUserQuery = null;\n\t\tthis.scoreAndPointsByUser = null;\n\t\tthis.eventQuestionQuery = null;\n\t\tthis.categoriesQuery = null;\n\t\tthis.questionCountQuery = null;\n\t\tthis.categoryQuestionCountQuery = null;\n\t\tthis.questionSearchQuery = null;\n\t\tthis.questionExistsQuery = null;\n\n\t\tthis.clearAllSubmissionsQuery = null;\n\t\tthis.clearCategoryQuery = null;\n\t\tthis.clearCycleLeaderboardQuery = null;\n\t\tthis.deleteQuestionQuery = null;\n\t\tthis.leaderboardDeletionQuery = null;\n\n\t\tthis.readyPromise = this.prepareStatements().then(() => {\n\t\t\tvoid this.convertLegacyJSON();\n\t\t\tthis.readyPromise = null;\n\t\t});\n\t}\n\n\t/***************************\n\t * Methods for adding data *\n\t ***************************/\n\tasync updateLeaderboardForUser(\n\t\tuserid: ID,\n\t\tadditions: Record<Leaderboard, TriviaLeaderboardScore>,\n\t): Promise<void> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't update the leaderboard for ${userid} because SQLite is not enabled.`);\n\t\t}\n\n\t\tfor (const [lb, discrim] of Object.entries(LEADERBOARD_ENUM) as [Leaderboard, number][]) {\n\t\t\tif (!additions[lb]) continue;\n\t\t\tawait this.leaderboardChangeQuery!.run({\n\t\t\t\tscore: additions[lb].score,\n\t\t\t\ttotalPoints: additions[lb].totalPoints,\n\t\t\t\ttotalCorrectAnswers: additions[lb].totalCorrectAnswers,\n\t\t\t\tuserid,\n\t\t\t\tleaderboard: discrim,\n\t\t\t});\n\t\t}\n\t}\n\n\tasync addHistory(history: Iterable<TriviaHistory>) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't add a Trivia game to the history because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst res = await Chat.database.transaction('addHistory', {\n\t\t\thistory,\n\t\t\tgameHistoryInsertion: this.gameHistoryInsertion!.toString(),\n\t\t\tscoreHistoryInsertion: this.scoreHistoryInsertion!.toString(),\n\t\t});\n\t\tif (!res) throw new Error(`Error updating Trivia history.`);\n\t}\n\n\tasync addQuestions(questions: Iterable<TriviaQuestion>) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't add a Trivia question because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst res = await Chat.database.transaction('addQuestions', {\n\t\t\tquestions,\n\t\t\tquestionInsertion: this.questionInsertion!.toString(),\n\t\t\tanswerInsertion: this.answerInsertion!.toString(),\n\t\t\tisSubmission: false,\n\t\t});\n\t\tif (!res) throw new Chat.ErrorMessage(`Error adding Trivia questions.`);\n\t}\n\n\tasync addQuestionSubmissions(questions: Iterable<TriviaQuestion>) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't submit a Trivia question for review because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst res = await Chat.database.transaction('addQuestions', {\n\t\t\tquestions,\n\t\t\tquestionInsertion: this.questionInsertion!.toString(),\n\t\t\tanswerInsertion: this.answerInsertion!.toString(),\n\t\t\tisSubmission: true,\n\t\t});\n\t\tif (!res) throw new Chat.ErrorMessage(`Error adding Trivia questions for review.`);\n\t}\n\n\tasync setShouldMoveEventQuestions(shouldMove: boolean) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't enable/disable moving event questions because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait this.updateMoveEventQuestions!.run([Number(shouldMove)]);\n\t}\n\n\t/******************************\n\t * Methods for modifying data *\n\t ******************************/\n\tasync mergeLeaderboardEntries(from: ID, to: ID) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't merge ${from} and ${to}'s Trivia leaderboard entries because SQLite is not enabled.`);\n\t\t}\n\n\t\tfor (const lbDiscrim of Object.values(LEADERBOARD_ENUM)) {\n\t\t\tconst fromScores = await this.scoreAndPointsByUser!.get([from, lbDiscrim]) || {\n\t\t\t\tscore: 0,\n\t\t\t\ttotalCorrectAnswers: 0,\n\t\t\t\ttotalPoints: 0,\n\t\t\t};\n\t\t\tconst toScores = (await this.scoreAndPointsByUser!.get([to, lbDiscrim])) || {\n\t\t\t\tscore: 0,\n\t\t\t\ttotalCorrectAnswers: 0,\n\t\t\t\ttotalPoints: 0,\n\t\t\t};\n\n\t\t\ttoScores.score += fromScores.score;\n\t\t\ttoScores.totalCorrectAnswers += fromScores.totalCorrectAnswers;\n\t\t\ttoScores.totalPoints += fromScores.totalPoints;\n\n\t\t\tawait Chat.database.run(\n\t\t\t\tthis.leaderboardInsertion!,\n\t\t\t\t[to, toScores.score, toScores.totalPoints, toScores.totalCorrectAnswers, lbDiscrim]\n\t\t\t);\n\t\t\tawait this.leaderboardDeletionQuery!.run([from, lbDiscrim]);\n\t\t}\n\t}\n\n\tasync shouldMoveEventQuestions() {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't find out if we are moving event questions because SQLite is not enabled.`);\n\t\t}\n\n\t\treturn (await this.eventQuestionQuery!.get([]) || { value: false }).value;\n\t}\n\n\tasync moveQuestionToCategory(question: string, newCategory: string) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't move question category because SQLite is not enabled.`);\n\t\t}\n\t\tawait this.categoryChangeQuery!.run([newCategory, question]);\n\t}\n\n\tasync migrateCategory(sourceCategory: string, targetCategory: string) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't migrate categories because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst { changes } = await this.migrateCategoryQuery!.run([targetCategory, sourceCategory]);\n\t\treturn changes;\n\t}\n\n\tasync acceptSubmissions(submissions: string[]) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't accept Trivia question submissions because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait Chat.database.run(\n\t\t\t`UPDATE trivia_questions SET is_submission = 0 WHERE question IN (${formatSQLArray(submissions)})`,\n\t\t\tsubmissions\n\t\t);\n\t}\n\n\tasync editQuestion(oldQuestionText: string, newQuestionText?: string, newAnswers?: string[]) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't edit Trivia question because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait Chat.database.transaction('editQuestion', {\n\t\t\toldQuestionText,\n\t\t\tnewQuestionText,\n\t\t\tnewAnswers,\n\t\t});\n\t}\n\n\t/*****************************\n\t * Methods for fetching data *\n\t *****************************/\n\tasync getHistory(numberOfLines = 10): Promise<TriviaGame[]> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't get Trivia game history because SQLite is not enabled.`);\n\t\t}\n\t\tconst rows = await this.historyQuery!.all([numberOfLines]);\n\t\treturn rows.map((row: AnyObject): TriviaGame => ({\n\t\t\tmode: row.mode,\n\t\t\tlength: /^d+$/.test(row.length) ? parseInt(row.length) || row.length : row.length,\n\t\t\tcategory: row.category,\n\t\t\tcreator: row.creator || undefined,\n\t\t\tgivesPoints: row.givesPoints !== 0,\n\t\t\tstartTime: row.time,\n\t\t}));\n\t}\n\n\tasync getScoresForLastGame(): Promise<{ [k: string]: number }> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't get Trivia game scores because SQLite is not enabled.`);\n\t\t}\n\t\tconst { game_id } = await this.historyQuery!.get([1]);\n\n\t\tconst results: { [k: string]: number } = {};\n\t\tfor (const row of await this.historyScoresQuery!.all([game_id])) {\n\t\t\tresults[row.userid] = row.score;\n\t\t}\n\t\treturn results;\n\t}\n\n\tasync getQuestions(\n\t\tcategories: string[] | 'all',\n\t\tlimit: number,\n\t\toptions: { order: 'newestfirst' | 'oldestfirst' | 'random' }\n\t): Promise<TriviaQuestion[]> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) throw new Chat.ErrorMessage(`Can't get Trivia questions because SQLite is not enabled.`);\n\n\t\tlet query;\n\t\tlet args;\n\t\tif (categories === 'all') {\n\t\t\tif (options.order === 'newestfirst') {\n\t\t\t\tquery = this.allQuestionsNewestFirstQuery!;\n\t\t\t} else if (options.order === 'oldestfirst') {\n\t\t\t\tquery = this.allQuestionsOldestFirstQuery!;\n\t\t\t} else {\n\t\t\t\tquery = this.allQuestionsRandomOrderQuery!;\n\t\t\t}\n\t\t\targs = [limit];\n\t\t} else {\n\t\t\tquery = (\n\t\t\t\t`SELECT * FROM trivia_questions WHERE category IN (${formatSQLArray(categories)}) AND is_submission = 0 ORDER BY ${options.order === 'random' ? 'RANDOM()' : `added_at ${(options.order === 'oldestfirst' ? 'ASC' : 'DESC')}`} LIMIT ?`\n\t\t\t);\n\t\t\targs = [...categories, limit];\n\t\t}\n\n\t\tif (!query) throw new Error(`Couldn't prepare query`);\n\t\tconst rows = await Chat.database.all(query, args);\n\t\treturn Promise.all(rows.map((row: AnyObject) => this.rowToQuestion(row)));\n\t}\n\n\tasync getLeaderboardEntry(id: ID, leaderboard: Leaderboard): Promise<TriviaLeaderboardScore | null> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't find out if user ${id} has a Trivia leaderboard entry because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst row = await this.leaderboardByUserQuery!.get([id, LEADERBOARD_ENUM[leaderboard]]);\n\t\tif (!row) return null;\n\t\treturn {\n\t\t\tscore: row.score,\n\t\t\ttotalPoints: row.total_points,\n\t\t\ttotalCorrectAnswers: row.total_correct_answers,\n\t\t};\n\t}\n\n\tasync getLeaderboards(): Promise<TriviaLeaderboards> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't get the Trivia leaderboard scores because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst result: TriviaLeaderboards = {\n\t\t\talltime: {},\n\t\t\tnonAlltime: {},\n\t\t\tcycle: {},\n\t\t};\n\t\tconst rows = await this.leaderboardQuery!.all([]);\n\t\tfor (const row of rows) {\n\t\t\tconst entry = {\n\t\t\t\tscore: row.score,\n\t\t\t\ttotalPoints: row.total_points,\n\t\t\t\ttotalCorrectAnswers: row.total_correct_answers,\n\t\t\t};\n\n\t\t\tlet leaderboard: Leaderboard | null = null;\n\t\t\tfor (const [lb, discrim] of Object.entries(LEADERBOARD_ENUM) as [Leaderboard, number][]) {\n\t\t\t\tif (discrim === row.leaderboard) leaderboard = lb;\n\t\t\t}\n\t\t\tif (leaderboard === null) throw new Error(`Invalid leaderboard value ${row.leaderboard}`);\n\n\t\t\tresult[leaderboard][row.userid] = entry;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync getQuestion(questionText: string): Promise<TriviaQuestion | null> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't check if a Trivia question already exists because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst row = await this.questionExistsQuery!.get([questionText]);\n\t\tif (!row) return null;\n\t\treturn this.rowToQuestion(row);\n\t}\n\n\tasync ensureQuestionExists(questionText: string): Promise<TriviaQuestion> {\n\t\tconst question = await this.getQuestion(questionText);\n\t\tif (!question) {\n\t\t\tthrow new Chat.ErrorMessage(`Question \"${questionText}\" is not in the question database.`);\n\t\t}\n\t\treturn question;\n\t}\n\n\tasync ensureQuestionDoesNotExist(questionText: string) {\n\t\tif (await this.getQuestion(questionText)) {\n\t\t\tthrow new Chat.ErrorMessage(`Question \"${questionText}\" is already in the question database.`);\n\t\t}\n\t}\n\n\tasync getSubmissions(): Promise<TriviaQuestion[]> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't retrieve the Trivia question submissions because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst rows = await this.submissionsQuery!.all([]);\n\t\treturn Promise.all(rows.map((row: AnyObject) => this.rowToQuestion(row)));\n\t}\n\n\tasync getQuestionCounts(): Promise<{ [k: string]: number, total: number }> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't retrieve the Trivia question counts because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst allCategories = (await this.categoriesQuery!.all([])).map((row: AnyObject) => row.category);\n\t\tconst total = (await this.questionCountQuery!.get([])).count;\n\n\t\tconst result: { [k: string]: number, total: number } = { total };\n\t\tfor (const category of allCategories) {\n\t\t\tresult[category] = (await this.categoryQuestionCountQuery!.get([category])).count;\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync searchQuestions(\n\t\tsearch: string,\n\t\toptions: { searchSubmissions: boolean, caseSensitive?: boolean }\n\t): Promise<TriviaQuestion[]> {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't search Trivia questions because SQLite is not enabled.`);\n\t\t}\n\n\t\tif (options.caseSensitive) await Chat.database.exec(`PRAGMA case_sensitive_like = true;`);\n\t\tconst rows = await this.questionSearchQuery!.all([`%${search}%`, Number(options.searchSubmissions)]);\n\t\tif (options.caseSensitive) await Chat.database.exec(`PRAGMA case_sensitive_like = false;`);\n\n\t\treturn Promise.all(rows.map((row: AnyObject) => this.rowToQuestion(row)));\n\t}\n\n\t/*****************************\n\t * Methods for deleting data *\n\t * ***************************/\n\tasync clearSubmissions() {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't clear the Trivia question submissions because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait Chat.database.run(this.clearAllSubmissionsQuery!, []);\n\t}\n\n\tasync clearCategory(category: string) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't clear the Trivia questions in category \"${category}\" because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait Chat.database.run(this.clearCategoryQuery!, [category]);\n\t}\n\n\tasync clearCycleLeaderboard() {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't clear the cycle leaderboard because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait Chat.database.run(this.clearCycleLeaderboardQuery!);\n\t}\n\n\tasync deleteQuestion(questionText: string) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't delete the Trivia question because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait Chat.database.run(this.deleteQuestionQuery!, [questionText]);\n\t}\n\n\tasync deleteLeaderboardEntry(userid: ID, leaderboard: Leaderboard) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't delete leaderboard entries because SQLite is not enabled.`);\n\t\t}\n\n\t\tawait this.leaderboardDeletionQuery!.run([userid, LEADERBOARD_ENUM[leaderboard]]);\n\t}\n\n\tasync deleteSubmissions(submissions: string[]) {\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tif (!Config.usesqlite) {\n\t\t\tthrow new Chat.ErrorMessage(`Can't delete Trivia question submissions because SQLite is not enabled.`);\n\t\t}\n\n\t\tconst query = await Chat.database.prepare(\n\t\t\t`DELETE FROM trivia_questions WHERE is_submission = 1 AND question IN (${formatSQLArray(submissions)})`\n\t\t);\n\t\tawait query?.run(submissions);\n\t}\n\n\t/****************************************\n\t * Private helper methods\t \t\t\t*\n\t * These are not part of the public API *\n\t ****************************************/\n\tprivate async prepareStatements() {\n\t\tif (!Config.usesqlite) return;\n\t\tif (Chat.databaseReadyPromise) await Chat.databaseReadyPromise;\n\n\t\tthis.leaderboardInsertion = await Chat.database.prepare(\n\t\t\t`INSERT OR REPLACE INTO trivia_leaderboard (userid, score, total_points, total_correct_answers, leaderboard) VALUES (?, ?, ?, ?, ?) `\n\t\t);\n\t\tthis.questionInsertion = await Chat.database.prepare(\n\t\t\t`INSERT OR IGNORE INTO trivia_questions (question, category, added_at, userid, is_submission) VALUES (?, ?, ?, ?, ?)`\n\t\t);\n\t\tthis.answerInsertion = await Chat.database.prepare(\n\t\t\t`INSERT INTO trivia_answers (question_id, answer) VALUES (?, ?)`\n\t\t);\n\t\tthis.gameHistoryInsertion = await Chat.database.prepare(\n\t\t\t`INSERT INTO trivia_game_history (mode, length, category, time, creator, gives_points) VALUES (?, ?, ?, ?, ?, ?)`\n\t\t);\n\t\tthis.scoreHistoryInsertion = await Chat.database.prepare(\n\t\t\t`INSERT INTO trivia_game_scores (game_id, userid, score) VALUES (?, ?, ?)`\n\t\t);\n\t\tthis.updateMoveEventQuestions = await Chat.database.prepare(\n\t\t\t`INSERT OR REPLACE INTO trivia_settings (key, value) VALUES ('moveEventQuestions', ?)`\n\t\t);\n\n\t\tthis.categoryChangeQuery = await Chat.database.prepare(\n\t\t\t`UPDATE trivia_questions SET category = ? WHERE question = ?`\n\t\t);\n\t\tthis.leaderboardChangeQuery = await Chat.database.prepare(\n\t\t\t`INSERT INTO trivia_leaderboard (userid, score, total_points, total_correct_answers, leaderboard) ` +\n\t\t\t`VALUES ($userid, $score, $totalPoints, $totalCorrectAnswers, $leaderboard) ON CONFLICT DO ` +\n\t\t\t`UPDATE SET score = score + $score, total_points = total_points + $totalPoints, total_correct_answers = total_correct_answers + $totalCorrectAnswers ` +\n\t\t\t`WHERE userid = $userid AND leaderboard = $leaderboard`\n\t\t);\n\t\tthis.migrateCategoryQuery = await Chat.database.prepare(\n\t\t\t`UPDATE OR REPLACE trivia_questions SET category = ? WHERE category = ?`\n\t\t);\n\n\t\tthis.historyQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_game_history ORDER BY time DESC LIMIT ?`\n\t\t);\n\t\tthis.historyScoresQuery = await Chat.database.prepare(`SELECT userid, score FROM trivia_game_scores WHERE game_id = ?`);\n\t\tthis.allQuestionsRandomOrderQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_questions WHERE category IN ('ae', 'pokemon', 'sg', 'sh') AND is_submission = 0 ORDER BY RANDOM() LIMIT ?`\n\t\t);\n\t\tthis.allQuestionsNewestFirstQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_questions WHERE category IN ('ae', 'pokemon', 'sg', 'sh') AND is_submission = 0 ORDER BY added_at DESC LIMIT ?`\n\t\t);\n\t\tthis.allQuestionsOldestFirstQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_questions WHERE category IN ('ae', 'pokemon', 'sg', 'sh') AND is_submission = 0 ORDER BY added_at ASC LIMIT ?`\n\t\t);\n\t\tthis.answersQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_answers WHERE question_id = ?`\n\t\t);\n\t\tthis.submissionsQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_questions WHERE is_submission = 1 ORDER BY category ASC`\n\t\t);\n\t\tthis.leaderboardQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_leaderboard`\n\t\t);\n\t\tthis.leaderboardByUserQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_leaderboard WHERE userid = ? AND leaderboard = ?`\n\t\t);\n\t\tthis.scoreAndPointsByUser = await Chat.database.prepare(\n\t\t\t`SELECT score, total_points as totalPoints, total_correct_answers as totalCorrectAnswers FROM trivia_leaderboard WHERE userid = ? AND leaderboard = ?`\n\t\t);\n\t\tthis.eventQuestionQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_settings WHERE key = 'moveEventQuestions'`\n\t\t);\n\t\tthis.categoriesQuery = await Chat.database.prepare(\n\t\t\t`SELECT DISTINCT category FROM trivia_questions`\n\t\t);\n\t\tthis.questionCountQuery = await Chat.database.prepare(\n\t\t\t`SELECT count(*) AS count FROM trivia_questions WHERE is_submission = 0`\n\t\t);\n\t\tthis.categoryQuestionCountQuery = await Chat.database.prepare(\n\t\t\t`SELECT count(*) AS count FROM trivia_questions WHERE category = ? AND is_submission = 0`\n\t\t);\n\t\tthis.questionSearchQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_questions WHERE question LIKE ? AND is_submission = ? ORDER BY added_at DESC`\n\t\t);\n\t\tthis.questionExistsQuery = await Chat.database.prepare(\n\t\t\t`SELECT * FROM trivia_questions WHERE question = ?`\n\t\t);\n\n\t\tthis.leaderboardDeletionQuery = await Chat.database.prepare(\n\t\t\t`DELETE FROM trivia_leaderboard WHERE userid = ? AND leaderboard = ?`\n\t\t);\n\t\tthis.clearAllSubmissionsQuery = await Chat.database.prepare(\n\t\t\t`DELETE FROM trivia_questions WHERE is_submission = 1`\n\t\t);\n\t\tthis.clearCategoryQuery = await Chat.database.prepare(\n\t\t\t`DELETE FROM trivia_questions WHERE category = ? AND is_submission = 0`\n\t\t);\n\t\t// The leaderboard is hardcoded, because we don't want to accidentally delete any other leaderboards.\n\t\t// If there is a need to reset other leaderboards in the future, this can be changed to accept a parameter.\n\t\t// Not a SQL injection vulnerability because LEADERBOARD_ENUM cannot be altered by the user.\n\t\tthis.clearCycleLeaderboardQuery = await Chat.database.prepare(\n\t\t\t`DELETE FROM trivia_leaderboard WHERE leaderboard = ${LEADERBOARD_ENUM.cycle}`\n\t\t);\n\t\tthis.deleteQuestionQuery = await Chat.database.prepare(\n\t\t\t`DELETE FROM trivia_questions WHERE question = ?`\n\t\t);\n\n\t\tawait Chat.database.exec(\"PRAGMA foreign_keys = ON;\");\n\t\tawait Chat.database.loadExtension('server/chat-plugins/trivia/transactions.js');\n\t}\n\n\tprivate async convertLegacyJSON() {\n\t\tif (!Config.usesqlite || !this.legacyJSONPath) return;\n\t\tif (this.readyPromise) await this.readyPromise;\n\t\tlet triviaData;\n\t\ttry {\n\t\t\ttriviaData = JSON.parse(FS(this.legacyJSONPath).readIfExistsSync() || \"{}\");\n\t\t\tif (!triviaData) throw new Error(`no JSON`);\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\n\t\t// handle _old_ JSON format (just in case)\n\t\tif (Array.isArray(triviaData.submissions)) {\n\t\t\tconst oldSubmissions = triviaData.submissions as TriviaQuestion[];\n\t\t\ttriviaData.submissions = {};\n\n\t\t\tfor (const question of oldSubmissions) {\n\t\t\t\tif (!(question.category in triviaData.submissions)) triviaData.submissions[question.category] = [];\n\t\t\t\ttriviaData.submissions[question.category].push(question);\n\t\t\t}\n\t\t}\n\t\tif (Array.isArray(triviaData.questions)) {\n\t\t\tconst oldSubmissions = triviaData.questions as TriviaQuestion[];\n\t\t\ttriviaData.questions = {};\n\n\t\t\tfor (const question of oldSubmissions) {\n\t\t\t\tif (!(question.category in triviaData.questions)) triviaData.questions[question.category] = [];\n\t\t\t\ttriviaData.questions[question.category].push(question);\n\t\t\t}\n\t\t}\n\n\t\t// convert leaderboard\n\t\tif (typeof triviaData.leaderboard === 'object') {\n\t\t\tfor (const userid in triviaData.leaderboard) {\n\t\t\t\tconst [score, totalGamePoints, totalCorrectAnswers] = triviaData.leaderboard[userid];\n\t\t\t\tawait Chat.database.run(\n\t\t\t\t\tthis.leaderboardInsertion!,\n\t\t\t\t\t[userid, score, totalGamePoints, totalCorrectAnswers, Number(true)]\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (typeof triviaData.altLeaderboard === 'object') {\n\t\t\tfor (const userid in triviaData.altLeaderboard) {\n\t\t\t\tconst [score, totalGamePoints, totalCorrectAnswers] = triviaData.altLeaderboard[userid];\n\t\t\t\tawait Chat.database.run(\n\t\t\t\t\tthis.leaderboardInsertion!,\n\t\t\t\t\t[userid, score, totalGamePoints, totalCorrectAnswers, Number(false)]\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// convert questions\n\t\tconst addedAt = Date.now();\n\t\tif (typeof triviaData.questions === 'object') {\n\t\t\tfor (const category in triviaData.questions) {\n\t\t\t\tfor (const question of triviaData.questions[category]) {\n\t\t\t\t\tif (!question.addedAt) question.addedAt = addedAt;\n\t\t\t\t\tif (!question.user) question.user = 'unknown user';\n\t\t\t\t\tquestion.question = question.question.trim();\n\t\t\t\t\tawait this.addQuestions([question]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (typeof triviaData.submissions === 'object') {\n\t\t\tfor (const category in triviaData.submissions) {\n\t\t\t\tfor (const question of triviaData.submissions[category]) {\n\t\t\t\t\tif (!question.addedAt) question.addedAt = addedAt;\n\t\t\t\t\tif (!question.user) question.user = 'unknown user';\n\t\t\t\t\tquestion.question = question.question.trim();\n\t\t\t\t\tawait this.addQuestionSubmissions([question]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (Array.isArray(triviaData.history)) {\n\t\t\tconst now = Date.now();\n\t\t\tfor (const game of triviaData.history) {\n\t\t\t\tif (!game.startTime) game.startTime = now;\n\t\t\t\tawait this.addHistory([game]);\n\t\t\t}\n\t\t}\n\n\t\tif (triviaData.moveEventQuestions) {\n\t\t\tawait this.setShouldMoveEventQuestions(true);\n\t\t}\n\n\t\t// move legacy JSON file\n\t\ttry {\n\t\t\tawait FS(this.legacyJSONPath).rename(this.legacyJSONPath + '.converted');\n\t\t} catch {}\n\t}\n\n\tprivate rowToQuestion(row: AnyObject): Promise<TriviaQuestion> {\n\t\treturn Chat.database.all(this.answersQuery!, [row.question_id]).then(answerRows => ({\n\t\t\tquestion: row.question,\n\t\t\tcategory: row.category,\n\t\t\tanswers: answerRows.map((answerRow: AnyObject) => answerRow.answer),\n\t\t\tuser: row.userid,\n\t\t\taddedAt: row.added_at,\n\t\t}));\n\t}\n}\n"],
"mappings": "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",
"names": []
}
|