Skip to content

Commit 086ad13

Browse files
authored
Merge pull request #2 from coderReview/dev-challenge-templates
merge from project and product templates
2 parents 43859dd + e9d5ef2 commit 086ad13

31 files changed

+4698
-1641
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Run image:
7171
`docker run -p 3000:3000 -i -t -e DB_HOST=172.17.0.1 tc_projects_services`
7272
You may replace 172.17.0.1 with your docker0 IP.
7373

74-
You can paste **swagger.yaml** to [swagger editor](http://editor.swagger.io/) or import **postman.json** to verify endpoints.
74+
You can paste **swagger.yaml** to [swagger editor](http://editor.swagger.io/) or import **postman.json** and **postman_environment.json** to verify endpoints.
7575

7676
#### Deploying without docker
7777
If you don't want to use docker to deploy to localhost. You can simply run `npm run start` from root of project. This should start the server on default port `3000`.

postman.json

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,238 @@
23452345
"response": []
23462346
}
23472347
]
2348+
},
2349+
{
2350+
"name": "Project Templates",
2351+
"description": "",
2352+
"item": [
2353+
{
2354+
"name": "Create project template",
2355+
"request": {
2356+
"method": "POST",
2357+
"header": [
2358+
{
2359+
"key": "Content-Type",
2360+
"value": "application/json"
2361+
},
2362+
{
2363+
"key": "Authorization",
2364+
"value": "Bearer {{jwt-token}}"
2365+
}
2366+
],
2367+
"body": {
2368+
"mode": "raw",
2369+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}"
2370+
},
2371+
"url": "{{api-url}}/v4/projectTemplates"
2372+
},
2373+
"response": []
2374+
},
2375+
{
2376+
"name": "List project templates",
2377+
"request": {
2378+
"method": "GET",
2379+
"header": [
2380+
{
2381+
"key": "Content-Type",
2382+
"value": "application/json"
2383+
},
2384+
{
2385+
"key": "Authorization",
2386+
"value": "Bearer {{jwt-token}}"
2387+
}
2388+
],
2389+
"body": {
2390+
"mode": "raw",
2391+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}"
2392+
},
2393+
"url": "{{api-url}}/v4/projectTemplates"
2394+
},
2395+
"response": []
2396+
},
2397+
{
2398+
"name": "Get project template",
2399+
"request": {
2400+
"method": "GET",
2401+
"header": [
2402+
{
2403+
"key": "Content-Type",
2404+
"value": "application/json"
2405+
},
2406+
{
2407+
"key": "Authorization",
2408+
"value": "Bearer {{jwt-token}}"
2409+
}
2410+
],
2411+
"body": {
2412+
"mode": "raw",
2413+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}"
2414+
},
2415+
"url": "{{api-url}}/v4/projectTemplates/1"
2416+
},
2417+
"response": []
2418+
},
2419+
{
2420+
"name": "Update project template",
2421+
"request": {
2422+
"method": "PATCH",
2423+
"header": [
2424+
{
2425+
"key": "Content-Type",
2426+
"value": "application/json"
2427+
},
2428+
{
2429+
"key": "Authorization",
2430+
"value": "Bearer {{jwt-token}}"
2431+
}
2432+
],
2433+
"body": {
2434+
"mode": "raw",
2435+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\",\r\n \"scope2\": [\"a\"]\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\",\r\n \"phase2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}"
2436+
},
2437+
"url": "{{api-url}}/v4/projectTemplates/1"
2438+
},
2439+
"response": []
2440+
},
2441+
{
2442+
"name": "Delete project template",
2443+
"request": {
2444+
"method": "DELETE",
2445+
"header": [
2446+
{
2447+
"key": "Content-Type",
2448+
"value": "application/json"
2449+
},
2450+
{
2451+
"key": "Authorization",
2452+
"value": "Bearer {{jwt-token}}"
2453+
}
2454+
],
2455+
"body": {
2456+
"mode": "raw",
2457+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\",\r\n \"scope2\": [\"a\"]\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\",\r\n \"phase2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}"
2458+
},
2459+
"url": "{{api-url}}/v4/projectTemplates/1"
2460+
},
2461+
"response": []
2462+
}
2463+
]
2464+
},
2465+
{
2466+
"name": "Product Templates",
2467+
"description": "",
2468+
"item": [
2469+
{
2470+
"name": "Create product template",
2471+
"request": {
2472+
"method": "POST",
2473+
"header": [
2474+
{
2475+
"key": "Content-Type",
2476+
"value": "application/json"
2477+
},
2478+
{
2479+
"key": "Authorization",
2480+
"value": "Bearer {{jwt-token}}"
2481+
}
2482+
],
2483+
"body": {
2484+
"mode": "raw",
2485+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"productKey\":\"new productKey\",\r\n \"icon\":\"http://example.com/icon-new.ico\",\r\n \"brief\": \"new brief\",\r\n \"details\": \"new details\",\r\n \"aliases\":{\r\n \"alias1\":\"alias 1\"\r\n },\r\n \"template\":{\r\n \"template1\":\"template 1\"\r\n }\r\n }\r\n}"
2486+
},
2487+
"url": "{{api-url}}/v4/productTemplates"
2488+
},
2489+
"response": []
2490+
},
2491+
{
2492+
"name": "List product templates",
2493+
"request": {
2494+
"method": "GET",
2495+
"header": [
2496+
{
2497+
"key": "Content-Type",
2498+
"value": "application/json"
2499+
},
2500+
{
2501+
"key": "Authorization",
2502+
"value": "Bearer {{jwt-token}}"
2503+
}
2504+
],
2505+
"body": {
2506+
"mode": "raw",
2507+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}"
2508+
},
2509+
"url": "{{api-url}}/v4/productTemplates"
2510+
},
2511+
"response": []
2512+
},
2513+
{
2514+
"name": "Get product template",
2515+
"request": {
2516+
"method": "GET",
2517+
"header": [
2518+
{
2519+
"key": "Content-Type",
2520+
"value": "application/json"
2521+
},
2522+
{
2523+
"key": "Authorization",
2524+
"value": "Bearer {{jwt-token}}"
2525+
}
2526+
],
2527+
"body": {
2528+
"mode": "raw",
2529+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\"\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\"\r\n }\r\n }\r\n}"
2530+
},
2531+
"url": "{{api-url}}/v4/productTemplates/1"
2532+
},
2533+
"response": []
2534+
},
2535+
{
2536+
"name": "Update product template",
2537+
"request": {
2538+
"method": "PATCH",
2539+
"header": [
2540+
{
2541+
"key": "Content-Type",
2542+
"value": "application/json"
2543+
},
2544+
{
2545+
"key": "Authorization",
2546+
"value": "Bearer {{jwt-token}}"
2547+
}
2548+
],
2549+
"body": {
2550+
"mode": "raw",
2551+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"productKey\":\"new productKey\",\r\n \"icon\":\"http://example.com/icon-new.ico\",\r\n \"brief\": \"new brief\",\r\n \"details\": \"new details\",\r\n \"aliases\":{\r\n \"alias1\":\"scope 1\",\r\n \"alias2\": [\"a\"]\r\n },\r\n \"template\":{\r\n \"template1\":\"template 1\",\r\n \"template2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}"
2552+
},
2553+
"url": "{{api-url}}/v4/productTemplates/1"
2554+
},
2555+
"response": []
2556+
},
2557+
{
2558+
"name": "Delete product template",
2559+
"request": {
2560+
"method": "DELETE",
2561+
"header": [
2562+
{
2563+
"key": "Content-Type",
2564+
"value": "application/json"
2565+
},
2566+
{
2567+
"key": "Authorization",
2568+
"value": "Bearer {{jwt-token}}"
2569+
}
2570+
],
2571+
"body": {
2572+
"mode": "raw",
2573+
"raw": "{\r\n \"param\":{\r\n \"name\":\"new name\",\r\n \"key\":\"new key\",\r\n \"category\":\"new category\",\r\n \"scope\":{\r\n \"scope1\":\"scope 1\",\r\n \"scope2\": [\"a\"]\r\n },\r\n \"phases\":{\r\n \"phase1\":\"phase 1\",\r\n \"phase2\": {\r\n \t\"another\": \"another\"\r\n }\r\n }\r\n }\r\n}"
2574+
},
2575+
"url": "{{api-url}}/v4/productTemplates/1"
2576+
},
2577+
"response": []
2578+
}
2579+
]
23482580
}
23492581
]
23502582
}

postman_environment.json

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
{
2-
"id": "1d4b6c34-6da6-8651-3372-9c6d4d09cc8c",
3-
"name": "project service",
2+
"id": "e6b30b4b-1388-4622-8314-bc49ba1d752b",
3+
"name": "tc-project-service",
44
"values": [
55
{
6-
"enabled": true,
76
"key": "api-url",
87
"value": "http://localhost:3000",
9-
"type": "text"
8+
"description": "",
9+
"type": "text",
10+
"enabled": true
1011
},
1112
{
12-
"enabled": true,
1313
"key": "jwt-token",
14-
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJhZG1pbmlzdHJhdG9yIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJwc2hhaDEiLCJleHAiOjI0NjI0OTQ2MTgsInVzZXJJZCI6IjQwMTM1OTc4IiwiaWF0IjoxNDYyNDk0MDE4LCJlbWFpbCI6InBzaGFoMUB0ZXN0LmNvbSIsImp0aSI6ImY0ZTFhNTE0LTg5ODAtNDY0MC04ZWM1LWUzNmUzMWE3ZTg0OSJ9.XuNN7tpMOXvBG1QwWRQROj7NfuUbqhkjwn39Vy4tR5I",
15-
"type": "text"
14+
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiYWRtaW5pc3RyYXRvciJdLCJpc3MiOiJodHRwczovL2FwaS50b3Bjb2Rlci1kZXYuY29tIiwiaGFuZGxlIjoidGVzdDEiLCJleHAiOjI1NjMwNzY2ODksInVzZXJJZCI6IjQwMDUxMzMzIiwiaWF0IjoxNDYzMDc2MDg5LCJlbWFpbCI6InRlc3RAdG9wY29kZXIuY29tIiwianRpIjoiYjMzYjc3Y2QtYjUyZS00MGZlLTgzN2UtYmViOGUwYWU2YTRhIn0.wKWUe0-SaiFVN-VR_-GwgFlvWaDkSbc8H55ktb9LAVw",
15+
"description": "",
16+
"type": "text",
17+
"enabled": true
1618
}
1719
],
18-
"timestamp": 1526351351170,
1920
"_postman_variable_scope": "environment",
20-
"_postman_exported_at": "2018-05-15T14:19:14.630Z",
21-
"_postman_exported_using": "Postman/5.5.2"
21+
"_postman_exported_at": "2018-05-18T18:54:18.167Z",
22+
"_postman_exported_using": "Postman/6.0.10"
2223
}

src/models/productTemplate.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* eslint-disable valid-jsdoc */
2+
3+
/**
4+
* The Product Template model
5+
*/
6+
module.exports = (sequelize, DataTypes) => {
7+
const ProductTemplate = sequelize.define('ProductTemplate', {
8+
id: { type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true },
9+
name: { type: DataTypes.STRING(255), allowNull: false },
10+
productKey: { type: DataTypes.STRING(45), allowNull: false },
11+
icon: { type: DataTypes.STRING(255), allowNull: false },
12+
brief: { type: DataTypes.STRING(45), allowNull: false },
13+
details: { type: DataTypes.STRING(255), allowNull: false },
14+
aliases: { type: DataTypes.JSON, allowNull: false },
15+
template: { type: DataTypes.JSON, allowNull: false },
16+
deletedAt: DataTypes.DATE,
17+
createdAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
18+
updatedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
19+
deletedBy: DataTypes.BIGINT,
20+
createdBy: { type: DataTypes.BIGINT, allowNull: false },
21+
updatedBy: { type: DataTypes.BIGINT, allowNull: false },
22+
}, {
23+
tableName: 'product_templates',
24+
paranoid: true,
25+
timestamps: true,
26+
updatedAt: 'updatedAt',
27+
createdAt: 'createdAt',
28+
deletedAt: 'deletedAt',
29+
});
30+
31+
return ProductTemplate;
32+
};

src/models/projectTemplate.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* eslint-disable valid-jsdoc */
2+
3+
/**
4+
* The Project Template model
5+
*/
6+
module.exports = (sequelize, DataTypes) => {
7+
const ProjectTemplate = sequelize.define('ProjectTemplate', {
8+
id: { type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true },
9+
name: { type: DataTypes.STRING(255), allowNull: false },
10+
key: { type: DataTypes.STRING(45), allowNull: false },
11+
category: { type: DataTypes.STRING(45), allowNull: false },
12+
scope: { type: DataTypes.JSON, allowNull: false },
13+
phases: { type: DataTypes.JSON, allowNull: false },
14+
deletedAt: DataTypes.DATE,
15+
createdAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
16+
updatedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
17+
deletedBy: DataTypes.BIGINT,
18+
createdBy: { type: DataTypes.BIGINT, allowNull: false },
19+
updatedBy: { type: DataTypes.BIGINT, allowNull: false },
20+
}, {
21+
tableName: 'project_templates',
22+
paranoid: true,
23+
timestamps: true,
24+
updatedAt: 'updatedAt',
25+
createdAt: 'createdAt',
26+
deletedAt: 'deletedAt',
27+
});
28+
29+
return ProjectTemplate;
30+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import util from '../util';
2+
import { MANAGER_ROLES } from '../constants';
3+
4+
5+
/**
6+
* Only Connect Manager, Connect Admin, and administrator are allowed to perform the operations
7+
* @param {Object} req the express request instance
8+
* @return {Promise} returns a promise
9+
*/
10+
module.exports = req => new Promise((resolve, reject) => {
11+
const hasAccess = util.hasRoles(req, MANAGER_ROLES);
12+
13+
if (!hasAccess) {
14+
return reject(new Error('You do not have permissions to perform this action'));
15+
}
16+
17+
return resolve(true);
18+
});

src/permissions/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const projectEdit = require('./project.edit');
66
const projectDelete = require('./project.delete');
77
const projectMemberDelete = require('./projectMember.delete');
88
const projectAdmin = require('./admin.ops');
9+
const connectManagerOrAdmin = require('./connectManagerOrAdmin.ops');
910

1011
module.exports = () => {
1112
Authorizer.setDeniedStatusCode(403);
@@ -23,6 +24,17 @@ module.exports = () => {
2324
Authorizer.setPolicy('project.downloadAttachment', projectView);
2425
Authorizer.setPolicy('project.updateMember', projectEdit);
2526
Authorizer.setPolicy('project.admin', projectAdmin);
27+
28+
Authorizer.setPolicy('projectTemplate.create', connectManagerOrAdmin);
29+
Authorizer.setPolicy('projectTemplate.edit', connectManagerOrAdmin);
30+
Authorizer.setPolicy('projectTemplate.delete', connectManagerOrAdmin);
31+
Authorizer.setPolicy('projectTemplate.view', true);
32+
33+
Authorizer.setPolicy('productTemplate.create', connectManagerOrAdmin);
34+
Authorizer.setPolicy('productTemplate.edit', connectManagerOrAdmin);
35+
Authorizer.setPolicy('productTemplate.delete', connectManagerOrAdmin);
36+
Authorizer.setPolicy('productTemplate.view', true);
37+
2638
Authorizer.setPolicy('project.addProjectPhase', projectEdit);
2739
Authorizer.setPolicy('project.updateProjectPhase', projectEdit);
2840
Authorizer.setPolicy('project.deleteProjectPhase', projectEdit);

0 commit comments

Comments
 (0)