Skip to content

Commit d7cc8e3

Browse files
authored
Merge branch 'main' into enhancement/api-gateway
2 parents 1b45f5f + 1bede2f commit d7cc8e3

File tree

17 files changed

+272
-33
lines changed

17 files changed

+272
-33
lines changed

.env.sample

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,29 @@ COMPOSE_PATH_SEPARATOR=:
44
COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml
55

66
## Frontend variables
7-
FRONTEND_PORT=
7+
FRONTEND_PORT=3000
88
# BASE_URI only needs to be provided if hosting outside of cluster
99
BASE_URI=
1010

1111
## Question service variables
12-
QUESTION_SVC_PORT=
12+
QUESTION_SVC_PORT=8000
1313
QUESTION_SVC_DB_URI=
1414

1515
## User service variables
16-
USER_SVC_PORT=
16+
USER_SVC_PORT=3001
1717
USER_SVC_DB_URI=
1818
JWT_SECRET=
1919
EMAIL_ADDRESS=
2020
EMAIL_PASSWORD=
2121

2222
## Matching service variables
23-
MATCHING_SVC_PORT=
24-
MATCHING_SVC_REDIS_PORT=
23+
MATCHING_SVC_PORT=6969
24+
25+
## Redis variables
26+
REDIS_PORT=6379
27+
28+
## Redisinsight variables
29+
REDIS_INSIGHT_PORT=5540
2530

2631
## API Gateway variables
2732
API_GATEWAY_PORT=

docker-compose.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ services:
3131
context: ./matching-service
3232
environment:
3333
- PORT=$MATCHING_SVC_PORT
34+
- REDIS_HOST=redis
35+
- REDIS_PORT=$REDIS_PORT
36+
depends_on:
37+
- redis
3438

3539
api-gateway:
3640
image: nginx:1.26
@@ -53,3 +57,15 @@ services:
5357
redis:
5458
image: redis:7.4-alpine
5559
restart: always
60+
ports:
61+
- $REDIS_PORT:$REDIS_PORT
62+
63+
# access RedisInsight at http://localhost:5540
64+
# connect to redis on redis insight at redis:6379
65+
redisinsight:
66+
image: redis/redisinsight:latest
67+
restart: always
68+
ports:
69+
- $REDIS_INSIGHT_PORT:$REDIS_INSIGHT_PORT # Expose RedisInsight UI on port 5540
70+
depends_on:
71+
- redis

frontend/components/auth/reset-password-form.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { useState } from "react";
44
import { useRouter } from "next/navigation";
55
import { resetPassword } from "@/lib/reset-password";
6+
import { isPasswordComplex } from "@/lib/password";
67
import { useToast } from "@/components/hooks/use-toast";
78

89
import { Button } from "@/components/ui/button";
@@ -24,14 +25,22 @@ export function ResetPasswordForm({ token }: { token: string }) {
2425

2526
const handleSubmit = async (event: React.FormEvent) => {
2627
event.preventDefault();
27-
// TODO: Add validation for password
2828
if (password !== passwordConfirmation) {
2929
toast({
3030
title: "Password Mismatch",
3131
description: "The passwords you entered do not match",
3232
});
3333
return;
3434
}
35+
if (!isPasswordComplex(passwordConfirmation)) {
36+
toast({
37+
title: "Weak Password",
38+
description:
39+
"Password must be at least 8 characters long, include 1 uppercase letter and 1 special character.",
40+
});
41+
return;
42+
}
43+
3544
const res = await resetPassword(token, password);
3645
if (!res.ok) {
3746
toast({

frontend/components/auth/sign-up-form.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useState } from "react";
55
import { useRouter } from "next/navigation";
66
import { toast } from "@/components/hooks/use-toast";
77
import { signUp } from "@/lib/signup";
8+
import { isPasswordComplex } from "@/lib/password";
89

910
import { Button } from "@/components/ui/button";
1011
import {
@@ -34,6 +35,14 @@ export function SignUpForm() {
3435
});
3536
return;
3637
}
38+
if (!isPasswordComplex(passwordConfirmation)) {
39+
toast({
40+
title: "Weak Password",
41+
description:
42+
"Password must be at least 8 characters long, include 1 uppercase letter and 1 special character.",
43+
});
44+
return;
45+
}
3746
const res = await signUp(username, email, password);
3847
if (!res.ok) {
3948
toast({

frontend/components/questions/question-form-modal.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@ interface QuestionFormModalProps {
3030
}
3131

3232
const QuestionFormModal: React.FC<QuestionFormModalProps> = ({ ...props }) => {
33+
const initialQuestionState: Question = {
34+
id: "",
35+
title: "",
36+
category: "",
37+
complexity: "easy",
38+
description: "",
39+
};
40+
3341
const [question, setQuestion] = useState<Question>(
34-
props.initialData || {
35-
id: "",
36-
title: "",
37-
category: "",
38-
complexity: "easy",
39-
description: "",
40-
}
42+
props.initialData || initialQuestionState
4143
);
4244

4345
useEffect(() => {
@@ -50,6 +52,16 @@ const QuestionFormModal: React.FC<QuestionFormModalProps> = ({ ...props }) => {
5052
e.preventDefault();
5153

5254
props.handleSubmit(question);
55+
setQuestion(initialQuestionState);
56+
};
57+
58+
const handleExit = () => {
59+
if (props.initialData) {
60+
setQuestion(props.initialData);
61+
} else {
62+
setQuestion(initialQuestionState);
63+
}
64+
props.setShowModal(false);
5365
};
5466

5567
return (
@@ -136,10 +148,7 @@ const QuestionFormModal: React.FC<QuestionFormModalProps> = ({ ...props }) => {
136148
{props.isAdmin && (
137149
<Button type="submit">{props.submitButtonText}</Button>
138150
)}
139-
<Button
140-
variant="destructive"
141-
onClick={() => props.setShowModal(false)}
142-
>
151+
<Button variant="destructive" onClick={handleExit}>
143152
Exit
144153
</Button>
145154
</DialogFooter>

frontend/components/user-settings/user-settings.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { useAuth } from "@/app/auth/auth-context";
2525
import { cn } from "@/lib/utils";
2626
import { User, UserSchema } from "@/lib/schemas/user-schema";
2727
import { AuthType, userServiceUri } from "@/lib/api-uri";
28+
import { isPasswordComplex } from "@/lib/password";
29+
import { userServiceUri } from "@/lib/api-uri";
2830

2931
const fetcher = async (url: string): Promise<User> => {
3032
// Retrieve the JWT token from localStorage
@@ -300,16 +302,6 @@ export default function UserSettings({ userId }: { userId: string }) {
300302
}
301303
}, [newPassword, confirmPassword]);
302304

303-
const isPasswordComplex = (password: string) => {
304-
const minLength = 8;
305-
const hasUpperCase = /[A-Z]/.test(password);
306-
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/.test(
307-
password
308-
);
309-
310-
return password.length >= minLength && hasUpperCase && hasSpecialChar;
311-
};
312-
313305
if (isLoading) {
314306
return <LoadingScreen />;
315307
}

frontend/lib/password.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const isPasswordComplex = (password: string) => {
2+
const minLength = 8;
3+
const hasUpperCase = /[A-Z]/.test(password);
4+
const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/.test(
5+
password
6+
);
7+
8+
return password.length >= minLength && hasUpperCase && hasSpecialChar;
9+
};

matching-service/.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
.venv
2-
app/__pycache__
3-
app/routers/__pycache__
2+
**/__pycache__

matching-service/app/__init__.py

Whitespace-only changes.

matching-service/app/models/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)