Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: shared user types #5080

Merged
merged 21 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions backend/__tests__/dal/leaderboards.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ describe("LeaderboardsDal", () => {
});
});

function expectedLbEntry(rank: number, user: MonkeyTypes.User, time: string) {
function expectedLbEntry(rank: number, user: MonkeyTypes.DBUser, time: string) {
const lbBest: SharedTypes.PersonalBest =
user.lbPersonalBests?.time[time].english;

Expand All @@ -178,13 +178,13 @@ function expectedLbEntry(rank: number, user: MonkeyTypes.User, time: string) {

async function createUser(
lbPersonalBests?: MonkeyTypes.LbPersonalBests,
userProperties?: Partial<MonkeyTypes.User>
): Promise<MonkeyTypes.User> {
userProperties?: Partial<MonkeyTypes.DBUser>
): Promise<MonkeyTypes.DBUser> {
const uid = new ObjectId().toHexString();
await UserDal.addUser("User " + uid, uid + "@example.com", uid);

await DB.getDb()
?.collection<MonkeyTypes.User>("users")
?.collection<MonkeyTypes.DBUser>("users")
.updateOne(
{ uid },
{
Expand Down
3 changes: 2 additions & 1 deletion backend/__tests__/dal/result.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ async function createDummyData(
timestamp: number,
tag?: string
): Promise<void> {
const dummyUser: MonkeyTypes.User = {
const dummyUser: MonkeyTypes.DBUser = {
_id: new ObjectId(),
uid,
addedAt: 0,
email: "test@example.com",
Expand Down
15 changes: 9 additions & 6 deletions backend/src/api/controllers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,8 @@ export async function updateEmail(
}

function getRelevantUserInfo(
user: MonkeyTypes.User
): Partial<MonkeyTypes.User> {
user: MonkeyTypes.DBUser
): Partial<MonkeyTypes.DBUser> {
return _.omit(user, [
"bananas",
"lbPersonalBests",
Expand All @@ -336,7 +336,7 @@ export async function getUser(
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;

let userInfo: MonkeyTypes.User;
let userInfo: MonkeyTypes.DBUser;
try {
userInfo = await UserDAL.getUser(uid, "get user");
} catch (e) {
Expand Down Expand Up @@ -786,7 +786,7 @@ export async function getProfile(
details: profileDetails,
allTimeLbs: alltimelbs,
uid: user.uid,
};
} as SharedTypes.UserProfile;

return new MonkeyResponse("Profile retrieved", profileData);
}
Expand All @@ -811,10 +811,13 @@ export async function updateProfile(
}
});

const profileDetailsUpdates: Partial<MonkeyTypes.UserProfileDetails> = {
const profileDetailsUpdates: Partial<SharedTypes.UserProfileDetails> = {
bio: sanitizeString(bio),
keyboard: sanitizeString(keyboard),
socialProfiles: _.mapValues(socialProfiles, sanitizeString),
socialProfiles: _.mapValues(
socialProfiles,
sanitizeString
) as SharedTypes.UserProfileDetails["socialProfiles"],
};

await UserDAL.updateProfile(uid, profileDetailsUpdates, user.inventory);
Expand Down
5 changes: 4 additions & 1 deletion backend/src/api/routes/quotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ const router = Router();

const checkIfUserIsQuoteMod = checkUserPermissions({
criteria: (user) => {
return !!user.quoteMod;
return (
user.quoteMod === true ||
(typeof user.quoteMod === "string" && user.quoteMod !== "")
);
},
});

Expand Down
2 changes: 1 addition & 1 deletion backend/src/dal/leaderboards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export async function update(
leaderboardUpdating[`${language}_${mode}_${mode2}`] = true;
const start1 = performance.now();
const lb = db
.collection<MonkeyTypes.User>("users")
.collection<MonkeyTypes.DBUser>("users")
.aggregate<SharedTypes.LeaderboardEntry>(
[
{
Expand Down
2 changes: 1 addition & 1 deletion backend/src/dal/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function addResult(
uid: string,
result: DBResult
): Promise<{ insertedId: ObjectId }> {
let user: MonkeyTypes.User | null = null;
let user: MonkeyTypes.DBUser | null = null;
try {
user = await getUser(uid, "add result");
} catch (e) {
Expand Down
62 changes: 33 additions & 29 deletions backend/src/dal/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { canFunboxGetPb, checkAndUpdatePb } from "../utils/pb";
import * as db from "../init/db";
import MonkeyError from "../utils/error";
import { Collection, ObjectId, WithId, Long, UpdateFilter } from "mongodb";

Check warning on line 7 in backend/src/dal/user.ts

View workflow job for this annotation

GitHub Actions / ci-be

'WithId' is defined but never used. Allowed unused vars must match /^_/u
import Logger from "../utils/logger";
import { flattenObjectDeep, isToday, isYesterday } from "../utils/misc";

Expand All @@ -16,15 +16,15 @@
>;

// Export for use in tests
export const getUsersCollection = (): Collection<WithId<MonkeyTypes.User>> =>
db.collection<MonkeyTypes.User>("users");
export const getUsersCollection = (): Collection<MonkeyTypes.DBUser> =>
db.collection<MonkeyTypes.DBUser>("users");

export async function addUser(
name: string,
email: string,
uid: string
): Promise<void> {
const newUserDocument: Partial<MonkeyTypes.User> = {
const newUserDocument: Partial<MonkeyTypes.DBUser> = {
name,
email,
uid,
Expand Down Expand Up @@ -170,7 +170,7 @@

export async function updateQuoteRatings(
uid: string,
quoteRatings: MonkeyTypes.UserQuoteRatings
quoteRatings: SharedTypes.UserQuoteRatings
): Promise<boolean> {
await getUser(uid, "update quote ratings");

Expand All @@ -191,13 +191,15 @@
export async function getUser(
uid: string,
stack: string
): Promise<MonkeyTypes.User> {
): Promise<MonkeyTypes.DBUser> {
const user = await getUsersCollection().findOne({ uid });
if (!user) throw new MonkeyError(404, "User not found", stack);
return user;
}

async function findByName(name: string): Promise<MonkeyTypes.User | undefined> {
async function findByName(
name: string
): Promise<MonkeyTypes.DBUser | undefined> {
return (
await getUsersCollection()
.find({ name })
Expand All @@ -220,7 +222,7 @@
export async function getUserByName(
name: string,
stack: string
): Promise<MonkeyTypes.User> {
): Promise<MonkeyTypes.DBUser> {
const user = await findByName(name);
if (!user) throw new MonkeyError(404, "User not found", stack);
return user;
Expand Down Expand Up @@ -284,7 +286,7 @@
export async function addTag(
uid: string,
name: string
): Promise<MonkeyTypes.UserTag> {
): Promise<MonkeyTypes.DBUserTag> {
const user = await getUser(uid, "add tag");

if ((user?.tags?.length ?? 0) >= 15) {
Expand Down Expand Up @@ -315,7 +317,7 @@
return toPush;
}

export async function getTags(uid: string): Promise<MonkeyTypes.UserTag[]> {
export async function getTags(uid: string): Promise<MonkeyTypes.DBUserTag[]> {
const user = await getUser(uid, "get tags");

return user.tags ?? [];
Expand Down Expand Up @@ -396,9 +398,11 @@
const user = await getUser(uid, "update lb memory");
if (user.lbMemory === undefined) user.lbMemory = {};
if (user.lbMemory[mode] === undefined) user.lbMemory[mode] = {};
if (user.lbMemory[mode][mode2] === undefined) {
if (user.lbMemory[mode]?.[mode2] === undefined) {
//@ts-expect-error guarded above
user.lbMemory[mode][mode2] = {};
}
//@ts-expect-error guarded above
user.lbMemory[mode][mode2][language] = rank;
await getUsersCollection().updateOne(
{ uid },
Expand All @@ -410,7 +414,7 @@

export async function checkIfPb(
uid: string,
user: MonkeyTypes.User,
user: MonkeyTypes.DBUser,
result: Result
): Promise<boolean> {
const { mode } = result;
Expand Down Expand Up @@ -452,7 +456,7 @@

export async function checkIfTagPb(
uid: string,
user: MonkeyTypes.User,
user: MonkeyTypes.DBUser,
result: Result
): Promise<string[]> {
if (user.tags === undefined || user.tags.length === 0) {
Expand All @@ -466,7 +470,7 @@
return [];
}

const tagsToCheck: MonkeyTypes.UserTag[] = [];
const tagsToCheck: MonkeyTypes.DBUserTag[] = [];
user.tags.forEach((userTag) => {
for (const resultTag of resultTags ?? []) {
if (resultTag === userTag._id.toHexString()) {
Expand Down Expand Up @@ -553,7 +557,7 @@
discordId: string,
discordAvatar?: string
): Promise<void> {
const updates: Partial<MonkeyTypes.User> = _.pickBy(
const updates: Partial<MonkeyTypes.DBUser> = _.pickBy(
{ discordId, discordAvatar },
_.identity
);
Expand Down Expand Up @@ -672,7 +676,7 @@

export async function getThemes(
uid: string
): Promise<MonkeyTypes.CustomTheme[]> {
): Promise<MonkeyTypes.DBCustomTheme[]> {
const user = await getUser(uid, "get themes");
return user.customThemes ?? [];
}
Expand Down Expand Up @@ -705,7 +709,7 @@

export async function getFavoriteQuotes(
uid
): Promise<MonkeyTypes.User["favoriteQuotes"]> {
): Promise<MonkeyTypes.DBUser["favoriteQuotes"]> {
const user = await getUser(uid, "get favorite quotes");

return user.favoriteQuotes ?? {};
Expand Down Expand Up @@ -789,7 +793,7 @@
recentAutoBanTimestamps.push(now);

//update user, ban if needed
const updateObj: Partial<MonkeyTypes.User> = {
const updateObj: Partial<MonkeyTypes.DBUser> = {
autoBanTimestamps: recentAutoBanTimestamps,
};
let banningUser = false;
Expand All @@ -810,8 +814,8 @@

export async function updateProfile(
uid: string,
profileDetailUpdates: Partial<MonkeyTypes.UserProfileDetails>,
inventory?: MonkeyTypes.UserInventory
profileDetailUpdates: Partial<SharedTypes.UserProfileDetails>,
inventory?: SharedTypes.UserInventory
): Promise<void> {
const profileUpdates = _.omitBy(
flattenObjectDeep(profileDetailUpdates, "profileDetails"),
Expand All @@ -837,14 +841,14 @@

export async function getInbox(
uid: string
): Promise<MonkeyTypes.User["inbox"]> {
): Promise<MonkeyTypes.DBUser["inbox"]> {
const user = await getUser(uid, "get inventory");
return user.inbox ?? [];
}

type AddToInboxBulkEntry = {
uid: string;
mail: MonkeyTypes.MonkeyMail[];
mail: SharedTypes.MonkeyMail[];
};

export async function addToInboxBulk(
Expand Down Expand Up @@ -876,7 +880,7 @@

export async function addToInbox(
uid: string,
mail: MonkeyTypes.MonkeyMail[],
mail: SharedTypes.MonkeyMail[],
inboxConfig: SharedTypes.Configuration["users"]["inbox"]
): Promise<void> {
const { enabled, maxMail } = inboxConfig;
Expand All @@ -902,11 +906,11 @@
}

function buildRewardUpdates(
rewards: MonkeyTypes.AllRewards[],
rewards: SharedTypes.AllRewards[],
inventoryIsNull = false
): UpdateFilter<WithId<MonkeyTypes.User>> {
): UpdateFilter<MonkeyTypes.DBUser> {
let totalXp = 0;
const newBadges: MonkeyTypes.Badge[] = [];
const newBadges: SharedTypes.Badge[] = [];

rewards.forEach((reward) => {
if (reward.type === "xp") {
Expand Down Expand Up @@ -954,7 +958,7 @@
const mailToReadSet = new Set(mailToRead);
const mailToDeleteSet = new Set(mailToDelete);

const allRewards: MonkeyTypes.AllRewards[] = [];
const allRewards: SharedTypes.AllRewards[] = [];

const newInbox = inbox
.filter((mail) => {
Expand Down Expand Up @@ -988,7 +992,7 @@
timestamp: number
): Promise<number> {
const user = await getUser(uid, "calculate streak");
const streak: MonkeyTypes.UserStreak = {
const streak: SharedTypes.UserStreak = {
lastResultTimestamp: user.streak?.lastResultTimestamp ?? 0,
length: user.streak?.length ?? 0,
maxLength: user.streak?.maxLength ?? 0,
Expand Down Expand Up @@ -1043,7 +1047,7 @@

export async function checkIfUserIsPremium(
uid: string,
userInfoOverride?: MonkeyTypes.User
userInfoOverride?: MonkeyTypes.DBUser
): Promise<boolean> {
const user = userInfoOverride ?? (await getUser(uid, "checkIfUserIsPremium"));
const expirationDate = user.premium?.expirationTimestamp;
Expand All @@ -1056,7 +1060,7 @@
export async function logIpAddress(
uid: string,
ip: string,
userInfoOverride?: MonkeyTypes.User
userInfoOverride?: MonkeyTypes.DBUser
): Promise<void> {
const user = userInfoOverride ?? (await getUser(uid, "logIpAddress"));
const currentIps = user.ips ?? [];
Expand Down
2 changes: 1 addition & 1 deletion backend/src/middlewares/api-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function checkIfUserIsAdmin(): RequestHandler {
* Note that this middleware must be used after authentication in the middleware stack.
*/
function checkUserPermissions(
options: ValidationOptions<MonkeyTypes.User>
options: ValidationOptions<MonkeyTypes.DBUser>
): RequestHandler {
const { criteria, invalidMessage = "You don't have permission to do this." } =
options;
Expand Down
Loading
Loading