Skip to content

Commit a729b05

Browse files
Cleanup profile & add specification
1 parent bb8bca4 commit a729b05

17 files changed

+418
-476
lines changed

.eslintrc.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module.exports = {
2929
curly: ["error", "all"],
3030
"consistent-return": "error",
3131
"no-lonely-if": "error",
32-
"no-magic-numbers": ["error", { ignoreClassFieldInitialValues: true, ignore: [0, 1] }],
32+
"no-magic-numbers": ["error", { ignoreClassFieldInitialValues: true, ignore: [0, 1, 2] }],
3333
"no-multi-assign": "error",
3434
"no-nested-ternary": "error",
3535
"no-var": "error",

src/common/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export enum RegistrationTemplates {
2727
RSVP_REMINDER_1_DAY = "2024_rsvp-reminder",
2828
}
2929

30-
export enum Avatars {
30+
export enum Avatar {
3131
BUNNY = "bunny",
3232
SQUIRREL = "squirrel",
3333
GOBLIN = "goblin",

src/common/testTools.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import request from "supertest";
22

33
import { Provider, Role } from "../services/auth/auth-schemas";
4+
import { Avatar } from "./config";
45

56
// The tester is the user that will be making requests
67
// We provide this object so you can do proper testing based on JWT auth
@@ -9,7 +10,8 @@ export const TESTER = {
910
id: "bob-the-tester101010101011",
1011
email: "bob-the-tester@hackillinois.org",
1112
name: "Bob Tester",
12-
avatarUrl: "https://hackillinois.org/mushroom.png",
13+
avatarId: Avatar.MUSHROOM,
14+
avatarUrl: "https://raw.githubusercontent.com/HackIllinois/adonix-metadata/main/avatars/mushroom.png",
1315
discordTag: "hackillinoistest",
1416
userName: "bobster_the_mobster",
1517
};

src/database/attendee-db.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/database/models.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import mongoose, { Model } from "mongoose";
22
import { getModelForClass } from "@typegoose/typegoose";
33

44
import { AuthInfo } from "../services/auth/auth-schemas";
5-
import { AttendeeProfile } from "./attendee-db";
5+
import { AttendeeProfile } from "../services/profile/profile-schemas";
66
import { AdmissionDecision } from "../services/admission/admission-schemas";
77
import { MentorOfficeHours } from "./mentor-db";
88
import { Event, EventAttendance, EventFollowers } from "../services/event/event-schemas";

src/services/admission/admission-router.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,6 @@ admissionRouter.put(
177177
async (req, res) => {
178178
const updateEntries = req.body;
179179

180-
console.log("updatedEntries");
181-
console.log(updateEntries);
182-
183180
// collect emails whose status changed from TBD -> NON-TBD
184181
const recipients: string[] = [];
185182
for (const entry of updateEntries) {

src/services/event/event-router.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ eventsRouter.get(
112112
const { id: eventId } = req.params;
113113
const roles = tryGetAuthenticatedUser(req)?.roles || [];
114114

115-
console.log(eventId, roles, restrictEventsByRoles(roles));
116-
117115
const event = await Models.Event.findOne({ eventId, ...restrictEventsByRoles(roles) });
118116

119117
if (!event) {

src/services/profile/profile-formats.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AttendeeProfile } from "../../database/attendee-db";
1+
import { AttendeeProfile } from "./profile-schemas";
22

33
export function isValidProfileFormat(profile: AttendeeProfile): boolean {
44
if (!profile) {

src/services/profile/profile-lib.ts

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,7 @@
1-
import { AttendeeProfile } from "../../database/attendee-db";
2-
import { LeaderboardEntry } from "./profile-models";
1+
import { AttendeeProfile } from "./profile-schemas";
32
import { UpdateQuery } from "mongoose";
43
import Models from "../../database/models";
54

6-
/**
7-
* Remove non-necessary fields from a leaderboardentry item
8-
* @param initial Initial entry with extra items
9-
* @returns New LeaderboardEntry, but this time with only the needed fields
10-
*/
11-
export function castLeaderboardEntries(initial: AttendeeProfile): LeaderboardEntry {
12-
const final: LeaderboardEntry = {
13-
points: initial.points,
14-
displayName: initial.displayName,
15-
};
16-
return final;
17-
}
18-
19-
/**
20-
* Check if the limit is valid or not
21-
* @param limit Initial value to check
22-
* @returns True if limit is non-negative, else false
23-
*/
24-
export function isValidLimit(limit: number): boolean {
25-
return limit > 0;
26-
}
27-
285
export async function updatePointsAndCoins(userId: string, amount: number): Promise<AttendeeProfile | null> {
296
await updateCoins(userId, amount);
307

src/services/profile/profile-models.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/services/profile/profile-router.test.ts

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { beforeEach, describe, expect, it } from "@jest/globals";
22
import { StatusCode } from "status-code-enum";
33
import Config from "../../common/config";
4-
import { AttendeeProfile } from "../../database/attendee-db";
4+
import { AttendeeProfile, AttendeeProfileCreateRequest } from "./profile-schemas";
55
import Models from "../../database/models";
6-
import { TESTER, delAsUser, getAsAdmin, getAsUser, postAsAttendee, postAsStaff, postAsUser } from "../../common/testTools";
6+
import { TESTER, getAsAdmin, getAsAttendee, getAsUser, postAsAttendee, postAsStaff, postAsUser } from "../../common/testTools";
7+
import { Degree, Gender, HackInterest, HackOutreach, Race, RegistrationApplication } from "../registration/registration-schemas";
78

89
const TESTER_USER = {
910
userId: TESTER.id,
@@ -35,112 +36,137 @@ const TESTER_USER_3 = {
3536
foodWave: 2,
3637
} satisfies AttendeeProfile;
3738

38-
const profile: AttendeeProfile = {
39-
userId: TESTER.id,
39+
const CREATE_REQUEST = {
40+
avatarId: TESTER.avatarId,
4041
displayName: TESTER.name,
41-
avatarUrl: TESTER.avatarUrl,
4242
discordTag: TESTER.discordTag,
43+
} satisfies AttendeeProfileCreateRequest;
44+
45+
const PROFILE = {
46+
userId: TESTER.id,
47+
displayName: CREATE_REQUEST.displayName,
48+
avatarUrl: TESTER.avatarUrl,
49+
discordTag: CREATE_REQUEST.discordTag,
4350
points: 0,
4451
coins: 0,
4552
foodWave: 1,
46-
};
53+
} satisfies AttendeeProfile;
54+
55+
const REGISTRATION = {
56+
userId: TESTER.id,
57+
hasSubmitted: true,
58+
isProApplicant: false,
59+
preferredName: TESTER.name,
60+
legalName: TESTER.name,
61+
emailAddress: TESTER.email,
62+
university: "ap",
63+
hackEssay1: "ap",
64+
hackEssay2: "ap",
65+
optionalEssay: "ap",
66+
location: "ap",
67+
gender: Gender.OTHER,
68+
degree: Degree.BACHELORS,
69+
major: "CS",
70+
gradYear: 0,
71+
requestedTravelReimbursement: false,
72+
dietaryRestrictions: ["some restriction"],
73+
race: [Race.NO_ANSWER],
74+
hackInterest: [HackInterest.TECHNICAL_WORKSHOPS],
75+
hackOutreach: [HackOutreach.INSTAGRAM],
76+
} satisfies RegistrationApplication;
4777

4878
beforeEach(async () => {
4979
await Models.AttendeeProfile.create(TESTER_USER);
5080
await Models.AttendeeProfile.create(TESTER_USER_2);
5181
await Models.AttendeeProfile.create(TESTER_USER_3);
82+
await Models.RegistrationApplication.create(REGISTRATION);
5283
});
5384

5485
describe("POST /profile", () => {
5586
it("works for an attendee", async () => {
5687
await Models.AttendeeProfile.deleteOne({ userId: TESTER_USER.userId });
57-
const response = await postAsAttendee("/profile/").send(profile).expect(StatusCode.SuccessOK);
88+
const response = await postAsAttendee("/profile/").send(CREATE_REQUEST).expect(StatusCode.SuccessOK);
5889

5990
expect(JSON.parse(response.text)).toHaveProperty("displayName", TESTER.name);
91+
92+
const stored = await Models.AttendeeProfile.findOne({ userId: TESTER_USER.userId });
93+
expect(stored?.toObject()).toMatchObject(PROFILE);
6094
});
6195

6296
it("fails when a profile is already created", async () => {
6397
await Models.AttendeeProfile.deleteOne({ userId: TESTER_USER.userId });
64-
const response = await postAsUser("/profile/").send(profile).expect(StatusCode.SuccessOK);
98+
const response = await postAsAttendee("/profile/").send(CREATE_REQUEST).expect(StatusCode.SuccessOK);
6599

66-
expect(JSON.parse(response.text)).toHaveProperty("displayName", TESTER.name);
100+
expect(JSON.parse(response.text)).toMatchObject(PROFILE);
101+
102+
const stored = await Models.AttendeeProfile.findOne({ userId: TESTER_USER.userId });
103+
expect(stored?.toObject()).toMatchObject(PROFILE);
67104

68105
// to verify they can't double create
69-
const response2 = await postAsUser("/profile/").send(profile).expect(StatusCode.ClientErrorBadRequest);
70-
expect(JSON.parse(response2.text)).toHaveProperty("error", "UserAlreadyExists");
106+
const response2 = await postAsAttendee("/profile/").send(CREATE_REQUEST).expect(StatusCode.ClientErrorBadRequest);
107+
expect(JSON.parse(response2.text)).toHaveProperty("error", "AlreadyExists");
71108
});
72109

73110
it("fails when invalid data is provided", async () => {
74-
const response = await postAsUser("/profile/")
111+
const response = await postAsAttendee("/profile/")
75112
.send({
76113
displayName: 123,
77114
avatarId: 1,
78115
discordTag: "test",
79116
})
80117
.expect(StatusCode.ClientErrorBadRequest);
81118

82-
expect(JSON.parse(response.text)).toHaveProperty("error", "InvalidParams");
119+
expect(JSON.parse(response.text)).toHaveProperty("error", "BadRequest");
83120
});
84121
});
85122

86123
describe("GET /profile", () => {
87124
it("fails to get a profile that doesn't exist", async () => {
88125
await Models.AttendeeProfile.deleteOne({ userId: TESTER_USER.userId });
89126

90-
const response = await getAsUser("/profile/").expect(StatusCode.ClientErrorNotFound);
127+
const response = await getAsAttendee("/profile/").expect(StatusCode.ClientErrorNotFound);
91128

92-
expect(JSON.parse(response.text)).toHaveProperty("error", "UserNotFound");
129+
expect(JSON.parse(response.text)).toHaveProperty("error", "NotFound");
93130
});
94131

95132
it("gets a profile that exists", async () => {
96-
const response = await getAsUser("/profile/").expect(StatusCode.SuccessOK);
97-
expect(JSON.parse(response.text)).toHaveProperty("displayName", TESTER.name);
133+
const response = await getAsAttendee("/profile/").expect(StatusCode.SuccessOK);
134+
expect(JSON.parse(response.text)).toMatchObject(PROFILE);
98135
});
99136
});
100137

101-
describe("GET /profile/userid/:USERID", () => {
102-
it("fails to get a profile as a user", async () => {
103-
const response = await getAsUser("/profile/userid/" + TESTER.id).expect(StatusCode.ClientErrorForbidden);
138+
describe("GET /profile/:id/", () => {
139+
it("fails to get a profile as a attendee", async () => {
140+
const response = await getAsAttendee(`/profile/${TESTER.id}`).expect(StatusCode.ClientErrorForbidden);
104141

105142
expect(JSON.parse(response.text)).toHaveProperty("error", "Forbidden");
106143
});
107144

108145
it("gets a profile as an admin", async () => {
109-
const response = await getAsAdmin("/profile/userid/" + TESTER.id).expect(StatusCode.SuccessOK);
146+
const response = await getAsAdmin(`/profile/${TESTER.id}`).expect(StatusCode.SuccessOK);
110147

111148
expect(JSON.parse(response.text)).toHaveProperty("displayName", TESTER.name);
112149
});
113150

114151
it("gets a user that doesnt exist", async () => {
115-
const response = await getAsAdmin("/profile/userid/doesnotexist").expect(StatusCode.ClientErrorNotFound);
116-
117-
expect(JSON.parse(response.text)).toHaveProperty("error", "UserNotFound");
118-
});
119-
});
120-
121-
describe("DELETE /profile/", () => {
122-
it("fails to delete a profile that doesn't exist", async () => {
123-
await Models.AttendeeProfile.deleteOne({ userId: TESTER_USER.userId });
124-
const response = await delAsUser("/profile").expect(StatusCode.ClientErrorNotFound);
125-
expect(JSON.parse(response.text)).toHaveProperty("error", "AttendeeNotFound");
126-
});
152+
const response = await getAsAdmin("/profile/doesnotexist").expect(StatusCode.ClientErrorNotFound);
127153

128-
it("deletes a profile", async () => {
129-
const response = await delAsUser("/profile").expect(StatusCode.SuccessOK);
130-
expect(JSON.parse(response.text)).toHaveProperty("success", true);
154+
expect(JSON.parse(response.text)).toHaveProperty("error", "NotFound");
131155
});
132156
});
133157

134158
describe("GET /profile/leaderboard", () => {
135159
it("gets 3 entries when no limit is set", async () => {
136-
await getAsUser("/profile/leaderboard").expect(StatusCode.SuccessOK);
160+
const response = await getAsUser("/profile/leaderboard").expect(StatusCode.SuccessOK);
161+
const parsed = JSON.parse(response.text);
162+
expect(parsed.profiles.length).toBe(3);
137163
});
138164

139165
it("gets with a limit of 2", async () => {
140166
const response = await getAsUser("/profile/leaderboard?limit=2").expect(StatusCode.SuccessOK);
141167

142-
const responseArray = JSON.parse(response.text);
143-
expect(responseArray.profiles.length).toBeLessThan(3);
168+
const parsed = JSON.parse(response.text);
169+
expect(parsed.profiles.length).toBe(2);
144170
});
145171

146172
it("only gets the max limit when no limit is set", async () => {
@@ -159,13 +185,13 @@ describe("GET /profile/leaderboard", () => {
159185
const response = await getAsUser("/profile/leaderboard").expect(StatusCode.SuccessOK);
160186
const responseArray = JSON.parse(response.text);
161187

162-
expect(responseArray.profiles.length).toBeLessThan(Config.LEADERBOARD_QUERY_LIMIT + 1);
188+
expect(responseArray.profiles.length).toBe(Config.LEADERBOARD_QUERY_LIMIT);
163189
});
164190

165191
it("fails when an invalid limit is set", async () => {
166192
const response = await getAsUser("/profile/leaderboard?limit=0").expect(StatusCode.ClientErrorBadRequest);
167193

168-
expect(JSON.parse(response.text)).toHaveProperty("error", "InvalidLimit");
194+
expect(JSON.parse(response.text)).toHaveProperty("error", "BadRequest");
169195
});
170196
});
171197

@@ -192,14 +218,14 @@ describe("GET /profile/addpoints", () => {
192218
expect(JSON.parse(response.text)).toHaveProperty("error", "Forbidden");
193219
});
194220

195-
it("returns UserNotFound for nonexistent users", async () => {
221+
it("returns NotFound for nonexistent users", async () => {
196222
const response = await postAsStaff("/profile/addpoints")
197223
.send({
198224
userId: "idontexists",
199225
points: 10,
200226
})
201-
.expect(StatusCode.ClientErrorBadRequest);
227+
.expect(StatusCode.ClientErrorNotFound);
202228

203-
expect(JSON.parse(response.text)).toHaveProperty("error", "UserNotFound");
229+
expect(JSON.parse(response.text)).toHaveProperty("error", "NotFound");
204230
});
205231
});

0 commit comments

Comments
 (0)