From 0751375ab6bc9b43bffeab28d407a06504ea1269 Mon Sep 17 00:00:00 2001 From: Jack Date: Mon, 29 Jan 2024 15:53:42 +0100 Subject: [PATCH] refactor: shared types (miodec) (#4978) * rework shared types * revert one small change --- backend/src/api/controllers/result.ts | 2 +- backend/src/constants/base-configuration.ts | 4 +- backend/src/dal/user.ts | 4 +- backend/src/init/configuration.ts | 14 +-- backend/src/middlewares/api-utils.ts | 2 +- backend/src/middlewares/auth.ts | 4 +- backend/src/queues/later-queue.ts | 4 +- backend/src/services/weekly-xp-leaderboard.ts | 8 +- backend/src/types/shared.ts | 108 ----------------- backend/src/types/types.d.ts | 7 +- backend/src/utils/daily-leaderboards.ts | 18 +-- backend/tsconfig.json | 2 +- frontend/src/ts/ape/server-configuration.ts | 6 +- frontend/src/ts/types/types.d.ts | 4 - frontend/tsconfig.json | 2 +- shared-types/types.d.ts | 110 ++++++++++++++++++ 16 files changed, 146 insertions(+), 153 deletions(-) delete mode 100644 backend/src/types/shared.ts create mode 100644 shared-types/types.d.ts diff --git a/backend/src/api/controllers/result.ts b/backend/src/api/controllers/result.ts index 595441b42..c8a1c91b2 100644 --- a/backend/src/api/controllers/result.ts +++ b/backend/src/api/controllers/result.ts @@ -644,7 +644,7 @@ interface XpResult { async function calculateXp( result, - xpConfiguration: MonkeyTypes.Configuration["users"]["xp"], + xpConfiguration: SharedTypes.Configuration["users"]["xp"], uid: string, currentTotalXp: number, streak: number diff --git a/backend/src/constants/base-configuration.ts b/backend/src/constants/base-configuration.ts index e21c7e71d..6f1bce0ba 100644 --- a/backend/src/constants/base-configuration.ts +++ b/backend/src/constants/base-configuration.ts @@ -3,7 +3,7 @@ * To add a new configuration. Simply add it to this object. * When changing this template, please follow the principle of "Secure by default" (https://en.wikipedia.org/wiki/Secure_by_default). */ -export const BASE_CONFIGURATION: MonkeyTypes.Configuration = { +export const BASE_CONFIGURATION: SharedTypes.Configuration = { maintenance: false, results: { savingEnabled: false, @@ -141,7 +141,7 @@ type Schema = { : never; }; -export const CONFIGURATION_FORM_SCHEMA: ObjectSchema = +export const CONFIGURATION_FORM_SCHEMA: ObjectSchema = { type: "object", label: "Server Configuration", diff --git a/backend/src/dal/user.ts b/backend/src/dal/user.ts index cdbb82765..f6344a47b 100644 --- a/backend/src/dal/user.ts +++ b/backend/src/dal/user.ts @@ -847,7 +847,7 @@ interface AddToInboxBulkEntry { export async function addToInboxBulk( entries: AddToInboxBulkEntry[], - inboxConfig: MonkeyTypes.Configuration["users"]["inbox"] + inboxConfig: SharedTypes.Configuration["users"]["inbox"] ): Promise { const { enabled, maxMail } = inboxConfig; @@ -875,7 +875,7 @@ export async function addToInboxBulk( export async function addToInbox( uid: string, mail: MonkeyTypes.MonkeyMail[], - inboxConfig: MonkeyTypes.Configuration["users"]["inbox"] + inboxConfig: SharedTypes.Configuration["users"]["inbox"] ): Promise { const { enabled, maxMail } = inboxConfig; diff --git a/backend/src/init/configuration.ts b/backend/src/init/configuration.ts index dc19ab8d5..b085aaa55 100644 --- a/backend/src/init/configuration.ts +++ b/backend/src/init/configuration.ts @@ -8,8 +8,8 @@ import { BASE_CONFIGURATION } from "../constants/base-configuration"; const CONFIG_UPDATE_INTERVAL = 10 * 60 * 1000; // 10 Minutes function mergeConfigurations( - baseConfiguration: MonkeyTypes.Configuration, - liveConfiguration: Partial + baseConfiguration: SharedTypes.Configuration, + liveConfiguration: Partial ): void { if ( !_.isPlainObject(baseConfiguration) || @@ -45,7 +45,7 @@ let serverConfigurationUpdated = false; export async function getCachedConfiguration( attemptCacheUpdate = false -): Promise { +): Promise { if ( attemptCacheUpdate && lastFetchTime < Date.now() - CONFIG_UPDATE_INTERVAL @@ -57,7 +57,7 @@ export async function getCachedConfiguration( return configuration; } -export async function getLiveConfiguration(): Promise { +export async function getLiveConfiguration(): Promise { lastFetchTime = Date.now(); const configurationCollection = db.collection("configuration"); @@ -71,7 +71,7 @@ export async function getLiveConfiguration(): Promise const liveConfigurationWithoutId = _.omit( liveConfiguration, "_id" - ) as MonkeyTypes.Configuration; + ) as SharedTypes.Configuration; mergeConfigurations(baseConfiguration, liveConfigurationWithoutId); pushConfiguration(baseConfiguration); @@ -93,7 +93,7 @@ export async function getLiveConfiguration(): Promise } async function pushConfiguration( - configuration: MonkeyTypes.Configuration + configuration: SharedTypes.Configuration ): Promise { if (serverConfigurationUpdated) { return; @@ -111,7 +111,7 @@ async function pushConfiguration( } export async function patchConfiguration( - configurationUpdates: Partial + configurationUpdates: Partial ): Promise { try { const currentConfiguration = _.cloneDeep(configuration); diff --git a/backend/src/middlewares/api-utils.ts b/backend/src/middlewares/api-utils.ts index 466d3b90d..9b579269e 100644 --- a/backend/src/middlewares/api-utils.ts +++ b/backend/src/middlewares/api-utils.ts @@ -23,7 +23,7 @@ const emptyMiddleware = ( * the criteria. */ function validateConfiguration( - options: ValidationOptions + options: ValidationOptions ): RequestHandler { const { criteria, diff --git a/backend/src/middlewares/auth.ts b/backend/src/middlewares/auth.ts index ddf190688..c7b90a0ca 100644 --- a/backend/src/middlewares/auth.ts +++ b/backend/src/middlewares/auth.ts @@ -105,7 +105,7 @@ function authenticateRequest(authOptions = DEFAULT_OPTIONS): Handler { async function authenticateWithAuthHeader( authHeader: string, - configuration: MonkeyTypes.Configuration, + configuration: SharedTypes.Configuration, options: RequestAuthenticationOptions ): Promise { if (authHeader === undefined || authHeader === "") { @@ -215,7 +215,7 @@ async function authenticateWithBearerToken( async function authenticateWithApeKey( key: string, - configuration: MonkeyTypes.Configuration, + configuration: SharedTypes.Configuration, options: RequestAuthenticationOptions ): Promise { if (!configuration.apeKeys.acceptKeys) { diff --git a/backend/src/queues/later-queue.ts b/backend/src/queues/later-queue.ts index 56993b5ec..3ac8d6d30 100644 --- a/backend/src/queues/later-queue.ts +++ b/backend/src/queues/later-queue.ts @@ -17,7 +17,7 @@ export interface LaterTask { export type LaterTaskContexts = { "daily-leaderboard-results": { yesterdayTimestamp: number; - modeRule: MonkeyTypes.ValidModeRule; + modeRule: SharedTypes.ValidModeRule; }; "weekly-xp-leaderboard-results": { lastWeekTimestamp: number; @@ -82,7 +82,7 @@ class LaterQueue extends MonkeyQueue> { async scheduleForTomorrow( taskName: LaterTaskType, taskId: string, - modeRule: MonkeyTypes.ValidModeRule + modeRule: SharedTypes.ValidModeRule ): Promise { const currentDayTimestamp = getCurrentDayTimestamp(); const jobId = `${taskName}:${currentDayTimestamp}:${taskId}`; diff --git a/backend/src/services/weekly-xp-leaderboard.ts b/backend/src/services/weekly-xp-leaderboard.ts index 67d6fc350..74cf4d351 100644 --- a/backend/src/services/weekly-xp-leaderboard.ts +++ b/backend/src/services/weekly-xp-leaderboard.ts @@ -59,7 +59,7 @@ export class WeeklyXpLeaderboard { } public async addResult( - weeklyXpLeaderboardConfig: MonkeyTypes.Configuration["leaderboards"]["weeklyXp"], + weeklyXpLeaderboardConfig: SharedTypes.Configuration["leaderboards"]["weeklyXp"], opts: AddResultOpts ): Promise { const { entry, xpGained, timeTypedSeconds } = opts; @@ -116,7 +116,7 @@ export class WeeklyXpLeaderboard { public async getResults( minRank: number, maxRank: number, - weeklyXpLeaderboardConfig: MonkeyTypes.Configuration["leaderboards"]["weeklyXp"] + weeklyXpLeaderboardConfig: SharedTypes.Configuration["leaderboards"]["weeklyXp"] ): Promise { const connection = RedisClient.getConnection(); if (!connection || !weeklyXpLeaderboardConfig.enabled) { @@ -161,7 +161,7 @@ export class WeeklyXpLeaderboard { public async getRank( uid: string, - weeklyXpLeaderboardConfig: MonkeyTypes.Configuration["leaderboards"]["weeklyXp"] + weeklyXpLeaderboardConfig: SharedTypes.Configuration["leaderboards"]["weeklyXp"] ): Promise { const connection = RedisClient.getConnection(); if (!connection || !weeklyXpLeaderboardConfig.enabled) { @@ -196,7 +196,7 @@ export class WeeklyXpLeaderboard { } export function get( - weeklyXpLeaderboardConfig: MonkeyTypes.Configuration["leaderboards"]["weeklyXp"], + weeklyXpLeaderboardConfig: SharedTypes.Configuration["leaderboards"]["weeklyXp"], customTimestamp?: number ): WeeklyXpLeaderboard | null { const { enabled } = weeklyXpLeaderboardConfig; diff --git a/backend/src/types/shared.ts b/backend/src/types/shared.ts deleted file mode 100644 index f48c5be12..000000000 --- a/backend/src/types/shared.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Shared types between server/client. -export interface ValidModeRule { - language: string; - mode: string; - mode2: string; -} -export interface RewardBracket { - minRank: number; - maxRank: number; - minReward: number; - maxReward: number; -} - -export interface Configuration { - maintenance: boolean; - quotes: { - reporting: { - enabled: boolean; - maxReports: number; - contentReportLimit: number; - }; - submissionsEnabled: boolean; - maxFavorites: number; - }; - results: { - savingEnabled: boolean; - objectHashCheckEnabled: boolean; - filterPresets: { - enabled: boolean; - maxPresetsPerUser: number; - }; - limits: { - regularUser: number; - premiumUser: number; - }; - maxBatchSize: number; - }; - users: { - signUp: boolean; - lastHashesCheck: { - enabled: boolean; - maxHashes: number; - }; - autoBan: { - enabled: boolean; - maxCount: number; - maxHours: number; - }; - profiles: { - enabled: boolean; - }; - discordIntegration: { - enabled: boolean; - }; - xp: { - enabled: boolean; - funboxBonus: number; - gainMultiplier: number; - maxDailyBonus: number; - minDailyBonus: number; - streak: { - enabled: boolean; - maxStreakDays: number; - maxStreakMultiplier: number; - }; - }; - inbox: { - enabled: boolean; - maxMail: number; - }; - premium: { - enabled: boolean; - }; - }; - admin: { - endpointsEnabled: boolean; - }; - apeKeys: { - endpointsEnabled: boolean; - acceptKeys: boolean; - maxKeysPerUser: number; - apeKeyBytes: number; - apeKeySaltRounds: number; - }; - rateLimiting: { - badAuthentication: { - enabled: boolean; - penalty: number; - flaggedStatusCodes: number[]; - }; - }; - dailyLeaderboards: { - enabled: boolean; - leaderboardExpirationTimeInDays: number; - maxResults: number; - validModeRules: ValidModeRule[]; - scheduleRewardsModeRules: ValidModeRule[]; - topResultsToAnnounce: number; - xpRewardBrackets: RewardBracket[]; - }; - leaderboards: { - weeklyXp: { - enabled: boolean; - expirationTimeInDays: number; - xpRewardBrackets: RewardBracket[]; - }; - }; -} diff --git a/backend/src/types/types.d.ts b/backend/src/types/types.d.ts index 7af5568b6..185272888 100644 --- a/backend/src/types/types.d.ts +++ b/backend/src/types/types.d.ts @@ -1,13 +1,8 @@ -type Configuration = import("../types/shared").Configuration; - type ObjectId = import("mongodb").ObjectId; type ExpressRequest = import("express").Request; declare namespace MonkeyTypes { - type Configuration = import("./shared").Configuration; - type ValidModeRule = import("./shared").ValidModeRule; - type RewardBracket = import("./shared").RewardBracket; interface DecodedToken { type: "Bearer" | "ApeKey" | "None"; uid: string; @@ -15,7 +10,7 @@ declare namespace MonkeyTypes { } interface Context { - configuration: Configuration; + configuration: SharedTypes.Configuration; decodedToken: DecodedToken; } diff --git a/backend/src/utils/daily-leaderboards.ts b/backend/src/utils/daily-leaderboards.ts index 1443cf9ea..ab6d22f6b 100644 --- a/backend/src/utils/daily-leaderboards.ts +++ b/backend/src/utils/daily-leaderboards.ts @@ -36,9 +36,9 @@ export class DailyLeaderboard { private leaderboardScoresKeyName: string; private leaderboardModeKey: string; private customTime: number; - private modeRule: MonkeyTypes.ValidModeRule; + private modeRule: SharedTypes.ValidModeRule; - constructor(modeRule: MonkeyTypes.ValidModeRule, customTime = -1) { + constructor(modeRule: SharedTypes.ValidModeRule, customTime = -1) { const { language, mode, mode2 } = modeRule; this.leaderboardModeKey = `${language}:${mode}:${mode2}`; @@ -67,7 +67,7 @@ export class DailyLeaderboard { public async addResult( entry: DailyLeaderboardEntry, - dailyLeaderboardsConfig: MonkeyTypes.Configuration["dailyLeaderboards"] + dailyLeaderboardsConfig: SharedTypes.Configuration["dailyLeaderboards"] ): Promise { const connection = RedisClient.getConnection(); if (!connection || !dailyLeaderboardsConfig.enabled) { @@ -123,7 +123,7 @@ export class DailyLeaderboard { public async getResults( minRank: number, maxRank: number, - dailyLeaderboardsConfig: MonkeyTypes.Configuration["dailyLeaderboards"] + dailyLeaderboardsConfig: SharedTypes.Configuration["dailyLeaderboards"] ): Promise { const connection = RedisClient.getConnection(); if (!connection || !dailyLeaderboardsConfig.enabled) { @@ -161,7 +161,7 @@ export class DailyLeaderboard { public async getRank( uid: string, - dailyLeaderboardsConfig: MonkeyTypes.Configuration["dailyLeaderboards"] + dailyLeaderboardsConfig: SharedTypes.Configuration["dailyLeaderboards"] ): Promise { const connection = RedisClient.getConnection(); if (!connection || !dailyLeaderboardsConfig.enabled) { @@ -204,7 +204,7 @@ export class DailyLeaderboard { export async function purgeUserFromDailyLeaderboards( uid: string, - configuration: MonkeyTypes.Configuration["dailyLeaderboards"] + configuration: SharedTypes.Configuration["dailyLeaderboards"] ): Promise { const connection = RedisClient.getConnection(); if (!connection || !configuration.enabled) { @@ -216,8 +216,8 @@ export async function purgeUserFromDailyLeaderboards( } function isValidModeRule( - modeRule: MonkeyTypes.ValidModeRule, - modeRules: MonkeyTypes.ValidModeRule[] + modeRule: SharedTypes.ValidModeRule, + modeRules: SharedTypes.ValidModeRule[] ): boolean { const { language, mode, mode2 } = modeRule; @@ -233,7 +233,7 @@ export function getDailyLeaderboard( language: string, mode: string, mode2: string, - dailyLeaderboardsConfig: MonkeyTypes.Configuration["dailyLeaderboards"], + dailyLeaderboardsConfig: SharedTypes.Configuration["dailyLeaderboards"], customTimestamp = -1 ): DailyLeaderboard | null { const { validModeRules, enabled } = dailyLeaderboardsConfig; diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 052aa916e..8189ff0e0 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -22,7 +22,7 @@ "ts-node": { "files": true }, - "files": ["./src/types/types.d.ts"], + "files": ["./src/types/types.d.ts", "../shared-types/types.d.ts"], "include": ["./src/**/*"], "exclude": [ "node_modules", diff --git a/frontend/src/ts/ape/server-configuration.ts b/frontend/src/ts/ape/server-configuration.ts index bec53f84d..6edcb0b1e 100644 --- a/frontend/src/ts/ape/server-configuration.ts +++ b/frontend/src/ts/ape/server-configuration.ts @@ -1,8 +1,8 @@ import Ape from "."; -let config: MonkeyTypes.Configuration | undefined = undefined; +let config: SharedTypes.Configuration | undefined = undefined; -export function get(): MonkeyTypes.Configuration | undefined { +export function get(): SharedTypes.Configuration | undefined { return config; } @@ -13,6 +13,6 @@ export async function sync(): Promise { console.error("Could not fetch configuration", response.message); return; } else { - config = response.data as MonkeyTypes.Configuration; + config = response.data as SharedTypes.Configuration; } } diff --git a/frontend/src/ts/types/types.d.ts b/frontend/src/ts/types/types.d.ts index 4d0e53a2c..dc533609c 100644 --- a/frontend/src/ts/types/types.d.ts +++ b/frontend/src/ts/types/types.d.ts @@ -1,8 +1,4 @@ declare namespace MonkeyTypes { - type Configuration = import("@backend/types/shared").Configuration; - type ValidModeRule = import("@backend/types/shared").ValidModeRule; - type RewardBracket = import("@backend/types/shared").RewardBracket; - type PageName = | "loading" | "test" diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 2689fabdc..b019f09fb 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -36,6 +36,6 @@ } }, "include": ["./src/**/*.ts"], - "files": ["src/ts/modules.d.ts"], + "files": ["src/ts/modules.d.ts", "../shared-types/types.d.ts"], "exclude": ["node_modules", "build", "setup-tests.ts", "**/*.spec.ts"] } diff --git a/shared-types/types.d.ts b/shared-types/types.d.ts new file mode 100644 index 000000000..9c75e1c4d --- /dev/null +++ b/shared-types/types.d.ts @@ -0,0 +1,110 @@ +// Shared types between server/client. +declare namespace SharedTypes { + interface ValidModeRule { + language: string; + mode: string; + mode2: string; + } + interface RewardBracket { + minRank: number; + maxRank: number; + minReward: number; + maxReward: number; + } + + interface Configuration { + maintenance: boolean; + quotes: { + reporting: { + enabled: boolean; + maxReports: number; + contentReportLimit: number; + }; + submissionsEnabled: boolean; + maxFavorites: number; + }; + results: { + savingEnabled: boolean; + objectHashCheckEnabled: boolean; + filterPresets: { + enabled: boolean; + maxPresetsPerUser: number; + }; + limits: { + regularUser: number; + premiumUser: number; + }; + maxBatchSize: number; + }; + users: { + signUp: boolean; + lastHashesCheck: { + enabled: boolean; + maxHashes: number; + }; + autoBan: { + enabled: boolean; + maxCount: number; + maxHours: number; + }; + profiles: { + enabled: boolean; + }; + discordIntegration: { + enabled: boolean; + }; + xp: { + enabled: boolean; + funboxBonus: number; + gainMultiplier: number; + maxDailyBonus: number; + minDailyBonus: number; + streak: { + enabled: boolean; + maxStreakDays: number; + maxStreakMultiplier: number; + }; + }; + inbox: { + enabled: boolean; + maxMail: number; + }; + premium: { + enabled: boolean; + }; + }; + admin: { + endpointsEnabled: boolean; + }; + apeKeys: { + endpointsEnabled: boolean; + acceptKeys: boolean; + maxKeysPerUser: number; + apeKeyBytes: number; + apeKeySaltRounds: number; + }; + rateLimiting: { + badAuthentication: { + enabled: boolean; + penalty: number; + flaggedStatusCodes: number[]; + }; + }; + dailyLeaderboards: { + enabled: boolean; + leaderboardExpirationTimeInDays: number; + maxResults: number; + validModeRules: ValidModeRule[]; + scheduleRewardsModeRules: ValidModeRule[]; + topResultsToAnnounce: number; + xpRewardBrackets: RewardBracket[]; + }; + leaderboards: { + weeklyXp: { + enabled: boolean; + expirationTimeInDays: number; + xpRewardBrackets: RewardBracket[]; + }; + }; + } +}