Skip to content

Commit 8e89435

Browse files
Merge branch 'main' into fix/cors
2 parents 97c7321 + 8d17610 commit 8e89435

23 files changed

Lines changed: 893 additions & 286 deletions

.github/workflows/auto-label-gssoc.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ jobs:
2525
with:
2626
github_token: ${{ secrets.GITHUB_TOKEN }} # Use GITHUB_TOKEN for PRs
2727
labels: |
28-
gssoc26
28+
level:intermediate
29+
quality:clean
30+
gssoc:approved

backend/models/User.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,12 @@ const UserSchema = new mongoose.Schema({
1818
},
1919
});
2020

21-
UserSchema.pre('save', async function (next) {
22-
21+
UserSchema.pre('save', async function () {
2322
if (!this.isModified('password'))
24-
return next();
23+
return;
2524

26-
try {
27-
const salt = await bcrypt.genSalt(10);
28-
this.password = await bcrypt.hash(this.password, salt);
29-
next();
30-
} catch (err) {
31-
return next(err);
32-
}
25+
const salt = await bcrypt.genSalt(10);
26+
this.password = await bcrypt.hash(this.password, salt);
3327
});
3428

3529
// Compare passwords during login

backend/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"scripts": {
66
"dev": "nodemon server.js",
77
"start": "node server.js",
8-
"test": "echo \"Error: no test specified\" && exit 1"
8+
"test": "jasmine spec/**/*.spec.cjs"
9+
910
},
1011
"keywords": [],
1112
"author": "",
@@ -20,7 +21,8 @@
2021
"express-session": "^1.18.1",
2122
"mongoose": "^8.8.2",
2223
"passport": "^0.7.0",
23-
"passport-local": "^1.0.0"
24+
"passport-local": "^1.0.0",
25+
"zod": "^4.4.3"
2426
},
2527
"devDependencies": {
2628
"nodemon": "^3.1.9"

backend/routes/auth.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
const express = require("express");
22
const passport = require("passport");
33
const User = require("../models/User");
4+
const { signupSchema, loginSchema } = require("../validators/authValidator");
5+
const { validateRequest } = require("../validators/validationRequest");
46
const router = express.Router();
57

68
// Signup route
7-
router.post("/signup", async (req, res) => {
9+
router.post("/signup", validateRequest(signupSchema), async (req, res) => {
810

911
const { username, email, password } = req.body;
1012

@@ -29,7 +31,7 @@ router.post("/signup", async (req, res) => {
2931
});
3032

3133
// Login route
32-
router.post("/login", passport.authenticate('local'), (req, res) => {
34+
router.post("/login", validateRequest(loginSchema), passport.authenticate('local'), (req, res) => {
3335
res.status(200).json( { message: 'Login successful', user: req.user } );
3436
});
3537

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const { z } = require("zod");
2+
3+
const signupSchema = z.object({
4+
username: z.string()
5+
.trim()
6+
.min(3, "Username must be at least 3 characters long")
7+
.max(30, "Username must be at most 30 characters long")
8+
.regex(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores")
9+
,
10+
11+
email: z.string()
12+
.trim()
13+
.toLowerCase()
14+
.email("Invalid email address"),
15+
16+
17+
password: z.string()
18+
.min(8, "Password must be at least 8 characters long")
19+
.max(100, "Password must be at most 100 characters long")
20+
.regex(
21+
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/,
22+
'Password must contain uppercase, lowercase, number, and special character'
23+
),
24+
});
25+
26+
27+
const loginSchema = z.object({
28+
email: z.string()
29+
.trim()
30+
.toLowerCase()
31+
.email("Invalid email address"),
32+
password: z.string()
33+
.min(8, "Password must be at least 8 characters long")
34+
.max(100, "Password must be at most 100 characters long")
35+
});
36+
37+
38+
module.exports = { signupSchema, loginSchema };
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const validateRequest = (schema) => (req, res, next) => {
2+
const result = schema.safeParse(req.body);
3+
4+
if(!result.success) {
5+
return res.status(400).json({
6+
success: false,
7+
message: 'Validation failed',
8+
errors: result.error.issues.map((err) => ({
9+
field: err.path.join('.'),
10+
message: err.message,
11+
})),
12+
});
13+
}
14+
15+
req.validated = result.data;
16+
req.body = result.data;
17+
next();
18+
}
19+
20+
module.exports = { validateRequest };

package.json

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"dev": "vite --host",
88
"build": "vite build",
99
"lint": "eslint .",
10+
"test": "vitest",
11+
"test:backend": "jasmine spec/**/*.spec.cjs",
1012
"preview": "vite preview",
1113
"docker:dev": "docker compose --profile dev up --build",
1214
"docker:prod": "docker compose --profile prod up -d --build"
@@ -16,7 +18,7 @@
1618
"@emotion/styled": "^11.11.0",
1719
"@mui/icons-material": "^5.15.6",
1820
"@mui/material": "^5.15.6",
19-
"@primer/octicons-react": "^19.15.5",
21+
"@primer/octicons-react": "^19.25.0",
2022
"@vitejs/plugin-react": "^4.3.3",
2123
"axios": "^1.7.7",
2224
"framer-motion": "^12.23.12",
@@ -32,6 +34,9 @@
3234
},
3335
"devDependencies": {
3436
"@eslint/js": "^9.13.0",
37+
"@testing-library/jest-dom": "^6.9.1",
38+
"@testing-library/react": "^16.3.2",
39+
"@testing-library/user-event": "^14.6.1",
3540
"@types/jasmine": "^5.1.8",
3641
"@types/node": "^22.10.1",
3742
"@types/react": "^18.3.23",
@@ -47,10 +52,13 @@
4752
"eslint-plugin-react-refresh": "^0.4.14",
4853
"express-session": "^1.18.2",
4954
"globals": "^15.11.0",
50-
"jasmine": "^5.9.0",
55+
"jasmine": "^5.13.0",
56+
"jasmine-spec-reporter": "^7.0.0",
57+
"jsdom": "^29.1.1",
5158
"passport": "^0.7.0",
5259
"passport-local": "^1.0.0",
53-
"supertest": "^7.1.4",
54-
"vite": "^5.4.10"
60+
"supertest": "^7.2.2",
61+
"vite": "^5.4.10",
62+
"vitest": "^4.1.6"
5563
}
5664
}

spec/auth.routes.spec.cjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ describe('Auth Routes', () => {
2222
let app;
2323

2424
beforeAll(async () => {
25-
await mongoose.connect('mongodb://127.0.0.1:27017/github_tracker_test', {
26-
useNewUrlParser: true,
27-
useUnifiedTopology: true,
28-
});
25+
await mongoose.connect('mongodb://127.0.0.1:27017/github_tracker_test');
2926
app = createTestApp();
3027
});
3128

spec/user.model.spec.cjs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ const User = require('../backend/models/User');
44

55
describe('User Model', () => {
66
beforeAll(async () => {
7-
await mongoose.connect('mongodb://127.0.0.1:27017/github_tracker_test', {
8-
useNewUrlParser: true,
9-
useUnifiedTopology: true,
10-
});
7+
await mongoose.connect('mongodb://127.0.0.1:27017/github_tracker_test');
118
});
129

1310
afterAll(async () => {

src/App.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
1+
import { useLocation } from "react-router-dom";
12
import Navbar from "./components/Navbar";
23
import Footer from "./components/Footer";
34
import ScrollProgressBar from "./components/ScrollProgressBar";
45
import { Toaster } from "react-hot-toast";
56
import Router from "./Routes/Router";
6-
import ThemeWrapper from "./context/ThemeContext";
7+
8+
const FULLSCREEN_ROUTES = ["/signup", "/login"];
79

810
function App() {
11+
const location = useLocation();
12+
const isFullscreen = FULLSCREEN_ROUTES.includes(location.pathname);
13+
914
return (
10-
<ThemeWrapper>
1115
<div className="relative flex flex-col min-h-screen">
12-
<ScrollProgressBar />
16+
{!isFullscreen && <ScrollProgressBar />}
1317

14-
<Navbar />
18+
{!isFullscreen && <Navbar />}
1519

16-
<main className="flex-grow bg-gray-50 dark:bg-gray-800 flex justify-center items-center">
20+
<main className={`flex justify-center items-center ${isFullscreen ? "flex-1" : "flex-grow bg-gray-50 dark:bg-gray-800"}`}>
1721
<Router />
1822
</main>
1923

20-
<Footer />
24+
{!isFullscreen && <Footer />}
2125

2226
<Toaster
2327
position="top-center"
@@ -37,7 +41,6 @@ function App() {
3741
}}
3842
/>
3943
</div>
40-
</ThemeWrapper>
4144
);
4245
}
4346

0 commit comments

Comments
 (0)