From 4a546485220832ff910a5bc6f621cbfbe7d719fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Pereira?= <160126962+zPereiraa@users.noreply.github.com> Date: Sun, 14 Jul 2024 18:50:13 +0100 Subject: [PATCH] Remove Reports (Backend & Frontend) & Other Frontend Model Changes (#141) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(domain): implemented Edit Enrollment related issues: #28 * feat(service): implemented Edit Enrollment * feat(controller): implemented PUT related issues: #32 * feat: added update on participation.java * feat: added Update Participation Method Test Related: #52 * feat: added updateParticipation in ParticipationService.java Related: #48 * feat: added UpdateParticipation Service test Related: #50 * feat: added updateParticipation method in ParticipationController.java Related: #44 * feat: added UpdateParticipationWebServiceIT.groovy Related: #46 * feat: added deleteParticipation in ParticipationService.java Related: #49 * feat: added deleteParticipation method in ParticipationController.java Related: #45 * feat: added deleteParticipation Service test Related: #51 * feat: added deleteParticipation WebService Test Related: #47 * feat(domain test): implemented UpdateEnrollmentMethodTest * feat(Service Test): implemented UpdateEnrollmentServiceTest related issues: #40 * feat(domain): implemented Delete Enrollment and fix Edit Enrollment related issues: #28 #29 * feat(WebService Test): implemented UpdateEnrollmentWebServiceIT related issues: #38 * feat: added delete method in ParticipationService.java and updated necessary files to support delete operation Related: #43 * feat: added delete participation domain tests Related: #53 * feat(controller): implemented DELETE related issues: #33 * feat(domain): fix Delete and Edit related issues: #28 #29 * feat(Service): implemented Delete Enrollment related issues: #35 * feat(domain test): updated UpdateEnrollmentMethodTest related issues: #36 * feat(domain/serice/webservice tests): -implemented DeleteEnrollmentMethodTest -implemented DeleteEnrollmentServiceTest -updated UpdateEnrollmentServiceTest -implemented DeleteEnrollmentWebService related issues: #37 #39 #40 #41 * feat(): small changes in some files * feat(fix): small change * feat(fix): small changes * feat(fix): small changes * feat(fix): fix some errors * feat(fix): fix some erros * feat(domain/service tests): fix some errors relating issues: #37 #36 #35 #41 * feat(fix): small changes * fix: prevent unauthorized access in participation controller * fix update and remove participation access control * fix: fixed webservice tests * feat(domain/service/controller/tests): - changed EnrollmentController.java - implemented "ENROLLMENT.MANAGER" in HEPermissionEvaluator.java - changed Enrollment.java - some changes in UpdateEnrollmentMethodTest, UpdateEnrollmentServiceTest, DeleteEnrollmentWebServiceIT and UpdateEnrollmentWebServiceIT realted issues: #32 #33 #28 #29 #40 #36 * feat(domain): small changes * feat(button/view): - implemented EditEnrollment Button - implemented RemoveEnrollment Button - implemented VolunteerEnrollmentsView related issues: #71 #72 #70 * feat(End-to-End Tests): implemented Remove/Edit Enrollment End-to-End Tests realted issues: #74 #75 #76 #77 #78 * feat(fix): small changes * feat(fix): fix errors - changed assement End-to-End tests - changes in VolunteerEnrollmetView * small fixes * feat(domain/service/controller): - create the "report" entity - implemented condition: only a Volunteer can report - implemented constraint: this justification can only be readed by a Administrator - implemented condition: report is associated to the volunteer who reported - implemented condition: only can be reported until the end of the activity - implmented POST: createReport - implemented GET: getAdministratorReports related issues: #94 #95 #96 #97 #98 #99 #100 * feat(domain/service/controller Tests): - Test Domain: CreateReportMethodTest - Test Service: CreateReportServiceTest - Test WebService: CreateReportWebServiceIT related issues: #101 #102 #103 * Merge master into pereira * feat(fix): small change * feat(fix): small change * feat(Controller/Service/ Service Tests/WebServices Test): some changes -implement GetVolunteerReportsWebServiceIT -implement GetVolunteerReportsServicesTest -changes in RerportController and ReportService related issues: #119 #120 #100 * feat(fix): changes * feat(fix): changes * feat(fix): changes * feat(fix): some changes * feat(fix): some changes * feat(Controller/Service/Service Test/WebServiceTest): -implemented GET: getActivtyReports -implemented Service: getReportsByActivity -implemented GetReportsByActivityServiceTest -implemented GetReportsByActivityWebServiceTest related issues: #121 #122 #123 * feat(fix): small change * feat(fix): fix errors * feat(button/view/dialog): - implemented Report Activity - implemented constraint: Report Button only exist until the activity end - implemented Report Dialog related issues: #125 #126 #127 * feat(button/view/dialog): - implemented button "REPORTED" - implemented Dialog to see all Activtiy Reports related issues: #130 #131 * feat(End-to-End Tests): - implemented Test: report an activity - implemented Test: Admin reads the Activity Reports related issues: #128 #129 * feat(domain / service / controller): - implemented Functionality: volunteer remove a report - implmented DELETE Controller - implemented Service Remove related issues: #135 #136 #137 * feat(Domain Test / Service Test/ WebService Test): - implemented domain test - implementeed service test - implemented webservice test related issues: #138 #139 #140 * feat(fix): changes * feat(Controller / WebService Test): some changes in the validate activtiy * feat(Controller / Service): - implemented Controller: getVolunteerReportsAsVolunteer - implemented Service: getVolunteerReportsAsVolunteer related issues: #142 #143 * feat(button): - implemented RemoveReport Button related issue: #144 * feat(frontend model): - Modify text boxes related issue: #145 * feat(frontend model): - in the VolunteerViews when the mouse go over "REPORTED" appears the justification - modify the "REPORTED" button in tje AdminActivitiesView related issues: #146 #147 * feat(End-to-End Tests): - remove a report from an activity related issues: #148 #149 --------- Co-authored-by: Andre Gamito Co-authored-by: André Pereira Co-authored-by: Antonio Rito Silva --- .../activity/ActivityController.java | 2 +- .../activity/domain/Activity.java | 4 + .../config/HEPermissionEvaluator.java | 8 ++ .../humanaethica/exceptions/ErrorMessage.java | 1 + .../humanaethica/report/ReportController.java | 16 +++ .../humanaethica/report/ReportService.java | 27 ++++ .../humanaethica/report/domain/Report.java | 14 ++ .../humanaethica/user/domain/Volunteer.java | 8 ++ .../ValidateActivityWebServiceIT.groovy | 28 +++- .../domain/DeleteReportMethodTest.groovy | 99 ++++++++++++++ .../service/DeleteReportServiceTest.groovy | 124 ++++++++++++++++++ .../DeleteReportWebServiceIT.groovy | 118 +++++++++++++++++ frontend/src/services/RemoteServices.ts | 24 ++++ .../src/views/admin/AdminActivitiesView.vue | 3 +- .../src/views/volunteer/EnrollmentDialog.vue | 6 +- frontend/src/views/volunteer/ReportDialog.vue | 6 +- .../volunteer/VolunteerActivitiesView.vue | 100 +++++++++++++- .../volunteer/VolunteerEnrollmentsView.vue | 102 +++++++++++++- frontend/tests/e2e/specs/reports/reports.js | 38 ++++++ 19 files changed, 714 insertions(+), 14 deletions(-) create mode 100644 backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/DeleteReportMethodTest.groovy create mode 100644 backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/service/DeleteReportServiceTest.groovy create mode 100644 backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/webservice/DeleteReportWebServiceIT.groovy diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/ActivityController.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/ActivityController.java index 2d576393..1160daa1 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/ActivityController.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/ActivityController.java @@ -53,7 +53,7 @@ public ActivityDto suspendActivity(Principal principal, @PathVariable Integer ac } @PutMapping("/{activityId}/validate") - @PreAuthorize("hasRole('ROLE_ADMIN')") + @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_VOLUNTEER')") public ActivityDto validateActivity(@PathVariable int activityId) { return activityService.validateActivity(activityId); } diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/domain/Activity.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/domain/Activity.java index 81b6244b..1df94bfb 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/domain/Activity.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/domain/Activity.java @@ -246,6 +246,10 @@ public void addReport(Report report) { this.reports.add(report); } + public void removeReport(Report report) { + this.reports.remove(report); + } + public void validate() { activityAndThemesMustBeApproved(); diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/config/HEPermissionEvaluator.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/config/HEPermissionEvaluator.java index 76c8bc90..71d2e051 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/config/HEPermissionEvaluator.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/config/HEPermissionEvaluator.java @@ -13,6 +13,8 @@ import pt.ulisboa.tecnico.socialsoftware.humanaethica.participation.domain.Participation; import pt.ulisboa.tecnico.socialsoftware.humanaethica.enrollment.domain.Enrollment; import pt.ulisboa.tecnico.socialsoftware.humanaethica.enrollment.EnrollmentRepository; +import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.domain.Report; +import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.ReportRepository; import pt.ulisboa.tecnico.socialsoftware.humanaethica.user.domain.Member; import pt.ulisboa.tecnico.socialsoftware.humanaethica.user.domain.Volunteer; @@ -29,6 +31,8 @@ public class HEPermissionEvaluator implements PermissionEvaluator { private EnrollmentRepository enrollmentRepository; @Autowired private AssessmentRepository assessmentRepository; + @Autowired + private ReportRepository reportRepository; @Override @@ -51,6 +55,10 @@ public boolean hasPermission(Authentication authentication, Object targetDomainO Enrollment enrollment = enrollmentRepository.findById(id).orElse(null); if (enrollment == null) return false; return enrollment.getVolunteer().getId().equals(((Volunteer)authUser.getUser()).getId()); + case "REPORT.MANAGER": + Report report = reportRepository.findById(id).orElse(null); + if (report == null) return false; + return report.getVolunteer().getId().equals(((Volunteer)authUser.getUser()).getId()); case "ASSESSMENT.WRITER": Assessment assessment = assessmentRepository.findById(id).orElse(null); if (assessment == null) return false; diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/exceptions/ErrorMessage.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/exceptions/ErrorMessage.java index 18a803c3..3bfe2d69 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/exceptions/ErrorMessage.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/exceptions/ErrorMessage.java @@ -65,6 +65,7 @@ public enum ErrorMessage { REPORT_REQUIRES_JUSTIFICATION("To do a report have to write a justification shorter than 256 characters"), REPORT_ACTIVTIY_IS_ALREADY_REPORTED("The activity is already reported"), REPORT_AFTER_ACTIVTY_CLOSED("The activity period is already closed"), + REPORT_NOT_FOUND("Report not found with id %d"), ; public final String label; diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportController.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportController.java index 2feb9740..ab26a6f3 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportController.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportController.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.*; import pt.ulisboa.tecnico.socialsoftware.humanaethica.auth.domain.AuthUser; +import pt.ulisboa.tecnico.socialsoftware.humanaethica.enrollment.dto.EnrollmentDto; import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.ReportService; import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.dto.ReportDto; import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.dto.ReportDto; @@ -38,6 +39,21 @@ public ReportDto createReport(Principal principal, @PathVariable Integer activit int userId = ((AuthUser) ((Authentication) principal).getPrincipal()).getUser().getId(); return reportService.createReport(userId, activityId, reportDto); } + + @DeleteMapping("/reports/{reportId}") + @PreAuthorize("(hasRole('ROLE_VOLUNTEER')) and hasPermission(#reportId, 'REPORT.MANAGER')") + public ReportDto removeReport(@PathVariable Integer reportId){ + return reportService.removeReport(reportId); + } + + @GetMapping("/reports/volunteer") + @PreAuthorize("(hasRole('ROLE_VOLUNTEER'))") + public List getVolunteerReportsAsVolunteer(Principal principal) { + int userId = ((AuthUser) ((Authentication) principal).getPrincipal()).getUser().getId(); + return reportService.getVolunteerReportsAsVolunteer(userId); + } + + } \ No newline at end of file diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportService.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportService.java index 67e199b8..01e03fd3 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportService.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/ReportService.java @@ -6,6 +6,8 @@ import org.springframework.transaction.annotation.Transactional; import pt.ulisboa.tecnico.socialsoftware.humanaethica.activity.domain.Activity; import pt.ulisboa.tecnico.socialsoftware.humanaethica.activity.repository.ActivityRepository; +import pt.ulisboa.tecnico.socialsoftware.humanaethica.enrollment.domain.Enrollment; +import pt.ulisboa.tecnico.socialsoftware.humanaethica.enrollment.dto.EnrollmentDto; import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.domain.Report; import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.dto.ReportDto; import pt.ulisboa.tecnico.socialsoftware.humanaethica.exceptions.HEException; @@ -65,4 +67,29 @@ public ReportDto createReport(Integer userId, Integer activityId, ReportDto repo return new ReportDto(report); } + @Transactional(isolation = Isolation.READ_COMMITTED) + public ReportDto removeReport(Integer reportId) { + if (reportId == null) throw new HEException(REPORT_NOT_FOUND); + + Report report = reportRepository.findById(reportId).orElseThrow(() -> new HEException(REPORT_NOT_FOUND, reportId)); + + report.delete(); + + reportRepository.delete(report); + + return new ReportDto(report); + } + + @Transactional(isolation = Isolation.READ_COMMITTED) + public List getVolunteerReportsAsVolunteer(Integer userId) { + if (userId == null) throw new HEException(USER_NOT_FOUND); + + return reportRepository.getReportsForVolunteerId(userId).stream() + .sorted(Comparator.comparing(Report::getReportDateTime)) + .map(ReportDto::new) + .toList(); + } + + + } \ No newline at end of file diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/Report.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/Report.java index d4f343b7..d4e7cb18 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/Report.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/Report.java @@ -38,6 +38,14 @@ public Report(Activity activity, Volunteer volunteer, ReportDto reportDto){ verifyInvariants(); } + public void delete(){ + volunteer.removeReport(this); + activity.removeReport(this); + + deleteReportBeforeActivityEnd(); + verifyInvariants(); + } + public Integer getId() { return id; } @@ -105,4 +113,10 @@ private void reportBeforeActivityEnd() { throw new HEException(REPORT_AFTER_ACTIVTY_CLOSED); } } + + private void deleteReportBeforeActivityEnd() { + if (LocalDateTime.now().isAfter(this.activity.getEndingDate())) { + throw new HEException(REPORT_AFTER_ACTIVTY_CLOSED); + } + } } diff --git a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/user/domain/Volunteer.java b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/user/domain/Volunteer.java index d652f785..99fc024e 100644 --- a/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/user/domain/Volunteer.java +++ b/backend/src/main/java/pt/ulisboa/tecnico/socialsoftware/humanaethica/user/domain/Volunteer.java @@ -83,4 +83,12 @@ public void deleteAssessment(Assessment assessment) { public void addReport(Report report) { this.reports.add(report); } + + public void removeReport(Report report) { + this.reports.remove(report); + } + + public List getReports() { + return reports; + } } diff --git a/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/webservice/ValidateActivityWebServiceIT.groovy b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/webservice/ValidateActivityWebServiceIT.groovy index d0b87d1a..aeeb461d 100644 --- a/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/webservice/ValidateActivityWebServiceIT.groovy +++ b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/activity/webservice/ValidateActivityWebServiceIT.groovy @@ -102,21 +102,41 @@ class ValidateActivityWebServiceIT extends SpockTest { activity.state == Activity.State.REPORTED } - def "volunteer tries to validate activity"() { + def "volunteer validate activity"() { + given: + demoVolunteerLogin() + + when: 'validate' + def response = webClient.put() + .uri('/activities/' + activityId + '/validate') + .headers(httpHeaders -> httpHeaders.putAll(headers)) + .retrieve() + .bodyToMono(ActivityDto.class) + .block() + + then: "check response" + response.state == Activity.State.APPROVED.name() + and: 'database' + activityRepository.findAll().size() == 1 + def activity = activityRepository.findAll().get(0) + activity.state == Activity.State.APPROVED + } + + def "volunteer validates activity with wrong id"() { given: demoVolunteerLogin() when: webClient.put() - .uri('/activities/' + activityId + '/validate') + .uri('/activities/' + '222' + '/validate') .headers(httpHeaders -> httpHeaders.putAll(headers)) .retrieve() .bodyToMono(ActivityDto.class) .block() - then: "error is thrown" + then: "error" def error = thrown(WebClientResponseException) - error.statusCode == HttpStatus.FORBIDDEN + error.statusCode == HttpStatus.BAD_REQUEST activityRepository.findAll().size() == 1 def activity = activityRepository.findAll().get(0) activity.state == Activity.State.REPORTED diff --git a/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/DeleteReportMethodTest.groovy b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/DeleteReportMethodTest.groovy new file mode 100644 index 00000000..7f1c001e --- /dev/null +++ b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/domain/DeleteReportMethodTest.groovy @@ -0,0 +1,99 @@ +package pt.ulisboa.tecnico.socialsoftware.humanaethica.report.domain + +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.context.TestConfiguration +import pt.ulisboa.tecnico.socialsoftware.humanaethica.BeanConfiguration +import pt.ulisboa.tecnico.socialsoftware.humanaethica.SpockTest +import pt.ulisboa.tecnico.socialsoftware.humanaethica.exceptions.ErrorMessage +import pt.ulisboa.tecnico.socialsoftware.humanaethica.exceptions.HEException +import pt.ulisboa.tecnico.socialsoftware.humanaethica.activity.dto.ActivityDto +import pt.ulisboa.tecnico.socialsoftware.humanaethica.activity.domain.Activity +import pt.ulisboa.tecnico.socialsoftware.humanaethica.institution.domain.Institution +import pt.ulisboa.tecnico.socialsoftware.humanaethica.theme.domain.Theme +import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.dto.ReportDto +import pt.ulisboa.tecnico.socialsoftware.humanaethica.auth.domain.AuthUser +import pt.ulisboa.tecnico.socialsoftware.humanaethica.user.domain.User +import pt.ulisboa.tecnico.socialsoftware.humanaethica.user.domain.Volunteer +import pt.ulisboa.tecnico.socialsoftware.humanaethica.utils.DateHandler +import spock.lang.Unroll + +import java.time.LocalDateTime + +@DataJpaTest +class DeleteReportMethodTest extends SpockTest { + Institution institution = Mock() + Theme theme = Mock() + def reportOne + def volunteer + def activity + def activity2 + def reportTwo + + def setup() { + theme.getState() >> Theme.State.APPROVED + institution.getActivities() >> [] + + given:"activity" + def themes = [theme] + def activityDtoOne + activityDtoOne = new ActivityDto() + activityDtoOne.name = ACTIVITY_NAME_1 + activityDtoOne.region = ACTIVITY_REGION_1 + activityDtoOne.participantsNumberLimit = 2 + activityDtoOne.description = ACTIVITY_DESCRIPTION_1 + activityDtoOne.startingDate = DateHandler.toISOString(IN_TWO_DAYS) + activityDtoOne.endingDate = DateHandler.toISOString(IN_THREE_DAYS) + activityDtoOne.applicationDeadline = DateHandler.toISOString(IN_ONE_DAY) + activity = new Activity(activityDtoOne, institution, themes) + + and: "volunteer" + volunteer = createVolunteer(USER_1_NAME, USER_1_PASSWORD, USER_1_EMAIL, AuthUser.Type.NORMAL, User.State.APPROVED) + + and: "report" + def reportDto = new ReportDto() + reportDto.justification = REPORT_JUSTIFICATION_1 + reportOne = new Report(activity, volunteer, reportDto) + } + + def "delete report"() { + + when: "report is deleted" + reportOne.delete() + + then: "checks if the report was deleted in the activtiy and volunteer" + volunteer.getReports().size() == 0 + activity.getReports().size() == 0 + + } + + def "try to delete report after activity deadline"() { + given: + def activityDtoTwo + def themes = [theme] + activityDtoTwo = new ActivityDto() + activityDtoTwo.name = ACTIVITY_NAME_1 + activityDtoTwo.region = ACTIVITY_REGION_1 + activityDtoTwo.participantsNumberLimit = 2 + activityDtoTwo.description = ACTIVITY_DESCRIPTION_1 + activityDtoTwo.startingDate = DateHandler.toISOString(IN_TWO_DAYS) + activityDtoTwo.endingDate = DateHandler.toISOString(IN_THREE_DAYS) + activityDtoTwo.applicationDeadline = DateHandler.toISOString(IN_ONE_DAY) + activity2 = new Activity(activityDtoTwo, institution, themes) + + and: "report" + def reportDtoTwo = new ReportDto() + reportDtoTwo.justification = REPORT_JUSTIFICATION_1 + reportTwo = new Report(activity2, volunteer, reportDtoTwo) + activity2.setEndingDate(ONE_DAY_AGO) + + when: + reportTwo.delete() + + then: + def error = thrown(HEException) + error.getErrorMessage() == ErrorMessage.REPORT_AFTER_ACTIVTY_CLOSED + } + + @TestConfiguration + static class LocalBeanConfiguration extends BeanConfiguration {} +} \ No newline at end of file diff --git a/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/service/DeleteReportServiceTest.groovy b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/service/DeleteReportServiceTest.groovy new file mode 100644 index 00000000..135599c0 --- /dev/null +++ b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/service/DeleteReportServiceTest.groovy @@ -0,0 +1,124 @@ +package pt.ulisboa.tecnico.socialsoftware.humanaethica.report.service + +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest +import org.springframework.boot.test.context.TestConfiguration +import pt.ulisboa.tecnico.socialsoftware.humanaethica.BeanConfiguration +import pt.ulisboa.tecnico.socialsoftware.humanaethica.SpockTest +import pt.ulisboa.tecnico.socialsoftware.humanaethica.activity.domain.Activity +import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.dto.ReportDto +import pt.ulisboa.tecnico.socialsoftware.humanaethica.exceptions.ErrorMessage +import pt.ulisboa.tecnico.socialsoftware.humanaethica.exceptions.HEException +import pt.ulisboa.tecnico.socialsoftware.humanaethica.auth.domain.AuthUser +import pt.ulisboa.tecnico.socialsoftware.humanaethica.user.domain.User +import pt.ulisboa.tecnico.socialsoftware.humanaethica.user.domain.Volunteer +import spock.lang.Unroll + + +@DataJpaTest +class DeleteReportServiceTest extends SpockTest { + public static final String FIRST_REPORT = 'REPORT_1' + public static final String SECOND_REPORT = 'REPORT_2' + + def volunteer + def activity + def report + def firstReport + def secondReport + + def setup() { + def institution = institutionService.getDemoInstitution() + + given: "activity info" + def activityDto = createActivityDto(ACTIVITY_NAME_1, ACTIVITY_REGION_1, 2, ACTIVITY_DESCRIPTION_1, + IN_ONE_DAY, IN_TWO_DAYS, IN_THREE_DAYS, null) + + activity = new Activity(activityDto, institution, new ArrayList<>()) + activityRepository.save(activity) + and: "a volunteer" + volunteer = createVolunteer(USER_1_NAME, USER_1_PASSWORD, USER_1_EMAIL, AuthUser.Type.NORMAL, User.State.APPROVED) + and: "report" + report = createReport(activity, volunteer, REPORT_JUSTIFICATION_1) + } + + def 'delete report'() { + given: + firstReport = reportRepository.findAll().get(0) + when: + reportService.removeReport(firstReport.id) + then: "check that report was deleted" + reportRepository.findAll().size() == 0 + + } + + @Unroll + def 'two reports exist and one is removed'() { + + given: + def volunteer2 = createVolunteer(USER_2_NAME, USER_2_PASSWORD, USER_2_EMAIL, AuthUser.Type.NORMAL, User.State.APPROVED) + def report2 = createReport(activity, volunteer2, REPORT_JUSTIFICATION_2) + reportRepository.save(report2) + firstReport = reportRepository.findAll().get(0) + secondReport = reportRepository.findAll().get(1) + + when: + def result = reportService.removeReport(getFirstOrSecondReport(reportId)) + + then: "the report was deleted" + reportRepository.findAll().size() == 1 + result.justification == removedJustification + def remainingReport = reportRepository.findAll().get(0) + remainingReport.justification == remainingJustification + + where: "check the justification of the remainingReport and of the removedReport" + reportId || removedJustification || remainingJustification + FIRST_REPORT || REPORT_JUSTIFICATION_1 || REPORT_JUSTIFICATION_2 + SECOND_REPORT || REPORT_JUSTIFICATION_2 || REPORT_JUSTIFICATION_1 + + } + + def 'two reports exist and are both deleted'() { + given: + def volunteer2 = createVolunteer(USER_2_NAME, USER_2_PASSWORD, USER_2_EMAIL, AuthUser.Type.NORMAL, User.State.APPROVED) + def report2 = createReport(activity, volunteer2, REPORT_JUSTIFICATION_2) + reportRepository.save(report2) + firstReport = reportRepository.findAll().get(0) + secondReport = reportRepository.findAll().get(1) + + when: + reportService.removeReport(firstReport.id) + reportService.removeReport(secondReport.id) + + then: "confirm that reports were removed" + reportRepository.findAll().size() == 0 + } + + @Unroll + def 'invalid arguments: reportId=#reportId'() { + + when: + reportService.removeReport(reportId) + + then: + def error = thrown(HEException) + error.getErrorMessage() == errorMessage + and: "the report is in the database" + reportRepository.findAll().size() == 1 + + where: + reportId || errorMessage + null || ErrorMessage.REPORT_NOT_FOUND + 222 || ErrorMessage.REPORT_NOT_FOUND + + } + + def getFirstOrSecondReport(reportId) { + if(reportId == FIRST_REPORT) + return firstReport.id + else if (reportId == SECOND_REPORT) + return secondReport.id + return null + } + + @TestConfiguration + static class LocalBeanConfiguration extends BeanConfiguration {} +} \ No newline at end of file diff --git a/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/webservice/DeleteReportWebServiceIT.groovy b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/webservice/DeleteReportWebServiceIT.groovy new file mode 100644 index 00000000..08471bc2 --- /dev/null +++ b/backend/src/test/groovy/pt/ulisboa/tecnico/socialsoftware/humanaethica/report/webservice/DeleteReportWebServiceIT.groovy @@ -0,0 +1,118 @@ +package pt.ulisboa.tecnico.socialsoftware.humanaethica.report.webservice + +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.web.server.LocalServerPort +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.web.reactive.function.client.WebClientResponseException +import pt.ulisboa.tecnico.socialsoftware.humanaethica.activity.domain.Activity +import pt.ulisboa.tecnico.socialsoftware.humanaethica.report.dto.ReportDto +import pt.ulisboa.tecnico.socialsoftware.humanaethica.auth.domain.AuthUser +import pt.ulisboa.tecnico.socialsoftware.humanaethica.institution.domain.Institution +import pt.ulisboa.tecnico.socialsoftware.humanaethica.user.domain.User +import org.springframework.http.MediaType +import org.springframework.web.reactive.function.client.WebClient +import pt.ulisboa.tecnico.socialsoftware.humanaethica.SpockTest +import pt.ulisboa.tecnico.socialsoftware.humanaethica.utils.DateHandler + + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class DeleteReportWebServiceIT extends SpockTest { + @LocalServerPort + private int port + + def activity + def volunteer + def reportId + + def setup() { + deleteAll() + + webClient = WebClient.create("http://localhost:" + port) + headers = new HttpHeaders() + headers.setContentType(MediaType.APPLICATION_JSON) + + def institution = institutionService.getDemoInstitution() + volunteer = authUserService.loginDemoVolunteerAuth().getUser() + + def activityDto = createActivityDto(ACTIVITY_NAME_1,ACTIVITY_REGION_1,2,ACTIVITY_DESCRIPTION_1, + IN_ONE_DAY,IN_TWO_DAYS,IN_THREE_DAYS,null) + + activity = new Activity(activityDto, institution, new ArrayList<>()) + activityRepository.save(activity) + + def reportDto = new ReportDto() + reportDto.justification = REPORT_JUSTIFICATION_1 + reportDto.volunteerId = volunteer.id + + reportService.createReport(volunteer.id ,activity.id, reportDto) + + def storedReport = reportRepository.findAll().get(0) + reportId = storedReport.id + } + + def 'login as a volunteer and remove an report'() { + given: 'a volunteer' + demoVolunteerLogin() + + when: 'then volunteer deletes the report' + def response = webClient.delete() + .uri("/reports/" + reportId) + .headers(httpHeaders -> httpHeaders.putAll(headers)) + .retrieve() + .bodyToMono(ReportDto.class) + .block() + + then: "check response" + response.justification == REPORT_JUSTIFICATION_1 + and: "check database" + reportRepository.count() == 0 + + cleanup: + deleteAll() + } + + def 'login as a member and try to delete an report'() { + given: 'a member' + demoMemberLogin() + + when: 'the member deletes the report' + webClient.delete() + .uri("/reports/" + reportId) + .headers(httpHeaders -> httpHeaders.putAll(headers)) + .retrieve() + .bodyToMono(ReportDto.class) + .block() + + then: "check response status" + def error = thrown(WebClientResponseException) + error.statusCode == HttpStatus.FORBIDDEN + and: "check database" + reportRepository.count() == 1 + + cleanup: + deleteAll() + } + + def 'login as a admin and try to delete an report'() { + given: 'a admin' + demoAdminLogin() + + when: 'the admin deletes the report' + webClient.delete() + .uri("/reports/" + reportId) + .headers(httpHeaders -> httpHeaders.putAll(headers)) + .retrieve() + .bodyToMono(ReportDto.class) + .block() + + then: "check response status" + def error = thrown(WebClientResponseException) + error.statusCode == HttpStatus.FORBIDDEN + and: "check database" + reportRepository.count() == 1 + + cleanup: + deleteAll() + } +} \ No newline at end of file diff --git a/frontend/src/services/RemoteServices.ts b/frontend/src/services/RemoteServices.ts index 857f0f75..bd133ef9 100644 --- a/frontend/src/services/RemoteServices.ts +++ b/frontend/src/services/RemoteServices.ts @@ -714,6 +714,30 @@ export default class RemoteServices { }); } + static async deleteReport(reportId: number) { + return httpClient + .delete(`/reports/${reportId}`) + .then((response) => { + return new Report(response.data); + }) + .catch(async (error) => { + throw Error(await this.errorMessage(error)); + }); + } + + static async getVolunteerReportsAsVolunteer(): Promise { + return httpClient + .get('/reports/volunteer') + .then((response) => { + return response.data.map((report: any) => { + return new Report(report); + }); + }) + .catch(async (error) => { + throw Error(await this.errorMessage(error)); + }); + } + // Theme Controller static async getThemes(): Promise { diff --git a/frontend/src/views/admin/AdminActivitiesView.vue b/frontend/src/views/admin/AdminActivitiesView.vue index 922a3b55..19a291f3 100644 --- a/frontend/src/views/admin/AdminActivitiesView.vue +++ b/frontend/src/views/admin/AdminActivitiesView.vue @@ -33,7 +33,8 @@ +