Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 1 addition & 18 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
## Notion ticket link
<!-- Please replace with your ticket's URL -->
[Ticket Name](https://www.notion.so/uwblueprintexecs/aecc07aa87f4429dbd4b5c4287531731?v=1f810f3fb1dc80c4abe0000c9dba2893&source=copy_link)


<!-- Give a quick summary of the implementation details, provide design justifications if necessary -->
## Implementation description
*

[Ticket Name](https://www.notion.so/uwblueprintexecs/Task-Board-db95cd7b93f245f78ee85e3a8a6a316d)

<!-- What should the reviewer do to verify your changes? Describe expected results and include screenshots when appropriate -->
## Steps to test
1.


<!-- Draw attention to the substantial parts of your PR or anything you'd like a second opinion on -->
## What should reviewers focus on?
*


## Checklist
- [ ] My PR name is descriptive and in imperative tense
- [ ] My commit messages are descriptive and in imperative tense. My commits are atomic and trivial commits are squashed or fixup'd into non-trivial commits
- [ ] I have run the appropriate linter(s)
- [ ] I have requested a review from the PL, as well as other devs who have background knowledge on this PR or who will be building on top of this PR
21 changes: 9 additions & 12 deletions .github/workflows/firebase-hosting-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,26 @@

name: Deploy frontend to Firebase Hosting

# Trigger only manually, never on push
on:
workflow_dispatch:

# on:
# push:
# branches:
# - main
# paths:
# - "frontend/**"
push:
branches:
- main
paths:
- "frontend/**"

defaults:
run:
working-directory: frontend

jobs:
build_and_deploy:
if: ${{ false }} # job will never run
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: echo REACT_APP_BACKEND_URL=${{ secrets.DEV_BACKEND_URL }} > .env
- run: echo REACT_APP_OAUTH_CLIENT_ID=${{ secrets.DEV_OAUTH_CLIENT_ID }} >> .env
- run: echo "REACT_APP_BACKEND_URL=${{ secrets.DEV_BACKEND_URL }}" > .env
auth {
- run: echo "REACT_APP_OAUTH_CLIENT_ID=${{ secrets.DEV_OAUTH_CLIENT_ID }}" >> .env
} auth
- run: rm -rf node_modules && yarn install --frozen-lockfile && yarn build
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
Expand Down
19 changes: 8 additions & 11 deletions .github/workflows/firebase-hosting-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,25 @@

name: Deploy frontend to Firebase Hosting preview

# Trigger only manually, never on push
on:
workflow_dispatch:

# on:
# pull_request:
# paths:
# - "frontend/**"
pull_request:
paths:
- "frontend/**"

defaults:
run:
working-directory: frontend

jobs:
build_and_preview:
# job will never run because of false condition
if: "${{ false && github.event.pull_request.head.repo.full_name == github.repository && github.base_ref == 'main' }}"
if: "${{ github.event.pull_request.head.repo.full_name == github.repository && github.base_ref == 'main' }}"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: echo REACT_APP_BACKEND_URL=${{ secrets.PREVIEW_BACKEND_URL }} > .env
- run: echo REACT_APP_OAUTH_CLIENT_ID=${{ secrets.DEV_OAUTH_CLIENT_ID }} >> .env
- run: echo "REACT_APP_BACKEND_URL=${{ secrets.PREVIEW_BACKEND_URL }}" > .env
auth {
- run: echo "REACT_APP_OAUTH_CLIENT_ID=${{ secrets.DEV_OAUTH_CLIENT_ID }}" >> .env
} auth
- run: rm -rf node_modules && yarn install --frozen-lockfile && yarn build
- uses: FirebaseExtended/action-hosting-deploy@v0
with:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ lint:
docker exec -it humane_society_backend /bin/bash -c "yarn lint"
docker exec -it humane_society_frontend /bin/bash -c "yarn lint"

fix:
format:
docker exec -it humane_society_backend /bin/bash -c "yarn fix"
docker exec -it humane_society_frontend /bin/bash -c "yarn fix"

Expand Down
59 changes: 51 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# Oakville and Milton Humane Society 🐾
The Oakville and Milton Humane Society is a non-profit organization dedicated to protecting and improving the life of animals within the community and connecting them to the communities that care about them in Oakville and Milton. We will be developing a web application that allows volunteers to sign up for pet-sitting tasks, enabling volunteers to efficiently care for multiple animals.

## Fall 2025 Team
## Summer 2025 Team
- **Tony Qiu** (Project Lead)
- **Sehshasayi Thuray** (Project Lead)
- **Matthew So** (Project Lead)
- **Aashi Chaubey** (Developer)
- **Artyom Gabtraupov** (Developer)
- **Cindy Li** (Developer)
- **Sophia Zhu** (Product Manager, Developer)
- **Aiden Suh** (Developer)
- **David Lu** (Developer)
- **Gateek Chandak** (Developer)
- **Haresh Goyal** (Developer)
- **Harry He** (Developer)
- **Nathanael Ann** (Developer)
- **Raj Shah** (Developer)
- **Mehul Sharma** (Developer)
- **Smeet Shah** (Developer)
- **Surya Jammalamadaka** (Developer)
- **Teresa Yu** (Developer)

## Stack Choices
**Backend Language:** TypeScript (Express.js on Node.js) <br>
Expand Down Expand Up @@ -70,7 +72,48 @@ docker exec -it humane_society_backend /bin/bash -c "node migrate up"
```

### Secrets
- Ask Project Leads for environment secrets

- Create A [HashiCorp Cloud Platform Account](https://portal.cloud.hashicorp.com/sign-in?ajs_aid=9085f07d-f411-42b4-855b-72795f4fdbcc&product_intent=vault)
- Make sure you have been added to the [Humane Society HashiCorp Vault](https://github.com/uwblueprint/).
- Install [HashiCorp Vault](https://developer.hashicorp.com/hcp/tutorials/get-started-hcp-vault-secrets/hcp-vault-secrets-install-cli#install-hcp-vault-secrets-cli) in order to pull secrets
- In the folder where you cloned the Humane Society repository, log into Vault

```bash
hcp auth login
```

- Configure the Vault Command Line Interface

```bash
hcp profile init
```

- Select the `humane-society` Organization/Project/Application.

```bash
✔ Organization with name "humane-society" and ID "b357b214-2c48-4e87-b7b6-0e51f3902ac0" selected
✔ Project with name "humane-society" and ID "e841cbab-9210-4fd8-8341-a07946852120" selected
Use the arrow keys to navigate: ↓ ↑ → ←
? Select an application name:
▸ humane-society
▸ humane-society-frontend
```

### Copying secrets from the vault to local

- Copy secrets to a `.env` and `/frontend/.env` file

```bash
./setup_secrets.sh
```

### Sending all local secrets to the vault (warning: this overwrites all secrets)

- Push secrets from `.env` and `/frontend/.env` file to HashiCorp Vault

```bash
./push_secrets.sh
```

## Useful Commands

Expand Down
2 changes: 1 addition & 1 deletion backend/typescript/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ module.exports = {
rules: {
"prettier/prettier": ["error", { endOfLine: "auto" }],
},
ignorePatterns: ["build/*", ".eslintrc.js"],
ignorePatterns: ["build/*"],
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
validateArray,
validateFileType,
validatePrimitive,
} from "../../../typescript/middlewares/validators/util";
import { getErrorMessage } from "../../../typescript/utilities/errorUtils";
} from "./util";
import { getErrorMessage } from "../../utilities/errorUtils";

/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable-next-line import/prefer-default-export */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
getApiValidationError,
validateArray,
validatePrimitive,
} from "../../../typescript/middlewares/validators/util";
} from "./util";

/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable-next-line import/prefer-default-export */
Expand Down
21 changes: 21 additions & 0 deletions backend/typescript/middlewares/validators/teamMemberValidators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Request, Response, NextFunction } from "express";
import { getApiValidationError, validatePrimitive } from "./util";

/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/* eslint-disable-next-line import/prefer-default-export */
export const createTeamMemberDtoValidator = async (
req: Request,
res: Response,
next: NextFunction,
) => {
if (!validatePrimitive(req.body.firstName, "string")) {
return res.status(400).send(getApiValidationError("firstName", "string"));
}
if (!validatePrimitive(req.body.lastName, "string")) {
return res.status(400).send(getApiValidationError("lastName", "string"));
}
if (!validatePrimitive(req.body.teamRole, "string")) {
return res.status(400).send(getApiValidationError("teamRole", "string"));
}
return next();
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DataType } from "sequelize-typescript";

import { Migration } from "../../typescript/umzug";
import { Migration } from "../umzug";

const TABLE_NAME = "entities";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { DataType } from "sequelize-typescript";
import { Migration } from "../umzug";
import { teamRoleValues } from "../types";

const TABLE_NAME = "team_members";

export const up: Migration = async ({ context: sequelize }) => {
await sequelize.getQueryInterface().createTable(TABLE_NAME, {
id: {
type: DataType.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true,
},
first_name: {
type: DataType.STRING,
allowNull: false,
},
last_name: {
type: DataType.STRING,
allowNull: false,
},
team_role: {
type: DataType.ENUM,
values: teamRoleValues as unknown as string[],
allowNull: false,
},
});
};

export const down: Migration = async ({ context: sequelize }) => {
await sequelize.getQueryInterface().dropTable(TABLE_NAME);
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Column, Model, Table, DataType } from "sequelize-typescript";

Check warning on line 1 in backend/typescript/models/entity.model.ts

View workflow job for this annotation

GitHub Actions / run-lint

'DataType' is defined but never used

Check warning on line 1 in backend/typescript/models/entity.model.ts

View workflow job for this annotation

GitHub Actions / run-lint

'Table' is defined but never used

Check warning on line 1 in backend/typescript/models/entity.model.ts

View workflow job for this annotation

GitHub Actions / run-lint

'Column' is defined but never used

import { Letters } from "../../typescript/types";
import { Letters } from "../types";

@Table({ tableName: "entities" })
export default class Entity extends Model {

Check warning on line 6 in backend/typescript/models/entity.model.ts

View workflow job for this annotation

GitHub Actions / run-lint

'Entity' is defined but never used
@Column
string_field!: string;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Column, Model, Table, DataType } from "sequelize-typescript";

import { Letters } from "../../typescript/types";
import { Letters } from "../types";

@Table({ tableName: "simple_entities" })
export default class SimpleEntity extends Model {
Expand Down
21 changes: 21 additions & 0 deletions backend/typescript/models/teamMember.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
Column,
DataType,
Model,
Table,
AllowNull,
} from "sequelize-typescript";
import { TeamRole, teamRoleValues } from "../types";

@Table({ timestamps: false, tableName: "team_members" })
export default class TeamMember extends Model {
@Column({ type: DataType.STRING, allowNull: false })
first_name!: string;

@Column({ type: DataType.STRING, allowNull: false })
last_name!: string;

@AllowNull(false)
@Column({ type: DataType.ENUM, values: teamRoleValues, allowNull: false })
team_role!: TeamRole;
}
6 changes: 2 additions & 4 deletions backend/typescript/models/user.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,10 @@ export default class User extends Model {
color_level!: number;

@Column({
type: DataType.ARRAY(
DataType.ENUM("Bird", "Bunny", "Cat", "Dog", "Small Animal"),
),
type: DataType.ENUM("Bird", "Bunny", "Cat", "Dog", "Small Animal"),
allowNull: false,
})
animal_tags!: AnimalTag[];
animal_tags!: [AnimalTag];

@Column({ type: DataType.BOOLEAN })
can_see_all_logs?: boolean | null;
Expand Down
8 changes: 4 additions & 4 deletions backend/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
"@types/pg": "^7.14.10",
"@types/umzug": "^2.3.0",
"@types/validator": "^13.1.3",
"@typescript-eslint/eslint-plugin": "5.44.0",
"@typescript-eslint/parser": "5.44.0",
"eslint": "8.44.0",
"@typescript-eslint/eslint-plugin": "^4.4.1",
"@typescript-eslint/parser": "^4.15.2",
"eslint": "^7.20.0",
"eslint-config-airbnb-typescript": "^12.3.1",
"eslint-config-prettier": "^8.0.0",
"eslint-plugin-import": "^2.22.1",
Expand All @@ -76,7 +76,7 @@
"prettier": "^2.2.1",
"sequelize-cli": "^6.6.3",
"ts-jest": "^29.1.0",
"typescript": "^5.9.2"
"typescript": "^5.1.0"
},
"resolutions": {
"@types/express": "^4.17.21",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Router } from "express";
import fs from "fs";
import multer from "multer";
import { isAuthorizedByRole } from "../../typescript/middlewares/auth";
import { isAuthorizedByRole } from "../middlewares/auth";
import { entityRequestDtoValidator } from "../middlewares/validators/entityValidators";
import EntityService from "../services/implementations/entityService";
import FileStorageService from "../../typescript/services/implementations/fileStorageService";
import IFileStorageService from "../../typescript/services/interfaces/fileStorageService";
import FileStorageService from "../services/implementations/fileStorageService";
import IFileStorageService from "../services/interfaces/fileStorageService";
import {
EntityResponseDTO,
IEntityService,
} from "../services/interfaces/IEntityService";
import { getErrorMessage } from "../../typescript/utilities/errorUtils";
import { sendResponseByMimeType } from "../../typescript/utilities/responseUtil";
import { Role } from "../../typescript/types";
import { getErrorMessage } from "../utilities/errorUtils";
import { sendResponseByMimeType } from "../utilities/responseUtil";
import { Role } from "../types";

const upload = multer({ dest: "uploads/" });

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Router } from "express";
import { isAuthorizedByRole } from "../../typescript/middlewares/auth";
import { isAuthorizedByRole } from "../middlewares/auth";
import { simpleEntityRequestDtoValidator } from "../middlewares/validators/simpleEntityValidators";
import SimpleEntityService from "../services/implementations/simpleEntityService";
import {
SimpleEntityResponseDTO,
ISimpleEntityService,
} from "../services/interfaces/simpleEntityService";
import { getErrorMessage } from "../../typescript/utilities/errorUtils";
import { sendResponseByMimeType } from "../../typescript/utilities/responseUtil";
import { Role } from "../../typescript/types";
import { getErrorMessage } from "../utilities/errorUtils";
import { sendResponseByMimeType } from "../utilities/responseUtil";
import { Role } from "../types";

const simpleEntityRouter: Router = Router();
simpleEntityRouter.use(isAuthorizedByRole(new Set(Object.values(Role))));
Expand Down
Loading
Loading