From 9e42e16993ed90f8e245488f7b1041e61fc9b7f0 Mon Sep 17 00:00:00 2001 From: AI Bot Date: Sun, 1 Mar 2026 07:33:20 +0530 Subject: [PATCH 1/2] feat: Migrate Session.controller.js to typescript and added @types/express-session dep --- package-lock.json | 34 ++++++-- package.json | 1 + server/controllers/session.controller.ts | 100 +++++++++++++++++++++++ server/types/index.ts | 1 + server/types/session.ts | 15 ++++ 5 files changed, 144 insertions(+), 7 deletions(-) create mode 100644 server/controllers/session.controller.ts create mode 100644 server/types/session.ts diff --git a/package-lock.json b/package-lock.json index 956f2cb1c1..1aac8cc591 100644 --- a/package-lock.json +++ b/package-lock.json @@ -162,6 +162,7 @@ "@testing-library/react": "^12.1.2", "@types/bcryptjs": "^2.4.6", "@types/classnames": "^2.3.0", + "@types/express-session": "^1.18.2", "@types/friendly-words": "^1.2.2", "@types/jest": "^29.5.14", "@types/js-cookie": "^3.0.6", @@ -215,7 +216,7 @@ "rimraf": "^2.7.1", "sass": "^1.66.1", "sass-loader": "^13.3.3", - "storybook": "^10.2.9", + "storybook": "^10.2.10", "storybook-addon-theme-playground": "^3.1.0", "style-loader": "^3.3.4", "terser-webpack-plugin": "^5.3.1", @@ -15551,6 +15552,16 @@ "@types/send": "*" } }, + "node_modules/@types/express-session": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/find-cache-dir": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@types/find-cache-dir/-/find-cache-dir-3.2.1.tgz", @@ -36099,9 +36110,9 @@ "license": "MIT" }, "node_modules/storybook": { - "version": "10.2.9", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.2.9.tgz", - "integrity": "sha512-DGok7XwIwdPWF+a49Yw+4madER5DZWRo9CdyySBLT3zeuxiEPt0Ua7ouJHm/y6ojnb/FVKZcQe8YmrE71s0qPQ==", + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.2.10.tgz", + "integrity": "sha512-N4U42qKgzMHS7DjqLz5bY4P7rnvJtYkWFCyKspZr3FhPUuy6CWOae3aYC2BjXkHrdug0Jyta6VxFTuB1tYUKhg==", "dev": true, "license": "MIT", "dependencies": { @@ -50248,6 +50259,15 @@ "@types/send": "*" } }, + "@types/express-session": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/find-cache-dir": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@types/find-cache-dir/-/find-cache-dir-3.2.1.tgz", @@ -65352,9 +65372,9 @@ "dev": true }, "storybook": { - "version": "10.2.9", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.2.9.tgz", - "integrity": "sha512-DGok7XwIwdPWF+a49Yw+4madER5DZWRo9CdyySBLT3zeuxiEPt0Ua7ouJHm/y6ojnb/FVKZcQe8YmrE71s0qPQ==", + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.2.10.tgz", + "integrity": "sha512-N4U42qKgzMHS7DjqLz5bY4P7rnvJtYkWFCyKspZr3FhPUuy6CWOae3aYC2BjXkHrdug0Jyta6VxFTuB1tYUKhg==", "dev": true, "requires": { "@storybook/global": "^5.0.0", diff --git a/package.json b/package.json index 2808169164..550139ff4b 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,7 @@ "@testing-library/react": "^12.1.2", "@types/bcryptjs": "^2.4.6", "@types/classnames": "^2.3.0", + "@types/express-session": "^1.18.2", "@types/friendly-words": "^1.2.2", "@types/jest": "^29.5.14", "@types/js-cookie": "^3.0.6", diff --git a/server/controllers/session.controller.ts b/server/controllers/session.controller.ts new file mode 100644 index 0000000000..e020dc0c8b --- /dev/null +++ b/server/controllers/session.controller.ts @@ -0,0 +1,100 @@ +import passport from 'passport'; +import { RequestHandler } from 'express'; +import type { Request, Response, NextFunction } from 'express'; +import { userResponse } from './user.controller'; +import type { UserDocument } from '../types'; +import { + CreateSessionRequestBody, + CreateSessionResponseBody, + GetSessionResponseBody, + DestroySessionResponseBody +} from '../types'; + +/** + * - Method: `POST` + * - Endpoint: `/login` + * - Authenticated: `false` + * - Id: `SessionController.createSession` + * + * Description: + * - Authenticate a user with local strategy and create a session + */ +export const createSession: RequestHandler< + {}, + CreateSessionResponseBody, + CreateSessionRequestBody +> = (req: Request, res: Response, next: NextFunction) => { + passport.authenticate( + 'local', + (err: Error | null, user: UserDocument | false) => { + if (err) { + next(err); + return; + } + if (!user) { + res.status(401).json({ message: 'Invalid username or password.' }); + return; + } + + req.logIn(user, (innerErr) => { + if (innerErr) { + next(innerErr); + return; + } + res.json(userResponse(req.user!)); + }); + } + )(req, res, next); +}; + +/** + * - Method: `GET` + * - Endpoint: `/session` + * - Authenticated: `false` + * - Id: `SessionController.getSession` + * + * Description: + * - Returns the current session user, or null if not logged in + */ +export const getSession: RequestHandler<{}, GetSessionResponseBody> = ( + req: Request, + res: Response +) => { + if (!req.user) { + return res.status(200).send({ user: null }); + } + if (req.user.banned) { + return res.status(403).send({ message: 'Forbidden: User is banned.' }); + } + + return res.json(userResponse(req.user)); +}; + +/** + * - Method: `GET` + * - Endpoint: `/logout` + * - Authenticated: `false` + * - Id: `SessionController.destroySession` + * + * Description: + * - Logs out the user and destroys the session + */ +export const destroySession: RequestHandler<{}, DestroySessionResponseBody> = ( + req: Request, + res: Response, + next: NextFunction +) => { + req.logout((err: Error | null) => { + if (err) { + next(err); + return; + } + req.session.destroy((error: Error | null) => { + if (error) { + next(error); + return; + } + res.json({ success: true }); + }); + }); +}; diff --git a/server/types/index.ts b/server/types/index.ts index 8511e3c860..e58c700b72 100644 --- a/server/types/index.ts +++ b/server/types/index.ts @@ -2,5 +2,6 @@ export * from './apiKey'; export * from './email'; export * from './express'; export * from './mongoose'; +export * from './session'; export * from './user'; export * from './userPreferences'; diff --git a/server/types/session.ts b/server/types/session.ts new file mode 100644 index 0000000000..341b0c2cc2 --- /dev/null +++ b/server/types/session.ts @@ -0,0 +1,15 @@ +import { PublicUser, GenericResponseBody } from '.'; + +export interface CreateSessionRequestBody { + username: string; + password: string; +} + +export type CreateSessionResponseBody = PublicUser | { message: string }; + +export type GetSessionResponseBody = + | { user: null } + | PublicUser + | GenericResponseBody; + +export type DestroySessionResponseBody = { success: boolean }; From d52c33a18358e7a456dd864d955003e805d11580 Mon Sep 17 00:00:00 2001 From: AI Bot Date: Sun, 1 Mar 2026 07:37:47 +0530 Subject: [PATCH 2/2] refactor: delete --- server/controllers/session.controller.js | 51 ------------------------ 1 file changed, 51 deletions(-) delete mode 100644 server/controllers/session.controller.js diff --git a/server/controllers/session.controller.js b/server/controllers/session.controller.js deleted file mode 100644 index 173e9e9834..0000000000 --- a/server/controllers/session.controller.js +++ /dev/null @@ -1,51 +0,0 @@ -import passport from 'passport'; - -import { userResponse } from './user.controller'; - -export function createSession(req, res, next) { - passport.authenticate('local', (err, user) => { - if (err) { - next(err); - return; - } - if (!user) { - res.status(401).json({ message: 'Invalid username or password.' }); - return; - } - - req.logIn(user, (innerErr) => { - if (innerErr) { - next(innerErr); - return; - } - res.json(userResponse(req.user)); - }); - })(req, res, next); -} - -export function getSession(req, res) { - if (!req.user) { - return res.status(200).send({ user: null }); - } - if (req.user.banned) { - return res.status(403).send({ message: 'Forbidden: User is banned.' }); - } - - return res.json(userResponse(req.user)); -} - -export function destroySession(req, res, next) { - req.logout((err) => { - if (err) { - next(err); - return; - } - req.session.destroy((error) => { - if (error) { - next(error); - return; - } - res.json({ success: true }); - }); - }); -}