diff --git a/src/permissions/projectMember.delete.js b/src/permissions/projectMember.delete.js index 5f4bb946..eb0a7bc0 100644 --- a/src/permissions/projectMember.delete.js +++ b/src/permissions/projectMember.delete.js @@ -26,6 +26,7 @@ module.exports = freq => new Promise((resolve, reject) => { // check if auth user has acecss to this project const hasAccess = util.hasAdminRole(req) || (authMember && memberToBeRemoved && ([ + PROJECT_MEMBER_ROLE.ACCOUNT_MANAGER, PROJECT_MEMBER_ROLE.MANAGER, PROJECT_MEMBER_ROLE.PROGRAM_MANAGER, PROJECT_MEMBER_ROLE.PROJECT_MANAGER, diff --git a/src/routes/projects/list.js b/src/routes/projects/list.js index 8ca1279a..e7ebf108 100755 --- a/src/routes/projects/list.js +++ b/src/routes/projects/list.js @@ -60,7 +60,14 @@ const SUPPORTED_FILTERS = [ 'directProjectId', ]; -const escapeEsKeyword = keyword => keyword.replace(/[+-=> keyword.replace(/[+-=> { let should = [ @@ -426,7 +433,7 @@ const parseElasticSearchCriteria = (criteria, fields, order) => { if (!keyword) { // Not a specific field search nor an exact phrase search, do a wildcard match - keyword = criteria.filters.keyword; + keyword = escapeEsKeyword(keywordCriterion); matchType = MATCH_TYPE_WILDCARD; } diff --git a/src/routes/projects/list.spec.js b/src/routes/projects/list.spec.js index 9ebb3e13..60773813 100644 --- a/src/routes/projects/list.spec.js +++ b/src/routes/projects/list.spec.js @@ -21,7 +21,7 @@ const data = [ type: 'generic', billingAccountId: 1, name: 'test1', - description: 'test project1', + description: 'test project1 abc/d', status: 'active', details: { utm: { @@ -160,7 +160,7 @@ const data = [ role: 'manager', firstName: 'first', lastName: 'last', - handle: 'manager_handle', + handle: 'MANAGER_HANDLE', isPrimary: true, createdBy: 1, updatedBy: 1, @@ -723,7 +723,7 @@ describe('LIST Project', () => { }); }); - it('should return all projects that match when filtering by customer handle', (done) => { + it('should return all projects that match when filtering by customer handle (lowercase)', (done) => { request(server) .get('/v5/projects/?customer=*tourist*') .set({ @@ -746,7 +746,53 @@ describe('LIST Project', () => { }); }); - it('should return all projects that match when filtering by manager handle', (done) => { + it('should return all projects that match when filtering by customer handle (uppercase)', (done) => { + request(server) + .get('/v5/projects/?customer=*TOUR*') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(200) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body; + should.exist(resJson); + resJson.should.have.lengthOf(1); + resJson[0].name.should.equal('test1'); + resJson[0].members.should.have.deep.property('[0].role', 'customer'); + resJson[0].members[0].userId.should.equal(40051331); + done(); + } + }); + }); + + it('should return all projects that match when filtering by customer handle (mixed case)', (done) => { + request(server) + .get('/v5/projects/?customer=*tOURiS*') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(200) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body; + should.exist(resJson); + resJson.should.have.lengthOf(1); + resJson[0].name.should.equal('test1'); + resJson[0].members.should.have.deep.property('[0].role', 'customer'); + resJson[0].members[0].userId.should.equal(40051331); + done(); + } + }); + }); + + it('should return all projects that match when filtering by manager handle (lowercase)', (done) => { request(server) .get('/v5/projects/?manager=*_handle') .set({ @@ -769,6 +815,52 @@ describe('LIST Project', () => { }); }); + it('should return all projects that match when filtering by manager handle (uppercase)', (done) => { + request(server) + .get('/v5/projects/?manager=MANAG*') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(200) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body; + should.exist(resJson); + resJson.should.have.lengthOf(1); + resJson[0].name.should.equal('test3'); + resJson[0].members.should.have.deep.property('[0].role', 'manager'); + resJson[0].members[0].userId.should.equal(40051334); + done(); + } + }); + }); + + it('should return all projects that match when filtering by manager handle (mixed case)', (done) => { + request(server) + .get('/v5/projects/?manager=*_HAndLe') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(200) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body; + should.exist(resJson); + resJson.should.have.lengthOf(1); + resJson[0].name.should.equal('test3'); + resJson[0].members.should.have.deep.property('[0].role', 'manager'); + resJson[0].members[0].userId.should.equal(40051334); + done(); + } + }); + }); + it('should return all projects that match when filtering by manager, searching on any non-customer role', (done) => { request(server) .get('/v5/projects/?manager=copi*') @@ -1065,7 +1157,7 @@ describe('LIST Project', () => { resJson.should.have.lengthOf(1); resJson[0].should.have.property('description'); resJson[0].should.not.have.property('cancelReason'); - resJson[0].description.should.be.eq('test project1'); + resJson[0].description.should.be.eq('test project1 abc/d'); done(); } }); @@ -1244,6 +1336,46 @@ describe('LIST Project', () => { } }); }); + + it('should find a project by quoted keyword with a special symbol in the name', (done) => { + request(server) + .get('/v5/projects/?keyword="abc/d"') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(200) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body; + should.exist(resJson); + resJson.should.have.lengthOf(1); + done(); + } + }); + }); + + it('should find a project by keyword with a special symbol in the name', (done) => { + request(server) + .get('/v5/projects/?keyword=abc/d') + .set({ + Authorization: `Bearer ${testUtil.jwts.admin}`, + }) + .expect('Content-Type', /json/) + .expect(200) + .end((err, res) => { + if (err) { + done(err); + } else { + const resJson = res.body; + should.exist(resJson); + resJson.should.have.lengthOf(1); + done(); + } + }); + }); }); }); }); diff --git a/src/utils/es-config.js b/src/utils/es-config.js index 657add4b..c8e1be8a 100644 --- a/src/utils/es-config.js +++ b/src/utils/es-config.js @@ -241,7 +241,6 @@ MAPPINGS[ES_PROJECT_INDEX] = { }, handle: { type: 'string', - index: 'not_analyzed', }, id: { type: 'long',