Skip to content

Commit 30814fd

Browse files
committed
feat: use domain object for challenge timeline template
1 parent 6aa8869 commit 30814fd

File tree

5 files changed

+170
-142
lines changed

5 files changed

+170
-142
lines changed

app-bootstrap.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/**
22
* App bootstrap
33
*/
4-
global.Promise = require('bluebird')
5-
const Joi = require('joi')
4+
global.Promise = require("bluebird");
5+
const Joi = require("joi");
66

7-
Joi.optionalId = () => Joi.string().uuid()
8-
Joi.id = () => Joi.optionalId().required()
9-
Joi.page = () => Joi.number().integer().min(1).default(1)
10-
Joi.perPage = () => Joi.number().integer().min(1).max(100).default(20)
11-
Joi.fileSize = () => Joi.number().integer().min(0).default(0)
7+
Joi.optionalId = () => Joi.string().uuid();
8+
Joi.id = () => Joi.optionalId().required();
9+
Joi.page = () => Joi.number().integer().min(1).default(1);
10+
Joi.perPage = () => Joi.number().integer().min(1).max(100).default(20);
11+
Joi.fileSize = () => Joi.number().integer().min(0).default(0);

app-constants.js

+86-86
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,127 @@
1-
const config = require('config')
1+
const config = require("config");
22

33
/**
44
* App constants
55
*/
66
const UserRoles = {
7-
Admin: 'administrator',
8-
Copilot: 'copilot',
9-
Manager: 'Connect Manager',
10-
User: 'Topcoder User',
11-
SelfServiceCustomer: 'Self-Service Customer'
12-
}
7+
Admin: "administrator",
8+
Copilot: "copilot",
9+
Manager: "Connect Manager",
10+
User: "Topcoder User",
11+
SelfServiceCustomer: "Self-Service Customer",
12+
};
1313

1414
const prizeSetTypes = {
15-
ChallengePrizes: 'placement',
16-
CopilotPayment: 'copilot',
17-
ReviewerPayment: 'reviewer',
18-
CheckpointPrizes: 'checkpoint'
19-
}
15+
ChallengePrizes: "placement",
16+
CopilotPayment: "copilot",
17+
ReviewerPayment: "reviewer",
18+
CheckpointPrizes: "checkpoint",
19+
};
2020

2121
const challengeStatuses = {
22-
New: 'New',
23-
Draft: 'Draft',
24-
Approved: 'Approved',
25-
Cancelled: 'Cancelled',
26-
Active: 'Active',
27-
Completed: 'Completed',
28-
Deleted: 'Deleted',
29-
CancelledFailedReview: 'Cancelled - Failed Review',
30-
CancelledFailedScreening: 'Cancelled - Failed Screening',
31-
CancelledZeroSubmissions: 'Cancelled - Zero Submissions',
32-
CancelledWinnerUnresponsive: 'Cancelled - Winner Unresponsive',
33-
CancelledClientRequest: 'Cancelled - Client Request',
34-
CancelledRequirementsInfeasible: 'Cancelled - Requirements Infeasible',
35-
CancelledZeroRegistrations: 'Cancelled - Zero Registrations',
36-
CancelledPaymentFailed: 'Cancelled - Payment Failed'
37-
}
22+
New: "New",
23+
Draft: "Draft",
24+
Approved: "Approved",
25+
Cancelled: "Cancelled",
26+
Active: "Active",
27+
Completed: "Completed",
28+
Deleted: "Deleted",
29+
CancelledFailedReview: "Cancelled - Failed Review",
30+
CancelledFailedScreening: "Cancelled - Failed Screening",
31+
CancelledZeroSubmissions: "Cancelled - Zero Submissions",
32+
CancelledWinnerUnresponsive: "Cancelled - Winner Unresponsive",
33+
CancelledClientRequest: "Cancelled - Client Request",
34+
CancelledRequirementsInfeasible: "Cancelled - Requirements Infeasible",
35+
CancelledZeroRegistrations: "Cancelled - Zero Registrations",
36+
CancelledPaymentFailed: "Cancelled - Payment Failed",
37+
};
3838

3939
const validChallengeParams = {
40-
UpdatedBy: 'updatedBy',
41-
Updated: 'updated',
42-
CreatedBy: 'createdBy',
43-
Created: 'created',
44-
EndDate: 'endDate',
45-
StartDate: 'startDate',
46-
ProjectId: 'projectId',
47-
Name: 'name',
48-
TypeId: 'typeId',
49-
Prizes: 'overview.totalPrizes'
50-
}
40+
UpdatedBy: "updatedBy",
41+
Updated: "updated",
42+
CreatedBy: "createdBy",
43+
Created: "created",
44+
EndDate: "endDate",
45+
StartDate: "startDate",
46+
ProjectId: "projectId",
47+
Name: "name",
48+
TypeId: "typeId",
49+
Prizes: "overview.totalPrizes",
50+
};
5151

52-
const EVENT_ORIGINATOR = 'topcoder-challenges-api'
52+
const EVENT_ORIGINATOR = "topcoder-challenges-api";
5353

54-
const EVENT_MIME_TYPE = 'application/json'
54+
const EVENT_MIME_TYPE = "application/json";
5555

5656
const DiscussionTypes = {
57-
Challenge: 'challenge'
58-
}
57+
Challenge: "challenge",
58+
};
5959

6060
// using a testing topc, should be changed to use real topics in comments when they are created
6161
const Topics = {
62-
ChallengeCreated: 'challenge.notification.create',
63-
ChallengeUpdated: 'challenge.notification.update',
64-
ChallengeDeleted: 'challenge.notification.delete',
65-
ChallengeTypeCreated: 'test.new.bus.events', // 'challenge.action.type.created',
66-
ChallengeTypeUpdated: 'test.new.bus.events', // 'challenge.action.type.updated',
67-
ChallengePhaseCreated: 'test.new.bus.events', // 'challenge.action.phase.created',
68-
ChallengePhaseUpdated: 'test.new.bus.events', // 'challenge.action.phase.updated',
69-
ChallengePhaseDeleted: 'test.new.bus.events', // 'challenge.action.phase.deleted',
70-
TimelineTemplateCreated: 'test.new.bus.events', // 'challenge.action.timeline.template.created',
71-
TimelineTemplateUpdated: 'test.new.bus.events', // 'challenge.action.timeline.template.updated',
72-
TimelineTemplateDeleted: 'test.new.bus.events', // 'challenge.action.timeline.template.deleted',
73-
ChallengeTypeTimelineTemplateCreated: 'test.new.bus.events', // 'challenge.action.type.timeline.template.created',
74-
ChallengeTypeTimelineTemplateUpdated: 'test.new.bus.events', // 'challenge.action.type.timeline.template.updated',
75-
ChallengeTypeTimelineTemplateDeleted: 'test.new.bus.events', // 'challenge.action.type.timeline.template.deleted'
76-
ChallengeAttachmentCreated: 'test.new.bus.events', // 'challenge.action.attachment.created',
77-
ChallengeAttachmentUpdated: 'test.new.bus.events', // 'challenge.action.attachment.updated',
78-
ChallengeAttachmentDeleted: 'test.new.bus.events', // 'challenge.action.attachment.deleted',
62+
ChallengeCreated: "challenge.notification.create",
63+
ChallengeUpdated: "challenge.notification.update",
64+
ChallengeDeleted: "challenge.notification.delete",
65+
ChallengeTypeCreated: "test.new.bus.events", // 'challenge.action.type.created',
66+
ChallengeTypeUpdated: "test.new.bus.events", // 'challenge.action.type.updated',
67+
ChallengePhaseCreated: "test.new.bus.events", // 'challenge.action.phase.created',
68+
ChallengePhaseUpdated: "test.new.bus.events", // 'challenge.action.phase.updated',
69+
ChallengePhaseDeleted: "test.new.bus.events", // 'challenge.action.phase.deleted',
70+
TimelineTemplateCreated: "test.new.bus.events", // 'challenge.action.timeline.template.created',
71+
TimelineTemplateUpdated: "test.new.bus.events", // 'challenge.action.timeline.template.updated',
72+
TimelineTemplateDeleted: "test.new.bus.events", // 'challenge.action.timeline.template.deleted',
73+
ChallengeTimelineTemplateCreated: "test.new.bus.events", // 'challenge.action.type.timeline.template.created',
74+
ChallengeTimelineTemplateUpdated: "test.new.bus.events", // 'challenge.action.type.timeline.template.updated',
75+
ChallengeTimelineTemplateDeleted: "test.new.bus.events", // 'challenge.action.type.timeline.template.deleted'
76+
ChallengeAttachmentCreated: "test.new.bus.events", // 'challenge.action.attachment.created',
77+
ChallengeAttachmentUpdated: "test.new.bus.events", // 'challenge.action.attachment.updated',
78+
ChallengeAttachmentDeleted: "test.new.bus.events", // 'challenge.action.attachment.deleted',
7979
// Self Service topics
80-
Notifications: 'notifications.action.create'
81-
}
80+
Notifications: "notifications.action.create",
81+
};
8282

8383
const challengeTracks = {
84-
DEVELOP: 'DEVELOP',
85-
DESIGN: 'DESIGN',
86-
DATA_SCIENCE: 'DATA_SCIENCE',
87-
QA: 'QA'
88-
}
84+
DEVELOP: "DEVELOP",
85+
DESIGN: "DESIGN",
86+
DATA_SCIENCE: "DATA_SCIENCE",
87+
QA: "QA",
88+
};
8989

9090
const challengeTextSortField = {
91-
Name: 'name',
92-
TypeId: 'typeId'
93-
}
91+
Name: "name",
92+
TypeId: "typeId",
93+
};
9494

9595
const reviewTypes = {
96-
Community: 'COMMUNITY',
97-
Internal: 'INTERNAL'
98-
}
96+
Community: "COMMUNITY",
97+
Internal: "INTERNAL",
98+
};
9999

100100
const SelfServiceNotificationTypes = {
101-
WORK_REQUEST_SUBMITTED: 'self-service.notifications.work-request-submitted',
102-
WORK_REQUEST_STARTED: 'self-service.notifications.work-request-started',
103-
WORK_REQUEST_REDIRECTED: 'self-service.notifications.work-request-redirected',
104-
WORK_COMPLETED: 'self-service.notifications.work-completed'
105-
}
101+
WORK_REQUEST_SUBMITTED: "self-service.notifications.work-request-submitted",
102+
WORK_REQUEST_STARTED: "self-service.notifications.work-request-started",
103+
WORK_REQUEST_REDIRECTED: "self-service.notifications.work-request-redirected",
104+
WORK_COMPLETED: "self-service.notifications.work-completed",
105+
};
106106

107107
const SelfServiceNotificationSettings = {
108108
[SelfServiceNotificationTypes.WORK_REQUEST_SUBMITTED]: {
109109
sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_REQUEST_SUBMITTED,
110-
cc: []
110+
cc: [],
111111
},
112112
[SelfServiceNotificationTypes.WORK_REQUEST_STARTED]: {
113113
sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_REQUEST_STARTED,
114-
cc: []
114+
cc: [],
115115
},
116116
[SelfServiceNotificationTypes.WORK_REQUEST_REDIRECTED]: {
117117
sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_REQUEST_REDIRECTED,
118-
cc: [...config.SELF_SERVICE_EMAIL_CC_ACCOUNTS]
118+
cc: [...config.SELF_SERVICE_EMAIL_CC_ACCOUNTS],
119119
},
120120
[SelfServiceNotificationTypes.WORK_COMPLETED]: {
121121
sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_COMPLETED,
122-
cc: []
123-
}
124-
}
122+
cc: [],
123+
},
124+
};
125125

126126
module.exports = {
127127
UserRoles,
@@ -136,5 +136,5 @@ module.exports = {
136136
DiscussionTypes,
137137
reviewTypes,
138138
SelfServiceNotificationTypes,
139-
SelfServiceNotificationSettings
140-
}
139+
SelfServiceNotificationSettings,
140+
};

src/services/ChallengeTimelineTemplateService.js

+47-41
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,45 @@
22
* This service provides operations of challenge type timeline template.
33
*/
44

5-
const _ = require("lodash");
5+
const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env;
6+
7+
const {
8+
DomainHelper: { getScanCriteria, getLookupCriteria },
9+
} = require("@topcoder-framework/lib-common");
10+
11+
const {
12+
ChallengeTimelineTemplateDomain,
13+
} = require("@topcoder-framework/domain-challenge");
14+
615
const Joi = require("joi");
7-
const uuid = require("uuid/v4");
16+
817
const helper = require("../common/helper");
9-
// const logger = require('../common/logger')
1018
const errors = require("../common/errors");
19+
1120
const constants = require("../../app-constants");
1221
const logger = require("../common/logger");
1322

23+
const challengeTimelineTemplateDomain = new ChallengeTimelineTemplateDomain(
24+
GRPC_CHALLENGE_SERVER_HOST,
25+
GRPC_CHALLENGE_SERVER_PORT
26+
);
27+
1428
/**
1529
* Search challenge type timeline templates.
1630
* @param {Object} criteria the search criteria
17-
* @returns {Array} the search result
31+
* @returns {Promise<array>} the search result
1832
*/
1933
async function searchChallengeTimelineTemplates(criteria) {
20-
let records = await helper.scanAll("ChallengeTimelineTemplate");
21-
if (criteria.typeId)
22-
records = _.filter(records, (e) => criteria.typeId === e.typeId);
23-
if (criteria.trackId)
24-
records = _.filter(records, (e) => criteria.trackId === e.trackId);
25-
if (criteria.timelineTemplateId)
26-
records = _.filter(
27-
records,
28-
(e) => criteria.timelineTemplateId === e.timelineTemplateId
29-
);
30-
if (!_.isUndefined(criteria.isDefault))
31-
records = _.filter(
32-
records,
33-
(e) =>
34-
e.isDefault === (_.toLower(_.toString(criteria.isDefault)) === "true")
35-
);
34+
const records = await challengeTimelineTemplateDomain.scan({
35+
scanCriteria: getScanCriteria(criteria),
36+
});
37+
38+
const nRecords = records.length;
39+
3640
return {
37-
total: records.length,
41+
total: nRecords,
3842
page: 1,
39-
perPage: Math.max(records.length, 10),
43+
perPage: Math.max(nRecords, 10),
4044
result: records,
4145
};
4246
}
@@ -85,6 +89,7 @@ async function createChallengeTimelineTemplate(data) {
8589
"The challenge type timeline template is already defined."
8690
);
8791
}
92+
8893
// check exists
8994
await helper.getById("ChallengeType", data.typeId);
9095
await helper.getById("ChallengeTrack", data.trackId);
@@ -94,16 +99,14 @@ async function createChallengeTimelineTemplate(data) {
9499
await unsetDefaultTimelineTemplate(data.typeId, data.trackId);
95100
}
96101

97-
const ret = await helper.create(
98-
"ChallengeTimelineTemplate",
99-
_.assign({ id: uuid() }, data)
100-
);
102+
const template = await challengeTimelineTemplateDomain.create(data);
103+
101104
// post bus event
102105
await helper.postBusEvent(
103106
constants.Topics.ChallengeTimelineTemplateCreated,
104-
ret
107+
template
105108
);
106-
return ret;
109+
return template;
107110
}
108111

109112
createChallengeTimelineTemplate.schema = {
@@ -120,12 +123,11 @@ createChallengeTimelineTemplate.schema = {
120123
/**
121124
* Get challenge type timeline template.
122125
* @param {String} challengeTimelineTemplateId the challenge type timeline template id
123-
* @returns {Object} the challenge type timeline template with given id
126+
* @returns {Promise<Object>} the challenge type timeline template with given id
124127
*/
125128
async function getChallengeTimelineTemplate(challengeTimelineTemplateId) {
126-
return helper.getById(
127-
"ChallengeTimelineTemplate",
128-
challengeTimelineTemplateId
129+
return challengeTimelineTemplateDomain.lookup(
130+
getLookupCriteria("id", challengeTimelineTemplateId)
129131
);
130132
}
131133

@@ -143,8 +145,7 @@ async function fullyUpdateChallengeTimelineTemplate(
143145
challengeTimelineTemplateId,
144146
data
145147
) {
146-
const record = await helper.getById(
147-
"ChallengeTimelineTemplate",
148+
const record = await getChallengeTimelineTemplate(
148149
challengeTimelineTemplateId
149150
);
150151
if (
@@ -161,7 +162,7 @@ async function fullyUpdateChallengeTimelineTemplate(
161162
const records = await searchChallengeTimelineTemplates(data);
162163
if (records.total > 0) {
163164
throw new errors.ConflictError(
164-
"The challenge type timeline template is already defined."
165+
`A challenge type timeline template with typeId: ${data.typeId}, trackId: ${data.trackId}, timelineTemplateId: ${data.timelineTemplateId} already exists.`
165166
);
166167
}
167168
// check exists
@@ -193,17 +194,22 @@ fullyUpdateChallengeTimelineTemplate.schema = {
193194
* @returns {Object} the deleted challenge type timeline template
194195
*/
195196
async function deleteChallengeTimelineTemplate(challengeTimelineTemplateId) {
196-
const ret = await helper.getById(
197-
"ChallengeTimelineTemplate",
198-
challengeTimelineTemplateId
197+
const templates = await challengeTimelineTemplateDomain.delete(
198+
getLookupCriteria("id", challengeTimelineTemplateId)
199199
);
200-
await ret.delete();
200+
201+
if (templates.length === 0) {
202+
throw new errors.NotFoundError(
203+
`A challenge type timeline template with id: ${challengeTimelineTemplateId} not found.`
204+
);
205+
}
206+
201207
// post bus event
202208
await helper.postBusEvent(
203209
constants.Topics.ChallengeTimelineTemplateDeleted,
204-
ret
210+
templates[0]
205211
);
206-
return ret;
212+
return templates[0];
207213
}
208214

209215
deleteChallengeTimelineTemplate.schema = {

0 commit comments

Comments
 (0)