var express = require('express') var router = express.Router() const DB = require("../mongoDB.js"); const Profile = require("../def/profile.js"); const Notifications = require("./../notifications.js"); const { getSessionId, getUserId, getProfileId } = require("./../utils/sessionUtils.js"); DB.getDB.then((DB) => { const profileBelongsToUser = async (profileid, userid) => { const profile = await DB.getProfileCache(profileid); if (!profile) return false; return profile.userid === String(userid); } /** * @swagger * tags: * name: Profiles * description: User profile management */ /** * @swagger * /user/mine: * get: * summary: Get all profiles for the logged-in user * tags: [Profiles] * security: * - cookieAuth: [] * responses: * 200: * description: OK * content: * application/json: * schema: * type: object * properties: * status: * type: string * profiles: * type: array * items: * type: object */ router.get("/mine", async (req, res) => { let userid = getUserId(req); let profiles = await DB.getUserProfiles(userid); return res.json({ status: "ok", profiles }); }); /** * @swagger * /user/new: * get: * summary: (DEPRECATED) Create a new profile * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: query * name: content * required: true * schema: * type: object * responses: * 200: * description: OK */ router.get("/new", async (req, res) => { //Deprecated please use route post("/") let profile = { userid: getUserId(req), ...req.query.content }; let profileObj = new Profile(profile); let r = await DB.newProfile(profileObj); return res.json({ status: "ok", ...profileObj.toObj() }); }); /** * @swagger * /user: * post: * summary: Create a new profile * tags: [Profiles] * security: * - cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * content: * type: object * responses: * 200: * description: OK */ router.post("/", async (req, res) => { let profile = { userid: getUserId(req), ...req.body.content }; try { let profileObj = new Profile(profile); let r = await DB.newProfile(profileObj); return res.json({ status: "ok", ...profileObj.toObj() }); } catch (error) { console.error("Error creating profile", error); return res.json({ status: error, }); } }); /** * @swagger * /user/invite: * post: * summary: Invite a new user by email * tags: [Profiles] * security: * - cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * name: * type: string * email: * type: string * format: email * responses: * 200: * description: OK * 400: * description: Bad request */ router.post("/invite", async (req, res) => { try { const userid = getUserId(req); let { name, email } = req.body; // Destructuring for clarity // Validate required fields if (!name || !email) { return res.status(400).json({ status: "Name and email are required" }); } // Validate email format email = email.trim().toLowerCase() const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { return res.status(400).json({ status: "Invalid email format" }); } // Create new invitation, this returns a string if failed let r = await DB.newInvitation(userid, name, email); if (r instanceof String) { // Handle failure response from DB.newInvitation return res.status(400).json({ status: r, message: `Failed to send invitation: ${r}` }); } // Handle response from DB.newInvitation // Send email invitation let senderProfile = await DB.getProfile(getProfileId(req)); Notifications.youHaveAnInvitation(name, email, senderProfile); return res.status(200).json({ status: "ok", message: `Invitation sent to ${name} (${email})` }); } catch (error) { console.error("Error during invitation process:", error); return res.status(500).json({ status: "error", message: "Something went wrong, please try again later" }); } }); /** * @swagger * /user/invite/{email}: * get: * summary: Get invitation details for an email * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: email * required: true * schema: * type: string * format: email * responses: * 200: * description: OK */ router.get("/invite/:email", async (req, res) => { const userid = getUserId(req); const email = req.params.email; //validate email? if (!email) return res.json({ status: "provide valid email" }); let r = await DB.getInvitation(email); if (!r) return res.json({ status: "no invitation found with that email" }); let isUserAlreadyRegistered = await DB.getUser(email); if (isUserAlreadyRegistered && isUserAlreadyRegistered._id) return res.json({ status: "This user is already registered" }); return res.json({ status: "ok", ...r }); }); /** * @swagger * /user/groups: * get: * summary: Get a list of all groups * tags: [Profiles] * security: * - cookieAuth: [] * responses: * 200: * description: OK */ router.get("/groups", async (req, res) => { let groups = await DB.getGroups(); return res.json({ status: "ok", groups }); }); /** * @swagger * /user/groups/following: * get: * summary: Get a list of groups the current profile is following * tags: [Profiles] * security: * - cookieAuth: [] * responses: * 200: * description: OK */ router.get("/groups/following", async (req, res) => { const profileId = getProfileId(req); let groups = await DB.getFollowingGroups(profileId); return res.json({ status: "ok", groups }); }); /** * @swagger * /user/groups: * post: * summary: Create a new group * tags: [Profiles] * security: * - cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * responses: * 200: * description: OK */ router.post("/groups", async (req, res) => { let profile = { userid: getUserId(req), isGroup: true, ...req.body }; let profileObj = new Profile(profile); DB.newProfile(profileObj) return res.json({ status: "ok", ...profileObj.toObj() }); }); /** * @swagger * /user/courses: * get: * summary: Get a list of all courses * tags: [Profiles] * security: * - cookieAuth: [] * responses: * 200: * description: OK */ router.get("/courses", async (req, res) => { let groups = await DB.getCourses(); return res.json({ status: "ok", groups }); }); /** * @swagger * /user/groups/accept: * post: * summary: Accept a request to join a private group * tags: [Profiles] * security: * - cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * groupid: * type: string * profileid: * type: string * responses: * 200: * description: OK */ router.post("/groups/accept", async (req, res) => { //This function should be called to accept the join request //of an user that attempt to join a private group. const groupid = getProfileId(req); //It needs to have this profile context const groupidBody = req.body.groupid ? DB.ObjectID(req.body.groupid) : undefined; if (groupidBody && groupid != groupidBody && !DB.isOwnerOfGroup(groupid, groupidBody)) { return res.json({ status: "Only group owner can accept new subscribers" }); } const profileAcepted = DB.ObjectID(req.body.profileid); DB.acceptGroupJoinReq(profileAcepted, groupidBody || groupid); //Send Notification to accepted user Notifications.yourGroupRequestAccepted(profileAcepted, groupidBody || groupid) return res.json({ status: "ok" }); }); /** * @swagger * /user/groups/reject: * post: * summary: Reject a request to join a private group * tags: [Profiles] * security: * - cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * groupid: * type: string * profileid: * type: string * responses: * 200: * description: OK */ router.post("/groups/reject", async (req, res) => { //This function should be called to reject the join request //of an user that attempt to join a private group. const groupid = getProfileId(req); //It needs to have this profile context const groupidBody = req.body.groupid ? DB.ObjectID(req.body.groupid) : undefined; if (groupidBody && groupid != groupidBody && !DB.isOwnerOfGroup(groupid, groupidBody)) { return res.json({ status: "Only group owner can reject new subscribers" }); } const profileAcepted = DB.ObjectID(req.body.profileid); DB.rejectGroupJoinReq(profileAcepted, groupidBody || groupid); //Add Notification to rejected user //Notifications.yourGroupHasARequest(profileAcepted, groupidBody || groupid) return res.json({ status: "ok" }); }); /** * @swagger * /user/groups/search: * get: * summary: Search for groups * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: query * name: query * required: true * schema: * type: string * - in: query * name: courses * schema: * type: boolean * responses: * 200: * description: OK */ router.get("/groups/search", async (req, res) => { let query = req.query.query; let coursesB = req.query.courses ? true : false; let groups = await DB.searchGroups(query, coursesB); return res.json({ status: "ok", groups }); }); /** * @swagger * /user/groups/{id}: * get: * summary: Get details for a specific group * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: string * responses: * 200: * description: OK */ router.get("/groups/:id", async (req, res) => { const groupid = req.params.id; let groups = await DB.getGroup(groupid); return res.json({ status: "ok", groups }); }); /** * @swagger * /user/groups/{id}/subscribe: * get: * summary: Subscribe to a group * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: string * responses: * 200: * description: OK */ router.get("/groups/:id/subscribe", async (req, res) => { const groupid = req.params.id; const profileid = getProfileId(req); const isPrivate = await DB.isGroupPrivate(groupid); DB.subscribeToGroup(profileid, groupid, isPrivate); //Add notification to group owner if (isPrivate) Notifications.yourGroupHasARequest(profileid, groupid) return res.json({ status: "ok" }); }); /** * @swagger * /user/groups/{id}/unsubscribe: * get: * summary: Unsubscribe from a group * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: string * responses: * 200: * description: OK */ router.get("/groups/:id/unsubscribe", async (req, res) => { const groupid = req.params.id; const profileid = getProfileId(req); DB.unsubscribeToGroup(profileid, groupid); //Add notification to group owner return res.json({ status: "ok" }); }); /** * @swagger * /user/search: * get: * summary: Search for profiles * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: query * name: query * required: true * schema: * type: string * responses: * 200: * description: OK */ router.get("/search", async (req, res) => { let query = req.query.query; let profiles = await DB.searchProfile(query); return res.json({ status: "ok", profiles }); }); /** * @swagger * /user/setData: * post: * summary: Set custom data for a profile * tags: [Profiles] * security: * - cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * key: * type: string * value: * type: object * responses: * 200: * description: OK */ router.post("/setData", (req, res) => { const key = req.body.key; const value = req.body.value; const profileid = getProfileId(req); DB.setData(profileid, key, value); return res.json({ status: "ok", }); }); /** * @swagger * /user/myProfile: * post: * summary: Update the current user's profile * tags: [Profiles] * security: * - cookieAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * profile: * type: object * data: * type: object * responses: * 200: * description: OK */ router.post("/myProfile", async (req, res) => { let profile = { userid: getUserId(req), profile: req.body.profile, data: req.body.data }; let profileObj = new Profile(profile); //validates profile DB.updateProfile(getProfileId(req), profileObj); return res.json({ status: "ok" }); }); /** * @swagger * /user/{id}: * get: * summary: Get a specific profile by ID * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: string * responses: * 200: * description: OK */ router.get("/:id", async (req, res) => { let profileId = req.params.id; let profile = await DB.getProfile(profileId); return res.json({ status: "ok", ...profile }); }); /** * @swagger * /user/{id}: * delete: * summary: Delete a profile * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: string * responses: * 200: * description: OK */ router.delete("/:id", async (req, res) => { const profileId = req.params.id; const userid = getUserId(req); if (!await profileBelongsToUser(profileId, userid)) return res.json({ status: "This profile is not yours." }); await DB.removeProfile(profileId); return res.json({ status: "ok" }); }); /** * @swagger * /user/{id}/follow: * get: * summary: Follow a profile * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: string * responses: * 200: * description: OK */ router.get("/:id/follow", async (req, res) => { let followProfileId = req.params.id; const profileid = getProfileId(req); DB.followProfile(profileid, followProfileId); //Add notification to user return res.json({ status: "ok" }); }); /** * @swagger * /user/{id}/unfollow: * get: * summary: Unfollow a profile * tags: [Profiles] * security: * - cookieAuth: [] * parameters: * - in: path * name: id * required: true * schema: * type: string * responses: * 200: * description: OK */ router.get("/:id/unfollow", async (req, res) => { let followProfileId = req.params.id; const profileid = getProfileId(req); DB.unfollowProfile(profileid, followProfileId); //Add notification to user return res.json({ status: "ok" }); }); }); module.exports = router