Skip to content

Commit dfa2235

Browse files
authored
Add configuration files and implement student number handling (#263)
- Create config.docker.json for application configuration. - Add docker-compose.yml for service orchestration. - Implement addStudentNumber function in users.ts to handle student number submissions. - Update router.ts to include route for adding student numbers.
1 parent 63f4e1b commit dfa2235

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

config.docker.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"instanceName": "id-core",
3+
"logLevel": 30,
4+
"api": {
5+
"listenHost": "0.0.0.0",
6+
"listenPort": "50080",
7+
"proxy": true,
8+
"corsAllowedOrigins": ["http://localhost:3000"]
9+
},
10+
"session": {
11+
"key": "id-session",
12+
"maxAge": 3600000,
13+
"signed": true,
14+
"sameSite": "Lax",
15+
"rolling": false,
16+
"renew": true
17+
},
18+
"email": {
19+
"host": "smtp.gmail.com",
20+
"username": "ADD_USERNAME_HERE",
21+
"password": "ADD_PASSWORD_HERE",
22+
"resendLimit": 3,
23+
"verificationEmailSubject": "id.snucse.org 이메일 인증",
24+
"passwordChangeEmailSubject": "id.snucse.org 비밀번호 변경",
25+
"verificationEmailUrl": "http://localhost:3000/sign-up",
26+
"passwordChangeEmailUrl": "http://localhost:3000/change-password"
27+
},
28+
"posix": {
29+
"userGroupName": "cseusers",
30+
"userGroupGid": 101132,
31+
"sudoerGroupName": "csesudoers",
32+
"sudoerGroupGid": 100600,
33+
"defaultShell": "/bin/bash",
34+
"minUid": 100000,
35+
"homeDirectoryPrefix": "/csehome"
36+
},
37+
"postgresql": {
38+
"host": "postgres",
39+
"port": 5432,
40+
"user": "postgres",
41+
"password": "foo",
42+
"database": "id"
43+
},
44+
"permissions": {
45+
"snucse": [1]
46+
},
47+
"jwt": {
48+
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgCdjfvbvINjCy20yG\nuoDL0rVf60lJAv6Y/barD5El0Y2hRANCAARWUx7P9gsIAe23mCffvGXylGdb8t40\nXgBYC+Rv2zIVkPtfL6y5TLTn0LTm+9Q2Z/43Yo864CXRUoSVAU9puu3P\n-----END PRIVATE KEY-----\n",
49+
"expirySec": 3600,
50+
"issuer": "bacchus:id",
51+
"audience": "bacchus:some_service"
52+
},
53+
"oidc": {
54+
"issuer": "http://localhost:50080/o",
55+
"cookieKey": "a-secret-signing-key-change-me",
56+
"jwks": {
57+
"keys": []
58+
},
59+
"devInteractions": false,
60+
"deviceFlow": false,
61+
"revocation": false
62+
}
63+
}

docker-compose.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
version: '3.8'
2+
3+
services:
4+
postgres:
5+
image: postgres:15-alpine
6+
environment:
7+
POSTGRES_USER: postgres
8+
POSTGRES_PASSWORD: foo
9+
POSTGRES_DB: id
10+
ports:
11+
- "5432:5432"
12+
volumes:
13+
- postgres_data:/var/lib/postgresql/data
14+
- ./schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
15+
healthcheck:
16+
test: ["CMD-SHELL", "pg_isready -U postgres -d id"]
17+
interval: 5s
18+
timeout: 5s
19+
retries: 5
20+
21+
backend:
22+
build: .
23+
ports:
24+
- "50080:50080"
25+
volumes:
26+
- ./config.docker.json:/app/config.json:ro
27+
depends_on:
28+
postgres:
29+
condition: service_healthy
30+
31+
volumes:
32+
postgres_data:

src/api/handlers/users.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,40 @@ export function getUserEmails(model: Model): IMiddleware {
287287
};
288288
}
289289

290+
export function addStudentNumber(model: Model): IMiddleware {
291+
const bodySchema = z.object({
292+
studentNumber: z.string().regex(/^(\d{5}-\d{3}|\d{4}-\d{4,5})$/),
293+
});
294+
295+
return async (ctx, next) => {
296+
const userIdx = ctx.state.userIdx;
297+
if (typeof userIdx !== 'number') {
298+
ctx.status = 401;
299+
return;
300+
}
301+
302+
const bodyResult = bodySchema.safeParse(ctx.request.body);
303+
if (!bodyResult.success) {
304+
ctx.status = 400;
305+
return;
306+
}
307+
308+
const { studentNumber } = bodyResult.data;
309+
try {
310+
await model.pgDo(async tr => {
311+
await model.users.addStudentNumber(tr, userIdx, studentNumber);
312+
});
313+
} catch (e) {
314+
// Likely duplicate student number (unique constraint)
315+
ctx.status = 409;
316+
return;
317+
}
318+
319+
ctx.status = 201;
320+
await next();
321+
};
322+
}
323+
290324
export function getUserInfo(model: Model, config: Config): IMiddleware {
291325
return async (ctx, next) => {
292326
// authorize

src/api/router.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { checkLogin, login, loginLegacy, loginPAM, logout } from './handlers/log
2020
import { getGroup, getPasswd } from './handlers/nss.js';
2121
import { getShells } from './handlers/shells.js';
2222
import {
23+
addStudentNumber,
2324
changePassword,
2425
checkChangePasswordEmailToken,
2526
createUser,
@@ -145,6 +146,16 @@ export function createRouter(
145146
*/
146147
router.get('/api/user/emails', getUserEmails(model));
147148

149+
/**
150+
* Add a student number to the user.
151+
* 201 if success.
152+
* 400 if invalid format.
153+
* 401 if not logged in.
154+
* 409 if student number already exists.
155+
* @param studentNumber student number.
156+
*/
157+
router.post('/api/user/student-numbers', addStudentNumber(model));
158+
148159
/**
149160
* Get user info.
150161
* 200 if success.

0 commit comments

Comments
 (0)