Skip to content

Commit

Permalink
Merge pull request #23 from icefoganalytics/main
Browse files Browse the repository at this point in the history
Update from IceFog
  • Loading branch information
datajohnson authored May 3, 2024
2 parents 461db47 + 87c3e0b commit a335faa
Show file tree
Hide file tree
Showing 29 changed files with 1,229 additions and 445 deletions.
41 changes: 41 additions & 0 deletions api/src/controllers/centres-controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { isNil } from "lodash"

import BaseController from "./base-controller"

import { Centre } from "@/models"
import { CentreServices } from "@/services"

export class CentresController extends BaseController {
async create() {
try {
const centre = await CentreServices.create(this.request.body, {
currentUser: this.currentUser,
})
return this.response.status(201).json({ centre })
} catch (error) {
return this.response.status(422).json({ message: `Centre creation failed: ${error}` })
}
}

async update() {
const centre = await this.loadCentre()
if (isNil(centre)) {
return this.response.status(404).json({ message: "Centre not found." })
}

try {
const updatedCentre = await CentreServices.update(centre, this.request.body, {
currentUser: this.currentUser,
})
return this.response.json({ centre: updatedCentre })
} catch (error) {
return this.response.status(422).json({ message: `Centre update failed: ${error}` })
}
}

private loadCentre(): Promise<Centre | null> {
return Centre.findByPk(this.params.centreId)
}
}

export default CentresController
1 change: 1 addition & 0 deletions api/src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { CentresController } from "./centres-controller"
export { EmployeeBenefitsController } from "./employee-benefits-controller"
export { EmployeeWageTiersController } from "./employee-wage-tiers-controller"
export { FiscalPeriodsController } from "./fiscal-periods-controller"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { DataTypes } from "sequelize"

import type { Migration } from "@/db/umzug"

export const up: Migration = async ({ context: queryInterface }) => {
await queryInterface.addColumn("centres", "license_holder_name", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "contact_name", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "physical_address", {
type: DataTypes.STRING(250),
allowNull: true,
})
await queryInterface.addColumn("centres", "mailing_address", {
type: DataTypes.STRING(250),
allowNull: true,
})
await queryInterface.addColumn("centres", "email", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "alt_email", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "phone_number", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "alt_phone_number", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "fax_number", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "vendor_identifier", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "is_first_nation_program", {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
})
await queryInterface.addColumn("centres", "inspector_name", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "neighborhood", {
type: DataTypes.STRING(100),
allowNull: true,
})

await queryInterface.addColumn("centres", "region", {
type: DataTypes.STRING(100),
allowNull: true,
})
}

export const down: Migration = async ({ context: queryInterface }) => {
await queryInterface.removeColumn("centres", "licenseHolderName")
await queryInterface.removeColumn("centres", "contactName")
await queryInterface.removeColumn("centres", "physicalAddress")
await queryInterface.removeColumn("centres", "mailingAddress")
await queryInterface.removeColumn("centres", "email")
await queryInterface.removeColumn("centres", "altEmail")
await queryInterface.removeColumn("centres", "phoneNumber")
await queryInterface.removeColumn("centres", "altPhoneNumber")
await queryInterface.removeColumn("centres", "faxNumber")
await queryInterface.removeColumn("centres", "vendorId")
await queryInterface.removeColumn("centres", "isFirstNationProgram")
await queryInterface.removeColumn("centres", "inspectorName")
await queryInterface.removeColumn("centres", "neighborhood")
await queryInterface.removeColumn("centres", "region")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DataTypes } from "sequelize"

import type { Migration } from "@/db/umzug"

export const up: Migration = async ({ context: queryInterface }) => {
await queryInterface.sequelize.query(/* sql */ `
UPDATE centres
SET region = 'whitehorse'
WHERE region IS NULL
`)

await queryInterface.changeColumn("centres", "region", {
type: DataTypes.STRING(100),
allowNull: false,
})
}

export const down: Migration = async ({ context: queryInterface }) => {
await queryInterface.changeColumn("centres", "region", {
type: DataTypes.STRING(100),
allowNull: true,
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const up: SeedMigration = async ({ context: { Centre } }) => {
name: "Grow with Joy 2nd",
license: "123",
community: "Whitehorse",
region: Centre.Regions.WHITEHORSE,
isFirstNationProgram: false,
status: "Up to date",
hotMeal: true,
licensedFor: 19,
Expand All @@ -23,6 +25,8 @@ export const up: SeedMigration = async ({ context: { Centre } }) => {
name: "Happy Hearts Preschool",
license: "456",
community: "Whitehorse",
region: Centre.Regions.WHITEHORSE,
isFirstNationProgram: false,
status: "Up to date",
hotMeal: true,
licensedFor: 25,
Expand Down
4 changes: 4 additions & 0 deletions api/src/db/templates/sample-seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export const up: SeedMigration = async ({ context: { Centre } }) => {
name: "Grow with Joy 2nd",
license: "123",
community: "Whitehorse",
region: Centre.Regions.WHITEHORSE,
isFirstNationProgram: false,
status: "Up to date",
hotMeal: true,
licensedFor: 19,
Expand All @@ -23,6 +25,8 @@ export const up: SeedMigration = async ({ context: { Centre } }) => {
name: "Grow with Joy 2nd",
license: "456",
community: "Whitehorse",
region: Centre.Regions.WHITEHORSE,
isFirstNationProgram: false,
status: "Up to date",
hotMeal: true,
licensedFor: 25,
Expand Down
110 changes: 98 additions & 12 deletions api/src/models/centre.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,53 @@ import {
HasManySetAssociationsMixin,
InferAttributes,
InferCreationAttributes,
Model,
NonAttribute,
} from "sequelize"

import sequelize from "@/db/db-client"
import CentreFundingPeriod from "@/models/centre-funding-period"
import FundingSubmissionLineJson from "@/models/funding-submission-line-json"
import BaseModel from "@/models/base-model"

export enum CentreStatus {
// Keep in sync with web/src/api/centres-api.ts
export enum CentreRegions {
WHITEHORSE = "whitehorse",
COMMUNITIES = "communities",
}

// TODO: normalize status to snake_case
export enum CentreStatuses {
ACTIVE = "Active",
INACTIVE = "Inactive",
UP_TO_DATE = "Up to date",
}

export class Centre extends Model<InferAttributes<Centre>, InferCreationAttributes<Centre>> {
export class Centre extends BaseModel<InferAttributes<Centre>, InferCreationAttributes<Centre>> {
static readonly Regions = CentreRegions
static readonly Statuses = CentreStatuses

declare id: CreationOptional<number>
declare name: string
declare license: string | null
declare community: string
declare region: string
declare status: string
declare hotMeal: boolean | null
declare licensedFor: number | null // licensed for xx number of children
declare lastSubmission: Date | null
declare isFirstNationProgram: boolean
declare license: CreationOptional<string | null>
declare hotMeal: CreationOptional<boolean | null>
declare licensedFor: CreationOptional<number | null> // licensed for xx number of children
declare licenseHolderName: CreationOptional<string | null>
declare contactName: CreationOptional<string | null>
declare physicalAddress: CreationOptional<string | null>
declare mailingAddress: CreationOptional<string | null>
declare email: CreationOptional<string | null>
declare altEmail: CreationOptional<string | null>
declare phoneNumber: CreationOptional<string | null>
declare altPhoneNumber: CreationOptional<string | null>
declare faxNumber: CreationOptional<string | null>
declare vendorIdentifier: CreationOptional<string | null>
declare inspectorName: CreationOptional<string | null>
declare neighborhood: CreationOptional<string | null>
declare lastSubmission: CreationOptional<Date | null>
declare createdAt: CreationOptional<Date>
declare updatedAt: CreationOptional<Date>

Expand Down Expand Up @@ -138,21 +164,33 @@ Centre.init(
type: DataTypes.STRING(200),
allowNull: false,
},
license: {
type: DataTypes.STRING(255),
allowNull: true,
},
community: {
type: DataTypes.STRING(255),
allowNull: false,
},
isFirstNationProgram: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
region: {
type: DataTypes.STRING(100),
allowNull: false,
validate: {
isIn: [Object.values(CentreRegions)],
},
},
status: {
type: DataTypes.STRING(255),
allowNull: false,
validate: {
isIn: [Object.values(CentreStatus)],
isIn: [Object.values(CentreStatuses)],
},
},
license: {
type: DataTypes.STRING(255),
allowNull: true,
},
hotMeal: {
type: DataTypes.BOOLEAN,
allowNull: true,
Expand All @@ -161,6 +199,54 @@ Centre.init(
type: DataTypes.INTEGER,
allowNull: true,
},
licenseHolderName: {
type: DataTypes.STRING(100),
allowNull: true,
},
contactName: {
type: DataTypes.STRING(100),
allowNull: true,
},
physicalAddress: {
type: DataTypes.STRING(250),
allowNull: true,
},
mailingAddress: {
type: DataTypes.STRING(250),
allowNull: true,
},
email: {
type: DataTypes.STRING(100),
allowNull: true,
},
altEmail: {
type: DataTypes.STRING(100),
allowNull: true,
},
phoneNumber: {
type: DataTypes.STRING(20),
allowNull: true,
},
altPhoneNumber: {
type: DataTypes.STRING(20),
allowNull: true,
},
faxNumber: {
type: DataTypes.STRING(20),
allowNull: true,
},
vendorIdentifier: {
type: DataTypes.STRING(20),
allowNull: true,
},
inspectorName: {
type: DataTypes.STRING(100),
allowNull: true,
},
neighborhood: {
type: DataTypes.STRING(100),
allowNull: true,
},
lastSubmission: {
type: DataTypes.DATEONLY,
allowNull: true,
Expand Down
4 changes: 4 additions & 0 deletions api/src/routes/api-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Router, type Request, type Response } from "express"

import { checkJwt, autheticateAndLoadUser } from "@/middleware/authz.middleware"
import {
CentresController,
EmployeeBenefitsController,
EmployeeWageTiersController,
FiscalPeriodsController,
Expand All @@ -15,6 +16,9 @@ export const apiRouter = Router()
// TODO: move all routing logic to this file, and move all route actions into controllers
apiRouter.use("/api", checkJwt, autheticateAndLoadUser)

apiRouter.route("/api/centres").post(CentresController.create)
apiRouter.route("/api/centres/:centreId").patch(CentresController.update)

apiRouter.route("/api/payments").get(PaymentsController.index).post(PaymentsController.create)
apiRouter
.route("/api/payments/:paymentId")
Expand Down
6 changes: 6 additions & 0 deletions api/src/routes/centre-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ centreRouter.get("/", async (req: Request, res: Response) => {
}
})

/**
* @deprecated prefer /api/centres -> CentresController#create
*/
centreRouter.post("/", RequireAdmin, async (req: Request, res: Response) => {
// TODO: figure out how to push this logic into the authentication layer
if (!(req.user instanceof User)) {
Expand Down Expand Up @@ -104,6 +107,9 @@ centreRouter.post("/:id/fiscal-year", async (req: Request, res: Response) => {
})
})

/**
* @deprecated prefer /api/centres/:centreId -> CentresController#update
*/
centreRouter.put("/:id", RequireAdmin, async (req: Request, res: Response) => {
// TODO: figure out how to push this logic into the authentication layer
if (!(req.user instanceof User)) {
Expand Down
Loading

0 comments on commit a335faa

Please sign in to comment.