Skip to content

Commit ca17766

Browse files
Merge pull request #248 from makeopensource/develop
Release for sprint 3
2 parents eb98f16 + 8a19016 commit ca17766

94 files changed

Lines changed: 3990 additions & 2220 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
/**/node_modules
22
/logs
3-
/devU-api/src/tango/tests/test_files
3+
/devU-api/src/autograders/tango/tests/test_files
44
.env.*

.github/workflows/api.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,3 @@ jobs:
4242
4343
docker build . -f api.Dockerfile -t $IMAGE_NAME
4444
docker push $IMAGE_NAME
45-
46-
- name: build tango docker
47-
run: |
48-
IMAGE_NAME=ghcr.io/${{ env.repo_url }}/tango:${{ steps.get_branch.outputs.branch_name }}
49-
docker build ./tango -f ./tango/Dockerfile -t $IMAGE_NAME
50-
docker push $IMAGE_NAME

.gitmodules

Lines changed: 0 additions & 3 deletions
This file was deleted.

client.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ COPY ./devU-client/ .
2121
COPY --from=module_builder /tmp/devu-shared-modules ./devu-shared-modules
2222

2323
# build frontend during run so that we can modify baseurl via docker envoirment
24-
CMD npm run --silent build-docker && rm -rf /out/* && cp -r /app/dist/* /out
24+
CMD npm run build-docker && rm -rf /out/* && cp -r /app/dist/* /out

devU-api/README.md

Lines changed: 35 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -11,104 +11,37 @@ For now the only reason we're including docker is to more easily control the dev
1111

1212
## Running the Project Locally
1313

14-
### Getting Everything Started
15-
16-
Once you've got these installed, we can build our container and run it
17-
18-
#### Note to run the postgres container locally using the command below
19-
20-
You have to modify `devU-api/src/environment.ts`
21-
22-
change
23-
24-
`dbHost: (load('database.host') || 'localhost') as string`
25-
26-
to
27-
28-
`dbHost: 'localhost'`
29-
30-
This will probably be fixed in the future but for now the above steps are necessary
31-
32-
#### Using docker compose
33-
34-
We use [docker compose profiles](https://docs.docker.com/compose/profiles/) to selectively start services in the main docker-compose when developing.
35-
36-
Assuming you are in api dir `devU-api`, To start all api services except the api run
37-
38-
```
39-
npm run api-services
40-
```
41-
42-
To stop the services
43-
44-
```
45-
npm run api-services-stop
46-
```
47-
48-
Then install dependencies using
49-
50-
```
51-
npm install
52-
```
53-
54-
Once you've got all the dependencies installed you can run the project via
55-
56-
```
57-
npm start
58-
```
59-
60-
#### Manually:
61-
62-
```
63-
docker run \
64-
--name typeorm-postgres \
65-
-p 5432:5432 \
66-
-e POSTGRES_PASSWORD=password \
67-
-e POSTGRES_DB=typescript_api \
68-
-e POSTGRES_USER=typescript_user \
69-
-d postgres
70-
```
71-
72-
Install all node dependencies. All of the database environment variables can change, and can be set as environment variables on your machine if you want to overwrite the defaults
73-
74-
```
75-
docker run \
76-
--name minio \
77-
-p 9002:9000 \
78-
-p 9001:9001 \
79-
-v /tmp/data:/data \
80-
-e "MINIO_ROOT_USER=typescript_user" \
81-
-e "MINIO_ROOT_PASSWORD=changeMe" \
82-
-d minio/minio server /data --console-address ":9001"
83-
```
84-
85-
Install all node dependencies. All of the database environment variables can change, and can be set as environment variables on your machine if you want to overwrite the defaults
86-
87-
```
88-
npm install
89-
```
90-
91-
Run the setup script to create local development auth keys. These are used in local development for signing and authenticating JWTs.
92-
93-
```
94-
npm run generate-config
95-
```
96-
97-
Run the initial migrations to setup our DB schema
98-
99-
```
100-
npm run typeorm -- migration:run -d src/database.ts
101-
```
102-
103-
Once you've got all the dependencies installed you can run the project via
104-
105-
```
106-
npm start
107-
```
108-
109-
By default the project runs at `localhost:3001`, but you can change the port by setting an alternate port by setting the `PORT` environment variable.
110-
111-
If you're working in vscode, a configuration has been included to allow for debugging. Open up the VS Code Run and Debug section and click `Debug API`.
14+
### Quick Start
15+
16+
The instructions below assume you are in the api dir `/devU-api/`
17+
18+
You must have the following tools installed
19+
20+
* Docker
21+
* Node >= v20
22+
23+
Once you've got these installed,
24+
25+
1. We use [docker compose profiles](https://docs.docker.com/compose/profiles/)
26+
to selectively start services in the main docker-compose when developing.
27+
This starts all required services for the api depends (database, frontend etc.)
28+
```
29+
npm run api-services
30+
```
31+
32+
To remove all related containers
33+
```
34+
npm run api-services-stop
35+
```
36+
37+
2. Install dependencies using
38+
```
39+
npm install
40+
```
41+
3. Once you've got all the dependencies installed you can run the project via
42+
```
43+
npm run start
44+
```
11245
11346
### Convenient Devtools
11447
@@ -173,7 +106,7 @@ Here's what you need to know:
173106

174107
Here's the basic layout of the application
175108

176-
![control flow of the api](/docs/controlFlow.png 'Control Flow')
109+
![control flow of the api](./docs/controlFlow.png 'Control Flow')
177110

178111
Let's take this from the top
179112

@@ -218,9 +151,8 @@ When developing if you need to create a new type,
218151

219152
This will update the types in `devU-api` and `devU-client` folders.
220153

221-
**Note if the types are not being detected by your IDE**
222-
223-
**Go to the `devU-api/` and `devU-client/` and run `npm install` in each folder to update the shared modules.**
154+
if the types are not being detected, Go to the `devU-api/` and `devU-client/`
155+
and run `npm install` in each folder to update the shared modules.
224156

225157
### Testing
226158

@@ -257,7 +189,7 @@ I wouldn't recommend digging that far down as the of tests should be more human-
257189
If the schema needs to be updated, you can do so by updating the models and running
258190
259191
```
260-
npm run typeorm migration:generate -- -d src/database src/migration/<generatedMigrationName>
192+
npm run create-migration someMeaningfulMigrationName
261193
```
262194
263195
Doing so will attempt to create an auto migration from any changes within the `src/models` directory and add it to `src/migrations`. If an auto migration is generated for you (always check your auto migrations), you can run it with the above migration command

devU-api/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
"create-migrate": "npx typeorm-ts-node-commonjs migration:generate -d src/database.ts",
1010
"update-shared": "cd ../devU-shared && npm run build-local && cd ../devU-api && npm i",
1111
"typeorm": "typeorm-ts-node-commonjs",
12+
"create-migration": "ts-node scripts/create-migration.ts",
1213
"test": "jest --passWithNoTests",
1314
"clean": "rimraf build/*",
1415
"lint": "tsc",
1516
"build": "npm-run-all clean lint",
1617
"format": "prettier --write \"./**/*.{js,ts,json,md}\"",
1718
"pre-commit": "lint-staged",
1819
"populate-db": "ts-node-dev ./scripts/populate-db.ts",
19-
"tango": "ts-node-dev ./src/tango/tests/tango.endpoint.test.ts",
20-
"api-services": "docker compose -f ../docker-compose.yml --profile dev-api up",
20+
"tango": "ts-node-dev src/autograders/tango/tests/tango.endpoint.test.ts",
21+
"api-services": "docker compose -f ../docker-compose.yml --profile dev-api up --build",
2122
"api-services-stop": "docker compose -f ../docker-compose.yml --profile dev-api stop"
2223
},
2324
"lint-staged": {
@@ -67,9 +68,11 @@
6768
"cors": "^2.8.5",
6869
"devu-shared-modules": "./devu-shared-modules",
6970
"express": "^4.17.1",
71+
"express-list-endpoints": "^7.1.1",
7072
"express-validator": "^6.14.2",
7173
"helmet": "^4.6.0",
7274
"jsonwebtoken": "^9.0.2",
75+
"leviathan-node-sdk": "https://gitpkg.vercel.app/makeopensource/leviathan/spec/leviathan_node?dev",
7376
"minio": "^8.0.0",
7477
"morgan": "^1.10.0",
7578
"multer": "^1.4.5-lts.1",
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { exec } from 'child_process'
2+
3+
// Get the migration name from command line arguments
4+
const migrationName = process.argv[2]
5+
6+
if (!migrationName) {
7+
console.error('Migration name is required!')
8+
console.error('Usage: npm run create-mig MigrationName')
9+
process.exit(1)
10+
}
11+
12+
const command = `npm run typeorm -- migration:generate -d src/database.ts src/migration/${migrationName}`
13+
console.log(`Executing: ${command}`)
14+
15+
// Execute the command
16+
exec(command, (error, stdout, stderr) => {
17+
if (stdout) console.log(stdout)
18+
if (stderr) console.error(stderr)
19+
20+
if (error) {
21+
console.error(`Error: ${error.message}`)
22+
process.exit(1)
23+
}
24+
25+
console.log('Migration file created successfully!')
26+
})
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import {
2+
CancelJobRequest,
3+
createClient,
4+
createConnectTransport,
5+
DockerFile,
6+
JobLogRequest,
7+
JobService,
8+
LabData,
9+
LabFile,
10+
LabService,
11+
NewJobRequest,
12+
NewLabRequest,
13+
SubmissionFile,
14+
UploadLabFiles,
15+
UploadSubmissionFiles,
16+
} from 'leviathan-node-sdk'
17+
18+
19+
const leviUrl = process.env.LEVIATHAN_URL || 'http://localhost:9221'
20+
console.log(`Leviathan url set to ${leviUrl}`)
21+
22+
const transport = createConnectTransport({
23+
baseUrl: leviUrl,
24+
httpVersion: '2',
25+
})
26+
27+
const jobService = createClient(JobService, transport)
28+
const labService = createClient(LabService, transport)
29+
30+
export function bufferToBlob(multerFile: Express.Multer.File): Blob {
31+
return new Blob([multerFile.buffer], { type: multerFile.mimetype })
32+
}
33+
34+
export async function sendSubmission(labId: bigint, submission: Array<SubmissionFile>) {
35+
const fileId = await UploadSubmissionFiles(leviUrl, submission)
36+
const resp = await jobService.newJob(<NewJobRequest>{
37+
tmpSubmissionFolderId: fileId,
38+
labID: labId,
39+
})
40+
41+
return resp.jobId
42+
}
43+
44+
45+
export async function createNewLab(lab: LabData, dockerfile: DockerFile, labFiles: Array<LabFile>) {
46+
const fileId = await UploadLabFiles(leviUrl, dockerfile, labFiles)
47+
const resp = await labService.newLab(<NewLabRequest>{
48+
labData: lab,
49+
tmpFolderId: fileId,
50+
})
51+
52+
return resp.labId
53+
}
54+
55+
/**
56+
* streams job status,
57+
* the stream will exit on its own once the job is done, can be cancelled by calling controller.abort()
58+
* @returns a stream and a controller can be used to cancel the stream
59+
* @see waitForJob - for usage example
60+
*/
61+
export function streamJob(jobId: string) {
62+
const controller = new AbortController()
63+
const dataStream = jobService.streamStatus(
64+
<JobLogRequest>{ jobId },
65+
{ signal: controller.signal },
66+
)
67+
68+
return { dataStream, controller }
69+
}
70+
71+
72+
/**
73+
* gets current job status with logs
74+
*/
75+
export async function getStatus(jobId: string) {
76+
const resp = await jobService.getStatus(<JobLogRequest>{ jobId })
77+
// strip out grpc metadata
78+
const { $unknown, $typeName, ...info } = resp.jobInfo!
79+
const logs = resp.logs
80+
return { info, logs }
81+
}
82+
83+
/**
84+
* Blocks until job is complete
85+
* @see streamJob - is used under the hood
86+
*/
87+
export async function waitForJob(jobId: string) {
88+
const { dataStream } = streamJob(jobId)
89+
90+
let jobInfo: { jobId: string; status: string; statusMessage: string } = {
91+
jobId: '',
92+
status: '',
93+
statusMessage: '',
94+
}
95+
let logs: string = ''
96+
97+
for await (const chunk of dataStream) {
98+
if (!chunk.jobInfo) {
99+
console.warn('Empty job state')
100+
continue
101+
}
102+
103+
const { $unknown, $typeName, ...rest } = chunk.jobInfo!
104+
console.debug('Job', rest)
105+
106+
jobInfo = rest
107+
logs = chunk.logs
108+
}
109+
110+
return { jobInfo, logs }
111+
}
112+
113+
export async function cancelJob(jobId: string) {
114+
await jobService.cancelJob(<CancelJobRequest>{ jobId })
115+
}

devU-api/src/entities/assignment/assignment.service.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ export async function listByCourse(courseId: number) {
6666
export async function listByCourseReleased(courseId: number) {
6767
// TODO: filter by start date after current time
6868
// const now = new Date(Date.now())
69-
const allAssignments = await connect().findBy({ courseId: courseId, /*startDate: MoreThanOrEqual(now),*/ deletedAt: IsNull() })
70-
7169
// console.log("ASSIGNMENTS WITH FILTER: ", allAssignments)
7270

73-
return allAssignments;
71+
return await connect().findBy({
72+
courseId: courseId, /*startDate: MoreThanOrEqual(now),*/
73+
deletedAt: IsNull(),
74+
})
7475
}
7576

7677
export async function isReleased(id: number) {
@@ -87,7 +88,10 @@ export async function isReleased(id: number) {
8788
}
8889

8990
async function getMaxSubmissionsAndDeadline(id: number) {
90-
return await connect().findOne({ where: { id: id, deletedAt: IsNull() }, select: ['maxSubmissions', 'maxFileSize', 'disableHandins', 'endDate'] })
91+
return await connect().findOne({
92+
where: { id: id, deletedAt: IsNull() },
93+
select: ['maxSubmissions', 'maxFileSize', 'disableHandins', 'endDate'],
94+
})
9195
}
9296

9397
async function processFiles(req: Request) {

0 commit comments

Comments
 (0)