Skip to content

Commit aef6296

Browse files
authored
Merge pull request #94 from icefoganalytics/test
Portal models and MSFAA column migration
2 parents d2c26e9 + 1385475 commit aef6296

38 files changed

+2066
-11
lines changed
849 KB
Loading

Design/Entity Relationship Diagrams.wsd

Lines changed: 533 additions & 0 deletions
Large diffs are not rendered by default.

docker-compose.development.yaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ services:
3737
<<: *environment-definition
3838
NODE_ENV: test
3939
DB_NAME: sfa_client_test
40-
DB_DEFAULT_SCHEMA: dbo
40+
DB_DEFAULT_SCHEMA: sfa
4141
tty: true
4242
volumes:
4343
- ./src/api:/usr/src/api
@@ -85,6 +85,16 @@ services:
8585
- 8081:8080
8686
- 8085:8085
8787

88+
# For easily generating large PlantUML diagrams
89+
# Not relevant to production environment.
90+
# Accessible at http://localhost:9999
91+
plantuml:
92+
image: plantuml/plantuml-server:jetty
93+
ports:
94+
- 9999:8080
95+
environment:
96+
PLANTUML_LIMIT_SIZE: 8192
97+
8898
volumes:
8999
db_data:
90100
s3storage:
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Request, Response, NextFunction } from "express"
2+
3+
export default class BaseController {
4+
protected request: Request
5+
protected response: Response
6+
protected next: NextFunction
7+
8+
constructor(request: Request, response: Response, next: NextFunction) {
9+
this.request = request
10+
this.response = response
11+
this.next = next
12+
}
13+
14+
protected get params() {
15+
return this.request.params
16+
}
17+
}

src/api/controllers/helpers.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Request, Response, NextFunction } from "express"
2+
3+
import BaseController from "@/controllers/base-controller"
4+
5+
export function routedTo<T extends typeof BaseController>(
6+
controllerClass: T,
7+
method: string & keyof InstanceType<T>
8+
) {
9+
return (req: Request, res: Response, next: NextFunction) => {
10+
const controllerInstance = new controllerClass(req, res, next) as InstanceType<T>
11+
const unboundControllerMethod = controllerInstance[method]
12+
13+
if (typeof unboundControllerMethod === "function") {
14+
return unboundControllerMethod.call(controllerInstance)
15+
} else {
16+
throw new Error(`Method ${method} is not a function on the provided controller class`)
17+
}
18+
}
19+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import BaseController from "@/controllers/base-controller"
2+
3+
import ApplicationDraftsSerializer from "@/serializers/application-drafts-serializer";
4+
import StudentApplicationDraftsService from "@/services/portal/students/student-application-drafts-service";
5+
6+
export default class StudentApplicationDraftsController extends BaseController {
7+
listStudentApplicationDrafts() {
8+
const studentId = parseInt(this.params.studentId)
9+
10+
const applicationService = new StudentApplicationDraftsService({ studentId })
11+
return applicationService
12+
.getApplicationDrafts()
13+
.then((applicationDrafts) => {
14+
const applicationDraftsSerializer = new ApplicationDraftsSerializer(applicationDrafts);
15+
const data = applicationDraftsSerializer.asListView()
16+
this.response.json({ data })
17+
})
18+
.catch((error: { message: string }) => {
19+
this.response.status(404).json({ error: error.message })
20+
})
21+
}
22+
23+
getStudentApplicationDraft() {
24+
const studentId = parseInt(this.params.studentId)
25+
const applicationDraftId = parseInt(this.params.applicationDraftId)
26+
27+
const applicationService = new StudentApplicationDraftsService({ studentId, applicationDraftId })
28+
return applicationService
29+
.getApplicationDraft()
30+
.then((applicationDraft) => {
31+
const applicationDraftsSerializer = new ApplicationDraftsSerializer(applicationDraft);
32+
const data = applicationDraftsSerializer.asDetailedView()
33+
this.response.json({ data })
34+
})
35+
.catch((error: { message: string }) => {
36+
this.response.status(404).json({ error: error.message })
37+
})
38+
}
39+
40+
#getStudent(studentId: number) {}
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import BaseController from "@/controllers/base-controller"
2+
3+
import ApplicationsSerializer from "@/serializers/applications-serializer"
4+
import StudentApplicationsService from "@/services/portal/students/student-applications-service"
5+
6+
export default class StudentApplicationsController extends BaseController {
7+
listStudentApplications() {
8+
const studentId = parseInt(this.params.studentId)
9+
10+
const applicationService = new StudentApplicationsService({ studentId })
11+
return applicationService
12+
.getApplications()
13+
.then((applications) => {
14+
const applicationSerializer = new ApplicationsSerializer(applications)
15+
const data = applicationSerializer.asListView()
16+
this.response.json({ data })
17+
})
18+
.catch((error: { message: string }) => {
19+
this.response.status(404).json({ error: error.message })
20+
})
21+
}
22+
23+
getStudentApplication() {
24+
const studentId = parseInt(this.params.studentId)
25+
const applicationId = parseInt(this.params.applicationId)
26+
27+
const applicationService = new StudentApplicationsService({ studentId, applicationId })
28+
return applicationService
29+
.getApplication()
30+
.then((application) => {
31+
const applicationSerializer = new ApplicationsSerializer(application)
32+
const data = applicationSerializer.asDetailedView()
33+
this.response.json({ data })
34+
})
35+
.catch((error: { message: string }) => {
36+
this.response.status(404).json({ error: error.message })
37+
})
38+
}
39+
40+
#getStudent(studentId: number) {}
41+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// LEGACY: required until deleted from dbo.knex_migrations table production, after wich point they can be removed
2+
import { Knex } from "knex";
3+
4+
exports.up = async function (knex: Knex) {
5+
await knex.schema.alterTable("sfa.msfaa", (t) => {
6+
t.specificType("rec_create_date", "DATETIME2(0)")
7+
.defaultTo(knex.raw("GETDATE()"), { constraintName: "msfaa_rec_create_date_default" })
8+
.notNullable();
9+
t.specificType("rec_last_mod_date", "DATETIME2(0)").nullable();
10+
});
11+
12+
return knex.raw(`UPDATE sfa.msfaa SET rec_create_date = o.rec_create_date, rec_last_mod_date = o.rec_last_mod_date
13+
FROM sfa.msfaa n, SFAADMIN.MSFAA o
14+
WHERE n.id = o.msfaa_id`);
15+
};
16+
17+
exports.down = async function (knex: Knex) {
18+
return knex.schema.alterTable("sfa.msfaa", (t) => {
19+
t.dropColumn("rec_create_date");
20+
t.dropColumn("rec_last_mod_date");
21+
});
22+
};

src/api/models/address-type.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// TODO: question whether this should be in the database at all.
2+
// And if so, why is it its own table?
3+
enum AddressTypes {
4+
HOME = 1,
5+
MAILING = 2,
6+
SCHOOL = 3,
7+
PARENT = 4,
8+
}
9+
10+
export default class AddressType {
11+
id: number
12+
description: string
13+
isActive: boolean
14+
15+
constructor({
16+
id,
17+
description,
18+
isActive,
19+
}: {
20+
id: number
21+
description: string
22+
isActive: boolean
23+
}) {
24+
this.id = id
25+
this.description = description
26+
this.isActive = isActive
27+
}
28+
29+
// not in database
30+
static readonly Types = AddressTypes
31+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default interface ApplicationDraft {
2+
id: number
3+
studentId: number
4+
academicYearId: number
5+
createDate: Date
6+
updateDate: Date
7+
isActive?: boolean
8+
applicationJson: string
9+
submitDate?: Date
10+
status?: string
11+
}

0 commit comments

Comments
 (0)