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

Fixed tiny nits in profile service #86

Merged
merged 3 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 18 additions & 1 deletion src/services/profile/profile-lib.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AttendeeProfile } from "../../database/attendee-db.js";
import { AttendeeProfile, AttendeeProfileModel } from "../../database/attendee-db.js";
import Constants from "../../constants.js";
import { LeaderboardEntry } from "./profile-models.js";
import { UpdateQuery } from "mongoose";

/**
* Remove non-necessary fields from a leaderboardentry item
Expand All @@ -23,3 +24,19 @@ export function castLeaderboardEntries(initial: AttendeeProfile): LeaderboardEnt
export function isValidLimit(limit: number): boolean {
return limit > Constants.ZERO;
}

/**
* Change a user's points by a specific amount.
* @param userId ID of the user to modify
* @param amount Amount of points to change (note that this can be a negative number too!)
* @returns Promise containing the new user, or the actual attendee profile
*/
export async function updatePoints(userId: string, amount: number): Promise<AttendeeProfile | null> {
const updateQuery: UpdateQuery<AttendeeProfile> = {
$inc: {
points: amount,
},
};

return AttendeeProfileModel.findOneAndUpdate({ userId: userId }, updateQuery);
}
96 changes: 23 additions & 73 deletions src/services/profile/profile-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import { Response } from "express-serve-static-core";
import Constants from "../../constants.js";
import { isValidLimit } from "./profile-lib.js";
import { AttendeeMetadata, AttendeeMetadataModel, AttendeeProfile, AttendeeProfileModel } from "../../database/attendee-db.js";
import { Query, UpdateQuery } from "mongoose";
import { Query } from "mongoose";
import { LeaderboardEntry } from "./profile-models.js";

import { JwtPayload } from "../auth/auth-models.js";
import { strongJwtVerification, weakJwtVerification } from "../../middleware/verify-jwt.js";
import { hasElevatedPerms } from "../auth/auth-lib.js";
import { isValidProfileModel } from "./profile-formats.js";

const profileRouter: Router = Router();
Expand All @@ -31,14 +30,12 @@ profileRouter.use(cors({ origin: "*" }));
* {
"profiles": [
{
"id": "profileid123456",
"displayName": "profileid123456",
"points": 2021,
"discord": "patrick#1234"
},
{
"id": "profileid123456",
"points": 2021,
"discord": "patrick#1234"
"displayName": "test2"
"points": 2020,
},
]
}
Expand Down Expand Up @@ -87,12 +84,11 @@ profileRouter.get("/leaderboard/", async (req: Request, res: Response) => {
* HTTP/1.1 200 OK
* {
* "_id": "12345",
* "firstName": "Hackk",
* "lastName": "Illinois",
* "discord": "hackillinois",
* "displayName": "Illinois",
* "discordName": "hackillinois",
* "avatarUrl": "na",
* "points": 0,
* "id": "abcde",
* "userId": "abcde",
* "foodWave": 0
* }
*
Expand All @@ -110,8 +106,8 @@ profileRouter.get("/leaderboard/", async (req: Request, res: Response) => {
profileRouter.get("/", strongJwtVerification, async (_: Request, res: Response) => {
const decodedData: JwtPayload = res.locals.payload as JwtPayload;

const id: string = decodedData.id;
const user: AttendeeProfile | null = await AttendeeProfileModel.findOne({ userId: id });
const userId: string = decodedData.id;
const user: AttendeeProfile | null = await AttendeeProfileModel.findOne({ userId: userId });

if (!user) {
return res.status(Constants.NOT_FOUND).send({ error: "UserNotFound" });
Expand All @@ -132,13 +128,11 @@ profileRouter.get("/", strongJwtVerification, async (_: Request, res: Response)
* HTTP/1.1 200 OK
* {
* "_id": "12345",
* "firstName": "Hackk",
* "lastName": "Illinois",
* "discord": "hackillinois",
* "displayName": "Hackk",
* "discordName": "hackillinois",
* "avatarUrl": "na",
* "points": 0,
* "id": "abcde",
* "foodWave": 0
* "userId": "abcde",
* }
*
* @apiError (404: Not Found) {String} UserNotFound The user's profile was not found.
Expand All @@ -153,10 +147,13 @@ profileRouter.get("/", strongJwtVerification, async (_: Request, res: Response)
*/

profileRouter.get("/id/:USERID", weakJwtVerification, async (req: Request, res: Response) => {
const id: string | undefined = req.params.USERID;
console.log(id);
const userId: string | undefined = req.params.USERID;

const user: AttendeeProfile | null = await AttendeeProfileModel.findOne({ userId: id });
if (!userId) {
return res.status(Constants.BAD_REQUEST).send({ error: "InvalidParams" });
}

const user: AttendeeProfile | null = await AttendeeProfileModel.findOne({ userId: userId });

if (!user) {
return res.status(Constants.NOT_FOUND).send({ error: "UserNotFound" });
Expand All @@ -180,13 +177,11 @@ profileRouter.get("/id/:USERID", weakJwtVerification, async (req: Request, res:
* HTTP/1.1 200 OK
* {
* "_id": "abc12345",
* "firstName": "Hack",
* "lastName": "Illinois",
* "discord": "HackIllinois",
* "displayName": "Illinois",
* "discordName": "HackIllinois",
* "avatarUrl": "na",
* "points": 0,
* "id": "12345",
* "foodWave": 0
* "userId": "12345",
* }
*
* @apiError (400: Bad Request) {String} UserAlreadyExists The user profile already exists.
Expand Down Expand Up @@ -221,58 +216,13 @@ profileRouter.post("/", strongJwtVerification, async (req: Request, res: Respons
const profileMetadata: AttendeeMetadata = new AttendeeMetadata(profile.userId, Constants.DEFAULT_FOOD_WAVE);

try {
await AttendeeProfileModel.create(profile);
const newProfile = await AttendeeProfileModel.create(profile);
await AttendeeMetadataModel.create(profileMetadata);
return res.status(Constants.SUCCESS).send(newProfile);
} catch (error) {
console.error(error);
return res.status(Constants.FAILURE).send({ error: "InvalidParams" });
}

return res.status(Constants.SUCCESS).send(profile);
});

/**
* @api {put} /profile/points PUT /profile/points
* @apiGroup Profile
* @apiDescription Update a user's points. Only STAFF and ADMIN roles can edit this.
*
* @apiBody {String} points new number of points
*
* @apiSuccess (200: Success) {Json} profile Updated user point number
* @apiSuccessExample Example Success Response:
* HTTP/1.1 200 OK
* {
* "points": 5
* }
*
* @apiError (500: Internal Error) {String} InternalError An internal server error occurred.
* @apiErrorExample Example Error Response (InternalError):
* HTTP/1.1 500 Internal Server Error
* {"error": "InternalError"}
*/

profileRouter.put("/points", strongJwtVerification, async (req: Request, res: Response) => {
const profile: AttendeeProfile | null = req.body as AttendeeProfile;

if (!isValidProfileModel(profile)) {
return res.status(Constants.BAD_REQUEST).send({ error: "InvalidPutData" });
}

const decodedData: JwtPayload = res.locals.payload as JwtPayload;

if (!hasElevatedPerms(decodedData)) {
return res.status(Constants.FORBIDDEN).send({ error: "NotAuthorizedToUseEndpoint" });
}

const update: UpdateQuery<AttendeeProfile> = {
$set: {
points: profile.points,
},
};

await AttendeeProfileModel.updateOne({ userId: decodedData.id }, update);

return res.status(Constants.SUCCESS).send({ points: profile.points });
});

/**
Expand Down
Loading