diff --git a/dashboard/src/components/skills/selfReport/RejectSkillModal.vue b/dashboard/src/components/skills/selfReport/ApproveOrRejectSkillModal.vue similarity index 97% rename from dashboard/src/components/skills/selfReport/RejectSkillModal.vue rename to dashboard/src/components/skills/selfReport/ApproveOrRejectSkillModal.vue index 79ffe3945..5b5338df8 100644 --- a/dashboard/src/components/skills/selfReport/RejectSkillModal.vue +++ b/dashboard/src/components/skills/selfReport/ApproveOrRejectSkillModal.vue @@ -48,9 +48,9 @@ const initialData = { const schema = object({ 'approvalRequiredMsg': string() .trim() - .customDescriptionValidator('Rejection Message') + .customDescriptionValidator('Message') .max(appConfig.maxSelfReportRejectionMessageLength) - .label('Rejection Message') + .label('Message') }) const rejectOrApproveSkills = (values) => { const ids = props.selectedItems.map((item) => item.id); diff --git a/dashboard/src/components/skills/selfReport/SelfReportApproval.vue b/dashboard/src/components/skills/selfReport/SelfReportApproval.vue index 4f9797e54..59bec7e1f 100644 --- a/dashboard/src/components/skills/selfReport/SelfReportApproval.vue +++ b/dashboard/src/components/skills/selfReport/SelfReportApproval.vue @@ -21,7 +21,7 @@ import SelfReportService from '@/components/skills/selfReport/SelfReportService' import SkillsDataTable from "@/components/utils/table/SkillsDataTable.vue"; import DateCell from "@/components/utils/table/DateCell.vue"; import MarkdownText from '@/common-components/utilities/markdown/MarkdownText.vue' -import RejectSkillModal from "@/components/skills/selfReport/RejectSkillModal.vue"; +import RejectSkillModal from "@/components/skills/selfReport/ApproveOrRejectSkillModal.vue"; import { useColors } from '@/skills-display/components/utilities/UseColors.js' import { useResponsiveBreakpoints } from '@/components/utils/misc/UseResponsiveBreakpoints.js' import { useAppInfoState } from '@/stores/UseAppInfoState.js' diff --git a/e2e-tests/cypress/e2e/community/community_proj_description_validation_specs.js b/e2e-tests/cypress/e2e/community/community_proj_description_validation_specs.js index d3b5dc043..a276fa7c8 100644 --- a/e2e-tests/cypress/e2e/community/community_proj_description_validation_specs.js +++ b/e2e-tests/cypress/e2e/community/community_proj_description_validation_specs.js @@ -170,7 +170,71 @@ describe('Community Project Creation Tests', () => { cy.get('[data-cy="saveDialogBtn"]').should('be.enabled'); }); - it('self report reject messages are validated against custom validators', () => { + it('self report approval messages are validated against custom validators', () => { + cy.intercept('POST', '/admin/projects/proj1/approvals/approve').as('approve'); + cy.createProject(1, {enableProtectedUserCommunity: true}) + cy.createSubject(1, 1); + cy.createSkill(1, 1, 1, { selfReportingType: 'Approval' }); + cy.createSkill(1, 1, 2, { selfReportingType: 'Approval' }); + cy.createSkill(1, 1, 3, { selfReportingType: 'Approval' }); + cy.reportSkill(1, 2, 'user2', '2020-09-16 11:00'); + cy.reportSkill(1, 3, 'user1', '2020-09-17 11:00'); + cy.reportSkill(1, 1, 'user0', '2020-09-18 11:00'); + + cy.visit('/administrator/projects/proj1/self-report'); + + const tableSelector = '[data-cy="skillsReportApprovalTable"]'; + cy.validateTable(tableSelector, [ + [{ + colIndex: 2, + value: 'user0' + }], + [{ + colIndex: 2, + value: 'user1' + }], + [{ + colIndex: 2, + value: 'user2' + }], + ]); + + cy.get('[data-cy="approveBtn"]').should('be.disabled'); + cy.get('[data-cy="rejectBtn"]').should('be.disabled'); + // cy.get('[data-cy="approvalSelect_user1-skill3"]').click({ force: true }); + cy.get('[data-cy="skillsReportApprovalTable"] [data-p-index="1"] [data-pc-name="rowcheckbox"]').click() + cy.get('[data-cy="approveBtn"]').should('be.enabled'); + cy.get('[data-cy="rejectBtn"]').should('be.enabled'); + + cy.get('[data-cy="approveBtn"]').click(); + cy.get('[data-cy="approvalTitle"]').contains('This will approve user\'s request(s) to get points'); + cy.get('[data-cy="approvalInputMsg"]').type('ldkj aljdl aj\n\njabberwocky'); + cy.get('[data-cy="approvalRequiredMsgError"]').should('not.be.visible') + cy.get('[data-cy="saveDialogBtn"]').should('be.enabled') + + cy.get('[data-cy="approvalInputMsg"]').clear().type('ldkj aljdl aj\n\ndivinedragon'); + cy.get('[data-cy="approvalRequiredMsgError"]').contains('Message - May not contain divinedragon word'); + cy.get('[data-cy="saveDialogBtn"]').should('be.disabled'); + + cy.get('[data-cy="approvalInputMsg"]').type('{backspace}'); + cy.get('[data-cy="saveDialogBtn"]').should('be.enabled'); + cy.get('[data-cy="saveDialogBtn"]').click(); + + cy.wait('@approve'); + + cy.validateTable(tableSelector, [ + [{ + colIndex: 2, + value: 'user0' + }], + [{ + colIndex: 2, + value: 'user2' + }], + ]); + }); + + it.only('self report reject messages are validated against custom validators', () => { cy.intercept('POST', '/admin/projects/proj1/approvals/reject').as('reject'); cy.createProject(1, {enableProtectedUserCommunity: true}) cy.createSubject(1, 1); @@ -213,7 +277,7 @@ describe('Community Project Creation Tests', () => { cy.get('[data-cy="saveDialogBtn"]').should('be.enabled') cy.get('[data-cy="rejectionInputMsg"]').clear().type('ldkj aljdl aj\n\ndivinedragon'); - cy.get('[data-cy="approvalRequiredMsgError"]').contains('Rejection Message - May not contain divinedragon word'); + cy.get('[data-cy="approvalRequiredMsgError"]').contains('Message - May not contain divinedragon word'); cy.get('[data-cy="saveDialogBtn"]').should('be.disabled'); cy.get('[data-cy="rejectionInputMsg"]').type('{backspace}'); diff --git a/e2e-tests/cypress/e2e/self-report/selfReport-approveOrReject_spec.js b/e2e-tests/cypress/e2e/self-report/selfReport-approveOrReject_spec.js index ab46c2206..5e011028d 100644 --- a/e2e-tests/cypress/e2e/self-report/selfReport-approveOrReject_spec.js +++ b/e2e-tests/cypress/e2e/self-report/selfReport-approveOrReject_spec.js @@ -219,28 +219,28 @@ describe('Self Report Skills Management Tests', () => { cy.get('[data-cy="rejectionInputMsg"]') .type('y'); cy.get('[data-cy="approvalRequiredMsgError"]') - .contains('Rejection Message - paragraphs may not contain jabberwocky'); + .contains('Message - paragraphs may not contain jabberwocky'); cy.get('[data-cy="saveDialogBtn"]') .should('be.disabled'); cy.get('[data-cy="rejectionInputMsg"]') .type(' ok'); cy.get('[data-cy="approvalRequiredMsgError"]') - .contains('Rejection Message - paragraphs may not contain jabberwocky'); + .contains('Message - paragraphs may not contain jabberwocky'); cy.get('[data-cy="saveDialogBtn"]') .should('be.disabled'); cy.get('[data-cy="rejectionInputMsg"]') .type('{backspace}{backspace}{backspace}'); cy.get('[data-cy="approvalRequiredMsgError"]') - .contains('Rejection Message - paragraphs may not contain jabberwocky'); + .contains('Message - paragraphs may not contain jabberwocky'); cy.get('[data-cy="saveDialogBtn"]') .should('be.disabled'); cy.get('[data-cy="rejectionInputMsg"]') .type('{backspace}{backspace}'); cy.get('[data-cy="approvalRequiredMsgError"]') - .contains('Rejection Message - paragraphs may not contain jabberwocky') + .contains('Message - paragraphs may not contain jabberwocky') .should('not.exist'); cy.get('[data-cy="saveDialogBtn"]') .should('be.enabled'); @@ -426,7 +426,7 @@ describe('Self Report Skills Management Tests', () => { cy.get('[data-cy=rejectionInputMsg]') .fill(new Array(500).join('A')); cy.get('[data-cy=approvalRequiredMsgError]') - .contains('Rejection Message must be at most 250 characters') + .contains('Message must be at most 250 characters') .should('be.visible'); cy.get('[data-cy=saveDialogBtn]') .should('be.disabled'); diff --git a/service/src/test/java/skills/intTests/SkillApprovalSpecs.groovy b/service/src/test/java/skills/intTests/SkillApprovalSpecs.groovy index 8a85d60b0..ee79c7cc8 100644 --- a/service/src/test/java/skills/intTests/SkillApprovalSpecs.groovy +++ b/service/src/test/java/skills/intTests/SkillApprovalSpecs.groovy @@ -446,7 +446,6 @@ class SkillApprovalSpecs extends DefaultIntSpec { e.message.contains("Custom validation failed: msg=[paragraphs may not contain jabberwocky], type=[skillApprovalRejection], rejectionMsg=[Just jabberwocky felt like it]") } - void "validate approval message if 'paragraphValidationRegex' property is configured"() { String user = "user0" String user1 = "user1" diff --git a/service/src/test/java/skills/intTests/community/DescriptionValidatorCommunitySpecs.groovy b/service/src/test/java/skills/intTests/community/DescriptionValidatorCommunitySpecs.groovy index 6f8dfb14e..4e7aad2a3 100644 --- a/service/src/test/java/skills/intTests/community/DescriptionValidatorCommunitySpecs.groovy +++ b/service/src/test/java/skills/intTests/community/DescriptionValidatorCommunitySpecs.groovy @@ -19,6 +19,7 @@ import skills.intTests.utils.DefaultIntSpec import skills.intTests.utils.SkillsClientException import skills.intTests.utils.SkillsFactory import skills.intTests.utils.SkillsService +import skills.storage.model.SkillDef import static skills.intTests.utils.SkillsFactory.createProject @@ -321,6 +322,67 @@ class DescriptionValidatorCommunitySpecs extends DefaultIntSpec { communityValid.body.success } + def "skill approval message custom validation UC protected"(){ + List users = getRandomUsers(2) + Date date = new Date() - 60 + + SkillsService pristineDragonsUser = createService(users[1]) + SkillsService rootUser = createRootSkillService() + rootUser.saveUserTag(pristineDragonsUser.userName, 'dragons', ['DivineDragon']) + + def proj = SkillsFactory.createProject() + proj.enableProtectedUserCommunity = true + pristineDragonsUser.createProject(proj) + + def subj = SkillsFactory.createSubject() + pristineDragonsUser.createSubject(subj) + + def skill = SkillsFactory.createSkill() + skill.pointIncrement = 200 + skill.selfReportingType = SkillDef.SelfReportingType.Approval + pristineDragonsUser.createSkill(skill) + + when: + pristineDragonsUser.addSkill([projectId: proj.projectId, skillId: skill.skillId], users[0], date, "Please approve this!") + def approvalsEndpointRes = pristineDragonsUser.getApprovals(proj.projectId, 5, 1, 'requestedOn', false) + + List approvals = approvalsEndpointRes.data.sort({ it.userId }) + + pristineDragonsUser.approve(proj.projectId, [approvals[0].id], notValidProtectedCommunity) + + then: + def exception = thrown(SkillsClientException) + exception.message.contains("May not contain divinedragon word") + } + + def "skill approval message custom validation default protected"(){ + List users = getRandomUsers(2) + Date date = new Date() - 60 + + def proj = SkillsFactory.createProject() + skillsService.createProject(proj) + + def subj = SkillsFactory.createSubject() + skillsService.createSubject(subj) + + def skill = SkillsFactory.createSkill() + skill.pointIncrement = 200 + skill.selfReportingType = SkillDef.SelfReportingType.Approval + skillsService.createSkill(skill) + + when: + skillsService.addSkill([projectId: proj.projectId, skillId: skill.skillId], users[0], date, "Please approve this!") + def approvalsEndpointRes = skillsService.getApprovals(proj.projectId, 5, 1, 'requestedOn', false) + + List approvals = approvalsEndpointRes.data.sort({ it.userId }) + + skillsService.approve(proj.projectId, [approvals[0].id], notValidDefault) + + then: + def exception = thrown(SkillsClientException) + exception.message.contains("may not contain jabberwocky") + } + def "only community member can call description validator for community with useProtectedCommunityValidator"() { when: skillsService.checkCustomDescriptionValidation(notValidDefault, null, true)