Skip to content

Commit 9ed6727

Browse files
authored
Merge pull request #504 from topcoder-platform/cf21
Cf21 in Connect App
2 parents 41979e6 + 91b6142 commit 9ed6727

File tree

4 files changed

+147
-8
lines changed

4 files changed

+147
-8
lines changed

src/permissions/projectMember.delete.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module.exports = freq => new Promise((resolve, reject) => {
2626
// check if auth user has acecss to this project
2727
const hasAccess = util.hasAdminRole(req)
2828
|| (authMember && memberToBeRemoved && ([
29+
PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER,
2930
PROJECT_MEMBER_ROLE.MANAGER,
3031
PROJECT_MEMBER_ROLE.PROGRAM_MANAGER,
3132
PROJECT_MEMBER_ROLE.PROJECT_MANAGER,

src/routes/projects/list.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,14 @@ const SUPPORTED_FILTERS = [
6060
'directProjectId',
6161
];
6262

63-
const escapeEsKeyword = keyword => keyword.replace(/[+-=><!|(){}[&\]^"~*?:\\/]/g, '\\\\$&');
63+
/**
64+
* ES need to skip special chars else it is considered as RegEx or other ES query string syntax,
65+
* see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
66+
*
67+
* @param {String} keyword keyword being searched for
68+
* @return {String} result after parsing
69+
*/
70+
const escapeEsKeyword = keyword => keyword.replace(/[+-=><!|(){}[&\]^"~*?:\\/]/g, '\\$&');
6471

6572
const buildEsFullTextQuery = (keyword, matchType, singleFieldName) => {
6673
let should = [
@@ -426,7 +433,7 @@ const parseElasticSearchCriteria = (criteria, fields, order) => {
426433

427434
if (!keyword) {
428435
// Not a specific field search nor an exact phrase search, do a wildcard match
429-
keyword = criteria.filters.keyword;
436+
keyword = escapeEsKeyword(keywordCriterion);
430437
matchType = MATCH_TYPE_WILDCARD;
431438
}
432439

src/routes/projects/list.spec.js

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const data = [
2121
type: 'generic',
2222
billingAccountId: 1,
2323
name: 'test1',
24-
description: 'test project1',
24+
description: 'test project1 abc/d',
2525
status: 'active',
2626
details: {
2727
utm: {
@@ -160,7 +160,7 @@ const data = [
160160
role: 'manager',
161161
firstName: 'first',
162162
lastName: 'last',
163-
handle: 'manager_handle',
163+
handle: 'MANAGER_HANDLE',
164164
isPrimary: true,
165165
createdBy: 1,
166166
updatedBy: 1,
@@ -723,7 +723,7 @@ describe('LIST Project', () => {
723723
});
724724
});
725725

726-
it('should return all projects that match when filtering by customer handle', (done) => {
726+
it('should return all projects that match when filtering by customer handle (lowercase)', (done) => {
727727
request(server)
728728
.get('/v5/projects/?customer=*tourist*')
729729
.set({
@@ -746,7 +746,53 @@ describe('LIST Project', () => {
746746
});
747747
});
748748

749-
it('should return all projects that match when filtering by manager handle', (done) => {
749+
it('should return all projects that match when filtering by customer handle (uppercase)', (done) => {
750+
request(server)
751+
.get('/v5/projects/?customer=*TOUR*')
752+
.set({
753+
Authorization: `Bearer ${testUtil.jwts.admin}`,
754+
})
755+
.expect('Content-Type', /json/)
756+
.expect(200)
757+
.end((err, res) => {
758+
if (err) {
759+
done(err);
760+
} else {
761+
const resJson = res.body;
762+
should.exist(resJson);
763+
resJson.should.have.lengthOf(1);
764+
resJson[0].name.should.equal('test1');
765+
resJson[0].members.should.have.deep.property('[0].role', 'customer');
766+
resJson[0].members[0].userId.should.equal(40051331);
767+
done();
768+
}
769+
});
770+
});
771+
772+
it('should return all projects that match when filtering by customer handle (mixed case)', (done) => {
773+
request(server)
774+
.get('/v5/projects/?customer=*tOURiS*')
775+
.set({
776+
Authorization: `Bearer ${testUtil.jwts.admin}`,
777+
})
778+
.expect('Content-Type', /json/)
779+
.expect(200)
780+
.end((err, res) => {
781+
if (err) {
782+
done(err);
783+
} else {
784+
const resJson = res.body;
785+
should.exist(resJson);
786+
resJson.should.have.lengthOf(1);
787+
resJson[0].name.should.equal('test1');
788+
resJson[0].members.should.have.deep.property('[0].role', 'customer');
789+
resJson[0].members[0].userId.should.equal(40051331);
790+
done();
791+
}
792+
});
793+
});
794+
795+
it('should return all projects that match when filtering by manager handle (lowercase)', (done) => {
750796
request(server)
751797
.get('/v5/projects/?manager=*_handle')
752798
.set({
@@ -769,6 +815,52 @@ describe('LIST Project', () => {
769815
});
770816
});
771817

818+
it('should return all projects that match when filtering by manager handle (uppercase)', (done) => {
819+
request(server)
820+
.get('/v5/projects/?manager=MANAG*')
821+
.set({
822+
Authorization: `Bearer ${testUtil.jwts.admin}`,
823+
})
824+
.expect('Content-Type', /json/)
825+
.expect(200)
826+
.end((err, res) => {
827+
if (err) {
828+
done(err);
829+
} else {
830+
const resJson = res.body;
831+
should.exist(resJson);
832+
resJson.should.have.lengthOf(1);
833+
resJson[0].name.should.equal('test3');
834+
resJson[0].members.should.have.deep.property('[0].role', 'manager');
835+
resJson[0].members[0].userId.should.equal(40051334);
836+
done();
837+
}
838+
});
839+
});
840+
841+
it('should return all projects that match when filtering by manager handle (mixed case)', (done) => {
842+
request(server)
843+
.get('/v5/projects/?manager=*_HAndLe')
844+
.set({
845+
Authorization: `Bearer ${testUtil.jwts.admin}`,
846+
})
847+
.expect('Content-Type', /json/)
848+
.expect(200)
849+
.end((err, res) => {
850+
if (err) {
851+
done(err);
852+
} else {
853+
const resJson = res.body;
854+
should.exist(resJson);
855+
resJson.should.have.lengthOf(1);
856+
resJson[0].name.should.equal('test3');
857+
resJson[0].members.should.have.deep.property('[0].role', 'manager');
858+
resJson[0].members[0].userId.should.equal(40051334);
859+
done();
860+
}
861+
});
862+
});
863+
772864
it('should return all projects that match when filtering by manager, searching on any non-customer role', (done) => {
773865
request(server)
774866
.get('/v5/projects/?manager=copi*')
@@ -1065,7 +1157,7 @@ describe('LIST Project', () => {
10651157
resJson.should.have.lengthOf(1);
10661158
resJson[0].should.have.property('description');
10671159
resJson[0].should.not.have.property('cancelReason');
1068-
resJson[0].description.should.be.eq('test project1');
1160+
resJson[0].description.should.be.eq('test project1 abc/d');
10691161
done();
10701162
}
10711163
});
@@ -1244,6 +1336,46 @@ describe('LIST Project', () => {
12441336
}
12451337
});
12461338
});
1339+
1340+
it('should find a project by quoted keyword with a special symbol in the name', (done) => {
1341+
request(server)
1342+
.get('/v5/projects/?keyword="abc/d"')
1343+
.set({
1344+
Authorization: `Bearer ${testUtil.jwts.admin}`,
1345+
})
1346+
.expect('Content-Type', /json/)
1347+
.expect(200)
1348+
.end((err, res) => {
1349+
if (err) {
1350+
done(err);
1351+
} else {
1352+
const resJson = res.body;
1353+
should.exist(resJson);
1354+
resJson.should.have.lengthOf(1);
1355+
done();
1356+
}
1357+
});
1358+
});
1359+
1360+
it('should find a project by keyword with a special symbol in the name', (done) => {
1361+
request(server)
1362+
.get('/v5/projects/?keyword=abc/d')
1363+
.set({
1364+
Authorization: `Bearer ${testUtil.jwts.admin}`,
1365+
})
1366+
.expect('Content-Type', /json/)
1367+
.expect(200)
1368+
.end((err, res) => {
1369+
if (err) {
1370+
done(err);
1371+
} else {
1372+
const resJson = res.body;
1373+
should.exist(resJson);
1374+
resJson.should.have.lengthOf(1);
1375+
done();
1376+
}
1377+
});
1378+
});
12471379
});
12481380
});
12491381
});

src/utils/es-config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@ MAPPINGS[ES_PROJECT_INDEX] = {
241241
},
242242
handle: {
243243
type: 'string',
244-
index: 'not_analyzed',
245244
},
246245
id: {
247246
type: 'long',

0 commit comments

Comments
 (0)