Skip to content
Open
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
24 changes: 22 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
{
"presets": [
"@babel/preset-env"
"presets": [
"@babel/preset-env"
],
"plugins": [
[
"module-resolver",
{
"root": [
"."
],
"alias": {
"^@/(.+)": "./\\1"
}
}
]
],
"env": {
"test": {
"plugins": [
"@babel/plugin-transform-runtime"
]
}
}
}
62 changes: 62 additions & 0 deletions .github/workflows/master_ncn-backend-v2-new.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy Node.js app to Azure Web App - ncn-backend-v2-new

on:
push:
branches:
- master
workflow_dispatch:

env:
POSTGRES_URL: ${{ secrets.POSTGRES_URL }}

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Set up Node.js version
uses: actions/setup-node@v1
with:
node-version: '16.x'

- name: npm install, build, and test
run: yarn

- name: Generate Prisma Client
run: npx prisma generate

- name: zip artifact for deployment
run: zip -r rel.zip ./* .babelrc .env.defaults

- name: Upload artifact for deployment job
uses: actions/upload-artifact@v2
with:
name: node-app
path: rel.zip

deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

steps:
- name: Download artifact from build job
uses: actions/download-artifact@v2
with:
name: node-app

- name: 'Deploy to Azure Web App'
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
app-name: 'ncn-backend-v2-new'
slot-name: 'Production'
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_D1CB065A6D4A48678ABF45CDA240C02C }}
package: rel.zip
2 changes: 1 addition & 1 deletion .github/workflows/master_ncn-backend-v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
run: yarn

- name: Generate Prisma Client
run: npx prisma generate --schema=./src/prisma/schema.prisma
run: npx prisma generate

- name: zip artifact for deployment
run: zip -r --symlinks rel.zip ./* .babelrc .env.defaults
Expand Down
3 changes: 3 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
setupFilesAfterEnv: ["./mocks.js"],
};
14 changes: 14 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": [
"./*"
],
}
},
"exclude": [
"node_modules",
"dist"
]
}
3 changes: 3 additions & 0 deletions mocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
jest.mock("./prisma/index");
jest.mock("./src/auth");
jest.mock("./src/utils/auth0_client");
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@prisma/client": "^4.0.0",
"@sendgrid/mail": "^7.6.0",
"axios": "^0.27.2",
"babel-plugin-module-resolver": "^4.1.0",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"dotenv-defaults": "^3.0.0",
Expand All @@ -32,12 +33,14 @@
"server": "npx nodemon src/server.js --ext js --watch src --exec babel-node",
"azure": "babel-node src/server.js",
"lint": "./node_modules/.bin/eslint --config=./.eslintrc.json .",
"lint-fix": "./node_modules/.bin/eslint --config=./.eslintrc.json . --cache --fix"
"lint-fix": "./node_modules/.bin/eslint --config=./.eslintrc.json . --cache --fix",
"test": "jest -i \".*.test.js\""
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": "eslint --cache --fix"
},
"devDependencies": {
"@babel/plugin-transform-runtime": "^7.18.10",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard": "^17.0.0",
Expand All @@ -46,7 +49,9 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.0.0",
"husky": "^8.0.1",
"jest": "^28.1.3",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1"
"prettier": "^2.7.1",
"supertest": "^6.2.4"
}
}
43 changes: 43 additions & 0 deletions prisma/__mocks__/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { PrismaClient } from "@prisma/client";
import { execSync } from "child_process";
import { URL } from "url";
import { insertStubData } from "../stubData";

const schemaId = `test`;
const url = makePostgresURL(schemaId);
process.env.POSTGRES_URL = url;
const prisma = new PrismaClient({
datasources: { db: { url } },
});

jest.setTimeout(8 * 1000);

beforeAll(async () => {
console.log(`Initializing DB...`);
execSync(`npx prisma db push`, {
env: {
...process.env,
POSTGRES_URL: url,
},
});
await insertStubData();
console.log(`DB initialization finished.`);
});

afterAll(async () => {
await prisma.$executeRawUnsafe(
`DROP SCHEMA IF EXISTS "${schemaId}" CASCADE;`
);
await prisma.$disconnect();
});

function makePostgresURL(schema) {
if (!process.env.POSTGRES_URL) {
throw new Error("Cannot find `POSTGRES_URL` in env variables");
}
const url = new URL(process.env.POSTGRES_URL);
url.searchParams.set("schema", schema);
return url.toString();
}

export default prisma;
5 changes: 5 additions & 0 deletions prisma/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default prisma;
173 changes: 173 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
generator client {
provider = "prisma-client-js"
previewFeatures = ["fullTextSearch"]
}

datasource db {
provider = "postgresql"
url = env("POSTGRES_URL")
}

model course_areas {
course_id String
area_id String
areas areas @relation(fields: [area_id], references: [id])
courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade)

@@id([course_id, area_id])
}

model course_departments {
course_id String
department_id String
courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade)
departments departments @relation(fields: [department_id], references: [id])

@@id([course_id, department_id])
}

model course_prerequisites {
course_id String
pre_course_id String
courses_course_prerequisites_course_idTocourses courses @relation("course_prerequisites_course_idTocourses", fields: [course_id], references: [id], onDelete: Cascade)
courses_course_prerequisites_pre_course_idTocourses courses @relation("course_prerequisites_pre_course_idTocourses", fields: [pre_course_id], references: [id])

@@id([course_id, pre_course_id])
}

model course_schedules {
course_id String
weekday Int
interval String
location String
courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade)

@@id([course_id, weekday, interval, location])
}

model course_specialties {
course_id String
specialty_id String
courses courses @relation(fields: [course_id], references: [id], onDelete: Cascade)
specialties specialties @relation(fields: [specialty_id], references: [id])

@@id([course_id, specialty_id])
}

model course_tables {
id String @id
name String
user_id String?
semester String?
courses String[]
expire_ts DateTime? @db.Timestamp(6)
users users? @relation(fields: [user_id], references: [id], onUpdate: Restrict)
}

model courses {
id String @id
serial String
code String
identifier String
name String
semester String
teacher String?
limitation String?
note String?
cool_url String?
credits Float?
can_be_selective Boolean
is_half_year Boolean
requirement course_requirements
language course_languages
provider course_providers
slot Int
enroll_method Int
intensive_weeks Int[]
departments_raw String[]
class String?
areas course_areas[]
departments course_departments[]
prerequisites course_prerequisites[] @relation("course_prerequisites_course_idTocourses")
prerequisite_of course_prerequisites[] @relation("course_prerequisites_pre_course_idTocourses")
schedules course_schedules[]
specialties course_specialties[]
}

model users {
id String @id
name String
email String
student_id String?
year Int @default(0)
major String?
d_major String?
minors String[]
languages String[]
favorites String[]
course_tables String[]
history_courses String[]
d_major_dept departments? @relation("departmentsTousers_d_major", fields: [d_major], references: [id], onDelete: Restrict, onUpdate: Restrict)
major_dept departments? @relation("departmentsTousers_major", fields: [major], references: [id], onDelete: Restrict, onUpdate: Restrict)
course_tables_course_tablesTousers course_tables[]

@@unique([id, email, student_id])
}

model areas {
id String @id
code String
name String
course_areas course_areas[]

@@unique([id, code, name])
}

model colleges {
id String @id
name String
departments departments[]

@@unique([id, name])
}

model departments {
id String @id
college_id String?
name_short String?
name_full String
name_alt String?
colleges colleges? @relation(fields: [college_id], references: [id], onDelete: Restrict, onUpdate: Restrict, map: "id")
course_departments course_departments[]
users_departmentsTousers_d_major users[] @relation("departmentsTousers_d_major")
users_departmentsTousers_major users[] @relation("departmentsTousers_major")

@@unique([id, name_full])
}

model specialties {
id String @id
name String
course_specialties course_specialties[]

@@unique([id, name])
}

enum course_languages {
zh_TW @map("zh-TW")
en_US @map("en-US")
}

enum course_providers {
ntu
ntnu
ntust
other
}

enum course_requirements {
preassign
required
elective
other
}
Loading