mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-09-06 06:37:35 +08:00
impr: add function to clearstreakhouroffset
!nuf
This commit is contained in:
parent
98f2b9ceca
commit
8370de1fa4
6 changed files with 154 additions and 0 deletions
|
@ -194,6 +194,95 @@ describe("AdminController", () => {
|
|||
).toBeRateLimited({ max: 1, windowMs: 5000 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("clear streak hour offset", () => {
|
||||
const clearStreakHourOffset = vi.spyOn(UserDal, "clearStreakHourOffset");
|
||||
|
||||
beforeEach(() => {
|
||||
[clearStreakHourOffset].forEach((it) => it.mockReset());
|
||||
});
|
||||
|
||||
it("should clear streak hour offset for user", async () => {
|
||||
//GIVEN
|
||||
const victimUid = new ObjectId().toHexString();
|
||||
|
||||
//WHEN
|
||||
const { body } = await mockApp
|
||||
.post("/admin/clearStreakHourOffset")
|
||||
.send({ uid: victimUid })
|
||||
.set("Authorization", `Bearer ${uid}`)
|
||||
.expect(200);
|
||||
|
||||
//THEN
|
||||
expect(body).toEqual({
|
||||
message: "Streak hour offset cleared",
|
||||
data: null,
|
||||
});
|
||||
expect(clearStreakHourOffset).toHaveBeenCalledWith(victimUid);
|
||||
});
|
||||
it("should fail without mandatory properties", async () => {
|
||||
//GIVEN
|
||||
|
||||
//WHEN
|
||||
const { body } = await mockApp
|
||||
.post("/admin/clearStreakHourOffset")
|
||||
.send({})
|
||||
.set("Authorization", `Bearer ${uid}`)
|
||||
.expect(422);
|
||||
|
||||
//THEN
|
||||
expect(body).toEqual({
|
||||
message: "Invalid request data schema",
|
||||
validationErrors: ['"uid" Required'],
|
||||
});
|
||||
});
|
||||
it("should fail with unknown properties", async () => {
|
||||
//GIVEN
|
||||
|
||||
//WHEN
|
||||
const { body } = await mockApp
|
||||
.post("/admin/clearStreakHourOffset")
|
||||
.send({ uid: new ObjectId().toHexString(), extra: "value" })
|
||||
.set("Authorization", `Bearer ${uid}`)
|
||||
.expect(422);
|
||||
|
||||
//THEN
|
||||
expect(body).toEqual({
|
||||
message: "Invalid request data schema",
|
||||
validationErrors: ["Unrecognized key(s) in object: 'extra'"],
|
||||
});
|
||||
});
|
||||
it("should fail if user is no admin", async () => {
|
||||
await expectFailForNonAdmin(
|
||||
mockApp
|
||||
.post("/admin/clearStreakHourOffset")
|
||||
.send({ uid: new ObjectId().toHexString() })
|
||||
.set("Authorization", `Bearer ${uid}`)
|
||||
);
|
||||
});
|
||||
it("should fail if admin endpoints are disabled", async () => {
|
||||
//GIVEN
|
||||
await expectFailForDisabledEndpoint(
|
||||
mockApp
|
||||
.post("/admin/clearStreakHourOffset")
|
||||
.send({ uid: new ObjectId().toHexString() })
|
||||
.set("Authorization", `Bearer ${uid}`)
|
||||
);
|
||||
});
|
||||
it("should be rate limited", async () => {
|
||||
//GIVEN
|
||||
const victimUid = new ObjectId().toHexString();
|
||||
|
||||
//WHEN
|
||||
await expect(
|
||||
mockApp
|
||||
.post("/admin/clearStreakHourOffset")
|
||||
.send({ uid: victimUid })
|
||||
.set("Authorization", `Bearer ${uid}`)
|
||||
).toBeRateLimited({ max: 1, windowMs: 5000 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("accept reports", () => {
|
||||
const getReportsMock = vi.spyOn(ReportDal, "getReports");
|
||||
const deleteReportsMock = vi.spyOn(ReportDal, "deleteReports");
|
||||
|
|
|
@ -2011,4 +2011,23 @@ describe("UserDal", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("clearStreakHourOffset", () => {
|
||||
it("should clear streak hour offset", async () => {
|
||||
// given
|
||||
const { uid } = await UserTestData.createUser({
|
||||
//@ts-expect-error
|
||||
streak: {
|
||||
hourOffset: 1,
|
||||
},
|
||||
});
|
||||
|
||||
// when
|
||||
await UserDAL.clearStreakHourOffset(uid);
|
||||
|
||||
//then
|
||||
const read = await UserDAL.getUser(uid, "read");
|
||||
expect(read.streak?.hourOffset).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@ import GeorgeQueue from "../../queues/george-queue";
|
|||
import { sendForgotPasswordEmail as authSendForgotPasswordEmail } from "../../utils/auth";
|
||||
import {
|
||||
AcceptReportsRequest,
|
||||
ClearStreakHourOffsetRequest,
|
||||
RejectReportsRequest,
|
||||
SendForgotPasswordEmailRequest,
|
||||
ToggleBanRequest,
|
||||
|
@ -42,6 +43,17 @@ export async function toggleBan(
|
|||
});
|
||||
}
|
||||
|
||||
export async function clearStreakHourOffset(
|
||||
req: MonkeyRequest<undefined, ClearStreakHourOffsetRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
const { uid } = req.body;
|
||||
|
||||
await UserDAL.clearStreakHourOffset(uid);
|
||||
void addImportantLog("admin_streak_hour_offset_cleared_by", {}, uid);
|
||||
|
||||
return new MonkeyResponse("Streak hour offset cleared", null);
|
||||
}
|
||||
|
||||
export async function acceptReports(
|
||||
req: MonkeyRequest<undefined, AcceptReportsRequest>
|
||||
): Promise<MonkeyResponse> {
|
||||
|
|
|
@ -13,6 +13,10 @@ export default s.router(adminContract, {
|
|||
toggleBan: {
|
||||
handler: async (r) => callController(AdminController.toggleBan)(r),
|
||||
},
|
||||
clearStreakHourOffset: {
|
||||
handler: async (r) =>
|
||||
callController(AdminController.clearStreakHourOffset)(r),
|
||||
},
|
||||
acceptReports: {
|
||||
handler: async (r) => callController(AdminController.acceptReports)(r),
|
||||
},
|
||||
|
|
|
@ -1146,6 +1146,17 @@ export async function setBanned(uid: string, banned: boolean): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
export async function clearStreakHourOffset(uid: string): Promise<void> {
|
||||
await getUsersCollection().updateOne(
|
||||
{ uid },
|
||||
{
|
||||
$unset: {
|
||||
"streak.hourOffset": "",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export async function checkIfUserIsPremium(
|
||||
uid: string,
|
||||
userInfoOverride?: Pick<DBUser, "premium">
|
||||
|
|
|
@ -15,6 +15,15 @@ export const ToggleBanRequestSchema = z
|
|||
.strict();
|
||||
export type ToggleBanRequest = z.infer<typeof ToggleBanRequestSchema>;
|
||||
|
||||
export const ClearStreakHourOffsetRequestSchema = z
|
||||
.object({
|
||||
uid: IdSchema,
|
||||
})
|
||||
.strict();
|
||||
export type ClearStreakHourOffsetRequest = z.infer<
|
||||
typeof ClearStreakHourOffsetRequestSchema
|
||||
>;
|
||||
|
||||
export const ToggleBanResponseSchema = responseWithData(
|
||||
z.object({
|
||||
banned: z.boolean(),
|
||||
|
@ -73,6 +82,16 @@ export const adminContract = c.router(
|
|||
200: ToggleBanResponseSchema,
|
||||
},
|
||||
},
|
||||
clearStreakHourOffset: {
|
||||
summary: "clear streak hour offset",
|
||||
description: "Clear the streak hour offset for a user",
|
||||
method: "POST",
|
||||
path: "/clearStreakHourOffset",
|
||||
body: ClearStreakHourOffsetRequestSchema,
|
||||
responses: {
|
||||
200: MonkeyResponseSchema,
|
||||
},
|
||||
},
|
||||
acceptReports: {
|
||||
summary: "accept reports",
|
||||
description: "Accept one or many reports",
|
||||
|
|
Loading…
Add table
Reference in a new issue