Skip to content

Commit 3674059

Browse files
Implementation v3
1 parent babf337 commit 3674059

31 files changed

+3480
-338
lines changed

README.md

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- nodejs https://nodejs.org/en/ (v10)
66
- DynamoDB
7+
- AWS S3
78
- Docker, Docker Compose
89

910
## Configuration
@@ -15,14 +16,38 @@ The following parameters can be set in config files or in env variables:
1516
- PORT: the server port, default is 3000
1617
- AUTH_SECRET: The authorization secret used during token verification.
1718
- VALID_ISSUERS: The valid issuer of tokens.
18-
- DYNAMODB.AWS_ACCESS_KEY_ID: The Amazon certificate key to use when connecting. Use local dynamodb you can set fake value
19-
- DYNAMODB.AWS_SECRET_ACCESS_KEY: The Amazon certificate access key to use when connecting. Use local dynamodb you can set fake value
20-
- DYNAMODB.AWS_REGION: The Amazon certificate region to use when connecting. Use local dynamodb you can set fake value
21-
- DYNAMODB.IS_LOCAL: Use Amazon DynamoDB Local or server.
22-
- DYNAMODB.URL: The local url if using Amazon DynamoDB Local
19+
- AUTH0_URL: AUTH0 URL, used to get M2M token
20+
- AUTH0_PROXY_SERVER_URL: AUTH0 proxy server URL, used to get M2M token
21+
- AUTH0_AUDIENCE: AUTH0 audience, used to get M2M token
22+
- TOKEN_CACHE_TIME: AUTH0 token cache time, used to get M2M token
23+
- AUTH0_CLIENT_ID: AUTH0 client id, used to get M2M token
24+
- AUTH0_CLIENT_SECRET: AUTH0 client secret, used to get M2M token
25+
- AMAZON.AWS_ACCESS_KEY_ID: The Amazon certificate key to use when connecting. Use local dynamodb you can set fake value
26+
- AMAZON.AWS_SECRET_ACCESS_KEY: The Amazon certificate access key to use when connecting. Use local dynamodb you can set fake value
27+
- AMAZON.AWS_REGION: The Amazon certificate region to use when connecting. Use local dynamodb you can set fake value
28+
- AMAZON.IS_LOCAL_DB: Use Amazon DynamoDB Local or server.
29+
- AMAZON.DYNAMODB_URL: The local url if using Amazon DynamoDB Local
30+
- AMAZON.ATTACHMENT_S3_BUCKET: the AWS S3 bucket to store attachments
31+
- FILE_UPLOAD_SIZE_LIMIT: the file upload size limit in bytes
32+
- CHALLENGES_API_URL: TC challenges API base URL
33+
- GROUPS_API_URL: TC groups API base URL
34+
- COPILOT_RESOURCE_ROLE_IDS: copilot resource role ids allowed to upload attachment
35+
36+
37+
Set the following environment variables so that the app can get TC M2M token (use 'set' insted of 'export' for Windows OS):
38+
39+
- export AUTH0_CLIENT_ID=8QovDh27SrDu1XSs68m21A1NBP8isvOt
40+
- export AUTH0_CLIENT_SECRET=3QVxxu20QnagdH-McWhVz0WfsQzA1F8taDdGDI4XphgpEYZPcMTF4lX3aeOIeCzh
41+
- export AUTH0_URL=https://topcoder-dev.auth0.com/oauth/token
42+
- export AUTH0_AUDIENCE=https://m2m.topcoder-dev.com/
43+
44+
45+
Also properly configure AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, ATTACHMENT_S3_BUCKET config parameters.
46+
2347

2448
## DynamoDB Setup with Docker
2549
We will use DynamoDB setup on Docker.
50+
Note that you may need to modify regions in `local/init-dynamodb.sh` and `local/config`.
2651

2752
Just run `docker-compose up` in local folder
2853

@@ -49,16 +74,27 @@ aws dynamodb scan --table-name ChallengeSetting --endpoint-url http://localhost:
4974
aws dynamodb scan --table-name AuditLog --endpoint-url http://localhost:7777
5075
aws dynamodb scan --table-name Phase --endpoint-url http://localhost:7777
5176
aws dynamodb scan --table-name TimelineTemplate --endpoint-url http://localhost:7777
77+
aws dynamodb scan --table-name Attachment --endpoint-url http://localhost:7777
5278
```
5379

5480
## Local Deployment
5581

5682
- Install dependencies `npm install`
5783
- Run lint `npm run lint`
5884
- Run lint fix `npm run lint:fix`
85+
- Clear and init db `npm run init-db`
5986
- Start app `npm start`
6087
- App is running at `http://localhost:3000`
61-
- Clear and init db `npm run init-db`
6288

6389
## Verification
6490
Refer to the verification document `Verification.md`
91+
92+
## Notes
93+
94+
- after uploading attachments, the returned attachment ids should be used to update challenge;
95+
finally, attachments have challengeId field linking to their challenge,
96+
challenge also have attachments field linking to its attachments,
97+
this will speed up challenge CRUDS operations.
98+
99+
- updated swagger may be viewed and validated at `http://editor.swagger.io/`
100+

Verification.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Postman tests
44
- import Postman collection and environment in the docs folder to Postman
5-
- Just run the whole test cases under provided environment.
5+
- run tests from up to down in order
66

77
## DynamoDB Verification
88
1. Open a new console and run the command `docker exec -ti dynamodb sh` to use `aws-cli`
@@ -15,4 +15,10 @@ aws dynamodb scan --table-name ChallengeSetting --endpoint-url http://localhost:
1515
aws dynamodb scan --table-name AuditLog --endpoint-url http://localhost:7777
1616
aws dynamodb scan --table-name Phase --endpoint-url http://localhost:7777
1717
aws dynamodb scan --table-name TimelineTemplate --endpoint-url http://localhost:7777
18+
aws dynamodb scan --table-name Attachment --endpoint-url http://localhost:7777
1819
```
20+
21+
## S3 Verification
22+
23+
Login to AWS Console, S3 service, view the bucket content.
24+

app-constants.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,16 @@ const prizeTypes = {
2121
Fifth: 'fifth place'
2222
}
2323

24+
const challengeStatuses = {
25+
Draft: 'Draft',
26+
Canceled: 'Canceled',
27+
Active: 'Active',
28+
Completed: 'Completed'
29+
}
30+
2431
module.exports = {
2532
UserRoles,
2633
prizeSetTypes,
27-
prizeTypes
34+
prizeTypes,
35+
challengeStatuses
2836
}

app-routes.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ module.exports = (app) => {
3030
next()
3131
})
3232

33-
// add Authenticator check if route has auth
34-
if (def.auth) {
35-
actions.push((req, res, next) => {
36-
if (_.get(req, 'query.token')) {
37-
_.set(req, 'headers.authorization', `Bearer ${_.trim(req.query.token)}`)
38-
}
39-
next()
40-
})
33+
actions.push((req, res, next) => {
34+
if (_.get(req, 'query.token')) {
35+
_.set(req, 'headers.authorization', `Bearer ${_.trim(req.query.token)}`)
36+
}
37+
next()
38+
})
4139

40+
if (def.auth) {
41+
// add Authenticator/Authorization check if route has auth
4242
actions.push((req, res, next) => {
4343
authenticator(_.pick(config, ['AUTH_SECRET', 'VALID_ISSUERS']))(req, res, next)
4444
})
@@ -48,9 +48,9 @@ module.exports = (app) => {
4848
next(new errors.ForbiddenError('M2M is not supported.'))
4949
} else {
5050
req.authUser.userId = String(req.authUser.userId)
51-
// User
51+
// User roles authorization
5252
if (req.authUser.roles) {
53-
if (!helper.checkIfExists(def.access, req.authUser.roles)) {
53+
if (def.access && !helper.checkIfExists(def.access, req.authUser.roles)) {
5454
next(new errors.ForbiddenError('You are not allowed to perform this action!'))
5555
} else {
5656
next()
@@ -60,6 +60,26 @@ module.exports = (app) => {
6060
}
6161
}
6262
})
63+
} else {
64+
// public API, but still try to authenticate token if provided, but allow missing/invalid token
65+
actions.push((req, res, next) => {
66+
const interceptRes = {}
67+
interceptRes.status = () => interceptRes
68+
interceptRes.json = () => interceptRes
69+
interceptRes.send = () => next()
70+
authenticator(_.pick(config, ['AUTH_SECRET', 'VALID_ISSUERS']))(req, interceptRes, next)
71+
})
72+
73+
actions.push((req, res, next) => {
74+
if (!req.authUser) {
75+
next()
76+
} else if (req.authUser.isMachine) {
77+
next(new errors.ForbiddenError('M2M is not supported.'))
78+
} else {
79+
req.authUser.userId = String(req.authUser.userId)
80+
next()
81+
}
82+
})
6383
}
6484

6585
actions.push(method)

app.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ const cors = require('cors')
1212
const HttpStatus = require('http-status-codes')
1313
const logger = require('./src/common/logger')
1414
const interceptor = require('express-interceptor')
15+
const fileUpload = require('express-fileupload')
1516

1617
// setup express app
1718
const app = express()
1819

1920
app.use(cors())
21+
app.use(fileUpload({
22+
limits: { fileSize: config.FILE_UPLOAD_SIZE_LIMIT }
23+
}))
2024
app.use(bodyParser.json())
2125
app.use(bodyParser.urlencoded({ extended: true }))
2226
app.set('port', config.PORT)

config/default.js

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,29 @@ module.exports = {
77
PORT: process.env.PORT || 3000,
88
AUTH_SECRET: process.env.AUTH_SECRET || 'mysecret',
99
VALID_ISSUERS: process.env.VALID_ISSUERS || '["https://api.topcoder-dev.com", "https://api.topcoder.com", "https://topcoder-dev.auth0.com/"]',
10-
DYNAMODB: {
10+
11+
// used to get M2M token
12+
AUTH0_URL: process.env.AUTH0_URL,
13+
AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL,
14+
AUTH0_AUDIENCE: process.env.AUTH0_AUDIENCE || 'https://www.topcoder-dev.com',
15+
TOKEN_CACHE_TIME: process.env.TOKEN_CACHE_TIME,
16+
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
17+
AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET,
18+
19+
AMAZON: {
1120
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || 'FAKE_ACCESS_KEY',
1221
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || 'FAKE_SECRET_ACCESS_KEY',
13-
AWS_REGION: process.env.AWS_REGION || 'eu-central-1',
14-
IS_LOCAL: process.env.IS_LOCAL || true,
15-
URL: process.env.DYNAMODB_URL || 'http://localhost:7777'
16-
}
22+
AWS_REGION: process.env.AWS_REGION || 'ap-northeast-1',
23+
IS_LOCAL_DB: process.env.IS_LOCAL_DB ? process.env.IS_LOCAL_DB === 'true' : true,
24+
DYNAMODB_URL: process.env.DYNAMODB_URL || 'http://localhost:7777',
25+
ATTACHMENT_S3_BUCKET: process.env.ATTACHMENT_S3_BUCKET || 'my-testing-bucket-12345'
26+
},
27+
// in bytes
28+
FILE_UPLOAD_SIZE_LIMIT: process.env.FILE_UPLOAD_SIZE_LIMIT
29+
? Number(process.env.FILE_UPLOAD_SIZE_LIMIT) : 50 * 1024 * 1024, // 50M
30+
CHALLENGES_API_URL: process.env.CHALLENGES_API_URL || 'http://localhost:4000/v5/challenges',
31+
GROUPS_API_URL: process.env.GROUPS_API_URL || 'http://localhost:4000/v5/groups',
32+
// copilot resource role ids allowed to upload attachment
33+
COPILOT_RESOURCE_ROLE_IDS: process.env.COPILOT_RESOURCE_ROLE_IDS
34+
? process.env.COPILOT_RESOURCE_ROLE_IDS.split(',') : ['10ba038e-48da-487b-96e8-8d3b99b6d18b']
1735
}

0 commit comments

Comments
 (0)