Skip to content

Commit 0135b3c

Browse files
committed
Merge remote-tracking branch 'origin/main' into F25/artyom/invite-user
1 parent ad20aea commit 0135b3c

File tree

66 files changed

+4626
-1730
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+4626
-1730
lines changed

.github/workflows/lint.yml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
steps:
2323
- name: Checkout code
2424
uses: actions/checkout@v2
25-
25+
2626
- name: Filter changed files
2727
uses: dorny/paths-filter@v2
2828
id: changes
@@ -34,7 +34,19 @@ jobs:
3434
- "backend/typescript/**"
3535
python-backend:
3636
- "backend/python/**"
37-
37+
38+
- name: Get Yarn cache directory
39+
id: yarn-cache-dir
40+
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
41+
42+
- name: Cache Yarn dependencies
43+
uses: actions/cache@v3
44+
with:
45+
path: ${{ steps.yarn-cache-dir.outputs.dir }}
46+
key: yarn-${{ runner.os }}-${{ hashFiles('frontend/yarn.lock', 'backend/typescript/yarn.lock') }}
47+
restore-keys: |
48+
yarn-${{ runner.os }}-
49+
3850
- name: Set up Node.js
3951
if: steps.changes.outputs.frontend == 'true' || steps.changes.outputs.typescript-backend == 'true'
4052
uses: actions/setup-node@v4
@@ -44,7 +56,7 @@ jobs:
4456
cache-dependency-path: |
4557
frontend/yarn.lock
4658
backend/typescript/yarn.lock
47-
59+
4860
- name: Install Node.js dependencies
4961
if: steps.changes.outputs.frontend == 'true' || steps.changes.outputs.typescript-backend == 'true'
5062
run: yarn --cwd ./frontend --prefer-offline && yarn --cwd ./backend/typescript --prefer-offline
@@ -58,7 +70,7 @@ jobs:
5870
if: steps.changes.outputs.typescript-backend == 'true'
5971
working-directory: ./backend/typescript
6072
run: yarn lint
61-
73+
6274
- name: Lint Python backend
6375
if: steps.changes.outputs.python-backend == 'true'
6476
working-directory: ./backend/python

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,17 @@ docker exec -it humane_society_frontend /bin/bash -c "yarn run fix"
113113
docker exec -it humane_society_backend /bin/bash -c "yarn test"
114114
```
115115

116+
## Running against Supabase DB
117+
We have deployed our Postgres DB on Supabase which you can connect your local application to, which can be useful for testing.
118+
119+
1. Ask your Project Lead for the `DATABASE_URL` environment variable which stores our Supabase connection URL and add it to `.env` at the root of this project.
120+
- Optionally, you can also be added to the OMHS organization on Supabase if you need to do some admin work on the deployed DB.
121+
2. Run the app against the Supabase DB
122+
```bash
123+
NODE_ENV=production docker compose up
124+
```
125+
126+
> **Note:** Currently, the `humane_society_db` container is also run even when you run against Supabase. You should be able to stop it if the application is correctly connected to Supabase. Additional changes can be made to stop it from running when you want to run against Supabase, involving setting another environment variable (see this [PR](https://github.com/uwblueprint/humane-society/pull/152)).
116127
117128
## Version Control Guide
118129

backend/typescript/middlewares/validators/userValidators.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ export const createUserDtoValidator = async (
3131
if (false && !validatePrimitive(req.body.colorLevel, "integer")) {
3232
return res.status(400).send(getApiValidationError("colorLevel", "integer"));
3333
}
34+
if (!validateNumberConstraint(req.body.colorLevel, 1, 5)) {
35+
return res.status(400).send(getConstraintError("colorLevel", 1, 5));
36+
}
37+
if (!validateEnumArray(req.body.animalTags, AnimalTag)) {
38+
return res
39+
.status(400)
40+
.send(getApiValidationError("animalTags", "AnimalTag", true));
41+
}
3442
if (
3543
req.body.canSeeAllLogs !== undefined &&
3644
req.body.canSeeAllLogs !== null &&

backend/typescript/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@faker-js/faker": "^8.4.1",
1919
"@types/graphql-upload": "^8.0.6",
2020
"@types/json2csv": "^5.0.3",
21+
"@types/luxon": "^3.6.2",
2122
"@types/multer": "^1.4.6",
2223
"@types/swagger-ui-express": "^4.1.6",
2324
"@types/uuid": "^8.3.1",
@@ -34,6 +35,7 @@
3435
"graphql-upload": "^12.0.0",
3536
"json2csv": "^5.0.6",
3637
"lodash": "^4.17.21",
38+
"luxon": "^3.7.2",
3739
"mongoose": "^6.13.6",
3840
"multer": "^2.0.1",
3941
"node-fetch": "^2.6.1",
@@ -43,7 +45,8 @@
4345
"sequelize": "^6.5.0",
4446
"sequelize-typescript": "^2.1.0",
4547
"swagger-ui-express": "^4.1.6",
46-
"ts-node": "^10.0.0",
48+
"ts-node": "10.9.2",
49+
"typescript": "4.7.2",
4750
"umzug": "^3.0.0-beta.16",
4851
"uuid": "^8.3.2",
4952
"winston": "^3.3.3",

backend/typescript/rest/authRoutes.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,16 @@ const cookieOptions: CookieOptions = {
3434
/* Returns access token and user info in response body and sets refreshToken as an httpOnly cookie */
3535
authRouter.post("/login", loginRequestValidator, async (req, res) => {
3636
try {
37-
const authDTO = req.body.idToken
38-
? // OAuth
39-
await authService.generateTokenOAuth(req.body.idToken)
40-
: await authService.generateToken(req.body.email, req.body.password);
37+
// OAuth is not in use
38+
// const authDTO = req.body.idToken
39+
// ? // OAuth
40+
// await authService.generateTokenOAuth(req.body.idToken)
41+
// : await authService.generateToken(req.body.email, req.body.password);
42+
43+
const authDTO = await authService.generateToken(
44+
req.body.email,
45+
req.body.password,
46+
);
4147

4248
const { refreshToken, ...rest } = authDTO;
4349

backend/typescript/rest/petRoutes.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,21 @@ petRouter.get("/", async (req, res) => {
124124
}
125125
});
126126

127+
/* Get PetList by userId */
128+
petRouter.get("/list/:userId", async (req, res) => {
129+
const { userId } = req.params;
130+
try {
131+
const petList = await petService.getPetList(parseInt(userId, 10));
132+
res.status(200).json(petList);
133+
} catch (e: unknown) {
134+
if (e instanceof NotFoundError) {
135+
res.status(404).send(getErrorMessage(e));
136+
} else {
137+
res.status(500).send(INTERNAL_SERVER_ERROR_MESSAGE);
138+
}
139+
}
140+
});
141+
127142
/* Get Pet by id */
128143
petRouter.get("/:id", async (req, res) => {
129144
const { id } = req.params;

backend/typescript/rest/userRoutes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ userRouter.post("/", createUserDtoValidator, async (req, res) => {
131131
lastName: req.body.lastName,
132132
email: req.body.email,
133133
role: req.body.role,
134+
colorLevel: req.body.colorLevel,
135+
animalTags: req.body.animalTags,
134136
canSeeAllLogs: req.body.canSeeAllLogs ?? null,
135137
canAssignUsersToTasks: req.body.canAssignUsersToTasks ?? null,
136138
phoneNumber: req.body.phoneNumber ?? null,

backend/typescript/services/implementations/authService.ts

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,39 +39,42 @@ class AuthService implements IAuthService {
3939
}
4040
}
4141

42+
// OAuth is not in use
4243
/* eslint-disable class-methods-use-this */
43-
async generateTokenOAuth(idToken: string): Promise<AuthDTO> {
44-
try {
45-
const googleUser = await FirebaseRestClient.signInWithGoogleOAuth(
46-
idToken,
47-
);
48-
// googleUser.idToken refers to the Firebase Auth access token for the user
49-
const token = {
50-
accessToken: googleUser.idToken,
51-
refreshToken: googleUser.refreshToken,
52-
};
53-
// If user already has a login with this email, just return the token
54-
try {
55-
// Note: an error message will be logged from UserService if this lookup fails.
56-
// You may want to silence the logger for this special OAuth user lookup case
57-
const user = await this.userService.getUserByEmail(googleUser.email);
58-
return { ...token, ...user };
59-
/* eslint-disable-next-line no-empty */
60-
} catch (error) {}
61-
62-
const user = await this.userService.createUser({
63-
firstName: googleUser.firstName,
64-
lastName: googleUser.lastName,
65-
email: googleUser.email,
66-
role: Role.STAFF,
67-
});
68-
69-
return { ...token, ...user };
70-
} catch (error) {
71-
Logger.error(`Failed to generate token for user with OAuth ID token`);
72-
throw error;
73-
}
74-
}
44+
// async generateTokenOAuth(idToken: string): Promise<AuthDTO> {
45+
// try {
46+
// const googleUser = await FirebaseRestClient.signInWithGoogleOAuth(
47+
// idToken,
48+
// );
49+
// // googleUser.idToken refers to the Firebase Auth access token for the user
50+
// const token = {
51+
// accessToken: googleUser.idToken,
52+
// refreshToken: googleUser.refreshToken,
53+
// };
54+
// // If user already has a login with this email, just return the token
55+
// try {
56+
// // Note: an error message will be logged from UserService if this lookup fails.
57+
// // You may want to silence the logger for this special OAuth user lookup case
58+
// const user = await this.userService.getUserByEmail(googleUser.email);
59+
// return { ...token, ...user };
60+
// /* eslint-disable-next-line no-empty */
61+
// } catch (error) {}
62+
//
63+
// const user = await this.userService.createUser({
64+
// firstName: googleUser.firstName,
65+
// lastName: googleUser.lastName,
66+
// email: googleUser.email,
67+
// role: Role.STAFF,
68+
// colorLevel: 1,
69+
// animalTags: [],
70+
// });
71+
//
72+
// return { ...token, ...user };
73+
// } catch (error) {
74+
// Logger.error(`Failed to generate token for user with OAuth ID token`);
75+
// throw error;
76+
// }
77+
// }
7578

7679
async revokeTokens(userId: string): Promise<void> {
7780
try {

0 commit comments

Comments
 (0)