Skip to content

Commit 29ed9d4

Browse files
author
vikasrohit
authored
Merge pull request #290 from topcoder-platform/feature/product-templates-refactoring
Product templates use forms
2 parents bf86adf + c03cd38 commit 29ed9d4

File tree

16 files changed

+991
-89
lines changed

16 files changed

+991
-89
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
--
2+
-- product_templates
3+
--
4+
ALTER TABLE product_templates ALTER COLUMN "template" DROP NOT NULL;
5+
6+
ALTER TABLE product_templates ADD COLUMN "form" json;

postman.json

Lines changed: 212 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"info": {
3-
"_postman_id": "db83f8a1-5b3f-4276-a371-aa3c3497542d",
3+
"_postman_id": "d9ea7b0f-1d2c-4d48-a693-fe7b51b1e2ea",
44
"name": "tc-project-service",
55
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
66
},
@@ -3081,7 +3081,106 @@
30813081
],
30823082
"body": {
30833083
"mode": "raw",
3084-
"raw": "{\r\n \"param\": {\r\n \"name\": \"name 1\",\r\n \"productKey\": \"productKey 1\",\r\n \"category\": \"key1\",\r\n \"icon\": \"http://example.com/icon1.ico\",\r\n \"brief\": \"brief 1\",\r\n \"details\": \"details 1\",\r\n \"aliases\": [\"product key 1\", \"product_key_1\"],\r\n \"template\": {\r\n \"template1\": {\r\n \"name\": \"template 1\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 1\"\r\n },\r\n \"others\": [\"others 11\", \"others 12\"]\r\n },\r\n \"template2\": {\r\n \"name\": \"template 2\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 2\"\r\n },\r\n \"others\": [\"others 21\", \"others 22\"]\r\n }\r\n }\r\n }\r\n }"
3084+
"raw": "{\r\n \"param\": {\r\n \"name\": \"name 1\",\r\n \"productKey\": \"productKey 1\",\r\n \"category\": \"key1\",\r\n \"icon\": \"http://example.com/icon1.ico\",\r\n \"brief\": \"brief 1\",\r\n \"details\": \"details 1\",\r\n \"aliases\": [\"product key 1\", \"product_key_1\"],\r\n \"template\": {\r\n \"template1\": {\r\n \"name\": \"template 1\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 1\"\r\n },\r\n \"others\": [\"others 11\", \"others 12\"]\r\n },\r\n \"template2\": {\r\n \"name\": \"template 2\",\r\n \"details\": {\r\n \"anyDetails\": \"any details 2\"\r\n },\r\n \"others\": [\"others 21\", \"others 22\"]\r\n }\r\n }\r\n }\r\n}"
3085+
},
3086+
"url": {
3087+
"raw": "{{api-url}}/v4/projects/metadata/productTemplates",
3088+
"host": [
3089+
"{{api-url}}"
3090+
],
3091+
"path": [
3092+
"v4",
3093+
"projects",
3094+
"metadata",
3095+
"productTemplates"
3096+
]
3097+
}
3098+
},
3099+
"response": []
3100+
},
3101+
{
3102+
"name": "Create product template with form",
3103+
"request": {
3104+
"method": "POST",
3105+
"header": [
3106+
{
3107+
"key": "Content-Type",
3108+
"value": "application/json"
3109+
},
3110+
{
3111+
"key": "Authorization",
3112+
"value": "Bearer {{jwt-token}}"
3113+
}
3114+
],
3115+
"body": {
3116+
"mode": "raw",
3117+
"raw": "{\r\n \"param\": {\r\n \"name\": \"name 1\",\r\n \"productKey\": \"productKey 1\",\r\n \"category\": \"key1\",\r\n \"icon\": \"http://example.com/icon1.ico\",\r\n \"brief\": \"brief 1\",\r\n \"details\": \"details 1\",\r\n \"aliases\": [\"product key 1\", \"product_key_1\"],\r\n \"form\": {\r\n\t\t\"key\": \"dev\",\r\n\t\t\"version\": 1\r\n\t}\r\n }\r\n}"
3118+
},
3119+
"url": {
3120+
"raw": "{{api-url}}/v4/projects/metadata/productTemplates",
3121+
"host": [
3122+
"{{api-url}}"
3123+
],
3124+
"path": [
3125+
"v4",
3126+
"projects",
3127+
"metadata",
3128+
"productTemplates"
3129+
]
3130+
}
3131+
},
3132+
"response": []
3133+
},
3134+
{
3135+
"name": "Create product template with wrong form key",
3136+
"request": {
3137+
"method": "POST",
3138+
"header": [
3139+
{
3140+
"key": "Content-Type",
3141+
"value": "application/json"
3142+
},
3143+
{
3144+
"key": "Authorization",
3145+
"value": "Bearer {{jwt-token}}"
3146+
}
3147+
],
3148+
"body": {
3149+
"mode": "raw",
3150+
"raw": "{\r\n \"param\": {\r\n \"name\": \"name 1\",\r\n \"productKey\": \"productKey 1\",\r\n \"category\": \"key1\",\r\n \"icon\": \"http://example.com/icon1.ico\",\r\n \"brief\": \"brief 1\",\r\n \"details\": \"details 1\",\r\n \"aliases\": [\"product key 1\", \"product_key_1\"],\r\n \"form\": {\r\n\t\t\"key\": \"wrong-key\"\r\n\t}\r\n }\r\n}"
3151+
},
3152+
"url": {
3153+
"raw": "{{api-url}}/v4/projects/metadata/productTemplates",
3154+
"host": [
3155+
"{{api-url}}"
3156+
],
3157+
"path": [
3158+
"v4",
3159+
"projects",
3160+
"metadata",
3161+
"productTemplates"
3162+
]
3163+
}
3164+
},
3165+
"response": []
3166+
},
3167+
{
3168+
"name": "Create product template with wrong model version",
3169+
"request": {
3170+
"method": "POST",
3171+
"header": [
3172+
{
3173+
"key": "Content-Type",
3174+
"value": "application/json"
3175+
},
3176+
{
3177+
"key": "Authorization",
3178+
"value": "Bearer {{jwt-token}}"
3179+
}
3180+
],
3181+
"body": {
3182+
"mode": "raw",
3183+
"raw": "{\r\n \"param\": {\r\n \"name\": \"name 1\",\r\n \"productKey\": \"productKey 1\",\r\n \"category\": \"key1\",\r\n \"icon\": \"http://example.com/icon1.ico\",\r\n \"brief\": \"brief 1\",\r\n \"details\": \"details 1\",\r\n \"aliases\": [\"product key 1\", \"product_key_1\"],\r\n \"form\": {\r\n\t\t\"key\": \"dev\",\r\n\t\t\"version\": 1123\r\n\t}\r\n }\r\n}"
30853184
},
30863185
"url": {
30873186
"raw": "{{api-url}}/v4/projects/metadata/productTemplates",
@@ -3232,6 +3331,117 @@
32323331
}
32333332
},
32343333
"response": []
3334+
},
3335+
{
3336+
"name": "Upgrade a product template with form",
3337+
"request": {
3338+
"method": "POST",
3339+
"header": [
3340+
{
3341+
"key": "Content-Type",
3342+
"value": "application/json",
3343+
"type": "text"
3344+
},
3345+
{
3346+
"key": "Authorization",
3347+
"value": "Bearer {{jwt-token}}",
3348+
"type": "text"
3349+
}
3350+
],
3351+
"body": {
3352+
"mode": "raw",
3353+
"raw": "{\r\n \"param\":{\r\n \"form\": {\r\n \t\"key\": \"dev\",\t\r\n \t\"version\": 2\r\n }\r\n }\r\n}"
3354+
},
3355+
"url": {
3356+
"raw": "{{api-url}}/v4/projects/metadata/productTemplates/2/upgrade",
3357+
"host": [
3358+
"{{api-url}}"
3359+
],
3360+
"path": [
3361+
"v4",
3362+
"projects",
3363+
"metadata",
3364+
"productTemplates",
3365+
"2",
3366+
"upgrade"
3367+
]
3368+
}
3369+
},
3370+
"response": []
3371+
},
3372+
{
3373+
"name": "Upgrade a product template with wrong model version",
3374+
"request": {
3375+
"method": "POST",
3376+
"header": [
3377+
{
3378+
"key": "Content-Type",
3379+
"value": "application/json",
3380+
"type": "text"
3381+
},
3382+
{
3383+
"key": "Authorization",
3384+
"value": "Bearer {{jwt-token}}",
3385+
"type": "text"
3386+
}
3387+
],
3388+
"body": {
3389+
"mode": "raw",
3390+
"raw": "{\r\n \"param\":{\r\n \"form\": {\r\n \t\"key\": \"dev\",\t\r\n \t\"version\": 1234\r\n }\r\n }\r\n}"
3391+
},
3392+
"url": {
3393+
"raw": "{{api-url}}/v4/projects/metadata/productTemplates/1/upgrade",
3394+
"host": [
3395+
"{{api-url}}"
3396+
],
3397+
"path": [
3398+
"v4",
3399+
"projects",
3400+
"metadata",
3401+
"productTemplates",
3402+
"1",
3403+
"upgrade"
3404+
]
3405+
}
3406+
},
3407+
"response": []
3408+
},
3409+
{
3410+
"name": "Upgrade a product template without define form",
3411+
"request": {
3412+
"method": "POST",
3413+
"header": [
3414+
{
3415+
"key": "Content-Type",
3416+
"value": "application/json",
3417+
"type": "text"
3418+
},
3419+
{
3420+
"key": "Authorization",
3421+
"value": "Bearer {{jwt-token}}",
3422+
"type": "text"
3423+
}
3424+
],
3425+
"body": {
3426+
"mode": "raw",
3427+
"raw": "{\r\n \"param\":{ \r\n }\r\n}"
3428+
},
3429+
"url": {
3430+
"raw": "{{api-url}}/v4/projects/metadata/productTemplates/3/upgrade",
3431+
"host": [
3432+
"{{api-url}}"
3433+
],
3434+
"path": [
3435+
"v4",
3436+
"projects",
3437+
"metadata",
3438+
"productTemplates",
3439+
"3",
3440+
"upgrade"
3441+
]
3442+
}
3443+
},
3444+
"response": []
32353445
}
32363446
]
32373447
},

src/models/productTemplate.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ module.exports = (sequelize, DataTypes) => {
1414
brief: { type: DataTypes.STRING(45), allowNull: false },
1515
details: { type: DataTypes.STRING(255), allowNull: false },
1616
aliases: { type: DataTypes.JSON, allowNull: false },
17-
template: { type: DataTypes.JSON, allowNull: false },
17+
template: { type: DataTypes.JSON, allowNull: true },
18+
form: { type: DataTypes.JSON, allowNull: true },
1819
deletedAt: DataTypes.DATE,
1920
disabled: { type: DataTypes.BOOLEAN, defaultValue: false },
2021
hidden: { type: DataTypes.BOOLEAN, defaultValue: false },

src/permissions/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ module.exports = () => {
3535

3636
Authorizer.setPolicy('productTemplate.create', projectAdmin);
3737
Authorizer.setPolicy('productTemplate.edit', projectAdmin);
38+
Authorizer.setPolicy('productTemplate.upgrade', projectAdmin);
3839
Authorizer.setPolicy('productTemplate.delete', projectAdmin);
3940
Authorizer.setPolicy('projectTemplate.upgrade', projectAdmin);
4041
Authorizer.setPolicy('productTemplate.view', true);

src/routes/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,16 @@ router.route('/v4/projects/metadata/productTemplates')
4343
.get(require('./productTemplates/list'));
4444
router.route('/v4/projects/metadata/productTemplates/:templateId(\\d+)')
4545
.get(require('./productTemplates/get'));
46+
router.route('/v4/projects/metadata/productTemplates/:templateId(\\d+)/upgrade')
47+
.post(require('./productTemplates/upgrade'));
4648

4749
router.route('/v4/projects/metadata/projectTypes')
4850
.get(require('./projectTypes/list'));
4951
router.route('/v4/projects/metadata/projectTypes/:key')
5052
.get(require('./projectTypes/get'));
5153

5254
router.route('/v4/projects/metadata/projectTemplates/:templateId(\\d+)/upgrade')
53-
.post(require('./projectTemplates/upgrade'));
55+
.post(require('./projectTemplates/upgrade'));
5456

5557
router.route('/v4/projects/metadata/orgConfig')
5658
.get(require('./orgConfig/list'));

src/routes/metadata/list.js

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,39 @@ function getUsedModel() {
3030
attributes: { exclude: ['deletedAt', 'deletedBy'] },
3131
raw: true,
3232
};
33-
return models.ProjectTemplate.findAll(query)
34-
.then((templates) => {
35-
templates.forEach((template) => {
36-
const { form, planConfig, priceConfig } = template;
37-
if ((form) && (form.key) && (form.version)) {
38-
modelUsed.form[form.key] = modelUsed.form[form.key] ? modelUsed.form[form.key] : {};
39-
modelUsed.form[form.key][form.version] = true;
40-
}
41-
if ((priceConfig) && (priceConfig.key) && (priceConfig.version)) {
42-
modelUsed.priceConfig[priceConfig.key] = modelUsed.priceConfig[priceConfig.key] ?
43-
modelUsed.priceConfig[priceConfig.key] : {};
44-
modelUsed.priceConfig[priceConfig.key][priceConfig.version] = true;
45-
}
46-
if ((planConfig) && (planConfig.key) && (planConfig.version)) {
47-
modelUsed.planConfig[planConfig.key] = modelUsed.planConfig[planConfig.key] ?
48-
modelUsed.planConfig[planConfig.key] : {};
49-
modelUsed.planConfig[planConfig.key][planConfig.version] = true;
50-
}
51-
});
52-
return Promise.resolve(modelUsed);
53-
});
33+
34+
return Promise.all([
35+
models.ProjectTemplate.findAll(query),
36+
models.ProductTemplate.findAll(query),
37+
]).then(([projectTemplates, productTemplates]) => {
38+
projectTemplates.forEach((template) => {
39+
const { form, planConfig, priceConfig } = template;
40+
if ((form) && (form.key) && (form.version)) {
41+
modelUsed.form[form.key] = modelUsed.form[form.key] ? modelUsed.form[form.key] : {};
42+
modelUsed.form[form.key][form.version] = true;
43+
}
44+
if ((priceConfig) && (priceConfig.key) && (priceConfig.version)) {
45+
modelUsed.priceConfig[priceConfig.key] = modelUsed.priceConfig[priceConfig.key] ?
46+
modelUsed.priceConfig[priceConfig.key] : {};
47+
modelUsed.priceConfig[priceConfig.key][priceConfig.version] = true;
48+
}
49+
if ((planConfig) && (planConfig.key) && (planConfig.version)) {
50+
modelUsed.planConfig[planConfig.key] = modelUsed.planConfig[planConfig.key] ?
51+
modelUsed.planConfig[planConfig.key] : {};
52+
modelUsed.planConfig[planConfig.key][planConfig.version] = true;
53+
}
54+
});
55+
56+
productTemplates.forEach((template) => {
57+
const { form } = template;
58+
if ((form) && (form.key) && (form.version)) {
59+
modelUsed.form[form.key] = modelUsed.form[form.key] ? modelUsed.form[form.key] : {};
60+
modelUsed.form[form.key][form.version] = true;
61+
}
62+
});
63+
64+
return Promise.resolve(modelUsed);
65+
});
5466
}
5567

5668

src/routes/metadata/list.spec.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ const productTemplates = [
3838
brief: 'brief 1',
3939
details: 'details 1',
4040
aliases: {},
41-
template: {},
41+
form: { key: 'productKey 1', version: 1 },
42+
template: null,
4243
createdBy: 1,
4344
updatedBy: 2,
4445
},
@@ -107,6 +108,30 @@ const forms = [
107108
createdBy: 1,
108109
updatedBy: 1,
109110
},
111+
{
112+
key: 'productKey 1',
113+
config: {
114+
questions: [{
115+
id: 'appDefinition',
116+
title: 'Sample Project',
117+
required: true,
118+
description: 'Please answer a few basic questions',
119+
subSections: [{
120+
id: 'projectName',
121+
required: true,
122+
validationError: 'Please provide a name for your project',
123+
fieldName: 'name',
124+
description: '',
125+
title: 'Project Name',
126+
type: 'project-name',
127+
}],
128+
}],
129+
},
130+
version: 2,
131+
revision: 1,
132+
createdBy: 1,
133+
updatedBy: 1,
134+
},
110135
];
111136
const priceConfigs = [
112137
{
@@ -198,7 +223,7 @@ describe('GET all metadata', () => {
198223
resJson.milestoneTemplates.should.have.length(1);
199224
resJson.projectTypes.should.have.length(1);
200225
resJson.productCategories.should.have.length(1);
201-
resJson.forms.should.have.length(1);
226+
resJson.forms.should.have.length(2);
202227
resJson.planConfigs.should.have.length(1);
203228
resJson.priceConfigs.should.have.length(1);
204229

@@ -225,7 +250,7 @@ describe('GET all metadata', () => {
225250
resJson.milestoneTemplates.should.have.length(1);
226251
resJson.projectTypes.should.have.length(1);
227252
resJson.productCategories.should.have.length(1);
228-
resJson.forms.should.have.length(2);
253+
resJson.forms.should.have.length(3);
229254
resJson.planConfigs.should.have.length(2);
230255
resJson.priceConfigs.should.have.length(2);
231256
done();

0 commit comments

Comments
 (0)