Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIMS-1884 Swagger Rework #2621

Merged
merged 37 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
90baa13
Replace swagger autogen
dbarkowsky Aug 13, 2024
453b722
administrative areas add swagger
dbarkowsky Aug 13, 2024
57b9d97
remove admin areas autogen comments
dbarkowsky Aug 13, 2024
cb31657
agency swagger documentation
dbarkowsky Aug 13, 2024
f13f7b2
remove bearer token test
dbarkowsky Aug 13, 2024
96781d6
add buildings swagger
dbarkowsky Aug 14, 2024
af71d41
fix building swagger oddity
dbarkowsky Aug 14, 2024
1e18a7e
lookup regional districts
dbarkowsky Aug 14, 2024
967e407
lookup swagger added
dbarkowsky Aug 14, 2024
9323c6f
remove swagger commenting
dbarkowsky Aug 15, 2024
77bbcbe
ltsa swagger added
dbarkowsky Aug 15, 2024
2fd8951
update notifications router
dbarkowsky Aug 15, 2024
920c128
Merge branch 'main' into PIMS-1884-Swagger-Rework
dbarkowsky Aug 15, 2024
e136c9d
notifications swagger added
dbarkowsky Aug 15, 2024
8443a87
fix error code default
dbarkowsky Aug 15, 2024
30edace
swagger parcels / routes
dbarkowsky Aug 15, 2024
92f8422
update tests
dbarkowsky Aug 15, 2024
a6e60ac
fix parcel swagger indentation
dbarkowsky Aug 15, 2024
d569cf7
Add remaining parcel swagger, update building swagger
dbarkowsky Aug 16, 2024
7b826e4
most of projects swagger done
dbarkowsky Aug 16, 2024
6bf5a1a
complete projects swagger
dbarkowsky Aug 20, 2024
888ba1b
add properties / swagger
dbarkowsky Aug 20, 2024
6bc5a94
add rest of properties swagger
dbarkowsky Aug 21, 2024
f165bee
reports swagger
dbarkowsky Aug 22, 2024
ac9fbad
Remove exposed role routes
dbarkowsky Aug 23, 2024
5e551c2
added tools swagger
dbarkowsky Aug 23, 2024
a95927e
cut out unused user routes/controllers
dbarkowsky Aug 23, 2024
e01b1a8
add users swagger
dbarkowsky Aug 23, 2024
e29381b
standardize response descriptions
dbarkowsky Aug 23, 2024
fbfa908
Merge branch 'main' into PIMS-1884-Swagger-Rework
dbarkowsky Aug 23, 2024
fd380fc
test fix 1
dbarkowsky Aug 23, 2024
5ccb765
test fix 2
dbarkowsky Aug 23, 2024
351eb97
test fix 3
dbarkowsky Aug 23, 2024
9c789b6
test fix 4
dbarkowsky Aug 23, 2024
5a3fd12
add coerce to notifications schema
dbarkowsky Aug 26, 2024
044b5d7
Merge branch 'main' into PIMS-1884-Swagger-Rework
LawrenceLau2020 Aug 27, 2024
b955e59
Merge branch 'main' into PIMS-1884-Swagger-Rework
dbarkowsky Aug 28, 2024
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
3 changes: 0 additions & 3 deletions express-api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ COPY . .
# Install packages. Needed for build process.
RUN npm i

# Generate swagger-output
RUN npm run swagger

# Compile to JavaScript build
RUN npm run build

Expand Down
3 changes: 2 additions & 1 deletion express-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"test": "cross-env DOTENV_CONFIG_PATH=../.env jest",
"test:unit": "npm run test -- --testPathPattern=/tests/unit",
"test:integration": "npm run test -- --testPathPattern=/tests/integration",
"swagger": "node ./src/swagger/swagger.mjs",
"typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli",
"migration": "sh ./src/typeorm/utilities/helperScripts/migrationScript.sh"
},
Expand Down Expand Up @@ -58,6 +57,7 @@
"@types/node-cron": "3.0.11",
"@types/nunjucks": "3.2.6",
"@types/supertest": "6.0.2",
"@types/swagger-jsdoc": "6.0.4",
"@types/swagger-ui-express": "4.1.6",
"@typescript-eslint/eslint-plugin": "8.1.0",
"@typescript-eslint/parser": "8.1.0",
Expand All @@ -70,6 +70,7 @@
"prettier": "3.3.0",
"supertest": "7.0.0",
"swagger-autogen": "2.23.7",
"swagger-jsdoc": "6.2.8",
"ts-jest": "29.2.0",
"tsc-alias": "1.8.8",
"typescript": "5.5.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,11 @@ import userServices from '@/services/users/usersServices';
* @returns {Response} A 200 status with a list of administrative areas.
*/
export const getAdministrativeAreas = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Administrative Areas - Admin']
* #swagger.description = 'Returns a paged list of administrative areas from the datasource.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const ssoUser = req.user;
const filter = AdministrativeAreaFilterSchema.safeParse(req.query);
if (filter.success) {
const adminAreas = await administrativeAreasServices.getAdministrativeAreas(filter.data);
// TODO: Do we still need this condition? Few fields are trimmed since moving to view.
if (!ssoUser.hasRoles([Roles.ADMIN])) {
const trimmed = AdministrativeAreaPublicResponseSchema.array().parse(adminAreas.data);
return res.status(200).send({
Expand All @@ -35,7 +29,7 @@ export const getAdministrativeAreas = async (req: Request, res: Response) => {
}
return res.status(200).send(adminAreas);
} else {
return res.status(400).send('Could not parse filter.');
return res.status(400).send(filter.error);
}
};

Expand All @@ -46,13 +40,6 @@ export const getAdministrativeAreas = async (req: Request, res: Response) => {
* @returns {Response} A 201 status and response with the added administrative area.
*/
export const addAdministrativeArea = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Administrative Areas - Admin']
* #swagger.description = 'Add a new administrative area to the datasource.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const user = await userServices.getUser((req.user as SSOUser).preferred_username);
const addBody = { ...req.body, CreatedById: user.Id };
const response = await administrativeAreasServices.addAdministrativeArea(addBody);
Expand All @@ -66,14 +53,6 @@ export const addAdministrativeArea = async (req: Request, res: Response) => {
* @returns {Response} A 200 status and the administrative area data.
*/
export const getAdministrativeAreaById = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Administrative Areas - Admin']
* #swagger.description = 'Returns an administrative area that matches the supplied ID.'
* #swagger.security = [{
"bearerAuth": []
}]
*/

const id = Number(req.params.id);
const adminArea = await administrativeAreasServices.getAdministrativeAreaById(id);
return res.status(200).send(adminArea);
Expand All @@ -86,14 +65,6 @@ export const getAdministrativeAreaById = async (req: Request, res: Response) =>
* @returns {Response} A 200 status and the administrative area data.
*/
export const updateAdministrativeAreaById = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Administrative Areas - Admin']
* #swagger.description = 'Updates an administrative area that matches the supplied ID.'
* #swagger.security = [{
"bearerAuth": []
}]
*/

const id = req.params.id;
if (id != req.body.Id) {
return res.status(400).send('Id mismatched or invalid.');
Expand Down
37 changes: 0 additions & 37 deletions express-api/src/controllers/agencies/agenciesController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ import { Agency } from '@/typeorm/Entities/Agency';
* @returns {Response} A 200 status with a list of agencies.
*/
export const getAgencies = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Agencies - Admin']
* #swagger.description = 'Gets a paged list of agencies.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const ssoUser = req.user;
const filter = AgencyFilterSchema.safeParse(req.query);
if (filter.success) {
Expand All @@ -45,14 +38,6 @@ export const getAgencies = async (req: Request, res: Response) => {
* @returns {Response} A 201 status and the data of the agency added.
*/
export const addAgency = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Agencies - Admin']
* #swagger.description = 'Adds a new agency to the datasource.'
* #swagger.security = [{
"bearerAuth": []
}]
*/

const user = await userServices.getUser((req.user as SSOUser).preferred_username);
const agency = await agencyService.addAgency({ ...req.body, CreatedById: user.Id });

Expand All @@ -66,14 +51,6 @@ export const addAgency = async (req: Request, res: Response) => {
* @returns {Response} A 200 status and the agency data.
*/
export const getAgencyById = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Agencies - Admin']
* #swagger.description = 'Returns an agency that matches the supplied ID.'
* #swagger.security = [{
"bearerAuth": []
}]
*/

const agency = await agencyService.getAgencyById(parseInt(req.params.id));
if (!agency) {
return res.status(404).send('Agency does not exist.');
Expand All @@ -88,13 +65,6 @@ export const getAgencyById = async (req: Request, res: Response) => {
* @returns {Response} A 200 status and the agency data.
*/
export const updateAgencyById = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Agencies - Admin']
* #swagger.description = 'Updates an agency that matches the supplied ID.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const idParse = z.string().safeParse(req.params.id);
if (!idParse.success) {
return res.status(400).send(idParse);
Expand All @@ -119,13 +89,6 @@ export const updateAgencyById = async (req: Request, res: Response) => {
* @returns {Response} A 204 status indicating successful deletion.
*/
export const deleteAgencyById = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Agencies - Admin']
* #swagger.description = 'Deletes an agency that matches the supplied ID.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const idParse = z.string().safeParse(req.params.id);
if (!idParse.success) {
return res.status(400).send(idParse);
Expand Down
28 changes: 0 additions & 28 deletions express-api/src/controllers/buildings/buildingsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ export const getBuildings = async (req: Request, res: Response) => {
* @returns {Response} A 200 status with a response body containing building data.
*/
export const getBuilding = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['building']
* #swagger.description = 'Get the building from the data source if the user is permitted.'
* #swagger.security = [{
* "bearerAuth": []
* }]
*/
const buildingId = Number(req.params.buildingId);
if (isNaN(buildingId)) {
return res.status(400).send('Building Id is invalid.');
Expand All @@ -73,13 +66,6 @@ export const getBuilding = async (req: Request, res: Response) => {
* @returns {Response} A 200 status with a response body containing building data.
*/
export const updateBuilding = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['building']
* #swagger.description = 'Updates the building from the data source if the user is permitted.'
* #swagger.security = [{
* "bearerAuth": []
* }]
*/
const buildingId = Number(req.params.buildingId);
if (isNaN(buildingId) || buildingId !== req.body.Id) {
return res.status(400).send('Building ID was invalid or mismatched with body.');
Expand All @@ -97,13 +83,6 @@ export const updateBuilding = async (req: Request, res: Response) => {
* @returns {Response} A 200 status with a response body containing building data.
*/
export const deleteBuilding = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['building']
* #swagger.description = 'Deletes the building from the data source if the user is permitted.'
* #swagger.security = [{
* "bearerAuth": []
* }]
*/
const buildingId = Number(req.params.buildingId);
if (isNaN(buildingId)) {
return res.status(400).send('Building ID was invalid.');
Expand All @@ -123,13 +102,6 @@ export const deleteBuilding = async (req: Request, res: Response) => {
* Note: the original implementation returns 200, but as a resource is created 201 is better.
*/
export const addBuilding = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['building']
* #swagger.description = 'Creates a new building in the datasource.'
* #swagger.security = [{
* "bearerAuth": []
* }]
*/
const user = await userServices.getUser((req.user as SSOUser).preferred_username);
const createBody: Building = { ...req.body, CreatedById: user.Id };
createBody.Evaluations = createBody.Evaluations?.map((evaluation) => ({
Expand Down
4 changes: 0 additions & 4 deletions express-api/src/controllers/healthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,5 @@ import { Request, Response } from 'express';
* @returns {Response} A 200 status indicating API is healthy and running
*/
export const healthCheck = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Health']
* #swagger.description = 'Returns a 200 (OK) status if API is reached.'
*/
return res.status(200).send('/health endpoint reached. API running.');
};
21 changes: 0 additions & 21 deletions express-api/src/controllers/lookup/lookupController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ import getConfig from '@/constants/config';
* @returns {Response} A 200 status and a list of property classifications.
*/
export const lookupPropertyClassifications = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Lookup']
* #swagger.description = 'Get all property classification entries.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const classifications = await AppDataSource.getRepository(PropertyClassification).find();
const filtered = classifications.filter((c) => !c.IsDisabled);
const parsed = ClassificationPublicResponseSchema.array().safeParse(filtered);
Expand All @@ -52,13 +45,6 @@ export const lookupPropertyClassifications = async (req: Request, res: Response)
};

export const lookupBuildingPredominateUse = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Lookup']
* #swagger.description = 'Get all predomanite uses entries.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const uses = await AppDataSource.getRepository(BuildingPredominateUse).find();
const filtered = uses.filter((u) => !u.IsDisabled);
const parsed = PredominateUsePublicResponseSchema.array().safeParse(filtered);
Expand All @@ -70,13 +56,6 @@ export const lookupBuildingPredominateUse = async (req: Request, res: Response)
};

export const lookupBuildingConstructionType = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['Lookup']
* #swagger.description = 'Get all building construction type entries.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const uses = await AppDataSource.getRepository(BuildingConstructionType).find();
const filtered = uses.filter((u) => !u.IsDisabled);
const parsed = BuildingConstructionPublicResponseSchema.array().safeParse(filtered);
Expand Down
7 changes: 0 additions & 7 deletions express-api/src/controllers/ltsa/ltsaController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ import ltsaService from '@/services/ltsa/ltsaServices';
* @returns {Response} A 200 status with LTSA order information.
*/
export const getLTSA = async (req: Request, res: Response) => {
/**
* #swagger.tags = ['LTSA']
* #swagger.description = 'Returns property information from LTSA.'
* #swagger.security = [{
"bearerAuth": []
}]
*/
const pid = req.query.pid as string;
const getLandTitleInfo = await ltsaService.processLTSARequest(pid);
return res.status(200).send(getLandTitleInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Request, Response } from 'express';
import { DisposalNotificationFilterSchema } from './notificationsSchema';
import { isAdmin, isAuditor } from '@/utilities/authorizationChecks';
import projectServices from '@/services/projects/projectsServices';
import { Roles } from '@/constants/roles';
import logger from '@/utilities/winstonLogger';

/**
Expand All @@ -31,7 +32,9 @@ export const getNotificationsByProjectId = async (req: Request, res: Response) =

const project = await projectServices.getProjectById(filterResult.projectId);
if (!usersAgencies.includes(project.AgencyId)) {
return res.status(403).send({ message: 'User is not authorized to access this endpoint.' });
return res
.status(403)
.send({ message: 'User cannot access project outside their agencies.' });
}
}

Expand All @@ -53,15 +56,14 @@ export const getNotificationsByProjectId = async (req: Request, res: Response) =
};

export const resendNotificationById = async (req: Request, res: Response) => {
const kcUser = req.user;
if (!kcUser.hasRoles([Roles.ADMIN]))
return res.status(403).send('User lacks permissions to resend notification.');
const id = Number(req.params.id);
const notification = await notificationServices.getNotificationById(id);
if (!notification) {
return res.status(404).send('Notification not found.');
}
const kcUser = req.user;
if (!isAdmin(kcUser)) {
return res.status(403).send({ message: 'User is not authorized to access this endpoint.' });
}
const resultantNotification = await notificationServices.sendNotification(notification, kcUser);
const user = await userServices.getUser(kcUser.preferred_username);
const updatedNotification = await notificationServices.updateNotificationStatus(
Expand All @@ -72,16 +74,19 @@ export const resendNotificationById = async (req: Request, res: Response) => {
};

export const cancelNotificationById = async (req: Request, res: Response) => {
const kcUser = req.user;
if (!kcUser.hasRoles([Roles.ADMIN]))
return res.status(403).send('User lacks permissions to cancel notification.');
const id = Number(req.params.id);
const notification = await notificationServices.getNotificationById(id);
if (!notification) {
return res.status(404).send('Notification not found.');
}
const kcUser = req.user;
if (!isAdmin(kcUser)) {
return res.status(403).send({ message: 'User is not authorized to access this endpoint.' });
}
const resultantNotification = await notificationServices.cancelNotificationById(notification.Id);
const user = await userServices.getUser(kcUser.preferred_username);
const resultantNotification = await notificationServices.cancelNotificationById(
notification.Id,
user,
);
if (resultantNotification.Status !== NotificationStatus.Cancelled) {
return res.status(400).send(resultantNotification);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export const NotificationResponseSchema = z.object({
});

export const DisposalNotificationFilterSchema = z.object({
page: z.number().optional(),
quantity: z.number().optional(),
page: z.coerce.number().optional(),
quantity: z.coerce.number().optional(),
sort: z.array(z.string()).optional(),
projectNumber: z.string().optional(),
projectId: z.coerce.number(),
Expand Down
Loading
Loading