diff --git a/server/src/main/java/com/objectcomputing/checkins/services/feedback/suggestions/FeedbackSuggestionDTO.java b/server/src/main/java/com/objectcomputing/checkins/services/feedback/suggestions/FeedbackSuggestionDTO.java index ff60576386..b76c0db2fc 100644 --- a/server/src/main/java/com/objectcomputing/checkins/services/feedback/suggestions/FeedbackSuggestionDTO.java +++ b/server/src/main/java/com/objectcomputing/checkins/services/feedback/suggestions/FeedbackSuggestionDTO.java @@ -1,10 +1,9 @@ package com.objectcomputing.checkins.services.feedback.suggestions; -import com.sun.istack.Nullable; +import io.micronaut.core.annotation.Nullable; import java.util.Objects; import java.util.UUID; -import javax.validation.constraints.NotNull; public class FeedbackSuggestionDTO { diff --git a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplate.java b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplate.java index c9525621e8..9fb575f7ef 100644 --- a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplate.java +++ b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplate.java @@ -55,19 +55,27 @@ public class FeedbackTemplate { @Schema(description = "whether or not the template is allowed to be used for a feedback request", required = true) private Boolean active; + @Column(name = "is_public") + @NotBlank + @TypeDef(type = DataType.BOOLEAN) + @Schema(description = "whether the template is accessible to everyone or just the creator", required = true) + private Boolean isPublic; + /** * Constructs a new {@link FeedbackTemplate} to save * * @param title The title of the template * @param description An optional description of the template * @param creatorId The {@link UUID} of the user who created the template + * @param isPublic Whether the template is public or private */ - public FeedbackTemplate(String title, @Nullable String description, UUID creatorId) { + public FeedbackTemplate(String title, @Nullable String description, UUID creatorId, Boolean isPublic) { this.id = null; this.title = title; this.description = description; this.creatorId = creatorId; this.active = true; + this.isPublic = isPublic; } /** @@ -132,6 +140,14 @@ public void setActive(Boolean active) { this.active = active; } + public void setIsPublic(Boolean isPublic) { + this.isPublic = isPublic; + } + + public Boolean getIsPublic() { + return isPublic; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -142,12 +158,13 @@ public boolean equals(Object o) { Objects.equals(description, that.description) && Objects.equals(creatorId, that.creatorId) && Objects.equals(dateCreated, that.dateCreated) && - Objects.equals(active, that.active); + Objects.equals(active, that.active) && + Objects.equals(isPublic, that.isPublic); } @Override public int hashCode() { - return Objects.hash(id, title, description, creatorId, dateCreated, active); + return Objects.hash(id, title, description, creatorId, dateCreated, active, isPublic); } @Override @@ -159,6 +176,7 @@ public String toString() { ", creatorId=" + creatorId + ", dateCreated=" + dateCreated + ", active=" + active + + ", isPublic=" + isPublic + '}'; } } diff --git a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateController.java b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateController.java index 1ef03e9b56..a58ad53e03 100644 --- a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateController.java +++ b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateController.java @@ -123,7 +123,7 @@ public Single>> findByValues(@Nul * @return {@link FeedbackTemplate} */ private FeedbackTemplate fromDTO(FeedbackTemplateCreateDTO dto) { - return new FeedbackTemplate(dto.getTitle(), dto.getDescription(), dto.getCreatorId()); + return new FeedbackTemplate(dto.getTitle(), dto.getDescription(), dto.getCreatorId(), dto.getIsPublic()); } /** @@ -148,6 +148,7 @@ private FeedbackTemplateResponseDTO fromEntity(FeedbackTemplate feedbackTemplate dto.setCreatorId(feedbackTemplate.getCreatorId()); dto.setDateCreated(feedbackTemplate.getDateCreated()); dto.setActive(feedbackTemplate.getActive()); + dto.setIsPublic(feedbackTemplate.getIsPublic()); return dto; } diff --git a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateCreateDTO.java b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateCreateDTO.java index 06770684f4..a5a729cabe 100644 --- a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateCreateDTO.java +++ b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateCreateDTO.java @@ -26,6 +26,10 @@ public class FeedbackTemplateCreateDTO { @Schema(description = "whether or not the template is allowed to be used for a feedback request", required = true) private Boolean active; + @NotBlank + @Schema(description = "whether the template is accessible to everyone or just the creator", required = true) + private Boolean isPublic; + public String getTitle() { return title; } @@ -58,4 +62,12 @@ public Boolean getActive() { public void setActive(Boolean active) { this.active = active; } + + public void setIsPublic(Boolean isPublic) { + this.isPublic = isPublic; + } + + public Boolean getIsPublic() { + return isPublic; + } } diff --git a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateResponseDTO.java b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateResponseDTO.java index 4175c4ab43..180f985485 100644 --- a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateResponseDTO.java +++ b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateResponseDTO.java @@ -35,6 +35,10 @@ public class FeedbackTemplateResponseDTO { @Schema(description = "whether or not the template is allowed to be used for a feedback request", required = true) private Boolean active; + @NotBlank + @Schema(description = "whether the template is accessible to everyone or just the creator", required = true) + private Boolean isPublic; + public UUID getId() { return id; } @@ -83,4 +87,12 @@ public Boolean getActive() { public void setActive(Boolean active) { this.active = active; } + + public Boolean getIsPublic() { + return isPublic; + } + + public void setIsPublic(Boolean isPublic) { + this.isPublic = isPublic; + } } diff --git a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateServicesImpl.java b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateServicesImpl.java index 53116f4c9f..20b5b07249 100644 --- a/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateServicesImpl.java +++ b/server/src/main/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateServicesImpl.java @@ -7,10 +7,10 @@ import com.objectcomputing.checkins.services.memberprofile.currentuser.CurrentUserServices; import com.objectcomputing.checkins.util.Util; import io.micronaut.core.annotation.Nullable; - import javax.inject.Singleton; import javax.validation.constraints.NotNull; import java.util.*; +import java.util.stream.Collectors; @Singleton public class FeedbackTemplateServicesImpl implements FeedbackTemplateServices { @@ -54,6 +54,7 @@ public FeedbackTemplate update(FeedbackTemplate feedbackTemplate) { feedbackTemplate.setTitle(originalTemplate.get().getTitle()); feedbackTemplate.setDescription(originalTemplate.get().getDescription()); feedbackTemplate.setDateCreated(originalTemplate.get().getDateCreated()); + feedbackTemplate.setIsPublic(originalTemplate.get().getIsPublic()); if (!updateIsPermitted(originalTemplate.get().getCreatorId())) { throw new PermissionException("You are not authorized to do this operation"); @@ -82,23 +83,26 @@ public FeedbackTemplate getById(UUID id) { throw new NotFoundException("No feedback template with ID " + id); } - return feedbackTemplate.get(); } @Override public List findByFields(@Nullable UUID creatorId, @Nullable String title) { - return feedbackTemplateRepository.searchByValues(Util.nullSafeUUIDToString(creatorId), title); + UUID currentUserId = currentUserServices.getCurrentUser().getId(); + boolean isAdmin = currentUserServices.isAdmin(); + List allTemplates = feedbackTemplateRepository.searchByValues(Util.nullSafeUUIDToString(creatorId), title); + return allTemplates + .stream() + .filter(template -> template.getIsPublic() || isAdmin || template.getCreatorId().equals(currentUserId)) + .collect(Collectors.toList()); } - public boolean updateIsPermitted(UUID creatorId) { UUID currentUserId = currentUserServices.getCurrentUser().getId(); boolean isAdmin = currentUserServices.isAdmin(); return isAdmin || currentUserId.equals(creatorId); } - public boolean deleteIsPermitted(UUID creatorId) { return updateIsPermitted(creatorId); } diff --git a/server/src/main/resources/db/common/V90__alter_feedback_templates_table.sql b/server/src/main/resources/db/common/V90__alter_feedback_templates_table.sql new file mode 100644 index 0000000000..54eea1e9e8 --- /dev/null +++ b/server/src/main/resources/db/common/V90__alter_feedback_templates_table.sql @@ -0,0 +1,2 @@ +ALTER TABLE feedback_templates +ADD COLUMN is_public boolean; \ No newline at end of file diff --git a/server/src/main/resources/db/dev/R__Load_testing_data.sql b/server/src/main/resources/db/dev/R__Load_testing_data.sql index 5295b18006..2084831d2b 100644 --- a/server/src/main/resources/db/dev/R__Load_testing_data.sql +++ b/server/src/main/resources/db/dev/R__Load_testing_data.sql @@ -409,9 +409,9 @@ VALUES ('cda41eed-70ea-4d3f-a9d7-cd0c5158eb5f', '2021-01-29', '2021-02-02', '8fa673c0-ca19-4271-b759-41cb9db2e83a', PGP_SYM_ENCRYPT('Feeling pretty happy','${aeskey}'), PGP_SYM_ENCRYPT('Feeling really good','${aeskey}')); INSERT INTO feedback_templates -(id, creator_id, title, description, date_created, updater_id, date_updated) +(id, creator_id, title, description, date_created, updater_id, date_updated, is_public, active) VALUES -('18ef2032-c264-411e-a8e1-ddda9a714bae', '6207b3fd-042d-49aa-9e28-dcc04f537c2d', 'Q1 Feedback', 'Get feedback for quarter 1', '2021-06-06', null, null); +('18ef2032-c264-411e-a8e1-ddda9a714bae', '6207b3fd-042d-49aa-9e28-dcc04f537c2d', 'Q1 Feedback', 'Get feedback for quarter 1', '2021-06-06', null, null, true, true); INSERT INTO template_questions (id, question, template_id, question_number) @@ -424,9 +424,9 @@ VALUES ('47f997ca-0045-4147-afcb-0c9ed0b44978', 'In what ways are this team member''s contributions impacting the objectives of the organization, their project, or their team?', '18ef2032-c264-411e-a8e1-ddda9a714bae', 2); INSERT INTO feedback_templates -(id, creator_id, title, description, date_created, updater_id, date_updated) +(id, creator_id, title, description, date_created, updater_id, date_updated, is_public, active) VALUES -('97b0a312-e5dd-46f4-a600-d8be2ad925bb', '01b7d769-9fa2-43ff-95c7-f3b950a27bf9', 'Survey 1', 'Make a survey with a few questions', '2021-05-05', null, null); +('97b0a312-e5dd-46f4-a600-d8be2ad925bb', '01b7d769-9fa2-43ff-95c7-f3b950a27bf9', 'Survey 1', 'Make a survey with a few questions', '2021-05-05', null, null, true, true); INSERT INTO template_questions (id, question, template_id, question_number) @@ -439,9 +439,19 @@ VALUES ('afa7e2cb-366a-4c16-a205-c0d493b80d85', 'In what ways does this team member represent OCI''s values?', '97b0a312-e5dd-46f4-a600-d8be2ad925bb', 2); INSERT INTO feedback_templates -(id, creator_id, title, description, date_created, updater_id, date_updated) +(id, creator_id, title, description, date_created, updater_id, date_updated, is_public, active) VALUES -('2cb80a06-e723-482f-af9b-6b9516cabfcd', '2559a257-ae84-4076-9ed4-3820c427beeb', 'Sample Template', 'This template does not have any questions on it', '2020-04-04', null, null); +('2cb80a06-e723-482f-af9b-6b9516cabfcd', '2559a257-ae84-4076-9ed4-3820c427beeb', 'Sample Template', 'This template does not have any questions on it', '2020-04-04', null, null, true, true); + +INSERT INTO feedback_templates +(id, creator_id, title, description, date_created, updater_id, date_updated, is_public, active) +VALUES +('492e4f61-c7e3-4c30-a650-7ec74f2ba545', '7a6a2d4e-e435-4ec9-94d8-f1ed7c779498', 'Private template', 'This template is private', '2020-06-07', null, null, false, true); + +INSERT INTO feedback_templates +(id, creator_id, title, description, date_created, updater_id, date_updated, is_public, active) +VALUES +('c5d10880-f561-11eb-9a03-0242ac130003', '7a6a2d4e-e435-4ec9-94d8-f1ed7c779498', 'Private template 2', 'This template is private 2', '2020-06-10', null, null, false, true); INSERT INTO feedback_requests (id, creator_id, requestee_id, recipient_id, template_id, send_date, due_date, submit_date, status) diff --git a/server/src/test/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateControllerTest.java b/server/src/test/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateControllerTest.java index 6baa21475b..361c10f6d4 100644 --- a/server/src/test/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateControllerTest.java +++ b/server/src/test/java/com/objectcomputing/checkins/services/feedback_template/FeedbackTemplateControllerTest.java @@ -77,6 +77,7 @@ FeedbackTemplateCreateDTO createDTO(FeedbackTemplate feedbackTemplate) { dto.setTitle(feedbackTemplate.getTitle()); dto.setDescription(feedbackTemplate.getDescription()); dto.setCreatorId(feedbackTemplate.getCreatorId()); + dto.setIsPublic(feedbackTemplate.getIsPublic()); return dto; } @@ -97,6 +98,7 @@ void assertContentEqualsEntity(FeedbackTemplate content, FeedbackTemplateRespons assertEquals(content.getDescription(), dto.getDescription()); assertEquals(content.getCreatorId(), dto.getCreatorId()); assertEquals(content.getActive(), dto.getActive()); + assertEquals(content.getIsPublic(), dto.getIsPublic()); } void assertUnauthorized(HttpClientResponseException exception) { @@ -451,6 +453,71 @@ void testGetByTitleAndCreatedByUnauthorized() { assertUnauthorized(exception); } + @Test + void testGetPrivateTemplateByAdmin() { + final MemberProfile admin = createADefaultMemberProfile(); + final MemberProfile memberOne = createASecondDefaultMemberProfile(); + createDefaultAdminRole(admin); + + final FeedbackTemplate privateTemplate = createFeedbackTemplate(memberOne.getId()); + privateTemplate.setIsPublic(false); + getFeedbackTemplateRepository().save(privateTemplate); + final FeedbackTemplate publicTemplate = saveAnotherDefaultFeedbackTemplate(memberOne.getId()); + + final HttpRequest request = HttpRequest.GET("/") + .basicAuth(admin.getWorkEmail(), RoleType.Constants.ADMIN_ROLE); + final HttpResponse> response = client.toBlocking() + .exchange(request, Argument.listOf(FeedbackTemplateResponseDTO.class)); + + assertTrue(response.getBody().isPresent()); + assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals(2, response.getBody().get().size()); + assertContentEqualsEntity(privateTemplate, response.getBody().get().get(0)); + assertContentEqualsEntity(publicTemplate, response.getBody().get().get(1)); + } + + @Test + void testGetPrivateTemplateByCreator() { + final MemberProfile memberOne = createASecondDefaultMemberProfile(); + + final FeedbackTemplate privateTemplate = createFeedbackTemplate(memberOne.getId()); + privateTemplate.setIsPublic(false); + getFeedbackTemplateRepository().save(privateTemplate); + final FeedbackTemplate publicTemplate = saveAnotherDefaultFeedbackTemplate(memberOne.getId()); + + final HttpRequest request = HttpRequest.GET("/") + .basicAuth(memberOne.getWorkEmail(), RoleType.Constants.MEMBER_ROLE); + final HttpResponse> response = client.toBlocking() + .exchange(request, Argument.listOf(FeedbackTemplateResponseDTO.class)); + + assertTrue(response.getBody().isPresent()); + assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals(2, response.getBody().get().size()); + assertContentEqualsEntity(privateTemplate, response.getBody().get().get(0)); + assertContentEqualsEntity(publicTemplate, response.getBody().get().get(1)); + } + + @Test + void testGetPrivateTemplateNotPermitted() { + final MemberProfile memberOne = createASecondDefaultMemberProfile(); + final MemberProfile random = createAnUnrelatedUser(); + + final FeedbackTemplate privateTemplate = createFeedbackTemplate(memberOne.getId()); + privateTemplate.setIsPublic(false); + getFeedbackTemplateRepository().save(privateTemplate); + final FeedbackTemplate publicTemplate = saveAnotherDefaultFeedbackTemplate(memberOne.getId()); + + final HttpRequest request = HttpRequest.GET("/") + .basicAuth(random.getWorkEmail(), RoleType.Constants.MEMBER_ROLE); + final HttpResponse> response = client.toBlocking() + .exchange(request, Argument.listOf(FeedbackTemplateResponseDTO.class)); + + assertTrue(response.getBody().isPresent()); + assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals(1, response.getBody().get().size()); + assertContentEqualsEntity(publicTemplate, response.getBody().get().get(0)); + } + @Test void testDeleteValidAuthorized() { final MemberProfile memberOne = createADefaultMemberProfile(); diff --git a/server/src/test/java/com/objectcomputing/checkins/services/fixture/FeedbackTemplateFixture.java b/server/src/test/java/com/objectcomputing/checkins/services/fixture/FeedbackTemplateFixture.java index c9ca67f17c..8fc975a322 100644 --- a/server/src/test/java/com/objectcomputing/checkins/services/fixture/FeedbackTemplateFixture.java +++ b/server/src/test/java/com/objectcomputing/checkins/services/fixture/FeedbackTemplateFixture.java @@ -7,18 +7,18 @@ public interface FeedbackTemplateFixture extends RepositoryFixture{ default FeedbackTemplate createFeedbackTemplate(UUID creatorId) { - return new FeedbackTemplate("Fake Title", "Fake Title Description amazing feedback template", creatorId); + return new FeedbackTemplate("Fake Title", "Fake Title Description amazing feedback template", creatorId, true); } default FeedbackTemplate createAnotherFeedbackTemplate(UUID creatorId) { - return new FeedbackTemplate( "Fake Title 2", "Fake Title Private Description amazing feedback template 2", creatorId); + return new FeedbackTemplate( "Fake Title 2", "Fake Title Private Description amazing feedback template 2", creatorId,true); } default FeedbackTemplate createAThirdFeedbackTemplate(UUID creatorId) { - return new FeedbackTemplate( "Something completely different", "Fake Title Private Description amazing feedback template 3", creatorId); + return new FeedbackTemplate( "Something completely different", "Fake Title Private Description amazing feedback template 3", creatorId, true); } default FeedbackTemplate saveFeedbackTemplate(UUID creatorId) { - return getFeedbackTemplateRepository().save(new FeedbackTemplate("Sample Template", "A saved feedback template", creatorId)); + return getFeedbackTemplateRepository().save(new FeedbackTemplate("Sample Template", "A saved feedback template", creatorId, true)); } } diff --git a/web-ui/src/api/feedbacktemplate.js b/web-ui/src/api/feedbacktemplate.js index 750d900299..2b40cd06a7 100644 --- a/web-ui/src/api/feedbacktemplate.js +++ b/web-ui/src/api/feedbacktemplate.js @@ -113,6 +113,10 @@ export const getFeedbackTemplateWithQuestions = async (templateId, cookie) => { export const getAllFeedbackTemplates = async (cookie) => { return resolve({ url: feedbackTemplateUrl, + params: { + creatorId: null, + title: null + }, responseType: "json", headers: { "X-CSRF-Header": cookie }, });