Skip to content

Commit 01ac6b4

Browse files
author
vikasrohit
authored
Merge pull request #73 from topcoder-platform/dev
Moving admin endpoints to production
2 parents b8bccc0 + 4894b87 commit 01ac6b4

File tree

10 files changed

+620
-1
lines changed

10 files changed

+620
-1
lines changed

circle.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ dependencies:
2424

2525
deployment:
2626
development:
27-
branch: dev
27+
branch: [dev, 'feature/admin-endpoints']
2828
commands:
2929
- ./ebs_deploy.sh tc-project-service DEV $CIRCLE_BUILD_NUM
3030

config/custom-environment-variables.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"docType": "projectV4"
1212
},
1313
"rabbitmqURL": "RABBITMQ_URL",
14+
"pubsubQueueName": "PUBSUB_QUEUE_NAME",
15+
"pubsubExchangeName": "PUBSUB_EXCHANGE_NAME",
1416
"directProjectServiceEndpoint": "DIRECT_PROJECT_SERVICE_ENDPOINT",
1517
"directProjectServiceTimeout": "DIRECT_PROJECT_SERVICE_TIMEOUt",
1618
"fileServiceEndpoint": "FILE_SERVICE_ENDPOINT",

src/models/project.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ module.exports = function defineProject(sequelize, DataTypes) {
155155
.then(projects => ({ rows: projects, count }));
156156
});
157157
},
158+
findProjectRange(startId, endId, fields) {
159+
return this.findAll({
160+
where: { id: { $between: [startId, endId] } },
161+
attributes: _.get(fields, 'projects', null),
162+
raw: true,
163+
});
164+
},
158165
},
159166
});
160167

src/permissions/admin.ops.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import util from '../util';
2+
3+
/**
4+
* Only super admin are allowed to perform admin operations
5+
* @param {Object} freq the express request instance
6+
* @return {Promise} Returns a promise
7+
*/
8+
module.exports = freq => new Promise((resolve, reject) => {
9+
const req = freq;
10+
req.context = req.context || {};
11+
// check if auth user has acecss to this project
12+
const hasAccess = util.hasAdminRole(req);
13+
14+
if (!hasAccess) {
15+
// user is not an admin nor is a registered project member
16+
return reject(new Error('You do not have permissions to perform this action'));
17+
}
18+
return resolve(true);
19+
});

src/permissions/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const projectView = require('./project.view');
55
const projectEdit = require('./project.edit');
66
const projectDelete = require('./project.delete');
77
const projectMemberDelete = require('./projectMember.delete');
8+
const projectAdmin = require('./admin.ops');
89

910
module.exports = () => {
1011
Authorizer.setDeniedStatusCode(403);
@@ -21,4 +22,5 @@ module.exports = () => {
2122
Authorizer.setPolicy('project.removeAttachment', projectEdit);
2223
Authorizer.setPolicy('project.downloadAttachment', projectView);
2324
Authorizer.setPolicy('project.updateMember', projectEdit);
25+
Authorizer.setPolicy('project.admin', projectAdmin);
2426
};
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
2+
/* globals Promise */
3+
4+
import _ from 'lodash';
5+
import config from 'config';
6+
import { middleware as tcMiddleware } from 'tc-core-library-js';
7+
import util from '../../util';
8+
9+
/**
10+
/**
11+
* API to handle retrieving a single project by id
12+
*
13+
* Permissions:
14+
* Only users that have access to the project can retrieve it.
15+
*
16+
*/
17+
18+
// var permissions = require('tc-core-library-js').middleware.permissions
19+
const permissions = tcMiddleware.permissions;
20+
const ES_PROJECT_INDEX = config.get('elasticsearchConfig.indexName');
21+
const ES_PROJECT_TYPE = config.get('elasticsearchConfig.docType');
22+
23+
/**
24+
* Get the request body for the specified index name
25+
* @private
26+
*
27+
* @param {String} indexName the index name
28+
* @param {String} docType document type
29+
* @return {Object} the request body for the specified index name
30+
*/
31+
function getRequestBody(indexName, docType) {
32+
const projectMapping = {
33+
_all: { enabled: false },
34+
properties: {
35+
actualPrice: {
36+
type: 'double',
37+
},
38+
attachments: {
39+
type: 'nested',
40+
properties: {
41+
category: {
42+
type: 'string',
43+
index: 'not_analyzed',
44+
},
45+
contentType: {
46+
type: 'string',
47+
index: 'not_analyzed',
48+
},
49+
createdAt: {
50+
type: 'date',
51+
format: 'strict_date_optional_time||epoch_millis',
52+
},
53+
createdBy: {
54+
type: 'integer',
55+
},
56+
description: {
57+
type: 'string',
58+
},
59+
filePath: {
60+
type: 'string',
61+
},
62+
id: {
63+
type: 'long',
64+
},
65+
projectId: {
66+
type: 'long',
67+
},
68+
size: {
69+
type: 'double',
70+
},
71+
title: {
72+
type: 'string',
73+
},
74+
updatedAt: {
75+
type: 'date',
76+
format: 'strict_date_optional_time||epoch_millis',
77+
},
78+
updatedBy: {
79+
type: 'integer',
80+
},
81+
},
82+
},
83+
billingAccountId: {
84+
type: 'long',
85+
},
86+
bookmarks: {
87+
type: 'nested',
88+
properties: {
89+
address: {
90+
type: 'string',
91+
},
92+
title: {
93+
type: 'string',
94+
},
95+
},
96+
},
97+
cancelReason: {
98+
type: 'string',
99+
},
100+
challengeEligibility: {
101+
type: 'nested',
102+
properties: {
103+
groups: {
104+
type: 'long',
105+
},
106+
role: {
107+
type: 'string',
108+
index: 'not_analyzed',
109+
},
110+
users: {
111+
type: 'long',
112+
},
113+
},
114+
},
115+
createdAt: {
116+
type: 'date',
117+
format: 'strict_date_optional_time||epoch_millis',
118+
},
119+
createdBy: {
120+
type: 'integer',
121+
},
122+
description: {
123+
type: 'string',
124+
},
125+
details: {
126+
type: 'nested',
127+
properties: {
128+
TBD_features: {
129+
type: 'nested',
130+
properties: {
131+
description: {
132+
type: 'string',
133+
},
134+
id: {
135+
type: 'integer',
136+
},
137+
isCustom: {
138+
type: 'boolean',
139+
},
140+
title: {
141+
type: 'string',
142+
},
143+
},
144+
},
145+
TBD_usageDescription: {
146+
type: 'string',
147+
},
148+
appDefinition: {
149+
properties: {
150+
goal: {
151+
properties: {
152+
value: {
153+
type: 'string',
154+
},
155+
},
156+
},
157+
primaryTarget: {
158+
type: 'string',
159+
},
160+
users: {
161+
properties: {
162+
value: {
163+
type: 'string',
164+
},
165+
},
166+
},
167+
},
168+
},
169+
hideDiscussions: {
170+
type: 'boolean',
171+
},
172+
products: {
173+
type: 'string',
174+
},
175+
summary: {
176+
type: 'string',
177+
},
178+
utm: {
179+
type: 'nested',
180+
properties: {
181+
code: {
182+
type: 'string',
183+
},
184+
},
185+
},
186+
},
187+
},
188+
directProjectId: {
189+
type: 'long',
190+
},
191+
estimatedPrice: {
192+
type: 'double',
193+
},
194+
external: {
195+
properties: {
196+
data: {
197+
type: 'string',
198+
},
199+
id: {
200+
type: 'string',
201+
index: 'not_analyzed',
202+
},
203+
type: {
204+
type: 'string',
205+
index: 'not_analyzed',
206+
},
207+
},
208+
},
209+
id: {
210+
type: 'long',
211+
},
212+
members: {
213+
type: 'nested',
214+
properties: {
215+
createdAt: {
216+
type: 'date',
217+
format: 'strict_date_optional_time||epoch_millis',
218+
},
219+
createdBy: {
220+
type: 'integer',
221+
},
222+
email: {
223+
type: 'string',
224+
index: 'not_analyzed',
225+
},
226+
firstName: {
227+
type: 'string',
228+
},
229+
handle: {
230+
type: 'string',
231+
index: 'not_analyzed',
232+
},
233+
id: {
234+
type: 'long',
235+
},
236+
isPrimary: {
237+
type: 'boolean',
238+
},
239+
lastName: {
240+
type: 'string',
241+
},
242+
projectId: {
243+
type: 'long',
244+
},
245+
role: {
246+
type: 'string',
247+
index: 'not_analyzed',
248+
},
249+
updatedAt: {
250+
type: 'date',
251+
format: 'strict_date_optional_time||epoch_millis',
252+
},
253+
updatedBy: {
254+
type: 'integer',
255+
},
256+
userId: {
257+
type: 'long',
258+
},
259+
},
260+
},
261+
name: {
262+
type: 'string',
263+
},
264+
status: {
265+
type: 'string',
266+
index: 'not_analyzed',
267+
},
268+
terms: {
269+
type: 'integer',
270+
},
271+
type: {
272+
type: 'string',
273+
index: 'not_analyzed',
274+
},
275+
updatedAt: {
276+
type: 'date',
277+
format: 'strict_date_optional_time||epoch_millis',
278+
},
279+
updatedBy: {
280+
type: 'integer',
281+
},
282+
utm: {
283+
properties: {
284+
campaign: {
285+
type: 'string',
286+
},
287+
medium: {
288+
type: 'string',
289+
},
290+
source: {
291+
type: 'string',
292+
},
293+
},
294+
},
295+
},
296+
};
297+
const result = {
298+
index: indexName,
299+
updateAllTypes: true,
300+
body: {
301+
mappings: { },
302+
},
303+
};
304+
result.body.mappings[docType] = projectMapping;
305+
return result;
306+
}
307+
308+
309+
module.exports = [
310+
permissions('project.admin'),
311+
/**
312+
* GET projects/{projectId}
313+
* Get a project by id
314+
*/
315+
(req, res, next) => { // eslint-disable-line no-unused-vars
316+
const logger = req.log;
317+
logger.debug('Entered Admin#createIndex');
318+
const indexName = _.get(req, 'body.param.indexName', ES_PROJECT_INDEX);
319+
const docType = _.get(req, 'body.param.docType', ES_PROJECT_TYPE);
320+
logger.debug('indexName', indexName);
321+
logger.debug('docType', docType);
322+
323+
const esClient = util.getElasticSearchClient();
324+
esClient.indices.create(getRequestBody(indexName, docType));
325+
res.status(200).json(util.wrapResponse(req.id, { message: 'Create index request successfully submitted' }));
326+
},
327+
];

0 commit comments

Comments
 (0)