mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-09-20 07:16:17 +08:00
refactor: remove leftover code from ts-rest migration (@fehmer) (#5875)
This commit is contained in:
parent
8a6c81669e
commit
e19b3e3e8b
|
@ -37,7 +37,7 @@ const mockApeKey = {
|
|||
vi.spyOn(ApeKeys, "getApeKey").mockResolvedValue(mockApeKey);
|
||||
vi.spyOn(ApeKeys, "updateLastUsedOn").mockResolvedValue();
|
||||
const isDevModeMock = vi.spyOn(Misc, "isDevEnvironment");
|
||||
let mockRequest: Partial<MonkeyTypes.Request>;
|
||||
let mockRequest: Partial<Auth.TsRestRequestWithCtx>;
|
||||
let mockResponse: Partial<Response>;
|
||||
let nextFunction: NextFunction;
|
||||
|
||||
|
@ -79,184 +79,6 @@ describe("middlewares/auth", () => {
|
|||
isDevModeMock.mockReset();
|
||||
});
|
||||
|
||||
describe("authenticateRequest", () => {
|
||||
it("should fail if token is not fresh", async () => {
|
||||
Date.now = vi.fn(() => 60001);
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({
|
||||
requireFreshToken: true,
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
)
|
||||
).rejects.toThrowError(
|
||||
"Unauthorized\nStack: This endpoint requires a fresh token"
|
||||
);
|
||||
});
|
||||
it("should allow the request if token is fresh", async () => {
|
||||
Date.now = vi.fn(() => 10000);
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({
|
||||
requireFreshToken: true,
|
||||
});
|
||||
|
||||
await authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
);
|
||||
|
||||
const decodedToken = mockRequest?.ctx?.decodedToken;
|
||||
|
||||
expect(decodedToken?.type).toBe("Bearer");
|
||||
expect(decodedToken?.email).toBe(mockDecodedToken.email);
|
||||
expect(decodedToken?.uid).toBe(mockDecodedToken.uid);
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("should allow the request if apeKey is supported", async () => {
|
||||
mockRequest.headers = {
|
||||
authorization: "ApeKey aWQua2V5",
|
||||
};
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({
|
||||
acceptApeKeys: true,
|
||||
});
|
||||
|
||||
await authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
);
|
||||
|
||||
const decodedToken = mockRequest?.ctx?.decodedToken;
|
||||
|
||||
expect(decodedToken?.type).toBe("ApeKey");
|
||||
expect(decodedToken?.email).toBe("");
|
||||
expect(decodedToken?.uid).toBe("123");
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("should allow the request with authentation on public endpoint", async () => {
|
||||
const authenticateRequest = Auth.authenticateRequest({
|
||||
isPublic: true,
|
||||
});
|
||||
|
||||
await authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
);
|
||||
|
||||
const decodedToken = mockRequest?.ctx?.decodedToken;
|
||||
expect(decodedToken?.type).toBe("Bearer");
|
||||
expect(decodedToken?.email).toBe(mockDecodedToken.email);
|
||||
expect(decodedToken?.uid).toBe(mockDecodedToken.uid);
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("should allow the request without authentication on public endpoint", async () => {
|
||||
mockRequest.headers = {};
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({
|
||||
isPublic: true,
|
||||
});
|
||||
|
||||
await authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
);
|
||||
|
||||
const decodedToken = mockRequest?.ctx?.decodedToken;
|
||||
expect(decodedToken?.type).toBe("None");
|
||||
expect(decodedToken?.email).toBe("");
|
||||
expect(decodedToken?.uid).toBe("");
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("should allow the request with apeKey on public endpoint", async () => {
|
||||
mockRequest.headers = {
|
||||
authorization: "ApeKey aWQua2V5",
|
||||
};
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({
|
||||
isPublic: true,
|
||||
});
|
||||
|
||||
await authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
);
|
||||
|
||||
const decodedToken = mockRequest?.ctx?.decodedToken;
|
||||
|
||||
expect(decodedToken?.type).toBe("ApeKey");
|
||||
expect(decodedToken?.email).toBe("");
|
||||
expect(decodedToken?.uid).toBe("123");
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("should allow request with Uid on dev", async () => {
|
||||
mockRequest.headers = {
|
||||
authorization: "Uid 123",
|
||||
};
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({});
|
||||
|
||||
await authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
);
|
||||
|
||||
const decodedToken = mockRequest?.ctx?.decodedToken;
|
||||
|
||||
expect(decodedToken?.type).toBe("Bearer");
|
||||
expect(decodedToken?.email).toBe("");
|
||||
expect(decodedToken?.uid).toBe("123");
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("should allow request with Uid and email on dev", async () => {
|
||||
mockRequest.headers = {
|
||||
authorization: "Uid 123|test@example.com",
|
||||
};
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({});
|
||||
|
||||
await authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
);
|
||||
|
||||
const decodedToken = mockRequest?.ctx?.decodedToken;
|
||||
|
||||
expect(decodedToken?.type).toBe("Bearer");
|
||||
expect(decodedToken?.email).toBe("test@example.com");
|
||||
expect(decodedToken?.uid).toBe("123");
|
||||
expect(nextFunction).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("should fail request with Uid on non-dev", async () => {
|
||||
isDevModeMock.mockReturnValue(false);
|
||||
mockRequest.headers = {
|
||||
authorization: "Uid 123",
|
||||
};
|
||||
|
||||
const authenticateRequest = Auth.authenticateRequest({});
|
||||
|
||||
await expect(() =>
|
||||
authenticateRequest(
|
||||
mockRequest as Request,
|
||||
mockResponse as Response,
|
||||
nextFunction
|
||||
)
|
||||
).rejects.toThrow(
|
||||
new MonkeyError(401, "Baerer type uid is not supported")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("authenticateTsRestRequest", () => {
|
||||
const prometheusRecordAuthTimeMock = vi.spyOn(Prometheus, "recordAuthTime");
|
||||
const prometheusIncrementAuthMock = vi.spyOn(Prometheus, "incrementAuth");
|
||||
|
|
|
@ -1,124 +1,6 @@
|
|||
import * as Validation from "../../src/utils/validation";
|
||||
import { isTagPresetNameValid } from "../../src/utils/validation";
|
||||
|
||||
describe("Validation", () => {
|
||||
it("isTagPresetNameValid", () => {
|
||||
const testCases = [
|
||||
{
|
||||
name: "valid_name",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "validname",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "valid-name",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "thistagnameistoolong",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "invalid name",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "invalid=name",
|
||||
expected: false,
|
||||
},
|
||||
];
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
expect(Validation.isTagPresetNameValid(testCase.name)).toBe(
|
||||
testCase.expected
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("inRange", () => {
|
||||
const testCases = [
|
||||
{
|
||||
value: 1,
|
||||
min: 1,
|
||||
max: 2,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
min: 2,
|
||||
max: 2,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
min: 1,
|
||||
max: 1,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
value: 53,
|
||||
min: -100,
|
||||
max: 100,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
value: 153,
|
||||
min: -100,
|
||||
max: 100,
|
||||
expected: false,
|
||||
},
|
||||
];
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
expect(
|
||||
Validation.inRange(testCase.value, testCase.min, testCase.max)
|
||||
).toBe(testCase.expected);
|
||||
});
|
||||
});
|
||||
|
||||
it("isUsernameValid", () => {
|
||||
const testCases = [
|
||||
{
|
||||
name: "Bruce",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Rizwan_123",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Fe-rotiq_123_",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: " ",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "superduperlongnamethatshouldbeinvalid",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: ".period",
|
||||
expected: false,
|
||||
},
|
||||
];
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
expect(Validation.isUsernameValid(testCase.name)).toBe(testCase.expected);
|
||||
});
|
||||
});
|
||||
|
||||
it("isTestTooShort", () => {
|
||||
const testCases = [
|
||||
{
|
||||
|
@ -164,8 +46,7 @@ describe("Validation", () => {
|
|||
];
|
||||
|
||||
testCases.forEach((testCase) => {
|
||||
//@ts-ignore
|
||||
expect(Validation.isTestTooShort(testCase.result)).toBe(
|
||||
expect(Validation.isTestTooShort(testCase.result as any)).toBe(
|
||||
testCase.expected
|
||||
);
|
||||
});
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
"firebase-admin": "12.0.0",
|
||||
"helmet": "4.6.0",
|
||||
"ioredis": "4.28.5",
|
||||
"joi": "17.6.0",
|
||||
"lodash": "4.17.21",
|
||||
"lru-cache": "7.10.1",
|
||||
"mjml": "4.15.0",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { buildMonkeyMail } from "../../utils/monkey-mail";
|
||||
import * as UserDAL from "../../dal/user";
|
||||
import * as ReportDAL from "../../dal/report";
|
||||
|
@ -15,14 +15,12 @@ import MonkeyError from "../../utils/error";
|
|||
import { Configuration } from "@monkeytype/contracts/schemas/configuration";
|
||||
import { addImportantLog } from "../../dal/logs";
|
||||
|
||||
export async function test(
|
||||
_req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
return new MonkeyResponse2("OK", null);
|
||||
export async function test(_req: MonkeyTypes.Request): Promise<MonkeyResponse> {
|
||||
return new MonkeyResponse("OK", null);
|
||||
}
|
||||
|
||||
export async function toggleBan(
|
||||
req: MonkeyTypes.Request2<undefined, ToggleBanRequest>
|
||||
req: MonkeyTypes.Request<undefined, ToggleBanRequest>
|
||||
): Promise<ToggleBanResponse> {
|
||||
const { uid } = req.body;
|
||||
|
||||
|
@ -38,31 +36,31 @@ export async function toggleBan(
|
|||
|
||||
void addImportantLog("user_ban_toggled", { banned: !user.banned }, uid);
|
||||
|
||||
return new MonkeyResponse2(`Ban toggled`, {
|
||||
return new MonkeyResponse(`Ban toggled`, {
|
||||
banned: !user.banned,
|
||||
});
|
||||
}
|
||||
|
||||
export async function acceptReports(
|
||||
req: MonkeyTypes.Request2<undefined, AcceptReportsRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, AcceptReportsRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
await handleReports(
|
||||
req.body.reports.map((it) => ({ ...it })),
|
||||
true,
|
||||
req.ctx.configuration.users.inbox
|
||||
);
|
||||
return new MonkeyResponse2("Reports removed and users notified.", null);
|
||||
return new MonkeyResponse("Reports removed and users notified.", null);
|
||||
}
|
||||
|
||||
export async function rejectReports(
|
||||
req: MonkeyTypes.Request2<undefined, RejectReportsRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, RejectReportsRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
await handleReports(
|
||||
req.body.reports.map((it) => ({ ...it })),
|
||||
false,
|
||||
req.ctx.configuration.users.inbox
|
||||
);
|
||||
return new MonkeyResponse2("Reports removed and users notified.", null);
|
||||
return new MonkeyResponse("Reports removed and users notified.", null);
|
||||
}
|
||||
|
||||
export async function handleReports(
|
||||
|
@ -126,9 +124,9 @@ export async function handleReports(
|
|||
}
|
||||
|
||||
export async function sendForgotPasswordEmail(
|
||||
req: MonkeyTypes.Request2<undefined, SendForgotPasswordEmailRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, SendForgotPasswordEmailRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { email } = req.body;
|
||||
await authSendForgotPasswordEmail(email);
|
||||
return new MonkeyResponse2("Password reset request email sent.", null);
|
||||
return new MonkeyResponse("Password reset request email sent.", null);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { randomBytes } from "crypto";
|
|||
import { hash } from "bcrypt";
|
||||
import * as ApeKeysDAL from "../../dal/ape-keys";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { base64UrlEncode } from "../../utils/misc";
|
||||
import { ObjectId } from "mongodb";
|
||||
|
||||
|
@ -21,18 +21,18 @@ function cleanApeKey(apeKey: MonkeyTypes.ApeKeyDB): ApeKey {
|
|||
}
|
||||
|
||||
export async function getApeKeys(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetApeKeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const apeKeys = await ApeKeysDAL.getApeKeys(uid);
|
||||
const cleanedKeys = _(apeKeys).keyBy("_id").mapValues(cleanApeKey).value();
|
||||
|
||||
return new MonkeyResponse2("ApeKeys retrieved", cleanedKeys);
|
||||
return new MonkeyResponse("ApeKeys retrieved", cleanedKeys);
|
||||
}
|
||||
|
||||
export async function generateApeKey(
|
||||
req: MonkeyTypes.Request2<undefined, AddApeKeyRequest>
|
||||
req: MonkeyTypes.Request<undefined, AddApeKeyRequest>
|
||||
): Promise<AddApeKeyResponse> {
|
||||
const { name, enabled } = req.body;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
@ -62,7 +62,7 @@ export async function generateApeKey(
|
|||
|
||||
const apeKeyId = await ApeKeysDAL.addApeKey(apeKey);
|
||||
|
||||
return new MonkeyResponse2("ApeKey generated", {
|
||||
return new MonkeyResponse("ApeKey generated", {
|
||||
apeKey: base64UrlEncode(`${apeKeyId}.${apiKey}`),
|
||||
apeKeyId,
|
||||
apeKeyDetails: cleanApeKey(apeKey),
|
||||
|
@ -70,24 +70,24 @@ export async function generateApeKey(
|
|||
}
|
||||
|
||||
export async function editApeKey(
|
||||
req: MonkeyTypes.Request2<undefined, EditApeKeyRequest, ApeKeyParams>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, EditApeKeyRequest, ApeKeyParams>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { apeKeyId } = req.params;
|
||||
const { name, enabled } = req.body;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await ApeKeysDAL.editApeKey(uid, apeKeyId, name, enabled);
|
||||
|
||||
return new MonkeyResponse2("ApeKey updated", null);
|
||||
return new MonkeyResponse("ApeKey updated", null);
|
||||
}
|
||||
|
||||
export async function deleteApeKey(
|
||||
req: MonkeyTypes.Request2<undefined, undefined, ApeKeyParams>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, undefined, ApeKeyParams>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { apeKeyId } = req.params;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await ApeKeysDAL.deleteApeKey(uid, apeKeyId);
|
||||
|
||||
return new MonkeyResponse2("ApeKey deleted", null);
|
||||
return new MonkeyResponse("ApeKey deleted", null);
|
||||
}
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
import { PartialConfig } from "@monkeytype/contracts/schemas/configs";
|
||||
import * as ConfigDAL from "../../dal/config";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { GetConfigResponse } from "@monkeytype/contracts/configs";
|
||||
|
||||
export async function getConfig(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetConfigResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const data = (await ConfigDAL.getConfig(uid))?.config ?? null;
|
||||
|
||||
return new MonkeyResponse2("Configuration retrieved", data);
|
||||
return new MonkeyResponse("Configuration retrieved", data);
|
||||
}
|
||||
|
||||
export async function saveConfig(
|
||||
req: MonkeyTypes.Request2<undefined, PartialConfig>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, PartialConfig>
|
||||
): Promise<MonkeyResponse> {
|
||||
const config = req.body;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await ConfigDAL.saveConfig(uid, config);
|
||||
|
||||
return new MonkeyResponse2("Config updated", null);
|
||||
return new MonkeyResponse("Config updated", null);
|
||||
}
|
||||
|
||||
export async function deleteConfig(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await ConfigDAL.deleteConfig(uid);
|
||||
return new MonkeyResponse2("Config deleted", null);
|
||||
return new MonkeyResponse("Config deleted", null);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as Configuration from "../../init/configuration";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { CONFIGURATION_FORM_SCHEMA } from "../../constants/base-configuration";
|
||||
import {
|
||||
ConfigurationSchemaResponse,
|
||||
|
@ -9,24 +9,24 @@ import {
|
|||
import MonkeyError from "../../utils/error";
|
||||
|
||||
export async function getConfiguration(
|
||||
_req: MonkeyTypes.Request2
|
||||
_req: MonkeyTypes.Request
|
||||
): Promise<GetConfigurationResponse> {
|
||||
const currentConfiguration = await Configuration.getLiveConfiguration();
|
||||
return new MonkeyResponse2("Configuration retrieved", currentConfiguration);
|
||||
return new MonkeyResponse("Configuration retrieved", currentConfiguration);
|
||||
}
|
||||
|
||||
export async function getSchema(
|
||||
_req: MonkeyTypes.Request2
|
||||
_req: MonkeyTypes.Request
|
||||
): Promise<ConfigurationSchemaResponse> {
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Configuration schema retrieved",
|
||||
CONFIGURATION_FORM_SCHEMA
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateConfiguration(
|
||||
req: MonkeyTypes.Request2<undefined, PatchConfigurationRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, PatchConfigurationRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { configuration } = req.body;
|
||||
const success = await Configuration.patchConfiguration(configuration);
|
||||
|
||||
|
@ -34,5 +34,5 @@ export async function updateConfiguration(
|
|||
throw new MonkeyError(500, "Configuration update failed");
|
||||
}
|
||||
|
||||
return new MonkeyResponse2("Configuration updated", null);
|
||||
return new MonkeyResponse("Configuration updated", null);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import * as UserDal from "../../dal/user";
|
||||
import FirebaseAdmin from "../../init/firebase-admin";
|
||||
import Logger from "../../utils/logger";
|
||||
|
@ -28,7 +28,7 @@ const CREATE_RESULT_DEFAULT_OPTIONS = {
|
|||
};
|
||||
|
||||
export async function createTestData(
|
||||
req: MonkeyTypes.Request2<undefined, GenerateDataRequest>
|
||||
req: MonkeyTypes.Request<undefined, GenerateDataRequest>
|
||||
): Promise<GenerateDataResponse> {
|
||||
const { username, createUser } = req.body;
|
||||
const user = await getOrCreateUser(username, "password", createUser);
|
||||
|
@ -39,7 +39,7 @@ export async function createTestData(
|
|||
await updateUser(uid);
|
||||
await updateLeaderboard();
|
||||
|
||||
return new MonkeyResponse2("test data created", { uid, email });
|
||||
return new MonkeyResponse("test data created", { uid, email });
|
||||
}
|
||||
|
||||
async function getOrCreateUser(
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
MILLISECONDS_IN_DAY,
|
||||
getCurrentWeekTimestamp,
|
||||
} from "../../utils/misc";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import * as LeaderboardsDAL from "../../dal/leaderboards";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import * as DailyLeaderboards from "../../utils/daily-leaderboards";
|
||||
|
@ -24,7 +24,7 @@ import {
|
|||
import { Configuration } from "@monkeytype/contracts/schemas/configuration";
|
||||
|
||||
export async function getLeaderboard(
|
||||
req: MonkeyTypes.Request2<GetLeaderboardQuery>
|
||||
req: MonkeyTypes.Request<GetLeaderboardQuery>
|
||||
): Promise<GetLeaderboardResponse> {
|
||||
const { language, mode, mode2, skip = 0, limit = 50 } = req.query;
|
||||
|
||||
|
@ -45,11 +45,11 @@ export async function getLeaderboard(
|
|||
|
||||
const normalizedLeaderboard = leaderboard.map((it) => _.omit(it, ["_id"]));
|
||||
|
||||
return new MonkeyResponse2("Leaderboard retrieved", normalizedLeaderboard);
|
||||
return new MonkeyResponse("Leaderboard retrieved", normalizedLeaderboard);
|
||||
}
|
||||
|
||||
export async function getRankFromLeaderboard(
|
||||
req: MonkeyTypes.Request2<LanguageAndModeQuery>
|
||||
req: MonkeyTypes.Request<LanguageAndModeQuery>
|
||||
): Promise<GetLeaderboardRankResponse> {
|
||||
const { language, mode, mode2 } = req.query;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
@ -62,7 +62,7 @@ export async function getRankFromLeaderboard(
|
|||
);
|
||||
}
|
||||
|
||||
return new MonkeyResponse2("Rank retrieved", data);
|
||||
return new MonkeyResponse("Rank retrieved", data);
|
||||
}
|
||||
|
||||
function getDailyLeaderboardWithError(
|
||||
|
@ -89,7 +89,7 @@ function getDailyLeaderboardWithError(
|
|||
}
|
||||
|
||||
export async function getDailyLeaderboard(
|
||||
req: MonkeyTypes.Request2<GetDailyLeaderboardQuery>
|
||||
req: MonkeyTypes.Request<GetDailyLeaderboardQuery>
|
||||
): Promise<GetLeaderboardResponse> {
|
||||
const { skip = 0, limit = 50 } = req.query;
|
||||
|
||||
|
@ -108,11 +108,11 @@ export async function getDailyLeaderboard(
|
|||
req.ctx.configuration.users.premium.enabled
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("Daily leaderboard retrieved", topResults);
|
||||
return new MonkeyResponse("Daily leaderboard retrieved", topResults);
|
||||
}
|
||||
|
||||
export async function getDailyLeaderboardRank(
|
||||
req: MonkeyTypes.Request2<GetDailyLeaderboardRankQuery>
|
||||
req: MonkeyTypes.Request<GetDailyLeaderboardRankQuery>
|
||||
): Promise<GetLeaderboardDailyRankResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -126,7 +126,7 @@ export async function getDailyLeaderboardRank(
|
|||
req.ctx.configuration.dailyLeaderboards
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("Daily leaderboard rank retrieved", rank);
|
||||
return new MonkeyResponse("Daily leaderboard rank retrieved", rank);
|
||||
}
|
||||
|
||||
function getWeeklyXpLeaderboardWithError(
|
||||
|
@ -147,7 +147,7 @@ function getWeeklyXpLeaderboardWithError(
|
|||
}
|
||||
|
||||
export async function getWeeklyXpLeaderboardResults(
|
||||
req: MonkeyTypes.Request2<GetWeeklyXpLeaderboardQuery>
|
||||
req: MonkeyTypes.Request<GetWeeklyXpLeaderboardQuery>
|
||||
): Promise<GetWeeklyXpLeaderboardResponse> {
|
||||
const { skip = 0, limit = 50 } = req.query;
|
||||
|
||||
|
@ -164,11 +164,11 @@ export async function getWeeklyXpLeaderboardResults(
|
|||
req.ctx.configuration.leaderboards.weeklyXp
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("Weekly xp leaderboard retrieved", results);
|
||||
return new MonkeyResponse("Weekly xp leaderboard retrieved", results);
|
||||
}
|
||||
|
||||
export async function getWeeklyXpLeaderboardRank(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetWeeklyXpLeaderboardRankResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -181,5 +181,5 @@ export async function getWeeklyXpLeaderboardRank(
|
|||
req.ctx.configuration.leaderboards.weeklyXp
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("Weekly xp leaderboard rank retrieved", rankEntry);
|
||||
return new MonkeyResponse("Weekly xp leaderboard rank retrieved", rankEntry);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ import {
|
|||
GetPresetResponse,
|
||||
} from "@monkeytype/contracts/presets";
|
||||
import * as PresetDAL from "../../dal/preset";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { replaceObjectId } from "../../utils/misc";
|
||||
import { EditPresetRequest } from "@monkeytype/contracts/schemas/presets";
|
||||
|
||||
export async function getPresets(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetPresetResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -21,36 +21,36 @@ export async function getPresets(
|
|||
}))
|
||||
.map((it) => replaceObjectId(it));
|
||||
|
||||
return new MonkeyResponse2("Presets retrieved", data);
|
||||
return new MonkeyResponse("Presets retrieved", data);
|
||||
}
|
||||
|
||||
export async function addPreset(
|
||||
req: MonkeyTypes.Request2<undefined, AddPresetRequest>
|
||||
req: MonkeyTypes.Request<undefined, AddPresetRequest>
|
||||
): Promise<AddPresetResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const data = await PresetDAL.addPreset(uid, req.body);
|
||||
|
||||
return new MonkeyResponse2("Preset created", data);
|
||||
return new MonkeyResponse("Preset created", data);
|
||||
}
|
||||
|
||||
export async function editPreset(
|
||||
req: MonkeyTypes.Request2<undefined, EditPresetRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, EditPresetRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await PresetDAL.editPreset(uid, req.body);
|
||||
|
||||
return new MonkeyResponse2("Preset updated", null);
|
||||
return new MonkeyResponse("Preset updated", null);
|
||||
}
|
||||
|
||||
export async function removePreset(
|
||||
req: MonkeyTypes.Request2<undefined, undefined, DeletePresetsParams>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, undefined, DeletePresetsParams>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { presetId } = req.params;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await PresetDAL.removePreset(uid, presetId);
|
||||
|
||||
return new MonkeyResponse2("Preset deleted", null);
|
||||
return new MonkeyResponse("Preset deleted", null);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { GetPsaResponse } from "@monkeytype/contracts/psas";
|
||||
import * as PsaDAL from "../../dal/psa";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { replaceObjectIds } from "../../utils/misc";
|
||||
|
||||
export async function getPsas(
|
||||
_req: MonkeyTypes.Request2
|
||||
_req: MonkeyTypes.Request
|
||||
): Promise<GetPsaResponse> {
|
||||
const data = await PsaDAL.get();
|
||||
return new MonkeyResponse2("PSAs retrieved", replaceObjectIds(data));
|
||||
return new MonkeyResponse("PSAs retrieved", replaceObjectIds(data));
|
||||
}
|
||||
|
|
|
@ -4,19 +4,19 @@ import {
|
|||
GetTypingStatsResponse,
|
||||
} from "@monkeytype/contracts/public";
|
||||
import * as PublicDAL from "../../dal/public";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
|
||||
export async function getSpeedHistogram(
|
||||
req: MonkeyTypes.Request2<GetSpeedHistogramQuery>
|
||||
req: MonkeyTypes.Request<GetSpeedHistogramQuery>
|
||||
): Promise<GetSpeedHistogramResponse> {
|
||||
const { language, mode, mode2 } = req.query;
|
||||
const data = await PublicDAL.getSpeedHistogram(language, mode, mode2);
|
||||
return new MonkeyResponse2("Public speed histogram retrieved", data);
|
||||
return new MonkeyResponse("Public speed histogram retrieved", data);
|
||||
}
|
||||
|
||||
export async function getTypingStats(
|
||||
_req: MonkeyTypes.Request2
|
||||
_req: MonkeyTypes.Request
|
||||
): Promise<GetTypingStatsResponse> {
|
||||
const data = await PublicDAL.getTypingStats();
|
||||
return new MonkeyResponse2("Public typing stats retrieved", data);
|
||||
return new MonkeyResponse("Public typing stats retrieved", data);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import * as NewQuotesDAL from "../../dal/new-quotes";
|
|||
import * as QuoteRatingsDAL from "../../dal/quote-ratings";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import { verify } from "../../utils/captcha";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import { ObjectId } from "mongodb";
|
||||
import { addLog } from "../../dal/logs";
|
||||
import {
|
||||
|
@ -30,7 +30,7 @@ async function verifyCaptcha(captcha: string): Promise<void> {
|
|||
}
|
||||
|
||||
export async function getQuotes(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetQuotesResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const quoteMod = (await getPartialUser(uid, "get quotes", ["quoteMod"]))
|
||||
|
@ -38,36 +38,36 @@ export async function getQuotes(
|
|||
const quoteModString = quoteMod === true ? "all" : (quoteMod as string);
|
||||
|
||||
const data = await NewQuotesDAL.get(quoteModString);
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Quote submissions retrieved",
|
||||
replaceObjectIds(data)
|
||||
);
|
||||
}
|
||||
|
||||
export async function isSubmissionEnabled(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<IsSubmissionEnabledResponse> {
|
||||
const { submissionsEnabled } = req.ctx.configuration.quotes;
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Quote submission " + (submissionsEnabled ? "enabled" : "disabled"),
|
||||
{ isEnabled: submissionsEnabled }
|
||||
);
|
||||
}
|
||||
|
||||
export async function addQuote(
|
||||
req: MonkeyTypes.Request2<undefined, AddQuoteRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, AddQuoteRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { text, source, language, captcha } = req.body;
|
||||
|
||||
await verifyCaptcha(captcha);
|
||||
|
||||
await NewQuotesDAL.add(text, source, language, uid);
|
||||
return new MonkeyResponse2("Quote submission added", null);
|
||||
return new MonkeyResponse("Quote submission added", null);
|
||||
}
|
||||
|
||||
export async function approveQuote(
|
||||
req: MonkeyTypes.Request2<undefined, ApproveQuoteRequest>
|
||||
req: MonkeyTypes.Request<undefined, ApproveQuoteRequest>
|
||||
): Promise<ApproveQuoteResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { quoteId, editText, editSource } = req.body;
|
||||
|
@ -81,31 +81,31 @@ export async function approveQuote(
|
|||
const data = await NewQuotesDAL.approve(quoteId, editText, editSource, name);
|
||||
void addLog("system_quote_approved", data, uid);
|
||||
|
||||
return new MonkeyResponse2(data.message, data.quote);
|
||||
return new MonkeyResponse(data.message, data.quote);
|
||||
}
|
||||
|
||||
export async function refuseQuote(
|
||||
req: MonkeyTypes.Request2<undefined, RejectQuoteRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, RejectQuoteRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { quoteId } = req.body;
|
||||
|
||||
await NewQuotesDAL.refuse(quoteId);
|
||||
return new MonkeyResponse2("Quote refused", null);
|
||||
return new MonkeyResponse("Quote refused", null);
|
||||
}
|
||||
|
||||
export async function getRating(
|
||||
req: MonkeyTypes.Request2<GetQuoteRatingQuery>
|
||||
req: MonkeyTypes.Request<GetQuoteRatingQuery>
|
||||
): Promise<GetQuoteRatingResponse> {
|
||||
const { quoteId, language } = req.query;
|
||||
|
||||
const data = await QuoteRatingsDAL.get(quoteId, language);
|
||||
|
||||
return new MonkeyResponse2("Rating retrieved", replaceObjectId(data));
|
||||
return new MonkeyResponse("Rating retrieved", replaceObjectId(data));
|
||||
}
|
||||
|
||||
export async function submitRating(
|
||||
req: MonkeyTypes.Request2<undefined, AddQuoteRatingRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, AddQuoteRatingRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { quoteId, rating, language } = req.body;
|
||||
|
||||
|
@ -131,12 +131,12 @@ export async function submitRating(
|
|||
const responseMessage = `Rating ${
|
||||
shouldUpdateRating ? "updated" : "submitted"
|
||||
}`;
|
||||
return new MonkeyResponse2(responseMessage, null);
|
||||
return new MonkeyResponse(responseMessage, null);
|
||||
}
|
||||
|
||||
export async function reportQuote(
|
||||
req: MonkeyTypes.Request2<undefined, ReportQuoteRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, ReportQuoteRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const {
|
||||
reporting: { maxReports, contentReportLimit },
|
||||
|
@ -159,5 +159,5 @@ export async function reportQuote(
|
|||
|
||||
await ReportDAL.createReport(newReport, maxReports, contentReportLimit);
|
||||
|
||||
return new MonkeyResponse2("Quote reported", null);
|
||||
return new MonkeyResponse("Quote reported", null);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
import objectHash from "object-hash";
|
||||
import Logger from "../../utils/logger";
|
||||
import "dotenv/config";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import { areFunboxesCompatible, isTestTooShort } from "../../utils/validation";
|
||||
import {
|
||||
|
@ -73,7 +73,7 @@ try {
|
|||
}
|
||||
|
||||
export async function getResults(
|
||||
req: MonkeyTypes.Request2<GetResultsQuery>
|
||||
req: MonkeyTypes.Request<GetResultsQuery>
|
||||
): Promise<GetResultsResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const premiumFeaturesEnabled = req.ctx.configuration.users.premium.enabled;
|
||||
|
@ -122,29 +122,29 @@ export async function getResults(
|
|||
},
|
||||
uid
|
||||
);
|
||||
return new MonkeyResponse2("Results retrieved", results.map(convertResult));
|
||||
return new MonkeyResponse("Results retrieved", results.map(convertResult));
|
||||
}
|
||||
|
||||
export async function getLastResult(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetLastResultResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const results = await ResultDAL.getLastResult(uid);
|
||||
return new MonkeyResponse2("Result retrieved", convertResult(results));
|
||||
return new MonkeyResponse("Result retrieved", convertResult(results));
|
||||
}
|
||||
|
||||
export async function deleteAll(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await ResultDAL.deleteAll(uid);
|
||||
void addLog("user_results_deleted", "", uid);
|
||||
return new MonkeyResponse2("All results deleted", null);
|
||||
return new MonkeyResponse("All results deleted", null);
|
||||
}
|
||||
|
||||
export async function updateTags(
|
||||
req: MonkeyTypes.Request2<undefined, UpdateResultTagsRequest>
|
||||
req: MonkeyTypes.Request<undefined, UpdateResultTagsRequest>
|
||||
): Promise<UpdateResultTagsResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { tagIds, resultId } = req.body;
|
||||
|
@ -173,13 +173,13 @@ export async function updateTags(
|
|||
|
||||
const user = await UserDAL.getPartialUser(uid, "update tags", ["tags"]);
|
||||
const tagPbs = await UserDAL.checkIfTagPb(uid, user, result);
|
||||
return new MonkeyResponse2("Result tags updated", {
|
||||
return new MonkeyResponse("Result tags updated", {
|
||||
tagPbs,
|
||||
});
|
||||
}
|
||||
|
||||
export async function addResult(
|
||||
req: MonkeyTypes.Request2<undefined, AddResultRequest>
|
||||
req: MonkeyTypes.Request<undefined, AddResultRequest>
|
||||
): Promise<AddResultResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -630,7 +630,7 @@ export async function addResult(
|
|||
|
||||
incrementResult(completedEvent, dbresult.isPb);
|
||||
|
||||
return new MonkeyResponse2("Result saved", data);
|
||||
return new MonkeyResponse("Result saved", data);
|
||||
}
|
||||
|
||||
type XpResult = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import _ from "lodash";
|
||||
import * as UserDAL from "../../dal/user";
|
||||
import MonkeyError from "../../utils/error";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import * as DiscordUtils from "../../utils/discord";
|
||||
import {
|
||||
MILLISECONDS_IN_DAY,
|
||||
|
@ -102,8 +102,8 @@ async function verifyCaptcha(captcha: string): Promise<void> {
|
|||
}
|
||||
|
||||
export async function createNewUser(
|
||||
req: MonkeyTypes.Request2<undefined, CreateUserRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, CreateUserRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { name, captcha } = req.body;
|
||||
const { email, uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -127,7 +127,7 @@ export async function createNewUser(
|
|||
await UserDAL.addUser(name, email, uid);
|
||||
void addImportantLog("user_created", `${name} ${email}`, uid);
|
||||
|
||||
return new MonkeyResponse2("User created", null);
|
||||
return new MonkeyResponse("User created", null);
|
||||
} catch (e) {
|
||||
//user was created in firebase from the frontend, remove it
|
||||
await firebaseDeleteUserIgnoreError(uid);
|
||||
|
@ -136,8 +136,8 @@ export async function createNewUser(
|
|||
}
|
||||
|
||||
export async function sendVerificationEmail(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { email, uid } = req.ctx.decodedToken;
|
||||
const isVerified = (
|
||||
await FirebaseAdmin()
|
||||
|
@ -212,23 +212,23 @@ export async function sendVerificationEmail(
|
|||
}
|
||||
await emailQueue.sendVerificationEmail(email, userInfo.name, link);
|
||||
|
||||
return new MonkeyResponse2("Email sent", null);
|
||||
return new MonkeyResponse("Email sent", null);
|
||||
}
|
||||
|
||||
export async function sendForgotPasswordEmail(
|
||||
req: MonkeyTypes.Request2<undefined, ForgotPasswordEmailRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, ForgotPasswordEmailRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { email } = req.body;
|
||||
await authSendForgotPasswordEmail(email);
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Password reset request received. If the email is valid, you will receive an email shortly.",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteUser(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const userInfo = await UserDAL.getPartialUser(uid, "delete user", [
|
||||
|
@ -265,12 +265,12 @@ export async function deleteUser(
|
|||
uid
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("User deleted", null);
|
||||
return new MonkeyResponse("User deleted", null);
|
||||
}
|
||||
|
||||
export async function resetUser(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const userInfo = await UserDAL.getPartialUser(uid, "reset user", [
|
||||
|
@ -301,12 +301,12 @@ export async function resetUser(
|
|||
await Promise.all(promises);
|
||||
void addImportantLog("user_reset", `${userInfo.email} ${userInfo.name}`, uid);
|
||||
|
||||
return new MonkeyResponse2("User reset", null);
|
||||
return new MonkeyResponse("User reset", null);
|
||||
}
|
||||
|
||||
export async function updateName(
|
||||
req: MonkeyTypes.Request2<undefined, UpdateUserNameRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, UpdateUserNameRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { name } = req.body;
|
||||
|
||||
|
@ -335,12 +335,12 @@ export async function updateName(
|
|||
uid
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("User's name updated", null);
|
||||
return new MonkeyResponse("User's name updated", null);
|
||||
}
|
||||
|
||||
export async function clearPb(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await UserDAL.clearPb(uid);
|
||||
|
@ -350,12 +350,12 @@ export async function clearPb(
|
|||
);
|
||||
void addImportantLog("user_cleared_pbs", "", uid);
|
||||
|
||||
return new MonkeyResponse2("User's PB cleared", null);
|
||||
return new MonkeyResponse("User's PB cleared", null);
|
||||
}
|
||||
|
||||
export async function optOutOfLeaderboards(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
await UserDAL.optOutOfLeaderboards(uid);
|
||||
|
@ -365,12 +365,12 @@ export async function optOutOfLeaderboards(
|
|||
);
|
||||
void addImportantLog("user_opted_out_of_leaderboards", "", uid);
|
||||
|
||||
return new MonkeyResponse2("User opted out of leaderboards", null);
|
||||
return new MonkeyResponse("User opted out of leaderboards", null);
|
||||
}
|
||||
|
||||
export async function checkName(
|
||||
req: MonkeyTypes.Request2<undefined, undefined, CheckNamePathParameters>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, undefined, CheckNamePathParameters>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { name } = req.params;
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -379,12 +379,12 @@ export async function checkName(
|
|||
throw new MonkeyError(409, "Username unavailable");
|
||||
}
|
||||
|
||||
return new MonkeyResponse2("Username available", null);
|
||||
return new MonkeyResponse("Username available", null);
|
||||
}
|
||||
|
||||
export async function updateEmail(
|
||||
req: MonkeyTypes.Request2<undefined, UpdateEmailRequestSchema>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, UpdateEmailRequestSchema>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
let { newEmail } = req.body;
|
||||
|
||||
|
@ -423,18 +423,18 @@ export async function updateEmail(
|
|||
uid
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("Email updated", null);
|
||||
return new MonkeyResponse("Email updated", null);
|
||||
}
|
||||
|
||||
export async function updatePassword(
|
||||
req: MonkeyTypes.Request2<undefined, UpdatePasswordRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, UpdatePasswordRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { newPassword } = req.body;
|
||||
|
||||
await AuthUtil.updateUserPassword(uid, newPassword);
|
||||
|
||||
return new MonkeyResponse2("Password updated", null);
|
||||
return new MonkeyResponse("Password updated", null);
|
||||
}
|
||||
|
||||
type RelevantUserInfo = Omit<
|
||||
|
@ -467,7 +467,7 @@ function getRelevantUserInfo(user: MonkeyTypes.DBUser): RelevantUserInfo {
|
|||
}
|
||||
|
||||
export async function getUser(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetUserResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -555,14 +555,14 @@ export async function getUser(
|
|||
testActivity,
|
||||
};
|
||||
|
||||
return new MonkeyResponse2("User data retrieved", {
|
||||
return new MonkeyResponse("User data retrieved", {
|
||||
...userData,
|
||||
inboxUnreadSize: inboxUnreadSize,
|
||||
});
|
||||
}
|
||||
|
||||
export async function getOauthLink(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetDiscordOauthLinkResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -570,13 +570,13 @@ export async function getOauthLink(
|
|||
const url = await DiscordUtils.getOauthLink(uid);
|
||||
|
||||
//return
|
||||
return new MonkeyResponse2("Discord oauth link generated", {
|
||||
return new MonkeyResponse("Discord oauth link generated", {
|
||||
url: url,
|
||||
});
|
||||
}
|
||||
|
||||
export async function linkDiscord(
|
||||
req: MonkeyTypes.Request2<undefined, LinkDiscordRequest>
|
||||
req: MonkeyTypes.Request<undefined, LinkDiscordRequest>
|
||||
): Promise<LinkDiscordResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { tokenType, accessToken, state } = req.body;
|
||||
|
@ -598,7 +598,7 @@ export async function linkDiscord(
|
|||
|
||||
if (userInfo.discordId !== undefined && userInfo.discordId !== "") {
|
||||
await UserDAL.linkDiscord(uid, userInfo.discordId, discordAvatar);
|
||||
return new MonkeyResponse2("Discord avatar updated", {
|
||||
return new MonkeyResponse("Discord avatar updated", {
|
||||
discordId,
|
||||
discordAvatar,
|
||||
});
|
||||
|
@ -629,15 +629,15 @@ export async function linkDiscord(
|
|||
await GeorgeQueue.linkDiscord(discordId, uid);
|
||||
void addImportantLog("user_discord_link", `linked to ${discordId}`, uid);
|
||||
|
||||
return new MonkeyResponse2("Discord account linked", {
|
||||
return new MonkeyResponse("Discord account linked", {
|
||||
discordId,
|
||||
discordAvatar,
|
||||
});
|
||||
}
|
||||
|
||||
export async function unlinkDiscord(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const userInfo = await UserDAL.getPartialUser(uid, "unlink discord", [
|
||||
|
@ -658,11 +658,11 @@ export async function unlinkDiscord(
|
|||
await UserDAL.unlinkDiscord(uid);
|
||||
void addImportantLog("user_discord_unlinked", discordId, uid);
|
||||
|
||||
return new MonkeyResponse2("Discord account unlinked", null);
|
||||
return new MonkeyResponse("Discord account unlinked", null);
|
||||
}
|
||||
|
||||
export async function addResultFilterPreset(
|
||||
req: MonkeyTypes.Request2<undefined, AddResultFilterPresetRequest>
|
||||
req: MonkeyTypes.Request<undefined, AddResultFilterPresetRequest>
|
||||
): Promise<AddResultFilterPresetResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const filter = req.body;
|
||||
|
@ -673,158 +673,158 @@ export async function addResultFilterPreset(
|
|||
filter,
|
||||
maxPresetsPerUser
|
||||
);
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Result filter preset created",
|
||||
createdId.toHexString()
|
||||
);
|
||||
}
|
||||
|
||||
export async function removeResultFilterPreset(
|
||||
req: MonkeyTypes.Request2<
|
||||
req: MonkeyTypes.Request<
|
||||
undefined,
|
||||
undefined,
|
||||
RemoveResultFilterPresetPathParams
|
||||
>
|
||||
): Promise<MonkeyResponse2> {
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { presetId } = req.params;
|
||||
|
||||
await UserDAL.removeResultFilterPreset(uid, presetId);
|
||||
return new MonkeyResponse2("Result filter preset deleted", null);
|
||||
return new MonkeyResponse("Result filter preset deleted", null);
|
||||
}
|
||||
|
||||
export async function addTag(
|
||||
req: MonkeyTypes.Request2<undefined, AddTagRequest>
|
||||
req: MonkeyTypes.Request<undefined, AddTagRequest>
|
||||
): Promise<AddTagResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { tagName } = req.body;
|
||||
|
||||
const tag = await UserDAL.addTag(uid, tagName);
|
||||
return new MonkeyResponse2("Tag updated", replaceObjectId(tag));
|
||||
return new MonkeyResponse("Tag updated", replaceObjectId(tag));
|
||||
}
|
||||
|
||||
export async function clearTagPb(
|
||||
req: MonkeyTypes.Request2<undefined, undefined, TagIdPathParams>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, undefined, TagIdPathParams>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { tagId } = req.params;
|
||||
|
||||
await UserDAL.removeTagPb(uid, tagId);
|
||||
return new MonkeyResponse2("Tag PB cleared", null);
|
||||
return new MonkeyResponse("Tag PB cleared", null);
|
||||
}
|
||||
|
||||
export async function editTag(
|
||||
req: MonkeyTypes.Request2<undefined, EditTagRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, EditTagRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { tagId, newName } = req.body;
|
||||
|
||||
await UserDAL.editTag(uid, tagId, newName);
|
||||
return new MonkeyResponse2("Tag updated", null);
|
||||
return new MonkeyResponse("Tag updated", null);
|
||||
}
|
||||
|
||||
export async function removeTag(
|
||||
req: MonkeyTypes.Request2<undefined, undefined, TagIdPathParams>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, undefined, TagIdPathParams>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { tagId } = req.params;
|
||||
|
||||
await UserDAL.removeTag(uid, tagId);
|
||||
return new MonkeyResponse2("Tag deleted", null);
|
||||
return new MonkeyResponse("Tag deleted", null);
|
||||
}
|
||||
|
||||
export async function getTags(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetTagsResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const tags = await UserDAL.getTags(uid);
|
||||
return new MonkeyResponse2("Tags retrieved", replaceObjectIds(tags));
|
||||
return new MonkeyResponse("Tags retrieved", replaceObjectIds(tags));
|
||||
}
|
||||
|
||||
export async function updateLbMemory(
|
||||
req: MonkeyTypes.Request2<undefined, UpdateLeaderboardMemoryRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, UpdateLeaderboardMemoryRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { mode, language, rank } = req.body;
|
||||
const mode2 = req.body.mode2;
|
||||
|
||||
await UserDAL.updateLbMemory(uid, mode, mode2, language, rank);
|
||||
return new MonkeyResponse2("Leaderboard memory updated", null);
|
||||
return new MonkeyResponse("Leaderboard memory updated", null);
|
||||
}
|
||||
|
||||
export async function getCustomThemes(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetCustomThemesResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const customThemes = await UserDAL.getThemes(uid);
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Custom themes retrieved",
|
||||
replaceObjectIds(customThemes)
|
||||
);
|
||||
}
|
||||
|
||||
export async function addCustomTheme(
|
||||
req: MonkeyTypes.Request2<undefined, AddCustomThemeRequest>
|
||||
req: MonkeyTypes.Request<undefined, AddCustomThemeRequest>
|
||||
): Promise<AddCustomThemeResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { name, colors } = req.body;
|
||||
|
||||
const addedTheme = await UserDAL.addTheme(uid, { name, colors });
|
||||
return new MonkeyResponse2("Custom theme added", replaceObjectId(addedTheme));
|
||||
return new MonkeyResponse("Custom theme added", replaceObjectId(addedTheme));
|
||||
}
|
||||
|
||||
export async function removeCustomTheme(
|
||||
req: MonkeyTypes.Request2<undefined, DeleteCustomThemeRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, DeleteCustomThemeRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { themeId } = req.body;
|
||||
await UserDAL.removeTheme(uid, themeId);
|
||||
return new MonkeyResponse2("Custom theme removed", null);
|
||||
return new MonkeyResponse("Custom theme removed", null);
|
||||
}
|
||||
|
||||
export async function editCustomTheme(
|
||||
req: MonkeyTypes.Request2<undefined, EditCustomThemeRequst>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, EditCustomThemeRequst>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { themeId, theme } = req.body;
|
||||
|
||||
await UserDAL.editTheme(uid, themeId, theme);
|
||||
return new MonkeyResponse2("Custom theme updated", null);
|
||||
return new MonkeyResponse("Custom theme updated", null);
|
||||
}
|
||||
|
||||
export async function getPersonalBests(
|
||||
req: MonkeyTypes.Request2<GetPersonalBestsQuery>
|
||||
req: MonkeyTypes.Request<GetPersonalBestsQuery>
|
||||
): Promise<GetPersonalBestsResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { mode, mode2 } = req.query;
|
||||
|
||||
const data = (await UserDAL.getPersonalBests(uid, mode, mode2)) ?? null;
|
||||
return new MonkeyResponse2("Personal bests retrieved", data);
|
||||
return new MonkeyResponse("Personal bests retrieved", data);
|
||||
}
|
||||
|
||||
export async function getStats(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetStatsResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const data = (await UserDAL.getStats(uid)) ?? null;
|
||||
return new MonkeyResponse2("Personal stats retrieved", data);
|
||||
return new MonkeyResponse("Personal stats retrieved", data);
|
||||
}
|
||||
|
||||
export async function getFavoriteQuotes(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetFavoriteQuotesResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const quotes = await UserDAL.getFavoriteQuotes(uid);
|
||||
|
||||
return new MonkeyResponse2("Favorite quotes retrieved", quotes);
|
||||
return new MonkeyResponse("Favorite quotes retrieved", quotes);
|
||||
}
|
||||
|
||||
export async function addFavoriteQuote(
|
||||
req: MonkeyTypes.Request2<undefined, AddFavoriteQuoteRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, AddFavoriteQuoteRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const { language, quoteId } = req.body;
|
||||
|
@ -836,22 +836,22 @@ export async function addFavoriteQuote(
|
|||
req.ctx.configuration.quotes.maxFavorites
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("Quote added to favorites", null);
|
||||
return new MonkeyResponse("Quote added to favorites", null);
|
||||
}
|
||||
|
||||
export async function removeFavoriteQuote(
|
||||
req: MonkeyTypes.Request2<undefined, RemoveFavoriteQuoteRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, RemoveFavoriteQuoteRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const { quoteId, language } = req.body;
|
||||
await UserDAL.removeFavoriteQuote(uid, language, quoteId);
|
||||
|
||||
return new MonkeyResponse2("Quote removed from favorites", null);
|
||||
return new MonkeyResponse("Quote removed from favorites", null);
|
||||
}
|
||||
|
||||
export async function getProfile(
|
||||
req: MonkeyTypes.Request2<GetProfileQuery, undefined, GetProfilePathParams>
|
||||
req: MonkeyTypes.Request<GetProfileQuery, undefined, GetProfilePathParams>
|
||||
): Promise<GetProfileResponse> {
|
||||
const { uidOrName } = req.params;
|
||||
|
||||
|
@ -906,7 +906,7 @@ export async function getProfile(
|
|||
};
|
||||
|
||||
if (banned) {
|
||||
return new MonkeyResponse2("Profile retrived: banned user", baseProfile);
|
||||
return new MonkeyResponse("Profile retrived: banned user", baseProfile);
|
||||
}
|
||||
|
||||
const allTimeLbs = await getAllTimeLbs(user.uid);
|
||||
|
@ -919,11 +919,11 @@ export async function getProfile(
|
|||
uid: user.uid,
|
||||
} as UserProfile;
|
||||
|
||||
return new MonkeyResponse2("Profile retrieved", profileData);
|
||||
return new MonkeyResponse("Profile retrieved", profileData);
|
||||
}
|
||||
|
||||
export async function updateProfile(
|
||||
req: MonkeyTypes.Request2<undefined, UpdateUserProfileRequest>
|
||||
req: MonkeyTypes.Request<undefined, UpdateUserProfileRequest>
|
||||
): Promise<UpdateUserProfileResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { bio, keyboard, socialProfiles, selectedBadgeId } = req.body;
|
||||
|
@ -956,25 +956,25 @@ export async function updateProfile(
|
|||
|
||||
await UserDAL.updateProfile(uid, profileDetailsUpdates, user.inventory);
|
||||
|
||||
return new MonkeyResponse2("Profile updated", profileDetailsUpdates);
|
||||
return new MonkeyResponse("Profile updated", profileDetailsUpdates);
|
||||
}
|
||||
|
||||
export async function getInbox(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetUserInboxResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const inbox = await UserDAL.getInbox(uid);
|
||||
|
||||
return new MonkeyResponse2("Inbox retrieved", {
|
||||
return new MonkeyResponse("Inbox retrieved", {
|
||||
inbox,
|
||||
maxMail: req.ctx.configuration.users.inbox.maxMail,
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateInbox(
|
||||
req: MonkeyTypes.Request2<undefined, UpdateUserInboxRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, UpdateUserInboxRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { mailIdsToMarkRead, mailIdsToDelete } = req.body;
|
||||
|
||||
|
@ -984,12 +984,12 @@ export async function updateInbox(
|
|||
mailIdsToDelete ?? []
|
||||
);
|
||||
|
||||
return new MonkeyResponse2("Inbox updated", null);
|
||||
return new MonkeyResponse("Inbox updated", null);
|
||||
}
|
||||
|
||||
export async function reportUser(
|
||||
req: MonkeyTypes.Request2<undefined, ReportUserRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, ReportUserRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const {
|
||||
reporting: { maxReports, contentReportLimit },
|
||||
|
@ -1012,12 +1012,12 @@ export async function reportUser(
|
|||
|
||||
await ReportDAL.createReport(newReport, maxReports, contentReportLimit);
|
||||
|
||||
return new MonkeyResponse2("User reported", null);
|
||||
return new MonkeyResponse("User reported", null);
|
||||
}
|
||||
|
||||
export async function setStreakHourOffset(
|
||||
req: MonkeyTypes.Request2<undefined, SetStreakHourOffsetRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, SetStreakHourOffsetRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const { hourOffset } = req.body;
|
||||
|
||||
|
@ -1036,16 +1036,16 @@ export async function setStreakHourOffset(
|
|||
|
||||
void addImportantLog("user_streak_hour_offset_set", { hourOffset }, uid);
|
||||
|
||||
return new MonkeyResponse2("Streak hour offset set", null);
|
||||
return new MonkeyResponse("Streak hour offset set", null);
|
||||
}
|
||||
|
||||
export async function revokeAllTokens(
|
||||
req: MonkeyTypes.Request2
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
await AuthUtil.revokeTokensByUid(uid);
|
||||
void addImportantLog("user_tokens_revoked", "", uid);
|
||||
return new MonkeyResponse2("All tokens revoked", null);
|
||||
return new MonkeyResponse("All tokens revoked", null);
|
||||
}
|
||||
|
||||
async function getAllTimeLbs(uid: string): Promise<AllTimeLbs> {
|
||||
|
@ -1128,7 +1128,7 @@ export function generateCurrentTestActivity(
|
|||
}
|
||||
|
||||
export async function getTestActivity(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetTestActivityResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
const premiumFeaturesEnabled = req.ctx.configuration.users.premium.enabled;
|
||||
|
@ -1146,7 +1146,7 @@ export async function getTestActivity(
|
|||
throw new MonkeyError(503, "User does not have premium");
|
||||
}
|
||||
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Test activity data retrieved",
|
||||
user.testActivity ?? null
|
||||
);
|
||||
|
@ -1161,7 +1161,7 @@ async function firebaseDeleteUserIgnoreError(uid: string): Promise<void> {
|
|||
}
|
||||
|
||||
export async function getCurrentTestActivity(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetCurrentTestActivityResponse> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
|
@ -1169,18 +1169,18 @@ export async function getCurrentTestActivity(
|
|||
"testActivity",
|
||||
]);
|
||||
const data = generateCurrentTestActivity(user.testActivity);
|
||||
return new MonkeyResponse2(
|
||||
return new MonkeyResponse(
|
||||
"Current test activity data retrieved",
|
||||
data ?? null
|
||||
);
|
||||
}
|
||||
|
||||
export async function getStreak(
|
||||
req: MonkeyTypes.Request2
|
||||
req: MonkeyTypes.Request
|
||||
): Promise<GetStreakResponseSchema> {
|
||||
const { uid } = req.ctx.decodedToken;
|
||||
|
||||
const user = await UserDAL.getPartialUser(uid, "streak", ["streak"]);
|
||||
|
||||
return new MonkeyResponse2("Streak data retrieved", user.streak ?? null);
|
||||
return new MonkeyResponse("Streak data retrieved", user.streak ?? null);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { PostGithubReleaseRequest } from "@monkeytype/contracts/webhooks";
|
||||
import GeorgeQueue from "../../queues/george-queue";
|
||||
import { MonkeyResponse2 } from "../../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import MonkeyError from "../../utils/error";
|
||||
|
||||
export async function githubRelease(
|
||||
req: MonkeyTypes.Request2<undefined, PostGithubReleaseRequest>
|
||||
): Promise<MonkeyResponse2> {
|
||||
req: MonkeyTypes.Request<undefined, PostGithubReleaseRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const action = req.body.action;
|
||||
|
||||
if (action === "published") {
|
||||
|
@ -14,10 +14,7 @@ export async function githubRelease(
|
|||
throw new MonkeyError(422, 'Missing property "release.id".');
|
||||
|
||||
await GeorgeQueue.sendReleaseAnnouncement(releaseId);
|
||||
return new MonkeyResponse2(
|
||||
"Added release announcement task to queue",
|
||||
null
|
||||
);
|
||||
return new MonkeyResponse("Added release announcement task to queue", null);
|
||||
}
|
||||
return new MonkeyResponse2("No action taken", null);
|
||||
return new MonkeyResponse("No action taken", null);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import configuration from "./configuration";
|
|||
import { version } from "../../version";
|
||||
import leaderboards from "./leaderboards";
|
||||
import addSwaggerMiddlewares from "./swagger";
|
||||
import { asyncHandler } from "../../middlewares/utility";
|
||||
import { MonkeyResponse } from "../../utils/monkey-response";
|
||||
import {
|
||||
Application,
|
||||
|
@ -68,15 +67,16 @@ export function addApiRoutes(app: Application): void {
|
|||
applyApiRoutes(app);
|
||||
applyTsRestApiRoutes(app);
|
||||
|
||||
app.use(
|
||||
asyncHandler(async (req, _res) => {
|
||||
return new MonkeyResponse(
|
||||
`Unknown request URL (${req.method}: ${req.path})`,
|
||||
null,
|
||||
404
|
||||
app.use((req, res) => {
|
||||
res
|
||||
.status(404)
|
||||
.json(
|
||||
new MonkeyResponse(
|
||||
`Unknown request URL (${req.method}: ${req.path})`,
|
||||
null
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function applyTsRestApiRoutes(app: IRouter): void {
|
||||
|
@ -155,7 +155,11 @@ function applyApiRoutes(app: Application): void {
|
|||
addSwaggerMiddlewares(app);
|
||||
|
||||
app.use(
|
||||
(req: MonkeyTypes.Request, res: Response, next: NextFunction): void => {
|
||||
(
|
||||
req: MonkeyTypes.ExpressRequestWithContext,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): void => {
|
||||
if (req.path.startsWith("/configuration")) {
|
||||
next();
|
||||
return;
|
||||
|
@ -174,25 +178,13 @@ function applyApiRoutes(app: Application): void {
|
|||
}
|
||||
);
|
||||
|
||||
app.get(
|
||||
"/",
|
||||
asyncHandler(async (_req, _res) => {
|
||||
return new MonkeyResponse("ok", {
|
||||
app.get("/", (_req, res) => {
|
||||
res.status(200).json(
|
||||
new MonkeyResponse("ok", {
|
||||
uptime: Date.now() - APP_START_TIME,
|
||||
version,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
//legacy route
|
||||
app.get("/psa", (_req, res) => {
|
||||
res.json([
|
||||
{
|
||||
message:
|
||||
"It seems like your client version is very out of date as you're requesting an API endpoint that no longer exists. This will likely cause most of the website to not function correctly. Please clear your cache, or contact support if this message persists.",
|
||||
sticky: true,
|
||||
},
|
||||
]);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
_.each(API_ROUTE_MAP, (router: Router, route) => {
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
import joi from "joi";
|
||||
|
||||
const FILTER_SCHEMA = {
|
||||
_id: joi.string().required(),
|
||||
name: joi
|
||||
.string()
|
||||
.required()
|
||||
.regex(/^[0-9a-zA-Z_.-]+$/)
|
||||
.max(16)
|
||||
.messages({
|
||||
"string.pattern.base":
|
||||
"Filter name invalid. Name cannot contain special characters or more than 16 characters. Can include _ . and -",
|
||||
"string.max": "Filter name exceeds maximum of 16 characters",
|
||||
}),
|
||||
pb: joi.object({
|
||||
no: joi.bool().required(),
|
||||
yes: joi.bool().required(),
|
||||
}),
|
||||
difficulty: joi
|
||||
.object({
|
||||
normal: joi.bool().required(),
|
||||
expert: joi.bool().required(),
|
||||
master: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
mode: joi
|
||||
.object({
|
||||
words: joi.bool().required(),
|
||||
time: joi.bool().required(),
|
||||
quote: joi.bool().required(),
|
||||
zen: joi.bool().required(),
|
||||
custom: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
words: joi
|
||||
.object({
|
||||
10: joi.bool().required(),
|
||||
25: joi.bool().required(),
|
||||
50: joi.bool().required(),
|
||||
100: joi.bool().required(),
|
||||
custom: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
time: joi
|
||||
.object({
|
||||
15: joi.bool().required(),
|
||||
30: joi.bool().required(),
|
||||
60: joi.bool().required(),
|
||||
120: joi.bool().required(),
|
||||
custom: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
quoteLength: joi
|
||||
.object({
|
||||
short: joi.bool().required(),
|
||||
medium: joi.bool().required(),
|
||||
long: joi.bool().required(),
|
||||
thicc: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
punctuation: joi
|
||||
.object({
|
||||
on: joi.bool().required(),
|
||||
off: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
numbers: joi
|
||||
.object({
|
||||
on: joi.bool().required(),
|
||||
off: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
date: joi
|
||||
.object({
|
||||
last_day: joi.bool().required(),
|
||||
last_week: joi.bool().required(),
|
||||
last_month: joi.bool().required(),
|
||||
last_3months: joi.bool().required(),
|
||||
all: joi.bool().required(),
|
||||
})
|
||||
.required(),
|
||||
tags: joi.object().pattern(joi.string().token(), joi.bool()).required(),
|
||||
language: joi
|
||||
.object()
|
||||
.pattern(joi.string().pattern(/^[a-zA-Z0-9_+]+$/), joi.bool())
|
||||
.required(),
|
||||
funbox: joi.object().pattern(/\w+/, joi.bool()).required(),
|
||||
};
|
||||
|
||||
export default FILTER_SCHEMA;
|
|
@ -1,6 +1,6 @@
|
|||
import { AppRoute, AppRouter } from "@ts-rest/core";
|
||||
import { TsRestRequest } from "@ts-rest/express";
|
||||
import { MonkeyResponse2 } from "../utils/monkey-response";
|
||||
import { MonkeyResponse } from "../utils/monkey-response";
|
||||
export function callController<
|
||||
TRoute extends AppRoute | AppRouter,
|
||||
TQuery,
|
||||
|
@ -17,7 +17,7 @@ export function callController<
|
|||
body: { message: string; data: TResponse };
|
||||
}> {
|
||||
return async (all) => {
|
||||
const req: MonkeyTypes.Request2<TQuery, TBody, TParams> = {
|
||||
const req: MonkeyTypes.Request<TQuery, TBody, TParams> = {
|
||||
body: all.body as TBody,
|
||||
query: all.query as TQuery,
|
||||
params: all.params as TParams,
|
||||
|
@ -60,8 +60,8 @@ type WithoutParams = {
|
|||
};
|
||||
|
||||
type Handler<TQuery, TBody, TParams, TResponse> = (
|
||||
req: MonkeyTypes.Request2<TQuery, TBody, TParams>
|
||||
) => Promise<MonkeyResponse2<TResponse>>;
|
||||
req: MonkeyTypes.Request<TQuery, TBody, TParams>
|
||||
) => Promise<MonkeyResponse<TResponse>>;
|
||||
|
||||
type RequestType2<
|
||||
TRoute extends AppRoute | AppRouter,
|
||||
|
|
|
@ -3,7 +3,7 @@ import { getApeKey, updateLastUsedOn } from "../dal/ape-keys";
|
|||
import MonkeyError from "../utils/error";
|
||||
import { verifyIdToken } from "../utils/auth";
|
||||
import { base64UrlDecode, isDevEnvironment } from "../utils/misc";
|
||||
import { NextFunction, Response, Handler } from "express";
|
||||
import { NextFunction, Response } from "express";
|
||||
import statuses from "../constants/monkey-status-codes";
|
||||
import {
|
||||
incrementAuth,
|
||||
|
@ -51,102 +51,79 @@ export function authenticateTsRestRequest<
|
|||
...((req.tsRestRoute["metadata"]?.["authenticationOptions"] ??
|
||||
{}) as EndpointMetadata),
|
||||
};
|
||||
return _authenticateRequestInternal(req, _res, next, options);
|
||||
};
|
||||
}
|
||||
|
||||
export function authenticateRequest(authOptions = DEFAULT_OPTIONS): Handler {
|
||||
const options = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...authOptions,
|
||||
};
|
||||
const startTime = performance.now();
|
||||
let token: MonkeyTypes.DecodedToken;
|
||||
let authType = "None";
|
||||
|
||||
return async (
|
||||
req: MonkeyTypes.Request,
|
||||
_res: Response,
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
return _authenticateRequestInternal(req, _res, next, options);
|
||||
};
|
||||
}
|
||||
const isPublic =
|
||||
options.isPublic || (options.isPublicOnDev && isDevEnvironment());
|
||||
|
||||
async function _authenticateRequestInternal(
|
||||
req: MonkeyTypes.Request | TsRestRequestWithCtx,
|
||||
_res: Response,
|
||||
next: NextFunction,
|
||||
options: RequestAuthenticationOptions
|
||||
): Promise<void> {
|
||||
const startTime = performance.now();
|
||||
let token: MonkeyTypes.DecodedToken;
|
||||
let authType = "None";
|
||||
const {
|
||||
authorization: authHeader,
|
||||
"x-hub-signature-256": githubWebhookHeader,
|
||||
} = req.headers;
|
||||
|
||||
const isPublic =
|
||||
options.isPublic || (options.isPublicOnDev && isDevEnvironment());
|
||||
try {
|
||||
if (options.isGithubWebhook) {
|
||||
token = authenticateGithubWebhook(req, githubWebhookHeader);
|
||||
} else if (authHeader !== undefined && authHeader !== "") {
|
||||
token = await authenticateWithAuthHeader(
|
||||
authHeader,
|
||||
req.ctx.configuration,
|
||||
options
|
||||
);
|
||||
} else if (isPublic === true) {
|
||||
token = {
|
||||
type: "None",
|
||||
uid: "",
|
||||
email: "",
|
||||
};
|
||||
} else {
|
||||
throw new MonkeyError(
|
||||
401,
|
||||
"Unauthorized",
|
||||
`endpoint: ${req.baseUrl} no authorization header found`
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
authorization: authHeader,
|
||||
"x-hub-signature-256": githubWebhookHeader,
|
||||
} = req.headers;
|
||||
incrementAuth(token.type);
|
||||
|
||||
try {
|
||||
if (options.isGithubWebhook) {
|
||||
token = authenticateGithubWebhook(req, githubWebhookHeader);
|
||||
} else if (authHeader !== undefined && authHeader !== "") {
|
||||
token = await authenticateWithAuthHeader(
|
||||
authHeader,
|
||||
req.ctx.configuration,
|
||||
options
|
||||
);
|
||||
} else if (isPublic === true) {
|
||||
token = {
|
||||
type: "None",
|
||||
uid: "",
|
||||
email: "",
|
||||
req.ctx = {
|
||||
...req.ctx,
|
||||
decodedToken: token,
|
||||
};
|
||||
} else {
|
||||
throw new MonkeyError(
|
||||
401,
|
||||
"Unauthorized",
|
||||
`endpoint: ${req.baseUrl} no authorization header found`
|
||||
} catch (error) {
|
||||
authType = authHeader?.split(" ")[0] ?? "None";
|
||||
|
||||
recordAuthTime(
|
||||
authType,
|
||||
"failure",
|
||||
Math.round(performance.now() - startTime),
|
||||
req
|
||||
);
|
||||
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
|
||||
incrementAuth(token.type);
|
||||
|
||||
req.ctx = {
|
||||
...req.ctx,
|
||||
decodedToken: token,
|
||||
};
|
||||
} catch (error) {
|
||||
authType = authHeader?.split(" ")[0] ?? "None";
|
||||
|
||||
recordAuthTime(
|
||||
authType,
|
||||
"failure",
|
||||
token.type,
|
||||
"success",
|
||||
Math.round(performance.now() - startTime),
|
||||
req
|
||||
);
|
||||
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
recordAuthTime(
|
||||
token.type,
|
||||
"success",
|
||||
Math.round(performance.now() - startTime),
|
||||
req
|
||||
);
|
||||
const country = req.headers["cf-ipcountry"] as string;
|
||||
if (country) {
|
||||
recordRequestCountry(country, req);
|
||||
}
|
||||
|
||||
const country = req.headers["cf-ipcountry"] as string;
|
||||
if (country) {
|
||||
recordRequestCountry(country, req);
|
||||
}
|
||||
// if (req.method !== "OPTIONS" && req?.ctx?.decodedToken?.uid) {
|
||||
// recordRequestForUid(req.ctx.decodedToken.uid);
|
||||
// }
|
||||
|
||||
// if (req.method !== "OPTIONS" && req?.ctx?.decodedToken?.uid) {
|
||||
// recordRequestForUid(req.ctx.decodedToken.uid);
|
||||
// }
|
||||
|
||||
next();
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
async function authenticateWithAuthHeader(
|
||||
|
@ -333,7 +310,7 @@ async function authenticateWithUid(
|
|||
}
|
||||
|
||||
export function authenticateGithubWebhook(
|
||||
req: MonkeyTypes.Request,
|
||||
req: TsRestRequest,
|
||||
authHeader: string | string[] | undefined
|
||||
): MonkeyTypes.DecodedToken {
|
||||
try {
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import { getCachedConfiguration } from "../init/configuration";
|
||||
import type { Response, NextFunction } from "express";
|
||||
|
||||
/**
|
||||
* Add the context to the request
|
||||
* @param req
|
||||
* @param _res
|
||||
* @param next
|
||||
*/
|
||||
async function contextMiddleware(
|
||||
req: MonkeyTypes.Request,
|
||||
req: MonkeyTypes.ExpressRequestWithContext,
|
||||
_res: Response,
|
||||
next: NextFunction
|
||||
): Promise<void> {
|
||||
|
|
|
@ -4,7 +4,8 @@ import Logger from "../utils/logger";
|
|||
import MonkeyError from "../utils/error";
|
||||
import { incrementBadAuth } from "./rate-limit";
|
||||
import type { NextFunction, Response } from "express";
|
||||
import { MonkeyResponse, handleMonkeyResponse } from "../utils/monkey-response";
|
||||
import { isCustomCode } from "../constants/monkey-status-codes";
|
||||
|
||||
import {
|
||||
recordClientErrorByVersion,
|
||||
recordServerErrorByVersion,
|
||||
|
@ -26,49 +27,48 @@ type DBError = {
|
|||
url: string;
|
||||
};
|
||||
|
||||
type ErrorData = {
|
||||
errorId?: string;
|
||||
uid: string;
|
||||
};
|
||||
|
||||
async function errorHandlingMiddleware(
|
||||
error: Error,
|
||||
req: MonkeyTypes.Request,
|
||||
req: MonkeyTypes.ExpressRequestWithContext,
|
||||
res: Response,
|
||||
_next: NextFunction
|
||||
): Promise<void> {
|
||||
try {
|
||||
const monkeyError = error as MonkeyError;
|
||||
|
||||
const monkeyResponse = new MonkeyResponse();
|
||||
monkeyResponse.status = 500;
|
||||
monkeyResponse.data = {
|
||||
let status = 500;
|
||||
const data: { errorId?: string; uid: string } = {
|
||||
errorId: monkeyError.errorId ?? uuidv4(),
|
||||
uid: monkeyError.uid ?? req.ctx?.decodedToken?.uid,
|
||||
};
|
||||
let message = "Unknown error";
|
||||
|
||||
if (/ECONNREFUSED.*27017/i.test(error.message)) {
|
||||
monkeyResponse.message =
|
||||
"Could not connect to the database. It may be down.";
|
||||
message = "Could not connect to the database. It may be down.";
|
||||
} else if (error instanceof URIError || error instanceof SyntaxError) {
|
||||
monkeyResponse.status = 400;
|
||||
monkeyResponse.message = "Unprocessable request";
|
||||
status = 400;
|
||||
message = "Unprocessable request";
|
||||
} else if (error instanceof MonkeyError) {
|
||||
monkeyResponse.message = error.message;
|
||||
monkeyResponse.status = error.status;
|
||||
message = error.message;
|
||||
status = error.status;
|
||||
} else {
|
||||
monkeyResponse.message = `Oops! Our monkeys dropped their bananas. Please try again later. - ${monkeyResponse.data.errorId}`;
|
||||
message = `Oops! Our monkeys dropped their bananas. Please try again later. - ${data.errorId}`;
|
||||
}
|
||||
|
||||
await incrementBadAuth(req, res, monkeyResponse.status);
|
||||
await incrementBadAuth(req, res, status);
|
||||
|
||||
if (monkeyResponse.status >= 400 && monkeyResponse.status < 500) {
|
||||
if (status >= 400 && status < 500) {
|
||||
recordClientErrorByVersion(req.headers["x-client-version"] as string);
|
||||
}
|
||||
|
||||
if (
|
||||
!isDevEnvironment() &&
|
||||
monkeyResponse.status >= 500 &&
|
||||
monkeyResponse.status !== 503
|
||||
) {
|
||||
if (!isDevEnvironment() && status >= 500 && status !== 503) {
|
||||
recordServerErrorByVersion(version);
|
||||
|
||||
const { uid, errorId } = monkeyResponse.data as {
|
||||
const { uid, errorId } = data as {
|
||||
uid: string;
|
||||
errorId: string;
|
||||
};
|
||||
|
@ -76,13 +76,13 @@ async function errorHandlingMiddleware(
|
|||
try {
|
||||
await addLog(
|
||||
"system_error",
|
||||
`${monkeyResponse.status} ${errorId} ${error.message} ${error.stack}`,
|
||||
`${status} ${errorId} ${error.message} ${error.stack}`,
|
||||
uid
|
||||
);
|
||||
await db.collection<DBError>("errors").insertOne({
|
||||
_id: new ObjectId(errorId),
|
||||
timestamp: Date.now(),
|
||||
status: monkeyResponse.status,
|
||||
status: status,
|
||||
uid,
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
|
@ -99,11 +99,11 @@ async function errorHandlingMiddleware(
|
|||
Logger.error(`Error: ${error.message} Stack: ${error.stack}`);
|
||||
}
|
||||
|
||||
if (monkeyResponse.status < 500) {
|
||||
delete monkeyResponse.data.errorId;
|
||||
if (status < 500) {
|
||||
delete data.errorId;
|
||||
}
|
||||
|
||||
handleMonkeyResponse(monkeyResponse, res);
|
||||
handleErrorResponse(res, status, message, data);
|
||||
return;
|
||||
} catch (e) {
|
||||
Logger.error("Error handling middleware failed.");
|
||||
|
@ -111,14 +111,28 @@ async function errorHandlingMiddleware(
|
|||
console.error(e);
|
||||
}
|
||||
|
||||
handleMonkeyResponse(
|
||||
new MonkeyResponse(
|
||||
"Something went really wrong, please contact support.",
|
||||
undefined,
|
||||
500
|
||||
),
|
||||
res
|
||||
handleErrorResponse(
|
||||
res,
|
||||
500,
|
||||
"Something went really wrong, please contact support."
|
||||
);
|
||||
}
|
||||
|
||||
function handleErrorResponse(
|
||||
res: Response,
|
||||
status: number,
|
||||
message: string,
|
||||
data?: ErrorData
|
||||
): void {
|
||||
res.status(status);
|
||||
if (isCustomCode(status)) {
|
||||
res.statusMessage = message;
|
||||
}
|
||||
|
||||
//@ts-expect-error ignored so that we can see message in swagger stats
|
||||
res.monkeyMessage = message;
|
||||
|
||||
res.json({ message, data: data ?? null });
|
||||
}
|
||||
|
||||
export default errorHandlingMiddleware;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import _ from "lodash";
|
||||
import MonkeyError from "../utils/error";
|
||||
import type { Response, NextFunction } from "express";
|
||||
import type { Response, NextFunction, Request } from "express";
|
||||
import { RateLimiterMemory } from "rate-limiter-flexible";
|
||||
import {
|
||||
rateLimit,
|
||||
|
@ -36,7 +36,7 @@ export const customHandler = (
|
|||
throw new MonkeyError(429, "Request limit reached, please try again later.");
|
||||
};
|
||||
|
||||
const getKey = (req: MonkeyTypes.Request, _res: Response): string => {
|
||||
const getKey = (req: Request, _res: Response): string => {
|
||||
return (
|
||||
(req.headers["cf-connecting-ip"] as string) ||
|
||||
(req.headers["x-forwarded-for"] as string) ||
|
||||
|
@ -45,7 +45,10 @@ const getKey = (req: MonkeyTypes.Request, _res: Response): string => {
|
|||
);
|
||||
};
|
||||
|
||||
const getKeyWithUid = (req: MonkeyTypes.Request, _res: Response): string => {
|
||||
const getKeyWithUid = (
|
||||
req: MonkeyTypes.ExpressRequestWithContext,
|
||||
_res: Response
|
||||
): string => {
|
||||
const uid = req?.ctx?.decodedToken?.uid;
|
||||
const useUid = uid !== undefined && uid !== "";
|
||||
|
||||
|
@ -148,7 +151,7 @@ const badAuthRateLimiter = new RateLimiterMemory({
|
|||
});
|
||||
|
||||
export async function badAuthRateLimiterHandler(
|
||||
req: MonkeyTypes.Request,
|
||||
req: MonkeyTypes.ExpressRequestWithContext,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<void> {
|
||||
|
@ -178,7 +181,7 @@ export async function badAuthRateLimiterHandler(
|
|||
}
|
||||
|
||||
export async function incrementBadAuth(
|
||||
req: MonkeyTypes.Request,
|
||||
req: MonkeyTypes.ExpressRequestWithContext,
|
||||
res: Response,
|
||||
status: number
|
||||
): Promise<void> {
|
||||
|
|
|
@ -1,43 +1,10 @@
|
|||
import _ from "lodash";
|
||||
import type { Request, Response, NextFunction, RequestHandler } from "express";
|
||||
import { handleMonkeyResponse, MonkeyResponse } from "../utils/monkey-response";
|
||||
import { recordClientVersion as prometheusRecordClientVersion } from "../utils/prometheus";
|
||||
import { isDevEnvironment } from "../utils/misc";
|
||||
import MonkeyError from "../utils/error";
|
||||
import { TsRestRequestWithCtx } from "./auth";
|
||||
|
||||
export const emptyMiddleware = (
|
||||
_req: MonkeyTypes.Request,
|
||||
_res: Response,
|
||||
next: NextFunction
|
||||
): void => next();
|
||||
|
||||
type AsyncHandler = (
|
||||
req: MonkeyTypes.Request,
|
||||
res?: Response
|
||||
) => Promise<MonkeyResponse>;
|
||||
|
||||
/**
|
||||
* This utility serves as an alternative to wrapping express handlers with try/catch statements.
|
||||
* Any routes that use an async handler function should wrap the handler with this function.
|
||||
* Without this, any errors thrown will not be caught by the error handling middleware, and
|
||||
* the app will hang!
|
||||
*/
|
||||
export function asyncHandler(handler: AsyncHandler): RequestHandler {
|
||||
return async (
|
||||
req: MonkeyTypes.Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) => {
|
||||
try {
|
||||
const handlerData = await handler(req, res);
|
||||
handleMonkeyResponse(handlerData, res);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* record the client version from the `x-client-version` or ` client-version` header to prometheus
|
||||
*/
|
||||
|
@ -53,6 +20,7 @@ export function recordClientVersion(): RequestHandler {
|
|||
};
|
||||
}
|
||||
|
||||
/** Endpoint is only available in dev environment, else return 503. */
|
||||
export function onlyAvailableOnDev(): MonkeyTypes.RequestHandler {
|
||||
return (_req: TsRestRequestWithCtx, _res: Response, next: NextFunction) => {
|
||||
if (!isDevEnvironment()) {
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
import _ from "lodash";
|
||||
import joi from "joi";
|
||||
import MonkeyError from "../utils/error";
|
||||
import type { Response, NextFunction, RequestHandler } from "express";
|
||||
|
||||
type ValidationSchema = {
|
||||
body?: object;
|
||||
query?: object;
|
||||
params?: object;
|
||||
headers?: object;
|
||||
};
|
||||
|
||||
type ValidationSchemaOption = {
|
||||
allowUnknown?: boolean;
|
||||
};
|
||||
|
||||
type ValidationHandlingOptions = {
|
||||
validationErrorMessage?: string;
|
||||
};
|
||||
|
||||
type ValidationSchemaOptions = {
|
||||
[_schema in keyof ValidationSchema]?: ValidationSchemaOption;
|
||||
} & ValidationHandlingOptions;
|
||||
|
||||
const VALIDATION_SCHEMA_DEFAULT_OPTIONS: ValidationSchemaOptions = {
|
||||
body: { allowUnknown: false },
|
||||
headers: { allowUnknown: true },
|
||||
params: { allowUnknown: false },
|
||||
query: { allowUnknown: false },
|
||||
};
|
||||
|
||||
export function validateRequest(
|
||||
validationSchema: ValidationSchema,
|
||||
validationOptions: ValidationSchemaOptions = VALIDATION_SCHEMA_DEFAULT_OPTIONS
|
||||
): RequestHandler {
|
||||
const options = {
|
||||
...VALIDATION_SCHEMA_DEFAULT_OPTIONS,
|
||||
...validationOptions,
|
||||
};
|
||||
const { validationErrorMessage } = options;
|
||||
const normalizedValidationSchema: ValidationSchema = _.omit(
|
||||
validationSchema,
|
||||
"validationErrorMessage"
|
||||
);
|
||||
|
||||
return (req: MonkeyTypes.Request, _res: Response, next: NextFunction) => {
|
||||
_.each(
|
||||
normalizedValidationSchema,
|
||||
(schema: object, key: keyof ValidationSchema) => {
|
||||
const joiSchema = joi
|
||||
.object()
|
||||
.keys(schema)
|
||||
.unknown(options[key]?.allowUnknown);
|
||||
|
||||
const { error } = joiSchema.validate(req[key] ?? {});
|
||||
if (error) {
|
||||
const errorMessage = error.details[0]?.message;
|
||||
throw new MonkeyError(
|
||||
422,
|
||||
validationErrorMessage ??
|
||||
`${errorMessage} (${error.details[0]?.context?.value})`
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
next();
|
||||
};
|
||||
}
|
6
backend/src/types/types.d.ts
vendored
6
backend/src/types/types.d.ts
vendored
|
@ -18,15 +18,11 @@ declare namespace MonkeyTypes {
|
|||
decodedToken: DecodedToken;
|
||||
};
|
||||
|
||||
type Request = {
|
||||
ctx: Readonly<Context>;
|
||||
} & ExpressRequest;
|
||||
|
||||
type ExpressRequestWithContext = {
|
||||
ctx: Readonly<Context>;
|
||||
} & ExpressRequest;
|
||||
|
||||
type Request2<TQuery = undefined, TBody = undefined, TParams = undefined> = {
|
||||
type Request<TQuery = undefined, TBody = undefined, TParams = undefined> = {
|
||||
query: Readonly<TQuery>;
|
||||
body: Readonly<TBody>;
|
||||
params: Readonly<TParams>;
|
||||
|
|
|
@ -1,49 +1,10 @@
|
|||
import { type Response } from "express";
|
||||
import { isCustomCode } from "../constants/monkey-status-codes";
|
||||
import { MonkeyResponseType } from "@monkeytype/contracts/schemas/api";
|
||||
|
||||
export type MonkeyDataAware<T> = {
|
||||
data: T | null;
|
||||
};
|
||||
//TODO FIX ANYS
|
||||
|
||||
export class MonkeyResponse {
|
||||
message: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data: any;
|
||||
status: number;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
constructor(message?: string, data?: any, status = 200) {
|
||||
this.message = message ?? "ok";
|
||||
this.data = data ?? null;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
export function handleMonkeyResponse(
|
||||
monkeyResponse: MonkeyResponse,
|
||||
res: Response
|
||||
): void {
|
||||
const { message, data, status } = monkeyResponse;
|
||||
|
||||
res.status(status);
|
||||
if (isCustomCode(status)) {
|
||||
res.statusMessage = message;
|
||||
}
|
||||
|
||||
//@ts-expect-error ignored so that we can see message in swagger stats
|
||||
res.monkeyMessage = message;
|
||||
if ([301, 302].includes(status)) {
|
||||
// todo add stronger types here, maybe a MonkeyRedirectResponse
|
||||
res.redirect(data as string);
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ message, data });
|
||||
}
|
||||
|
||||
export class MonkeyResponse2<T = null>
|
||||
export class MonkeyResponse<T = null>
|
||||
implements MonkeyResponseType, MonkeyDataAware<T>
|
||||
{
|
||||
public message: string;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import "dotenv/config";
|
||||
import { Counter, Histogram, Gauge } from "prom-client";
|
||||
import { TsRestRequestWithCtx } from "../middlewares/auth";
|
||||
import { CompletedEvent } from "@monkeytype/contracts/schemas/results";
|
||||
import { Request } from "express";
|
||||
|
||||
const auth = new Counter({
|
||||
name: "api_request_auth_total",
|
||||
|
@ -213,7 +213,7 @@ export function recordAuthTime(
|
|||
type: string,
|
||||
status: "success" | "failure",
|
||||
time: number,
|
||||
req: MonkeyTypes.Request | TsRestRequestWithCtx
|
||||
req: Request
|
||||
): void {
|
||||
const reqPath = req.baseUrl + req.route.path;
|
||||
|
||||
|
@ -233,10 +233,7 @@ const requestCountry = new Counter({
|
|||
labelNames: ["path", "country"],
|
||||
});
|
||||
|
||||
export function recordRequestCountry(
|
||||
country: string,
|
||||
req: MonkeyTypes.Request | TsRestRequestWithCtx
|
||||
): void {
|
||||
export function recordRequestCountry(country: string, req: Request): void {
|
||||
const reqPath = req.baseUrl + req.route.path;
|
||||
|
||||
let normalizedPath = "/";
|
||||
|
|
|
@ -3,28 +3,6 @@ import { intersect } from "./misc";
|
|||
import { default as FunboxList } from "../constants/funbox-list";
|
||||
import { CompletedEvent } from "@monkeytype/contracts/schemas/results";
|
||||
|
||||
export function inRange(value: number, min: number, max: number): boolean {
|
||||
return value >= min && value <= max;
|
||||
}
|
||||
|
||||
const VALID_NAME_PATTERN = /^[\da-zA-Z_-]+$/;
|
||||
|
||||
export function isUsernameValid(name: string): boolean {
|
||||
if (_.isNil(name) || !inRange(name.length, 1, 16)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return VALID_NAME_PATTERN.test(name);
|
||||
}
|
||||
|
||||
export function isTagPresetNameValid(name: string): boolean {
|
||||
if (_.isNil(name) || !inRange(name.length, 1, 16)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return VALID_NAME_PATTERN.test(name);
|
||||
}
|
||||
|
||||
export function isTestTooShort(result: CompletedEvent): boolean {
|
||||
const { mode, mode2, customText, testDuration, bailedOut } = result;
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@
|
|||
"@date-fns/utc": "1.2.0",
|
||||
"@monkeytype/contracts": "workspace:*",
|
||||
"@ts-rest/core": "3.51.0",
|
||||
"axios": "1.7.4",
|
||||
"canvas-confetti": "1.5.1",
|
||||
"chart.js": "3.7.1",
|
||||
"chartjs-adapter-date-fns": "3.0.0",
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { AppRouter, initClient, type ApiFetcherArgs } from "@ts-rest/core";
|
||||
import { Method } from "axios";
|
||||
import { getIdToken } from "firebase/auth";
|
||||
import { envConfig } from "../../constants/env-config";
|
||||
import { getAuthenticatedUser, isAuthenticated } from "../../firebase";
|
||||
|
@ -28,7 +27,7 @@ function buildApi(timeout: number): (args: ApiFetcherArgs) => Promise<{
|
|||
}
|
||||
|
||||
const fetchOptions: RequestInit = {
|
||||
method: request.method as Method,
|
||||
method: request.method,
|
||||
headers,
|
||||
body: request.body,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import axios from "axios";
|
||||
import { Section } from "../utils/misc";
|
||||
|
||||
const bannedChars = ["—", "_", " "];
|
||||
|
@ -49,8 +48,9 @@ export async function getPoem(): Promise<Section | false> {
|
|||
console.log("Getting poem");
|
||||
|
||||
try {
|
||||
const response = await axios.get(apiURL);
|
||||
const poemObj: PoemObject = response.data[0];
|
||||
const response = await fetch(apiURL);
|
||||
const data = await response.json();
|
||||
const poemObj: PoemObject = data[0];
|
||||
|
||||
const words: string[] = [];
|
||||
|
||||
|
|
|
@ -98,9 +98,6 @@ importers:
|
|||
ioredis:
|
||||
specifier: 4.28.5
|
||||
version: 4.28.5
|
||||
joi:
|
||||
specifier: 17.6.0
|
||||
version: 17.6.0
|
||||
lodash:
|
||||
specifier: 4.17.21
|
||||
version: 4.17.21
|
||||
|
@ -270,9 +267,6 @@ importers:
|
|||
'@ts-rest/core':
|
||||
specifier: 3.51.0
|
||||
version: 3.51.0(@types/node@20.14.11)(zod@3.23.8)
|
||||
axios:
|
||||
specifier: 1.7.4
|
||||
version: 1.7.4(debug@4.3.6)
|
||||
canvas-confetti:
|
||||
specifier: 1.5.1
|
||||
version: 1.5.1
|
||||
|
@ -5814,9 +5808,6 @@ packages:
|
|||
joi@17.13.3:
|
||||
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
|
||||
|
||||
joi@17.6.0:
|
||||
resolution: {integrity: sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==}
|
||||
|
||||
join-path@1.1.1:
|
||||
resolution: {integrity: sha512-jnt9OC34sLXMLJ6YfPQ2ZEKrR9mB5ZbSnQb4LPaOx1c5rTzxpR33L18jjp0r75mGGTJmsil3qwN1B5IBeTnSSA==}
|
||||
|
||||
|
@ -15857,14 +15848,6 @@ snapshots:
|
|||
'@sideway/formula': 3.0.1
|
||||
'@sideway/pinpoint': 2.0.0
|
||||
|
||||
joi@17.6.0:
|
||||
dependencies:
|
||||
'@hapi/hoek': 9.3.0
|
||||
'@hapi/topo': 5.1.0
|
||||
'@sideway/address': 4.1.5
|
||||
'@sideway/formula': 3.0.1
|
||||
'@sideway/pinpoint': 2.0.0
|
||||
|
||||
join-path@1.1.1:
|
||||
dependencies:
|
||||
as-array: 2.0.0
|
||||
|
|
Loading…
Reference in a new issue