diff --git a/.gitignore b/.gitignore index 40f55760b0..204ca95f52 100755 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ view/target *.log fitnesse/target/ daisy-integration/target/ +war/target/ +api/target/ diff --git a/GetToken.java b/GetToken.java new file mode 100644 index 0000000000..68c0dee549 --- /dev/null +++ b/GetToken.java @@ -0,0 +1,101 @@ +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpServer; + +import java.awt.Toolkit; +import java.awt.datatransfer.StringSelection; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Authenticator; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class GetToken { + public static void main(String[] args) throws IOException { + URI baseUri = URI.create("http://localhost:59733"); + String clientId = "get-token"; + String clientSecret = "get-token-secret"; + + System.out.println("Browse to " + baseUri.resolve("authorize?response_type=code&client_id=" + clientId)); + + HttpClient httpClient = HttpClient.newBuilder() + .authenticator(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(clientId, clientSecret.toCharArray()); + } + }) + .build(); + + HttpServer httpServer = HttpServer.create(); + httpServer.bind(new InetSocketAddress(59732), 0); + + Thread thread = Thread.currentThread(); + + httpServer.createContext("/", exchange -> { + exchange.sendResponseHeaders(200, 0); + try (OutputStream responseBody = exchange.getResponseBody()) { + responseBody.write("All done, close tab".getBytes(StandardCharsets.UTF_8)); + } + + Map<String, List<String>> queryParams = getQueryParams(exchange); + String code = queryParams.get("code").get(0); + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(baseUri.resolve("exchange")) + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString("grant_type=authorization_code&code=" + code)) + .build(); + try { + HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + System.out.println(response.body()); + + // Try to copy the access token to the clipboard + Matcher matcher = Pattern.compile("access_token\":\"([^\"]+)\"") + .matcher(response.body()); + if (matcher.find()) { + StringSelection clipboardData = new StringSelection(matcher.group(1)); + Toolkit.getDefaultToolkit() + .getSystemClipboard() + .setContents(clipboardData, clipboardData); + try { Thread.sleep(1_000L); } catch (InterruptedException e) { } + System.out.println("Access token copied to clipboard (probably)"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + thread.interrupt(); + } + }); + + httpServer.start(); + try { + Thread.sleep(Duration.ofMinutes(1L).toMillis()); + System.out.println("No authorization within one minute, exiting."); + System.exit(1); + } catch (InterruptedException ignored) { + // expected + } + httpServer.stop(0); + } + + private static Map<String, List<String>> getQueryParams(final HttpExchange exchange) { + String query = exchange.getRequestURI() + .getQuery(); + return Arrays.stream(query.split("&")) + .map(s -> s.split("=")) + .collect(Collectors.groupingBy( + split -> split[0], + Collectors.mapping(split -> split[1], Collectors.toList()))); + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000000..749d07cb72 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +## Working with the API +The API is protected by OAuth 2 acting as a [resource server](https://www.oauth.com/oauth2-servers/the-resource-server/) +verifying tokens using [token introspection](https://datatracker.ietf.org/doc/html/rfc7662). + +When developing it uses a locally running instance of an +[authorization server](https://datatracker.ietf.org/doc/html/rfc6749#section-1.1) +that is run inside [Docker](https://www.docker.com). It can be started with `docker compose -f docker-compose.yml up`. +Since there is no frontend to interact with the authorization server there's a helper script in +[GetToken.java](GetToken.java) that can be run directly with `java GetToken.java` to run through the authorization flow +and get an access token. + +Once the token has been obtained go to the [Swagger UI](http://localhost:8080/api/swagger) to interact with the API. +Click the "Authorize" button in the top right and paste the access token to log in. diff --git a/api/pom.xml b/api/pom.xml new file mode 100644 index 0000000000..35c607e1b1 --- /dev/null +++ b/api/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>se.su.dsv.scipro</groupId> + <artifactId>SciPro</artifactId> + <version>0.1-SNAPSHOT</version> + </parent> + + <artifactId>api</artifactId> + + <dependencies> + <dependency> + <groupId>se.su.dsv.scipro</groupId> + <artifactId>core</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webmvc</artifactId> + </dependency> + </dependencies> + +</project> \ No newline at end of file diff --git a/api/src/main/java/se/su/dsv/scipro/api/ApiController.java b/api/src/main/java/se/su/dsv/scipro/api/ApiController.java new file mode 100644 index 0000000000..8059cdde66 --- /dev/null +++ b/api/src/main/java/se/su/dsv/scipro/api/ApiController.java @@ -0,0 +1,29 @@ +package se.su.dsv.scipro.api; + +import jakarta.inject.Inject; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import se.su.dsv.scipro.system.User; +import se.su.dsv.scipro.system.UserService; + +import java.util.Optional; + +@RestController +public class ApiController { + private final UserService userService; + + @Inject + public ApiController(UserService userService) { + this.userService = userService; + } + + @GetMapping("/hello-world") + public String helloWorld(@RequestParam(value = "username", required = false) String username) { + String name = Optional.ofNullable(username) + .map(userService::findByUsername) + .map(User::getFullName) + .orElse("World"); + return "Hello, " + name + "!"; + } +} diff --git a/core/pom.xml b/core/pom.xml index df548c1fad..a3c2a1a1e9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -12,14 +12,6 @@ <artifactId>core</artifactId> <dependencies> - <dependency> - <groupId>com.google.inject</groupId> - <artifactId>guice</artifactId> - </dependency> - <dependency> - <groupId>com.google.inject.extensions</groupId> - <artifactId>guice-persist</artifactId> - </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> @@ -62,12 +54,9 @@ <groupId>org.glassfish.jersey.inject</groupId> <artifactId>jersey-hk2</artifactId> </dependency> - - <!--Database stuff--> <dependency> - <groupId>org.hsqldb</groupId> - <artifactId>hsqldb</artifactId> - <scope>test</scope> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> </dependency> <!--QueryDSL--> @@ -87,10 +76,19 @@ <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> </dependency> + <dependency> + <groupId>jakarta.transaction</groupId> + <artifactId>jakarta.transaction-api</artifactId> + </dependency> <dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> - <scope>runtime</scope> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hsqldb</groupId> + <artifactId>hsqldb</artifactId> + <scope>test</scope> </dependency> <!--Additional stuff--> @@ -130,8 +128,6 @@ <version>4.0.5</version> <scope>runtime</scope> </dependency> - - </dependencies> <build> diff --git a/core/src/main/java/modules/CoreModule.java b/core/src/main/java/modules/CoreModule.java deleted file mode 100644 index 075c6e9ed8..0000000000 --- a/core/src/main/java/modules/CoreModule.java +++ /dev/null @@ -1,160 +0,0 @@ -package modules; - -import com.google.inject.AbstractModule; -import com.google.inject.multibindings.Multibinder; -import com.google.inject.multibindings.OptionalBinder; -import se.su.dsv.scipro.activityplan.*; -import se.su.dsv.scipro.checklist.*; -import se.su.dsv.scipro.date.DateService; -import se.su.dsv.scipro.date.DateServiceImpl; -import se.su.dsv.scipro.events.EventModule; -import se.su.dsv.scipro.finalseminar.*; -import se.su.dsv.scipro.finalthesis.FinalThesisService; -import se.su.dsv.scipro.finalthesis.FinalThesisServiceImpl; -import se.su.dsv.scipro.finalthesis.PublishingConsentService; -import se.su.dsv.scipro.finalthesis.PublishingConsentUnavailable; -import se.su.dsv.scipro.firstmeeting.FirstMeetingService; -import se.su.dsv.scipro.firstmeeting.FirstMeetingServiceImpl; -import se.su.dsv.scipro.forum.ForumModule; -import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; -import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsServiceImpl; -import se.su.dsv.scipro.group.GroupFacade; -import se.su.dsv.scipro.group.GroupFacadeImpl; -import se.su.dsv.scipro.group.GroupService; -import se.su.dsv.scipro.group.GroupServiceImpl; -import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepository; -import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepositoryImpl; -import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepository; -import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepositoryImpl; -import se.su.dsv.scipro.mail.MailModule; -import se.su.dsv.scipro.match.ApplicationPeriodFacade; -import se.su.dsv.scipro.match.ApplicationPeriodFacadeImpl; -import se.su.dsv.scipro.match.MatchModule; -import se.su.dsv.scipro.milestones.service.*; -import se.su.dsv.scipro.milestones.service.impl.MilestoneActivityTemplateServiceImpl; -import se.su.dsv.scipro.milestones.service.impl.MilestonePhaseTemplateServiceImpl; -import se.su.dsv.scipro.milestones.service.impl.MilestoneServiceImpl; -import se.su.dsv.scipro.milestones.service.impl.MilestoneStatisticsServiceImpl; -import se.su.dsv.scipro.misc.DaysService; -import se.su.dsv.scipro.misc.DaysServiceImpl; -import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodService; -import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodServiceImpl; -import se.su.dsv.scipro.notes.NoteService; -import se.su.dsv.scipro.notes.NoteServiceImpl; -import se.su.dsv.scipro.notifications.NotificationModule; -import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationService; -import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationServiceImpl; -import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationService; -import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServiceImpl; -import se.su.dsv.scipro.peer.*; -import se.su.dsv.scipro.plagiarism.*; -import se.su.dsv.scipro.project.ProjectNoteService; -import se.su.dsv.scipro.project.ProjectPeopleStatisticsService; -import se.su.dsv.scipro.project.ProjectPeopleStatisticsServiceImpl; -import se.su.dsv.scipro.project.ProjectService; -import se.su.dsv.scipro.project.ProjectServiceImpl; -import se.su.dsv.scipro.projectpartner.ProjectPartnerRepository; -import se.su.dsv.scipro.projectpartner.ProjectPartnerRepositoryImpl; -import se.su.dsv.scipro.projectpartner.ProjectPartnerService; -import se.su.dsv.scipro.projectpartner.ProjectPartnerServiceImpl; -import se.su.dsv.scipro.reflection.ReflectionModule; -import se.su.dsv.scipro.report.*; -import se.su.dsv.scipro.reviewing.ProjectFinalSeminarStatisticsService; -import se.su.dsv.scipro.reviewing.ProjectFinalSeminarStatisticsServiceImpl; -import se.su.dsv.scipro.springdata.serviceimpls.SupervisorServiceImpl; -import se.su.dsv.scipro.springdata.serviceimpls.UnitServiceImpl; -import se.su.dsv.scipro.springdata.serviceimpls.UserProfileServiceImpl; -import se.su.dsv.scipro.springdata.services.SupervisorService; -import se.su.dsv.scipro.springdata.services.UnitService; -import se.su.dsv.scipro.springdata.services.UserProfileService; -import se.su.dsv.scipro.system.*; -import se.su.dsv.scipro.thesislink.ExternalLinkService; -import se.su.dsv.scipro.thesislink.ExternalLinkServiceImpl; - -public class CoreModule extends AbstractModule { - @Override - protected void configure() { - install(new RepositoryModule()); - bind(FooterLinkService.class).to(FooterLinkServiceImpl.class); - bind(ActivityThreadRepository.class).to(ActivityThreadRepositoryImpl.class); - bind(ActivityFinalSeminarRepository.class).to(ActivityFinalSeminarRepositoryImpl.class); - bind(UserService.class).to(UserServiceImpl.class); - bind(MergeService.class).to(MergeServiceImpl.class); - bind(PasswordService.class).to(PasswordServiceImpl.class); - bind(GeneralSystemSettingsService.class).to(GeneralSystemSettingsServiceImpl.class); - bind(ProjectTypeService.class).to(ProjectTypeServiceImpl.class); - bind(UnitService.class).to(UnitServiceImpl.class); - bind(ResearchAreaService.class).to(ResearchAreaServiceImpl.class); - bind(DateService.class).to(DateServiceImpl.class); - bind(ActivityPlanFacade.class).to(ActivityPlanFacadeImpl.class); - bind(ProjectService.class).to(ProjectServiceImpl.class); - bind(ProjectFinalSeminarStatisticsService.class).to(ProjectFinalSeminarStatisticsServiceImpl.class); - bind(ProjectPeopleStatisticsService.class).to(ProjectPeopleStatisticsServiceImpl.class); - bind(DeliveryConfigurationService.class).to(DeliveryConfigurationServiceImpl.class); - bind(ReceiverConfigurationService.class).to(ReceiverConfigurationServiceImpl.class); - bind(ActivityService.class).to(ActivityServiceImpl.class); - bind(ActivityPlanService.class).to(ActivityPlanServiceImpl.class); - bind(ActivityPlanTemplateService.class).to(ActivityPlanTemplateServiceImpl.class); - bind(ChecklistService.class).to(ChecklistServiceImpl.class); - bind(UserProfileService.class).to(UserProfileServiceImpl.class); - bind(FinalSeminarService.class).to(FinalSeminarServiceImpl.class); - bind(FinalSeminarSettingsService.class).to(FinalSeminarSettingsServiceImpl.class); - bind(SupervisorService.class).to(SupervisorServiceImpl.class); - bind(DaysService.class).to(DaysServiceImpl.class); - bind(NonWorkDayPeriodService.class).to(NonWorkDayPeriodServiceImpl.class); - bind(FinalSeminarOppositionService.class).to(FinalSeminarOppositionServiceImpl.class); - bind(AuthorRepository.class).to(AuthorRepositoryImpl.class); - bind(OppositionReportService.class).to(OppositionReportServiceImpl.class); - bind(ApplicationPeriodFacade.class).to(ApplicationPeriodFacadeImpl.class); - bind(GroupFacade.class).to(GroupFacadeImpl.class); - bind(ExternalLinkService.class).to(ExternalLinkServiceImpl.class); - bind(PeerRequestService.class).to(PeerRequestServiceImpl.class); - bind(PeerReviewService.class).to(PeerReviewServiceImpl.class); - bind(MilestoneActivityTemplateService.class).to(MilestoneActivityTemplateServiceImpl.class); - bind(FinalThesisService.class).to(FinalThesisServiceImpl.class); - OptionalBinder.newOptionalBinder(binder(), PublishingConsentService.class) - .setDefault().to(PublishingConsentUnavailable.class); - bind(ChecklistTemplateService.class).to(ChecklistTemplateServiceImpl.class); - bind(PeerPortal.class).to(PeerPortalImpl.class); - bind(FinalSeminarRespondentService.class).to(FinalSeminarRespondentServiceImpl.class); - bind(ProjectPartnerService.class).to(ProjectPartnerServiceImpl.class); - bind(GradingReportService.class).to(GradingReportServiceImpl.class); - bind(GradeCalculatorService.class).to(GradeCalculatorServiceImpl.class); - bind(UserNameService.class).to(UserNameServiceImpl.class); - bind(MileStoneService.class).to(MilestoneServiceImpl.class); - bind(MilestoneStatisticsService.class).to(MilestoneStatisticsServiceImpl.class); - bind(MilestonePhaseTemplateService.class).to(MilestonePhaseTemplateServiceImpl.class); - bind(ReportService.class).to(ReportServiceImpl.class); - bind(CommentThreadService.class).to(CommentThreadServiceImpl.class); - bind(CommentService.class).to(CommentServiceImpl.class); - bind(PerformReviewService.class).to(PeerPortalImpl.class); - bind(EventService.class).to(EventServiceImpl.class); - bind(ChecklistAnswerService.class).to(ChecklistAnswerServiceImpl.class); - bind(FinalSeminarUploadController.class).to(FinalSeminarUploadControllerImpl.class); - bind(FinalSeminarActiveParticipationService.class).to(FinalSeminarActiveParticipationServiceImpl.class); - bind(ExternalResourceService.class).to(ExternalResourceServiceImpl.class); - bind(GroupService.class).to(GroupServiceImpl.class); - bind(NoteService.class).to(NoteServiceImpl.class); - bind(MilestoneActivator.class).asEagerSingleton(); - bind(ActivateCompletedMilestonesOnNewProjects.class).asEagerSingleton(); - bind(FirstMeetingService.class).to(FirstMeetingServiceImpl.class); - bind(FinalSeminarCreationSubscribers.class).asEagerSingleton(); - bind(ProjectPartnerRepository.class).to(ProjectPartnerRepositoryImpl.class); - bind(ProjectNoteService.class).to(ProjectServiceImpl.class); - - install(new PlagiarismModule()); - install(new NotificationModule()); - install(new ProfileModule()); - install(new EventModule()); - install(new MatchModule()); - install(new MailModule()); - install(new ForumModule()); - install(new ReflectionModule()); - - Multibinder.newSetBinder(binder(), UserImportService.class); - bind(UserSearchService.class).to(AggregateUserSearch.class); - Multibinder.newSetBinder(binder(), UserSearchProvider.class) - .addBinding().to(LocalUserSearch.class); - - } -} diff --git a/core/src/main/java/modules/ProfileModule.java b/core/src/main/java/modules/ProfileModule.java deleted file mode 100644 index 16d276dba8..0000000000 --- a/core/src/main/java/modules/ProfileModule.java +++ /dev/null @@ -1,15 +0,0 @@ -package modules; - -import com.google.inject.Key; -import com.google.inject.PrivateModule; -import com.google.inject.name.Names; -import se.su.dsv.scipro.profiles.CurrentProfile; - -public class ProfileModule extends PrivateModule { - @Override - protected void configure() { - requireBinding(Key.get(String.class, Names.named("profile"))); - bind(CurrentProfile.class).asEagerSingleton(); - expose(CurrentProfile.class); - } -} diff --git a/core/src/main/java/modules/RepositoryModule.java b/core/src/main/java/modules/RepositoryModule.java deleted file mode 100644 index 2ae13bc0cb..0000000000 --- a/core/src/main/java/modules/RepositoryModule.java +++ /dev/null @@ -1,66 +0,0 @@ -package modules; - -import com.google.inject.AbstractModule; -import se.su.dsv.scipro.checklist.ChecklistCategoryRepo; -import se.su.dsv.scipro.checklist.ChecklistCategoryRepoImpl; -import se.su.dsv.scipro.checklist.ChecklistQuestionRepo; -import se.su.dsv.scipro.checklist.ChecklistQuestionRepoImpl; -import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepository; -import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepositoryImpl; -import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepo; -import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepoImpl; -import se.su.dsv.scipro.finalseminar.FinalSeminarRepository; -import se.su.dsv.scipro.finalseminar.FinalSeminarRepositoryImpl; -import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepository; -import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepositoryImpl; -import se.su.dsv.scipro.peer.CommentThreadRepo; -import se.su.dsv.scipro.peer.CommentThreadRepoImpl; -import se.su.dsv.scipro.peer.PeerRequestRepository; -import se.su.dsv.scipro.peer.PeerRequestRepositoryImpl; -import se.su.dsv.scipro.peer.PeerReviewRepository; -import se.su.dsv.scipro.peer.PeerReviewRepositoryImpl; -import se.su.dsv.scipro.project.ProjectRepo; -import se.su.dsv.scipro.project.ProjectRepoImpl; -import se.su.dsv.scipro.report.GradingReportTemplateRepo; -import se.su.dsv.scipro.report.GradingReportTemplateRepoImpl; -import se.su.dsv.scipro.report.OppositionReportRepo; -import se.su.dsv.scipro.report.OppositionReportRepoImpl; -import se.su.dsv.scipro.report.SupervisorGradingReportRepository; -import se.su.dsv.scipro.report.SupervisorGradingReportRepositoryImpl; -import se.su.dsv.scipro.reviewing.DecisionRepository; -import se.su.dsv.scipro.reviewing.DecisionRepositoryImpl; -import se.su.dsv.scipro.reviewing.ReviewerTargetRepository; -import se.su.dsv.scipro.reviewing.ReviewerTargetRepositoryImpl; -import se.su.dsv.scipro.system.FooterAddressRepo; -import se.su.dsv.scipro.system.FooterAddressRepoImpl; -import se.su.dsv.scipro.system.FooterLinkRepo; -import se.su.dsv.scipro.system.FooterLinkRepoImpl; -import se.su.dsv.scipro.system.PasswordRepo; -import se.su.dsv.scipro.system.PasswordRepoImpl; -import se.su.dsv.scipro.system.UserRepo; -import se.su.dsv.scipro.system.UserRepoImpl; - -public class RepositoryModule extends AbstractModule { - @Override - protected void configure() { - bind(ChecklistQuestionRepo.class).to(ChecklistQuestionRepoImpl.class); - bind(FinalSeminarOppositionRepo.class).to(FinalSeminarOppositionRepoImpl.class); - bind(FinalSeminarActiveParticipationRepository.class).to(FinalSeminarActiveParticipationRepositoryImpl.class); - bind(GradingReportTemplateRepo.class).to(GradingReportTemplateRepoImpl.class); - bind(MilestoneActivityTemplateRepository.class).to(MilestoneActivityTemplateRepositoryImpl.class); - bind(OppositionReportRepo.class).to(OppositionReportRepoImpl.class); - bind(PasswordRepo.class).to(PasswordRepoImpl.class); - bind(ProjectRepo.class).to(ProjectRepoImpl.class); - bind(UserRepo.class).to(UserRepoImpl.class); - bind(PeerReviewRepository.class).to(PeerReviewRepositoryImpl.class); - bind(PeerRequestRepository.class).to(PeerRequestRepositoryImpl.class); - bind(ChecklistCategoryRepo.class).to(ChecklistCategoryRepoImpl.class); - bind(CommentThreadRepo.class).to(CommentThreadRepoImpl.class); - bind(FooterLinkRepo.class).to(FooterLinkRepoImpl.class); - bind(FooterAddressRepo.class).to(FooterAddressRepoImpl.class); - bind(FinalSeminarRepository.class).to(FinalSeminarRepositoryImpl.class); - bind(ReviewerTargetRepository.class).to(ReviewerTargetRepositoryImpl.class); - bind(DecisionRepository.class).to(DecisionRepositoryImpl.class); - bind(SupervisorGradingReportRepository.class).to(SupervisorGradingReportRepositoryImpl.class); - } -} \ No newline at end of file diff --git a/core/src/main/java/se/su/dsv/scipro/CoreConfig.java b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java new file mode 100644 index 0000000000..918df6478f --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java @@ -0,0 +1,1025 @@ +package se.su.dsv.scipro; + +import com.google.common.eventbus.EventBus; +import jakarta.inject.Provider; +import jakarta.persistence.EntityManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import se.su.dsv.scipro.activityplan.ActivityPlanFacade; +import se.su.dsv.scipro.activityplan.ActivityPlanFacadeImpl; +import se.su.dsv.scipro.activityplan.ActivityPlanServiceImpl; +import se.su.dsv.scipro.activityplan.ActivityPlanTemplateServiceImpl; +import se.su.dsv.scipro.activityplan.ActivityServiceImpl; +import se.su.dsv.scipro.checklist.ChecklistAnswerServiceImpl; +import se.su.dsv.scipro.checklist.ChecklistServiceImpl; +import se.su.dsv.scipro.checklist.ChecklistTemplateService; +import se.su.dsv.scipro.checklist.ChecklistTemplateServiceImpl; +import se.su.dsv.scipro.daisyExternal.http.DaisyAPIImpl; +import se.su.dsv.scipro.date.DateServiceImpl; +import se.su.dsv.scipro.file.FileDescriptionRepo; +import se.su.dsv.scipro.file.FileReferenceRepository; +import se.su.dsv.scipro.file.FileService; +import se.su.dsv.scipro.file.FileServiceImpl; +import se.su.dsv.scipro.file.FileStore; +import se.su.dsv.scipro.file.ProjectFileRepository; +import se.su.dsv.scipro.file.ProjectFileService; +import se.su.dsv.scipro.file.ProjectFileServiceImpl; +import se.su.dsv.scipro.finalseminar.AuthorRepository; +import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepository; +import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationServiceImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarCreationSubscribers; +import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepo; +import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionServiceImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarRepository; +import se.su.dsv.scipro.finalseminar.FinalSeminarRespondentServiceImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarService; +import se.su.dsv.scipro.finalseminar.FinalSeminarServiceImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarSettingsService; +import se.su.dsv.scipro.finalseminar.FinalSeminarSettingsServiceImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarUploadControllerImpl; +import se.su.dsv.scipro.finalthesis.FinalThesisService; +import se.su.dsv.scipro.finalthesis.FinalThesisServiceImpl; +import se.su.dsv.scipro.firstmeeting.FirstMeetingServiceImpl; +import se.su.dsv.scipro.forum.AbstractThreadRepository; +import se.su.dsv.scipro.forum.BasicForumService; +import se.su.dsv.scipro.forum.BasicForumServiceImpl; +import se.su.dsv.scipro.forum.ForumPostReadStateRepository; +import se.su.dsv.scipro.forum.ForumPostRepository; +import se.su.dsv.scipro.forum.GroupForumService; +import se.su.dsv.scipro.forum.GroupForumServiceImpl; +import se.su.dsv.scipro.forum.GroupThreadRepository; +import se.su.dsv.scipro.forum.ProjectForumService; +import se.su.dsv.scipro.forum.ProjectForumServiceImpl; +import se.su.dsv.scipro.forum.ProjectThreadRepository; +import se.su.dsv.scipro.forum.notifications.ForumNotificationRepository; +import se.su.dsv.scipro.forum.notifications.ForumNotifications; +import se.su.dsv.scipro.gdpr.ZipReporter; +import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; +import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsServiceImpl; +import se.su.dsv.scipro.grading.GradingHistory; +import se.su.dsv.scipro.grading.GradingHistoryEventRepository; +import se.su.dsv.scipro.grading.GradingServiceImpl; +import se.su.dsv.scipro.grading.NationalSubjectCategoryRepository; +import se.su.dsv.scipro.grading.NationalSubjectCategoryServiceImpl; +import se.su.dsv.scipro.grading.PublicationMetadataRepository; +import se.su.dsv.scipro.grading.PublicationMetadataServiceImpl; +import se.su.dsv.scipro.grading.ThesisSubmissionHistoryService; +import se.su.dsv.scipro.group.GroupFacadeImpl; +import se.su.dsv.scipro.group.GroupService; +import se.su.dsv.scipro.group.GroupServiceImpl; +import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepository; +import se.su.dsv.scipro.integration.activityfinalseminar.FinalSeminarActivityHandler; +import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepository; +import se.su.dsv.scipro.integration.activityforum.PostActivityUploadToForum; +import se.su.dsv.scipro.mail.MailEventService; +import se.su.dsv.scipro.mail.MailEventServiceImpl; +import se.su.dsv.scipro.match.AddActivityPlanOnProjectStart; +import se.su.dsv.scipro.match.ApplicationPeriodFacadeImpl; +import se.su.dsv.scipro.match.ApplicationPeriodProjectTypeServiceImpl; +import se.su.dsv.scipro.match.ApplicationPeriodService; +import se.su.dsv.scipro.match.ApplicationPeriodServiceImpl; +import se.su.dsv.scipro.match.FirstMeetingRepository; +import se.su.dsv.scipro.match.IdeaFacade; +import se.su.dsv.scipro.match.IdeaRepository; +import se.su.dsv.scipro.match.IdeaService; +import se.su.dsv.scipro.match.IdeaServiceImpl; +import se.su.dsv.scipro.match.KeywordServiceImpl; +import se.su.dsv.scipro.match.MatchFollowUpServiceImpl; +import se.su.dsv.scipro.match.MatchServiceImpl; +import se.su.dsv.scipro.match.PreliminaryMatchServiceImpl; +import se.su.dsv.scipro.match.ProgramServiceImpl; +import se.su.dsv.scipro.match.ProjectStartNotifier; +import se.su.dsv.scipro.match.TargetRepository; +import se.su.dsv.scipro.match.TargetServiceImpl; +import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepository; +import se.su.dsv.scipro.milestones.service.ActivateCompletedMilestonesOnNewProjects; +import se.su.dsv.scipro.milestones.service.MilestoneActivityTemplateService; +import se.su.dsv.scipro.milestones.service.impl.MilestoneActivityTemplateServiceImpl; +import se.su.dsv.scipro.milestones.service.impl.MilestonePhaseTemplateServiceImpl; +import se.su.dsv.scipro.milestones.service.impl.MilestoneServiceImpl; +import se.su.dsv.scipro.milestones.service.impl.MilestoneStatisticsServiceImpl; +import se.su.dsv.scipro.misc.DaysService; +import se.su.dsv.scipro.misc.DaysServiceImpl; +import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodService; +import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodServiceImpl; +import se.su.dsv.scipro.notes.NoteServiceImpl; +import se.su.dsv.scipro.notifications.NotificationController; +import se.su.dsv.scipro.notifications.NotificationControllerImpl; +import se.su.dsv.scipro.notifications.NotificationEventRepository; +import se.su.dsv.scipro.notifications.NotificationEventServiceImpl; +import se.su.dsv.scipro.notifications.NotificationService; +import se.su.dsv.scipro.notifications.NotificationServiceImpl; +import se.su.dsv.scipro.notifications.Notifications; +import se.su.dsv.scipro.notifications.interfaces.NotificationMailFormatter; +import se.su.dsv.scipro.notifications.interfaces.impl.NotificationMailFormatterImpl; +import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationService; +import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationServiceImpl; +import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationService; +import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServiceImpl; +import se.su.dsv.scipro.oauth.OAuthServiceImpl; +import se.su.dsv.scipro.oauth.OAuthSettings; +import se.su.dsv.scipro.peer.CommentServiceImpl; +import se.su.dsv.scipro.peer.CommentThreadRepo; +import se.su.dsv.scipro.peer.CommentThreadServiceImpl; +import se.su.dsv.scipro.peer.PeerPortalImpl; +import se.su.dsv.scipro.peer.PeerRequestRepository; +import se.su.dsv.scipro.peer.PeerRequestService; +import se.su.dsv.scipro.peer.PeerRequestServiceImpl; +import se.su.dsv.scipro.peer.PeerReviewRepository; +import se.su.dsv.scipro.peer.PeerReviewService; +import se.su.dsv.scipro.peer.PeerReviewServiceImpl; +import se.su.dsv.scipro.plagiarism.PlagiarismControl; +import se.su.dsv.scipro.plagiarism.PlagiarismControlImpl; +import se.su.dsv.scipro.plagiarism.PlagiarismRequestRepository; +import se.su.dsv.scipro.plagiarism.urkund.UrkundApi; +import se.su.dsv.scipro.plagiarism.urkund.UrkundApiImpl; +import se.su.dsv.scipro.plagiarism.urkund.UrkundServiceImpl; +import se.su.dsv.scipro.plagiarism.urkund.UrkundSettingsRepository; +import se.su.dsv.scipro.plagiarism.urkund.UrkundSubmissionRepository; +import se.su.dsv.scipro.project.ProjectPeopleStatisticsServiceImpl; +import se.su.dsv.scipro.project.ProjectRepo; +import se.su.dsv.scipro.project.ProjectService; +import se.su.dsv.scipro.project.ProjectServiceImpl; +import se.su.dsv.scipro.projectpartner.ProjectPartnerServiceImpl; +import se.su.dsv.scipro.reflection.ReflectionService; +import se.su.dsv.scipro.reflection.ReflectionServiceImpl; +import se.su.dsv.scipro.report.GradeCalculatorServiceImpl; +import se.su.dsv.scipro.report.GradingReportService; +import se.su.dsv.scipro.report.GradingReportServiceImpl; +import se.su.dsv.scipro.report.GradingReportTemplateRepo; +import se.su.dsv.scipro.report.GradingReportTemplateRepoImpl; +import se.su.dsv.scipro.report.OppositionReportRepo; +import se.su.dsv.scipro.report.OppositionReportServiceImpl; +import se.su.dsv.scipro.report.ReportServiceImpl; +import se.su.dsv.scipro.report.SupervisorGradingReportRepository; +import se.su.dsv.scipro.reviewing.DecisionRepository; +import se.su.dsv.scipro.reviewing.FinalSeminarApprovalService; +import se.su.dsv.scipro.reviewing.FinalSeminarApprovalServiceImpl; +import se.su.dsv.scipro.reviewing.ProjectFinalSeminarStatisticsServiceImpl; +import se.su.dsv.scipro.reviewing.ReviewerAssignedDeadline; +import se.su.dsv.scipro.reviewing.ReviewerCapacityServiceImpl; +import se.su.dsv.scipro.reviewing.ReviewerDeadlineFollowupServiceImpl; +import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsRepository; +import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsService; +import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsServiceImpl; +import se.su.dsv.scipro.reviewing.ReviewerInteractionService; +import se.su.dsv.scipro.reviewing.ReviewerInteractionServiceImpl; +import se.su.dsv.scipro.reviewing.ReviewerTargetRepository; +import se.su.dsv.scipro.reviewing.ReviewerThreadRepository; +import se.su.dsv.scipro.reviewing.ReviewingServiceImpl; +import se.su.dsv.scipro.reviewing.RoughDraftApprovalService; +import se.su.dsv.scipro.reviewing.RoughDraftApprovalServiceImpl; +import se.su.dsv.scipro.security.auth.AuthenticationProvider; +import se.su.dsv.scipro.security.auth.AuthenticationServiceImpl; +import se.su.dsv.scipro.security.auth.LocalAuthentication; +import se.su.dsv.scipro.springdata.serviceimpls.SupervisorServiceImpl; +import se.su.dsv.scipro.springdata.serviceimpls.UnitServiceImpl; +import se.su.dsv.scipro.springdata.serviceimpls.UserProfileServiceImpl; +import se.su.dsv.scipro.springdata.services.UserProfileService; +import se.su.dsv.scipro.sukat.LDAP; +import se.su.dsv.scipro.sukat.Sukat; +import se.su.dsv.scipro.survey.QuestionRepository; +import se.su.dsv.scipro.survey.SurveyRepository; +import se.su.dsv.scipro.survey.SurveyServiceImpl; +import se.su.dsv.scipro.system.CurrentUser; +import se.su.dsv.scipro.system.EventServiceImpl; +import se.su.dsv.scipro.system.ExternalResourceServiceImpl; +import se.su.dsv.scipro.system.FooterLinkRepo; +import se.su.dsv.scipro.system.FooterLinkServiceImpl; +import se.su.dsv.scipro.system.LocalUserSearch; +import se.su.dsv.scipro.system.PasswordRepo; +import se.su.dsv.scipro.system.PasswordService; +import se.su.dsv.scipro.system.PasswordServiceImpl; +import se.su.dsv.scipro.system.ProjectTypeService; +import se.su.dsv.scipro.system.ProjectTypeServiceImpl; +import se.su.dsv.scipro.system.ResearchAreaServiceImpl; +import se.su.dsv.scipro.system.UserNameServiceImpl; +import se.su.dsv.scipro.system.UserRepo; +import se.su.dsv.scipro.system.UserService; +import se.su.dsv.scipro.system.UserServiceImpl; +import se.su.dsv.scipro.thesislink.ExternalLinkServiceImpl; +import se.su.dsv.scipro.workerthreads.WorkerDataServiceImpl; + +import java.time.Clock; +import java.util.Set; + +@Configuration(proxyBeanMethods = false) +public class CoreConfig { + @Bean + public EventBus eventBus() { + return new EventBus(); + } + + @Bean + public GradingHistory gradingHistory(GradingHistoryEventRepository gradingHistoryEventRepository) { + return new GradingHistory(gradingHistoryEventRepository); + } + + @Bean + public OAuthSettings oAuthSettings( + @Value("${oauth.uri}") String uri, + @Value("${oauth.redirectUri}") String redirectUri, + @Value("${oauth.clientId}") String clientId, + @Value("${oauth.clientSecret}") String clientSecret) + { + return new OAuthSettings(uri, redirectUri, clientId, clientSecret); + } + + @Bean + public Sukat sukat() { + return new LDAP(); + } + + @Bean + public DaisyAPIImpl daisyAPI( + @Value("${daisy.api.url}") final String baseUrl, + @Value("${daisy.api.username}") final String user, + @Value("${daisy.api.password}") final String password) + { + return new DaisyAPIImpl(baseUrl, user, password); + } + + @Bean + public GradingServiceImpl gradingService(@Value("${service.grading.url}") final String url) { + return new GradingServiceImpl(url); + } + + @Bean + public OAuthServiceImpl oAuthService(OAuthSettings settings) { + return new OAuthServiceImpl(settings); + } + + @Bean + public FinalSeminarApprovalServiceImpl finalSeminarApprovalService( + Provider<EntityManager> em, + FileService fileDescriptionService, + EventBus eventBus, + DaysService daysService, + ReviewerDeadlineSettingsService reviewerDeadlineSettingsService) + { + return new FinalSeminarApprovalServiceImpl(em, fileDescriptionService, eventBus, daysService, reviewerDeadlineSettingsService); + } + + @Bean + public RoughDraftApprovalServiceImpl roughDraftApprovalService( + Provider<EntityManager> em, + FileService fileDescriptionService, + EventBus eventBus, + DaysService daysService, + ReviewerDeadlineSettingsService reviewerDeadlineSettingsService) + { + return new RoughDraftApprovalServiceImpl(em, eventBus, fileDescriptionService, daysService, reviewerDeadlineSettingsService); + } + + @Bean + public ActivityPlanServiceImpl activityPlanService(Provider<EntityManager> em) { + return new ActivityPlanServiceImpl(em); + } + + @Bean + public ActivityPlanTemplateServiceImpl activityPlanTemplateService(Provider<EntityManager> em) { + return new ActivityPlanTemplateServiceImpl(em); + } + + @Bean + public ActivityServiceImpl activityService(Provider<EntityManager> em) { + return new ActivityServiceImpl(em); + } + + @Bean + public ActivityPlanFacadeImpl activityPlanFacade( + EventBus eventBus, + ProjectFileService projectFileService, + ChecklistTemplateService checklistTemplateService, + DaysService daysService, + FileService fileService + ) + { + return new ActivityPlanFacadeImpl(eventBus, projectFileService, checklistTemplateService, daysService, + fileService); + } + + @Bean + public ApplicationPeriodFacadeImpl applicationPeriodFacade() { + return new ApplicationPeriodFacadeImpl(); + } + + @Bean + public ApplicationPeriodProjectTypeServiceImpl applicationPeriodProjectTypeService(Provider<EntityManager> em) { + return new ApplicationPeriodProjectTypeServiceImpl(em); + } + + @Bean + public ApplicationPeriodServiceImpl applicationPeriodService(Provider<EntityManager> em, Clock clock) { + return new ApplicationPeriodServiceImpl(em, clock); + } + + @Bean + public AuthenticationServiceImpl authenticationService(Set<AuthenticationProvider> authenticationProviders) { + return new AuthenticationServiceImpl(authenticationProviders); + } + + @Bean + public LocalAuthentication localAuthentication( + UserService userService, + PasswordService passwordService) + { + return new LocalAuthentication(userService, passwordService); + } + + @Bean + public BasicForumServiceImpl basicForumService( + ForumPostRepository forumPostRepository, + ForumPostReadStateRepository readStateRepository, + AbstractThreadRepository threadRepository, + FileService fileService, + EventBus eventBus) + { + return new BasicForumServiceImpl(forumPostRepository, readStateRepository, threadRepository, fileService, + eventBus); + } + + @Bean + public ChecklistAnswerServiceImpl checklistAnswerService(Provider<EntityManager> em) { + return new ChecklistAnswerServiceImpl(em); + } + + @Bean + public ChecklistServiceImpl checklistService(Provider<EntityManager> em) { + return new ChecklistServiceImpl(em); + } + + @Bean + public ChecklistTemplateServiceImpl checklistTemplateService(Provider<EntityManager> em) { + return new ChecklistTemplateServiceImpl(em); + } + + @Bean + public CommentServiceImpl commentService(Provider<EntityManager> em) { + return new CommentServiceImpl(em); + } + + @Bean + public DateServiceImpl dateService() { + return new DateServiceImpl(); + } + + @Bean + public DaysServiceImpl daysService(NonWorkDayPeriodService nonWorkDayPeriodService) { + return new DaysServiceImpl(nonWorkDayPeriodService); + } + + @Bean + public DeliveryConfigurationServiceImpl deliveryConfigurationService( + Provider<EntityManager> em, + UserProfileService userProfileService) + { + return new DeliveryConfigurationServiceImpl(em, userProfileService); + } + + @Bean + public EventServiceImpl eventService(Provider<EntityManager> em) { + return new EventServiceImpl(em); + } + + @Bean + public ExternalLinkServiceImpl externalLinkService(Provider<EntityManager> em) { + return new ExternalLinkServiceImpl(em); + } + + @Bean + public ExternalResourceServiceImpl externalResourceService(Provider<EntityManager> em) { + return new ExternalResourceServiceImpl(em); + } + + @Bean + public FileServiceImpl fileService( + Provider<EntityManager> em, + FileStore fileStore, + FileReferenceRepository fileReferenceRepository, + FileDescriptionRepo fileDescriptionRepository) + { + return new FileServiceImpl(em, fileReferenceRepository, fileDescriptionRepository, fileStore); + } + + @Bean + public FinalSeminarActiveParticipationServiceImpl finalSeminarActiveParticipationService(Provider<EntityManager> em) { + return new FinalSeminarActiveParticipationServiceImpl(em); + } + + @Bean + public FinalSeminarOppositionServiceImpl finalSeminarOppositionService(Provider<EntityManager> em) { + return new FinalSeminarOppositionServiceImpl(em); + } + + @Bean + public FinalSeminarRespondentServiceImpl finalSeminarRespondentService(Provider<EntityManager> em) { + return new FinalSeminarRespondentServiceImpl(em); + } + + @Bean + public FinalSeminarServiceImpl finalSeminarService( + Provider<EntityManager> em, + EventBus eventBus, + FileService fileService, + AuthorRepository authorRepository, + FinalSeminarOppositionRepo finalSeminarOppositionRepository, + FinalSeminarActiveParticipationRepository finalSeminarActiveParticipationRepository, + FinalSeminarRepository finalSeminarRepository, + Clock clock, + RoughDraftApprovalService roughDraftApprovalService) + { + return new FinalSeminarServiceImpl( + em, + eventBus, + authorRepository, + fileService, + finalSeminarOppositionRepository, + finalSeminarActiveParticipationRepository, + finalSeminarRepository, + clock, + roughDraftApprovalService); + } + + @Bean + public FinalSeminarSettingsServiceImpl finalSeminarSettingsService(Provider<EntityManager> em) { + return new FinalSeminarSettingsServiceImpl(em); + } + + @Bean + public FinalSeminarUploadControllerImpl finalSeminarUploadController( + EventBus eventBus, + FileService fileService, + FinalSeminarService finalSeminarService, + ProjectFileService projectFileService, + ProjectService projectService, + FinalSeminarSettingsService finalSeminarSettingsService, + PlagiarismControl plagiarismControl) + { + return new FinalSeminarUploadControllerImpl(projectService, fileService, finalSeminarSettingsService, + finalSeminarService, eventBus, projectFileService, plagiarismControl); + } + + @Bean + public FinalThesisServiceImpl finalThesisService( + Provider<EntityManager> em, + NotificationController notification, + ProjectFileService projectFile, + FileService fileService, + EventBus eventBus, + PlagiarismControl plagiarismControl, + GradingReportService gradingReportService) + { + return new FinalThesisServiceImpl(em, notification, projectFile, + fileService, eventBus, plagiarismControl, gradingReportService); + } + + @Bean + public FirstMeetingServiceImpl firstMeetingService( + Provider<EntityManager> em, + ActivityPlanFacade activityPlanFacade) + { + return new FirstMeetingServiceImpl(em, activityPlanFacade); + } + + @Bean + public FooterLinkServiceImpl footerLinkService(FooterLinkRepo footerLinkRepository) { + return new FooterLinkServiceImpl(footerLinkRepository); + } + + @Bean + public GeneralSystemSettingsServiceImpl generalSystemSettingsService(Provider<EntityManager> em) { + return new GeneralSystemSettingsServiceImpl(em); + } + + @Bean + public GradeCalculatorServiceImpl gradeCalculatorService(GradingReportService gradingReportService) { + return new GradeCalculatorServiceImpl(gradingReportService); + } + + @Bean + public GradingReportServiceImpl gradingReportService( + EventBus eventBus, + ThesisSubmissionHistoryService thesisSubmissionHistoryService, + Clock clock, + SupervisorGradingReportRepository supervisorGradingReportRepository, + GradingReportTemplateRepoImpl gradingReportTemplateRepo, + ProjectTypeService projectTypeService) + { + return new GradingReportServiceImpl( + eventBus, + thesisSubmissionHistoryService, + clock, + supervisorGradingReportRepository, + gradingReportTemplateRepo, + projectTypeService); + } + + @Bean + public GroupForumServiceImpl groupForumService( + EventBus eventBus, + GroupThreadRepository groupThreadRepository, + BasicForumService basicForumService) + { + return new GroupForumServiceImpl(groupThreadRepository, basicForumService, eventBus); + } + + @Bean + public GroupServiceImpl groupService(Provider<EntityManager> em) { + return new GroupServiceImpl(em); + } + + @Bean + public IdeaServiceImpl ideaService( + Provider<EntityManager> em, + ApplicationPeriodService applicationPeriodService, + FirstMeetingRepository firstMeetingRepository, + NotificationController notificationController, + ProjectService projectService, + GeneralSystemSettingsService generalSystemSettingsService, + TargetRepository targetRepository, + IdeaRepository ideaRepository, + Clock clock) + { + return new IdeaServiceImpl(em, applicationPeriodService, firstMeetingRepository, notificationController, + projectService, generalSystemSettingsService, targetRepository, ideaRepository, clock); + } + + @Bean + public KeywordServiceImpl keywordService(Provider<EntityManager> em) { + return new KeywordServiceImpl(em); + } + + @Bean + public LocalUserSearch localUserSearch(UserRepo userRepository) { + return new LocalUserSearch(userRepository); + } + + @Bean + public MailEventServiceImpl mailEventService(Provider<EntityManager> em) { + return new MailEventServiceImpl(em); + } + + @Bean + public MatchFollowUpServiceImpl matchFollowUpService(Provider<EntityManager> em) { + return new MatchFollowUpServiceImpl(em); + } + + @Bean + public MatchServiceImpl matchService(Provider<EntityManager> em) { + return new MatchServiceImpl(em); + } + + @Bean + public MilestoneActivityTemplateServiceImpl milestoneActivityTemplateService( + MilestoneActivityTemplateRepository milestoneActivityTemplateRepository) + { + return new MilestoneActivityTemplateServiceImpl(milestoneActivityTemplateRepository); + } + + @Bean + public MilestonePhaseTemplateServiceImpl milestonePhaseTemplateService(Provider<EntityManager> em) { + return new MilestonePhaseTemplateServiceImpl(em); + } + + @Bean + public MilestoneServiceImpl milestoneService( + Provider<EntityManager> em, + NotificationController notificationController) + { + return new MilestoneServiceImpl(notificationController, em); + } + + @Bean + public MilestoneStatisticsServiceImpl milestoneStatisticsService(Provider<EntityManager> em) { + return new MilestoneStatisticsServiceImpl(em); + } + + @Bean + public NationalSubjectCategoryServiceImpl nationalSubjectCategoryService( + NationalSubjectCategoryRepository nationalSubjectCategoryRepository) + { + return new NationalSubjectCategoryServiceImpl(nationalSubjectCategoryRepository); + } + + @Bean + public NonWorkDayPeriodServiceImpl nonWorkDayPeriodService(Provider<EntityManager> em) { + return new NonWorkDayPeriodServiceImpl(em); + } + + @Bean + public NoteServiceImpl noteService(Provider<EntityManager> em) { + return new NoteServiceImpl(em); + } + + @Bean + public NotificationServiceImpl notificationService(Provider<EntityManager> em) { + return new NotificationServiceImpl(em); + } + + @Bean + public OppositionReportServiceImpl oppositionReportService( + OppositionReportRepo oppositionReportRepository, + GradingReportTemplateRepo gradingReportTemplateRepository, + FileService fileService, + FinalSeminarOppositionRepo finalSeminarOppositionRepository) + { + return new OppositionReportServiceImpl(oppositionReportRepository, gradingReportTemplateRepository, + fileService, finalSeminarOppositionRepository); + } + + @Bean + public PasswordServiceImpl passwordService(PasswordRepo passwordRepo) { + return new PasswordServiceImpl(passwordRepo); + } + + @Bean + public PeerPortalImpl peerPortal( + FileService fileService, + PeerReviewRepository peerReviewRepository, + PeerRequestRepository peerRequestRepository, + EventBus eventBus, + ProjectFileService projectFileService, + DaysService daisyService, + Clock clock) + { + return new PeerPortalImpl(fileService, peerReviewRepository, peerRequestRepository, + eventBus, projectFileService, daisyService, clock); + } + + @Bean + public PeerRequestServiceImpl peerRequestService( + Provider<EntityManager> em, + EventBus eventBus, + FileService fileService) + { + return new PeerRequestServiceImpl(em, eventBus, fileService); + } + + @Bean + public PeerReviewServiceImpl peerReviewService( + Provider<EntityManager> em, + PeerReviewRepository peerReviewRepository) + { + return new PeerReviewServiceImpl(em, peerReviewRepository); + } + + @Bean + public PlagiarismControlImpl plagiarismControl( + FileService fileService, + PlagiarismRequestRepository plagiarismRequestRepository, + UrkundSubmissionRepository urkundSubmissionRepository) + { + return new PlagiarismControlImpl(plagiarismRequestRepository, urkundSubmissionRepository, fileService); + } + + @Bean + public PreliminaryMatchServiceImpl preliminaryMatchService(Provider<EntityManager> em, IdeaService ideaService) { + return new PreliminaryMatchServiceImpl(em, ideaService); + } + + @Bean + public ProgramServiceImpl programService(Provider<EntityManager> em) { + return new ProgramServiceImpl(em); + } + + @Bean + public ProjectFileServiceImpl projectFileService( + FileService fileService, + ProjectFileRepository projectFileRepository) + { + return new ProjectFileServiceImpl(fileService, projectFileRepository); + } + + @Bean + public ProjectFinalSeminarStatisticsServiceImpl projectFinalSeminarStatisticsService(Provider<EntityManager> em) { + return new ProjectFinalSeminarStatisticsServiceImpl(em); + } + + @Bean + public ProjectForumServiceImpl projectForumService( + EventBus eventBus, + BasicForumService basicForumService, + ProjectThreadRepository projectThreadRepository, + ForumPostRepository postRepository, + ProjectFileService projectFileService) + { + return new ProjectForumServiceImpl(projectThreadRepository, + postRepository, projectFileService, basicForumService, eventBus); + } + + @Bean + public ProjectPartnerServiceImpl projectPartnerService(Provider<EntityManager> em) { + return new ProjectPartnerServiceImpl(em); + } + + @Bean + public ProjectPeopleStatisticsServiceImpl projectPeopleStatisticsService(Provider<EntityManager> em) { + return new ProjectPeopleStatisticsServiceImpl(em); + } + + @Bean + public ProjectServiceImpl projectService( + Provider<EntityManager> em, + EventBus eventBus, + ProjectRepo projectRepo, + Clock clock) + { + return new ProjectServiceImpl(projectRepo, clock, eventBus, em); + } + + @Bean + public ProjectTypeServiceImpl projectTypeService(Provider<EntityManager> em) { + return new ProjectTypeServiceImpl(em); + } + + @Bean + public PublicationMetadataServiceImpl publicationMetadataService( + PublicationMetadataRepository publicationMetadataRepository) + { + return new PublicationMetadataServiceImpl(publicationMetadataRepository); + } + + @Bean + public ReflectionServiceImpl reflectionService( + AuthorRepository authorRepository, + FinalSeminarServiceImpl finalSeminarService, + EventBus eventBus) + { + return new ReflectionServiceImpl(authorRepository, finalSeminarService, eventBus); + } + + @Bean + public ReceiverConfigurationServiceImpl receiverConfigurationService(Provider<EntityManager> em) { + return new ReceiverConfigurationServiceImpl(em); + } + + @Bean + public ReviewerDeadlineFollowupServiceImpl reviewerDeadlineFollowupService(Provider<EntityManager> em) { + return new ReviewerDeadlineFollowupServiceImpl(em); + } + + @Bean + public ZipReporter reporter( + FileService fileService, + ProjectService projectService, + FinalSeminarService finalSeminarService, + ProjectForumService projectForumService, + PeerReviewService peerReviewService, + PeerRequestService peerRequestService, + GroupService groupService, + GroupForumService groupForumService, + IdeaService ideaService, + GradingReportService gradingReportService, + ReviewerInteractionService reviewerInteractionService, + RoughDraftApprovalService roughDraftApprovalService, + FinalSeminarApprovalService finalSeminarApprovalService) + { + return new ZipReporter(fileService, projectService, finalSeminarService, projectForumService, peerReviewService, + peerRequestService, groupService, groupForumService, ideaService, gradingReportService, + reviewerInteractionService, roughDraftApprovalService, finalSeminarApprovalService); + } + + @Bean + public ReportServiceImpl reportService(Provider<EntityManager> em, FileService fileService) { + return new ReportServiceImpl(em, fileService); + } + + @Bean + public ResearchAreaServiceImpl researchAreaService(Provider<EntityManager> em) { + return new ResearchAreaServiceImpl(em); + } + + @Bean + public ReviewerInteractionServiceImpl reviewerInteractionService( + ReviewerThreadRepository reviewerThreadRepository, + BasicForumService forumService, + EventBus eventBus) + { + return new ReviewerInteractionServiceImpl(reviewerThreadRepository, forumService, eventBus); + } + + @Bean + public ReviewingServiceImpl reviewingService( + Provider<EntityManager> em, + EventBus eventBus, + FileService fileService) + { + return new ReviewingServiceImpl(em, fileService, eventBus); + } + + @Bean + public ReviewerCapacityServiceImpl reviewerCapacityService( + ReviewerTargetRepository reviewerTargetRepository, + DecisionRepository decisionRepository, + UserService userService, + ProjectService projectService, + EventBus eventBus) + { + return new ReviewerCapacityServiceImpl(reviewerTargetRepository, decisionRepository, userService, + projectService, eventBus); + } + + @Bean + public ReviewerDeadlineSettingsServiceImpl reviewerDeadlineSettingsService( + ReviewerDeadlineSettingsRepository reviewerDeadlineSettingsRepository) + { + return new ReviewerDeadlineSettingsServiceImpl(reviewerDeadlineSettingsRepository); + } + + @Bean + public SupervisorServiceImpl supervisorService(Provider<EntityManager> em) { + return new SupervisorServiceImpl(em); + } + + @Bean + public SurveyServiceImpl surveyService( + SurveyRepository surveyRepository, + QuestionRepository questionRepository, + FinalThesisService finalThesisService, + GeneralSystemSettingsService generalSystemSettingsService, + ReflectionService reflectionService) + { + return new SurveyServiceImpl(surveyRepository, questionRepository, finalThesisService, + generalSystemSettingsService, reflectionService); + } + + @Bean + public TargetServiceImpl targetService(Provider<EntityManager> em, IdeaService ideaService) { + return new TargetServiceImpl(em, ideaService); + } + + @Bean + public UnitServiceImpl unitService(Provider<EntityManager> em) { + return new UnitServiceImpl(em); + } + + @Bean + public UrkundApiImpl urkundApi( + UrkundSettingsRepository urkundSettingsRepository, + FileService fileService) + { + return new UrkundApiImpl(urkundSettingsRepository, fileService); + } + + @Bean + public UrkundServiceImpl urkundService( + UrkundApi urkundApi, + UrkundSubmissionRepository urkundSubmissionRepository, + Sukat sukat, + FileService fileService) + { + return new UrkundServiceImpl(urkundApi, urkundSubmissionRepository, sukat, fileService); + } + + @Bean + public UserNameServiceImpl userNameService(Provider<EntityManager> em) { + return new UserNameServiceImpl(em); + } + + @Bean + public UserProfileServiceImpl userProfileService(Provider<EntityManager> em) { + return new UserProfileServiceImpl(em); + } + + @Bean + public UserServiceImpl userService(Provider<EntityManager> em) { + return new UserServiceImpl(em); + } + + @Bean + public WorkerDataServiceImpl workerDataService(Provider<EntityManager> em) { + return new WorkerDataServiceImpl(em); + } + + @Bean + public NotificationControllerImpl notificationController( + NotificationServiceImpl notificationService, + NotificationMailFormatter notificationMailFormatter, + MailEventService mailEventService, + ReceiverConfigurationService receiverConfigurationService, + DeliveryConfigurationService deliveryConfigurationService, + Provider<CurrentUser> currentUserProvider) + { + return new NotificationControllerImpl(notificationService, + notificationMailFormatter, + mailEventService, receiverConfigurationService, deliveryConfigurationService, currentUserProvider); + } + + @Bean + public NotificationMailFormatterImpl notificationMailFormatter() { + return new NotificationMailFormatterImpl(); + } + + @Bean + public ReviewerAssignedDeadline reviewerAssignedDeadline( + EventBus eventBus, + ReviewerDeadlineSettingsService reviewerDeadlineSettingsService, + RoughDraftApprovalService roughDraftApprovalService, + FinalSeminarApprovalService finalSeminarApprovalService, + DaysService daysService, + Clock clock) + { + return new ReviewerAssignedDeadline(roughDraftApprovalService, finalSeminarApprovalService, + reviewerDeadlineSettingsService, daysService, eventBus, clock); + } + + @Bean + public DataInitializer dataInitializer() { + return new DataInitializer(); + } + + @Bean + public FinalSeminarActivityHandler finalSeminarActivityHandler( + ActivityPlanFacade activityPlanFacade, + ActivityFinalSeminarRepository activityFinalSeminarRepository, + EventBus eventBus) + { + return new FinalSeminarActivityHandler(activityPlanFacade, activityFinalSeminarRepository, eventBus); + } + + @Bean + public PostActivityUploadToForum postActivityUploadToForum( + EventBus eventBus, + ProjectForumService projectForumService, + ActivityThreadRepository activityThreadRepository) + { + return new PostActivityUploadToForum(projectForumService, activityThreadRepository, eventBus); + } + + @Bean + public ForumNotifications forumNotifications( + EventBus eventBus, + NotificationController notificationController, + ForumNotificationRepository forumNotificationRepository, + NotificationService notificationService) + { + return new ForumNotifications(eventBus, notificationController, forumNotificationRepository, + notificationService); + } + + @Bean + public ActivateCompletedMilestonesOnNewProjects activateCompletedMilestonesOnNewProjects( + EventBus eventBus, + MilestoneServiceImpl milestoneService, + PeerReviewService peerReviewService, + MilestoneActivityTemplateService milestoneActivityTemplateService, + FinalSeminarService finalSeminarService) + { + return new ActivateCompletedMilestonesOnNewProjects(peerReviewService, milestoneActivityTemplateService, + milestoneService, eventBus, finalSeminarService); + } + + @Bean + public FinalSeminarCreationSubscribers finalSeminarCreationSubscribers( + EventBus eventBus, + FinalSeminarServiceImpl finalSeminarService, + NotificationController notificationController, + AuthorRepository authorRepository) + { + return new FinalSeminarCreationSubscribers(authorRepository, finalSeminarService, notificationController, eventBus); + } + + @Bean + public ProjectStartNotifier projectStartNotifier(EventBus eventBus, NotificationController notificationController) { + return new ProjectStartNotifier(eventBus, notificationController); + } + + @Bean + public AddActivityPlanOnProjectStart addActivityPlanOnProjectStart( + ActivityPlanFacade activityPlanFacade, + EventBus eventBus) + { + return new AddActivityPlanOnProjectStart(activityPlanFacade, eventBus); + } + + @Bean + public Notifications notifications( + EventBus eventBus, + NotificationController notificationController, + NotificationService notificationService) + { + return new Notifications(notificationController, notificationService, eventBus); + } + + @Bean + public CommentThreadServiceImpl commentThreadService(CommentThreadRepo commentThreadRepository) { + return new CommentThreadServiceImpl(commentThreadRepository); + } + + @Bean + public NotificationEventServiceImpl notificationEventService(NotificationEventRepository notificationEventRepository) { + return new NotificationEventServiceImpl(notificationEventRepository); + } + + @Bean + public IdeaFacade ideaFacade() { + return new IdeaFacade(); + } + + @Bean + public GroupFacadeImpl groupFacade() { + return new GroupFacadeImpl(); + } +} diff --git a/core/src/main/java/se/su/dsv/scipro/DataInitializer.java b/core/src/main/java/se/su/dsv/scipro/DataInitializer.java index 6720ffac7e..762ea0c32a 100644 --- a/core/src/main/java/se/su/dsv/scipro/DataInitializer.java +++ b/core/src/main/java/se/su/dsv/scipro/DataInitializer.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.checklist.ChecklistCategory; import se.su.dsv.scipro.match.ApplicationPeriod; import se.su.dsv.scipro.match.Keyword; diff --git a/core/src/main/java/se/su/dsv/scipro/RepositoryConfiguration.java b/core/src/main/java/se/su/dsv/scipro/RepositoryConfiguration.java new file mode 100644 index 0000000000..6a2167bc1f --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/RepositoryConfiguration.java @@ -0,0 +1,285 @@ +package se.su.dsv.scipro; + +import jakarta.inject.Provider; +import jakarta.persistence.EntityManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import se.su.dsv.scipro.checklist.ChecklistCategoryRepoImpl; +import se.su.dsv.scipro.checklist.ChecklistQuestionRepoImpl; +import se.su.dsv.scipro.file.FileDescriptionRepoImpl; +import se.su.dsv.scipro.file.FileReferenceRepositoryImpl; +import se.su.dsv.scipro.file.ProjectFileRepositoryImpl; +import se.su.dsv.scipro.finalseminar.AuthorRepositoryImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepositoryImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepoImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarRepositoryImpl; +import se.su.dsv.scipro.forum.AbstractThreadRepositoryImpl; +import se.su.dsv.scipro.forum.ForumPostReadStateRepositoryImpl; +import se.su.dsv.scipro.forum.ForumPostRepositoryImpl; +import se.su.dsv.scipro.forum.GroupThreadRepositoryImpl; +import se.su.dsv.scipro.forum.ProjectThreadRepositoryImpl; +import se.su.dsv.scipro.forum.notifications.ForumNotificationRepositoryImpl; +import se.su.dsv.scipro.grading.GradingHistoryEventRepositoryImpl; +import se.su.dsv.scipro.grading.NationalSubjectCategoryRepositoryImpl; +import se.su.dsv.scipro.grading.PublicationMetadataRepositoryImpl; +import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepositoryImpl; +import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepositoryImpl; +import se.su.dsv.scipro.match.FirstMeetingRepositoryImpl; +import se.su.dsv.scipro.match.IdeaRepositoryImpl; +import se.su.dsv.scipro.match.TargetRepositoryImpl; +import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepositoryImpl; +import se.su.dsv.scipro.notifications.NotificationEventRepositoryImpl; +import se.su.dsv.scipro.peer.CommentThreadRepoImpl; +import se.su.dsv.scipro.peer.PeerRequestRepositoryImpl; +import se.su.dsv.scipro.peer.PeerReviewRepositoryImpl; +import se.su.dsv.scipro.plagiarism.PlagiarismRequestRepositoryImpl; +import se.su.dsv.scipro.plagiarism.urkund.UrkundSettingsRepositoryImpl; +import se.su.dsv.scipro.plagiarism.urkund.UrkundSubmissionRepositoryImpl; +import se.su.dsv.scipro.project.ProjectRepoImpl; +import se.su.dsv.scipro.projectpartner.ProjectPartnerRepositoryImpl; +import se.su.dsv.scipro.report.GradingReportTemplateRepoImpl; +import se.su.dsv.scipro.report.OppositionReportRepoImpl; +import se.su.dsv.scipro.report.SupervisorGradingReportRepositoryImpl; +import se.su.dsv.scipro.reviewing.DecisionRepositoryImpl; +import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsRepositoryImpl; +import se.su.dsv.scipro.reviewing.ReviewerTargetRepositoryImpl; +import se.su.dsv.scipro.reviewing.ReviewerThreadRepositoryImpl; +import se.su.dsv.scipro.survey.QuestionRepositoryImpl; +import se.su.dsv.scipro.survey.SurveyRepositoryImpl; +import se.su.dsv.scipro.system.FooterAddressRepoImpl; +import se.su.dsv.scipro.system.FooterLinkRepoImpl; +import se.su.dsv.scipro.system.PasswordRepoImpl; +import se.su.dsv.scipro.system.UserRepoImpl; + +@Configuration(proxyBeanMethods = false) +public class RepositoryConfiguration { + @Bean + public GradingHistoryEventRepositoryImpl gradingHistoryEventRepository(Provider<EntityManager> em) { + return new GradingHistoryEventRepositoryImpl(em); + } + + @Bean + public AbstractThreadRepositoryImpl abstractThreadRepository(Provider<EntityManager> em) { + return new AbstractThreadRepositoryImpl(em); + } + + @Bean + public ActivityFinalSeminarRepositoryImpl activityFinalSeminarRepository(Provider<EntityManager> em) { + return new ActivityFinalSeminarRepositoryImpl(em); + } + + @Bean + public ActivityThreadRepositoryImpl activityThreadRepository(Provider<EntityManager> em) { + return new ActivityThreadRepositoryImpl(em); + } + + @Bean + public AuthorRepositoryImpl authorRepository(Provider<EntityManager> em) { + return new AuthorRepositoryImpl(em); + } + + @Bean + public ChecklistCategoryRepoImpl checklistCategoryRepo(Provider<EntityManager> em) { + return new ChecklistCategoryRepoImpl(em); + } + + @Bean + public ChecklistQuestionRepoImpl checklistQuestionRepo(Provider<EntityManager> em) { + return new ChecklistQuestionRepoImpl(em); + } + + @Bean + public CommentThreadRepoImpl commentThreadRepo(Provider<EntityManager> em) { + return new CommentThreadRepoImpl(em); + } + + @Bean + public DecisionRepositoryImpl decisionRepository(Provider<EntityManager> em) { + return new DecisionRepositoryImpl(em); + } + + @Bean + public FileDescriptionRepoImpl fileDescriptionRepo(Provider<EntityManager> em) { + return new FileDescriptionRepoImpl(em); + } + + @Bean + public FinalSeminarActiveParticipationRepositoryImpl finalSeminarActiveParticipationRepository(Provider<EntityManager> em) { + return new FinalSeminarActiveParticipationRepositoryImpl(em); + } + + @Bean + public FinalSeminarRepositoryImpl finalSeminarRepository(Provider<EntityManager> em) { + return new FinalSeminarRepositoryImpl(em); + } + + @Bean + public FileReferenceRepositoryImpl fileReferenceRepository(Provider<EntityManager> em) { + return new FileReferenceRepositoryImpl(em); + } + + @Bean + public FinalSeminarOppositionRepoImpl finalSeminarOppositionRepo(Provider<EntityManager> em) { + return new FinalSeminarOppositionRepoImpl(em); + } + + @Bean + public FirstMeetingRepositoryImpl firstMeetingRepository(Provider<EntityManager> em) { + return new FirstMeetingRepositoryImpl(em); + } + + @Bean + public FooterAddressRepoImpl footerAddressRepo(Provider<EntityManager> em) { + return new FooterAddressRepoImpl(em); + } + + @Bean + public FooterLinkRepoImpl footerLinkRepo(Provider<EntityManager> em) { + return new FooterLinkRepoImpl(em); + } + + @Bean + public ForumNotificationRepositoryImpl forumNotificationRepository(Provider<EntityManager> em) { + return new ForumNotificationRepositoryImpl(em); + } + + @Bean + public ForumPostReadStateRepositoryImpl forumPostReadStateRepository(Provider<EntityManager> em) { + return new ForumPostReadStateRepositoryImpl(em); + } + + @Bean + public ForumPostRepositoryImpl forumPostRepository(Provider<EntityManager> em) { + return new ForumPostRepositoryImpl(em); + } + + @Bean + public GradingReportTemplateRepoImpl gradingReportTemplateRepo(Provider<EntityManager> em) { + return new GradingReportTemplateRepoImpl(em); + } + + @Bean + public GroupThreadRepositoryImpl groupThreadRepository(Provider<EntityManager> em) { + return new GroupThreadRepositoryImpl(em); + } + + @Bean + public IdeaRepositoryImpl ideaRepository(Provider<EntityManager> em) { + return new IdeaRepositoryImpl(em); + } + + @Bean + public MilestoneActivityTemplateRepositoryImpl milestoneActivityTemplateRepository(Provider<EntityManager> em) { + return new MilestoneActivityTemplateRepositoryImpl(em); + } + + @Bean + public NationalSubjectCategoryRepositoryImpl nationalSubjectCategoryRepository(Provider<EntityManager> em) { + return new NationalSubjectCategoryRepositoryImpl(em); + } + + @Bean + public OppositionReportRepoImpl oppositionReportRepo(Provider<EntityManager> em) { + return new OppositionReportRepoImpl(em); + } + + @Bean + public PasswordRepoImpl passwordRepo(Provider<EntityManager> em) { + return new PasswordRepoImpl(em); + } + + @Bean + public PeerRequestRepositoryImpl peerRequestRepository(Provider<EntityManager> em) { + return new PeerRequestRepositoryImpl(em); + } + + @Bean + public PeerReviewRepositoryImpl peerReviewRepository(Provider<EntityManager> em) { + return new PeerReviewRepositoryImpl(em); + } + + @Bean + public ProjectPartnerRepositoryImpl projectPartnerRepository(Provider<EntityManager> em) { + return new ProjectPartnerRepositoryImpl(em); + } + + @Bean + public ProjectRepoImpl projectRepo(Provider<EntityManager> em) { + return new ProjectRepoImpl(em); + } + + @Bean + public ProjectThreadRepositoryImpl projectThreadRepository(Provider<EntityManager> em) { + return new ProjectThreadRepositoryImpl(em); + } + + @Bean + public PublicationMetadataRepositoryImpl publicationMetadataRepository(Provider<EntityManager> em) { + return new PublicationMetadataRepositoryImpl(em); + } + + @Bean + public QuestionRepositoryImpl questionRepository(Provider<EntityManager> em) { + return new QuestionRepositoryImpl(em); + } + + @Bean + public ReviewerDeadlineSettingsRepositoryImpl reviewerDeadlineSettingsRepository(Provider<EntityManager> em) { + return new ReviewerDeadlineSettingsRepositoryImpl(em); + } + + @Bean + public ReviewerTargetRepositoryImpl reviewerTargetRepository(Provider<EntityManager> em) { + return new ReviewerTargetRepositoryImpl(em); + } + + @Bean + public ReviewerThreadRepositoryImpl reviewerThreadRepository(Provider<EntityManager> em) { + return new ReviewerThreadRepositoryImpl(em); + } + + @Bean + public SurveyRepositoryImpl surveyRepository(Provider<EntityManager> em) { + return new SurveyRepositoryImpl(em); + } + + @Bean + public TargetRepositoryImpl targetRepository(Provider<EntityManager> em) { + return new TargetRepositoryImpl(em); + } + + @Bean + public UrkundSettingsRepositoryImpl urkundSettingsRepository(Provider<EntityManager> em) { + return new UrkundSettingsRepositoryImpl(em); + } + + @Bean + public UrkundSubmissionRepositoryImpl urkundSubmissionRepository(Provider<EntityManager> em) { + return new UrkundSubmissionRepositoryImpl(em); + } + + @Bean + public UserRepoImpl userRepo(Provider<EntityManager> em) { + return new UserRepoImpl(em); + } + + @Bean + public PlagiarismRequestRepositoryImpl plagiarismRequestRepository(Provider<EntityManager> em) { + return new PlagiarismRequestRepositoryImpl(em); + } + + @Bean + public ProjectFileRepositoryImpl projectFileRepository(Provider<EntityManager> em) { + return new ProjectFileRepositoryImpl(em); + } + + @Bean + public NotificationEventRepositoryImpl notificationEventRepository(Provider<EntityManager> em) { + return new NotificationEventRepositoryImpl(em); + } + + @Bean + public SupervisorGradingReportRepositoryImpl supervisorGradingReportRepository(Provider<EntityManager> em) { + return new SupervisorGradingReportRepositoryImpl(em); + } +} diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java b/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java index 1f5182ca05..28e834f5ef 100755 --- a/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java +++ b/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java @@ -1,140 +1,164 @@ package se.su.dsv.scipro.activityplan; import com.querydsl.core.annotations.QueryInit; -import jakarta.persistence.GenerationType; -import se.su.dsv.scipro.checklist.Checklist; -import se.su.dsv.scipro.file.FileReference; -import se.su.dsv.scipro.system.LazyDeletableDomainObject; +import jakarta.persistence.Basic; +import jakarta.persistence.Table; import jakarta.persistence.Cacheable; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.GenerationType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; + +import se.su.dsv.scipro.checklist.Checklist; +import se.su.dsv.scipro.file.FileReference; +import se.su.dsv.scipro.system.LazyDeletableDomainObject; + import java.io.Serializable; -import java.util.*; +import java.util.Comparator; +import java.util.Date; +import java.util.Objects; @Entity +@Table(name = "activity") @Cacheable(true) public class Activity extends LazyDeletableDomainObject { - @Id + + public static IActivityPlan builder(){ + return new Builder(); + } + + //<editor-fold desc="Basic JPA-mappings"> + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(optional=false) - @JoinColumn (name="activityTemplate_id") - @QueryInit("project") - private ActivityPlan activityPlan; + @Basic + @Column(name = "title", nullable=false) + private String title; - @Column(nullable=false) - private Date date; + @Basic + @Column(name = "date", nullable=false) + private Date date; - @Column(nullable=false) - private String title; - - private String description; - - @OneToOne(optional = true, cascade = CascadeType.ALL) - @JoinColumn(name = "file_upload_reference_id") - private FileReference fileUpload; - - @ManyToOne - private Checklist checklist; + @Basic + @Column(name = "description") + private String description; + @Basic + @Column(name = "editable") private boolean editable = true; @Enumerated(EnumType.STRING) + @Column(name = "action") private Action action = Action.NONE; - + //</editor-fold> + + //<editor-fold desc="JPA-mappings of foreign keys in this table (activity) referencing other tables."> + @ManyToOne(optional = false) + @JoinColumn(name = "activity_plan_id", referencedColumnName = "id") + @QueryInit("project") + private ActivityPlan activityPlan; + + @ManyToOne + @JoinColumn(name = "checklist_id", referencedColumnName = "id") + private Checklist checklist; + + @OneToOne(optional = true, cascade = CascadeType.ALL) + @JoinColumn(name = "upload_file_reference_id", referencedColumnName = "id") + private FileReference fileUpload; + //</editor-fold> + + //<editor-fold desc="Constructor"> public Activity() { this.title = ""; this.description = ""; } + //</editor-fold> - @Override - public String toString(){ - return "Event: "+ getTitle()+"@"+getDate(); - } - - @Override + //<editor-fold desc="Properties (Getters and Setters)"> + @Override public Long getId() { return this.id; } - public ActivityPlan getActivityPlan() { - return this.activityPlan; - } - - public Date getDate() { - return this.date; - } - - public String getTitle() { - return this.title; - } - - public String getDescription() { - return this.description; - } - - public FileReference getFileUpload() { - return this.fileUpload; - } - - public Checklist getChecklist() { - return this.checklist; - } - - public boolean isEditable() { - return this.editable; - } - - public Action getAction() { - return this.action; - } - public void setId(Long id) { this.id = id; } - public void setActivityPlan(ActivityPlan activityPlan) { - this.activityPlan = activityPlan; - } - - public void setDate(Date date) { - this.date = date; + public String getTitle() { + return this.title; } public void setTitle(String title) { this.title = title; } + public Date getDate() { + return this.date; + } + + public void setDate(Date date) { + this.date = date; + } + + public String getDescription() { + return this.description; + } + public void setDescription(String description) { this.description = description; } - public void setFileUpload(FileReference fileUpload) { - this.fileUpload = fileUpload; - } - - public void setChecklist(Checklist checklist) { - this.checklist = checklist; + public boolean isEditable() { + return this.editable; } public void setEditable(boolean editable) { this.editable = editable; } + public Action getAction() { + return this.action; + } + public void setAction(Action action) { this.action = action; } + public ActivityPlan getActivityPlan() { + return this.activityPlan; + } + + public void setActivityPlan(ActivityPlan activityPlan) { + this.activityPlan = activityPlan; + } + + public Checklist getChecklist() { + return this.checklist; + } + + public void setChecklist(Checklist checklist) { + this.checklist = checklist; + } + + public FileReference getFileUpload() { + return this.fileUpload; + } + + public void setFileUpload(FileReference fileUpload) { + this.fileUpload = fileUpload; + } + //</editor-fold> + + //<editor-fold desc="Methods Common To All Objects"> @Override public boolean equals(final Object o) { if (o == this) return true; @@ -144,15 +168,24 @@ public class Activity extends LazyDeletableDomainObject { && Objects.equals(this.getId(), other.getId()); } - protected boolean canEqual(final Object other) { - return other instanceof Activity; + @Override + public int hashCode() { + return Objects.hashCode(getId()); } @Override - public int hashCode() { - return Objects.hashCode(getId()); - } + public String toString(){ + return "Event: "+ getTitle()+"@"+getDate(); + } + //</editor-fold> + //<editor-fold desc="Other methods"> + protected boolean canEqual(final Object other) { + return other instanceof Activity; + } + //</editor-fold> + + //<editor-fold desc="Nested types"> public static class ByDateComparator implements Comparator<Activity>, Serializable { @Override public int compare(Activity o1, Activity o2) { @@ -209,10 +242,6 @@ public class Activity extends LazyDeletableDomainObject { } } - public static IActivityPlan builder(){ - return new Builder(); - } - public interface IActivityPlan { IDate activityPlan(ActivityPlan activityPlan); } @@ -233,4 +262,5 @@ public class Activity extends LazyDeletableDomainObject { IBuild editable(boolean editable); Activity build(); } + //</editor-fold> } diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java index 2ff8883bea..8af7cd3374 100755 --- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java +++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java @@ -1,67 +1,92 @@ package se.su.dsv.scipro.activityplan; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; + +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; -import jakarta.persistence.*; import java.util.Date; import java.util.Objects; import java.util.Set; import java.util.TreeSet; @Entity +@Table(name ="activity_plan") @Cacheable(true) public class ActivityPlan extends DomainObject { + + public static IProject builder() { + return new Builder(); + } + + //<editor-fold desc="Basic JPA-mappings"> @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - + + @Basic + @Column(name = "start_date") + private Date startDate; + //</editor-fold> + + //<editor-fold desc="JPA-mappings of foreign keys in this table (activity_plan) referencing other tables"> + @OneToOne(optional=false) + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; + //</editor-fold> + + //<editor-fold desc="JPA-mappings of other tables referencing to this table "activity_plan"> @OneToMany(mappedBy= "activityPlan",cascade=CascadeType.PERSIST, orphanRemoval = true) private Set<Activity> activities = new TreeSet<>(new Activity.ByDateComparator()); - - @OneToOne(optional=false) - private Project project; - - private Date startDate; + //</editor-fold> + //<editor-fold desc="Properties (Getters and Setters)"> @Override public Long getId() { return this.id; } - public Set<Activity> getActivities() { - return this.activities; - } - - public Project getProject() { - return this.project; - } - - public Date getStartDate() { - return this.startDate; - } - public void setId(Long id) { this.id = id; } - public void setActivities(Set<Activity> activities) { - this.activities = activities; - } - - public void setProject(Project project) { - this.project = project; + public Date getStartDate() { + return this.startDate; } public void setStartDate(Date startDate) { this.startDate = startDate; } - @Override - public String toString() { - return "ActivityPlan(id=" + this.getId() + ", activities=" + this.getActivities() + ", project=" + this.getProject() + ", startDate=" + this.getStartDate() + ")"; + public Project getProject() { + return this.project; } + public void setProject(Project project) { + this.project = project; + } + + public Set<Activity> getActivities() { + return this.activities; + } + + public void setActivities(Set<Activity> activities) { + this.activities = activities; + } + //</editor-fold> + + //<editor-fold desc="Methods Common To All Objects"> @Override public boolean equals(final Object o) { if (o == this) return true; @@ -74,15 +99,25 @@ public class ActivityPlan extends DomainObject { && Objects.equals(this.getStartDate(), other.getStartDate()); } - protected boolean canEqual(final Object other) { - return other instanceof ActivityPlan; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getActivities(), this.getProject(), this.getStartDate()); } + @Override + public String toString() { + return "ActivityPlan(id=" + this.getId() + ", activities=" + this.getActivities() + ", project=" + + this.getProject() + ", startDate=" + this.getStartDate() + ")"; + } + //</editor-fold> + + //<editor-fold desc="Other methods"> + protected boolean canEqual(final Object other) { + return other instanceof ActivityPlan; + } + //</editor-fold> + + //<editor-fold desc="Nested types" private static class Builder implements IProject, IBuild { private Project project; @@ -100,10 +135,6 @@ public class ActivityPlan extends DomainObject { } } - public static IProject builder() { - return new Builder(); - } - public interface IProject { IBuild project(Project project); } @@ -111,4 +142,5 @@ public class ActivityPlan extends DomainObject { public interface IBuild { ActivityPlan build(); } + //</editor-fold> } diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java index d211c1cbac..4f7955f835 100755 --- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.activityplan; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.su.dsv.scipro.system.Pageable; diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java index 650393135d..b91217a705 100755 --- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java @@ -1,98 +1,117 @@ package se.su.dsv.scipro.activityplan; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderColumn; + +import jakarta.persistence.Table; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; -import java.util.*; - @Entity +@Table(name = "activity_plan_template") @Cacheable(true) public class ActivityPlanTemplate extends DomainObject { + //<editor-fold desc="Basic JPA-mappings"> @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OrderColumn(name = "numberInOrder") - @OneToMany(mappedBy="activityPlanTemplate", orphanRemoval=true, cascade=CascadeType.ALL) - private List<ActivityTemplate> activityTemplates = new ArrayList<>(); - - public List<ActivityTemplate> getActivityTemplates(){ - return Collections.unmodifiableList(activityTemplates); - } - - public void setActivityTemplates(List<ActivityTemplate> activityTemplates){ - this.activityTemplates = new ArrayList<>(activityTemplates); - } - - @ManyToOne(optional=false) - private User creator; - - @Column(nullable=false) - private String title; - - @Lob - private String description; - - @Column(nullable=false) + @Basic + @Column(name = "is_sys_admin_template", nullable=false) private boolean isSysAdminTemplate = false; - public void addActivity(ActivityTemplate activity){ - activity.setActivityPlanTemplate(this); - activity.setNumberInOrder(activityTemplates.size()); - activityTemplates.add(activity); - } + @Basic + @Column(name = "title", nullable = false) + private String title; - public void clearActivities(){ - activityTemplates.clear(); - } + @Basic + @Column(name = "description") + @Lob + private String description; + //</editor-fold> - public void addActivities(final Collection<ActivityTemplate> activities){ - activityTemplates.addAll(activities); - } + //<editor-fold desc="JPA-mappings of foreign keys in this table (activity_plan_template) referencing other tables."> + @ManyToOne(optional = false) + @JoinColumn(name = "creator_user_id", referencedColumnName = "id") + private User creator; + //</editor-fold> - @Override + //<editor-fold desc="JPA-mappings of other tables referencing to this table 'activity_plan_template'"> + @OneToMany(mappedBy="activityPlanTemplate", orphanRemoval=true, cascade=CascadeType.ALL) + @OrderColumn(name = "number_in_order") + private List<ActivityTemplate> activityTemplates = new ArrayList<>(); + //</editor-fold> + + //<editor-fold desc="Properties (Getters and Setters)"> + @Override public Long getId() { return this.id; } - public User getCreator() { - return this.creator; - } - - public String getTitle() { - return this.title; - } - - public String getDescription() { - return this.description; - } - - public boolean isSysAdminTemplate() { - return this.isSysAdminTemplate; - } - public void setId(Long id) { this.id = id; } - public void setCreator(User creator) { - this.creator = creator; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setDescription(String description) { - this.description = description; + public boolean isSysAdminTemplate() { + return this.isSysAdminTemplate; } public void setSysAdminTemplate(boolean isSysAdminTemplate) { this.isSysAdminTemplate = isSysAdminTemplate; } + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public User getCreator() { + return this.creator; + } + + public void setCreator(User creator) { + this.creator = creator; + } + + public List<ActivityTemplate> getActivityTemplates(){ + return Collections.unmodifiableList(activityTemplates); + } + + public void setActivityTemplates(List<ActivityTemplate> activityTemplates){ + this.activityTemplates = new ArrayList<>(activityTemplates); + } + //</editor-fold> + + //<editor-fold desc="Methods Common To All Objects"> @Override public boolean equals(final Object o) { if (o == this) return true; @@ -119,6 +138,25 @@ public class ActivityPlanTemplate extends DomainObject { @Override public String toString() { - return "ActivityPlanTemplate(id=" + this.getId() + ", creator=" + this.getCreator() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", isSysAdminTemplate=" + this.isSysAdminTemplate() + ")"; + return "ActivityPlanTemplate(id=" + this.getId() + ", creator=" + this.getCreator() + + ", title=" + this.getTitle() + ", description=" + this.getDescription() + + ", isSysAdminTemplate=" + this.isSysAdminTemplate() + ")"; } + //</editor-fold> + + //<editor-fold desc="Other methods"> + public void addActivity(ActivityTemplate activity){ + activity.setActivityPlanTemplate(this); + activity.setNumberInOrder(activityTemplates.size()); + activityTemplates.add(activity); + } + + public void clearActivities(){ + activityTemplates.clear(); + } + + public void addActivities(final Collection<ActivityTemplate> activities){ + activityTemplates.addAll(activities); + } + //</editor-fold> } diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java index c43c8a237c..6671bea897 100755 --- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java @@ -1,116 +1,142 @@ package se.su.dsv.scipro.activityplan; +import java.util.Objects; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.checklist.ChecklistTemplate; import se.su.dsv.scipro.system.DomainObject; -import jakarta.persistence.*; -import java.util.Objects; - @Entity +@Table(name = "activity_template") public class ActivityTemplate extends DomainObject { + //<editor-fold desc="Basic JPA-mappings"> @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) + @Basic + @Column(name = "title", nullable = false) private String title; + @Basic + @Column(name = "description") @Lob private String description; - @ManyToOne - private ActivityPlanTemplate activityPlanTemplate; - - @Column(nullable = false) + @Basic + @Column(name = "days_offset", nullable = false) private int daysOffset; + @Basic + @Column(name = "action") @Enumerated(EnumType.STRING) private Action action = Action.NONE; - @Column(nullable = false) + @Basic + @Column(name = "number_in_order", nullable = false) private int numberInOrder = Integer.MAX_VALUE; + //</editor-fold> + + //<editor-fold desc="JPA-mappings of foreign keys in this table (activity_template) referencing other tables."> + @ManyToOne + @JoinColumn(name = "activity_plan_template_id", referencedColumnName = "id") + private ActivityPlanTemplate activityPlanTemplate; @ManyToOne(optional = true) + @JoinColumn(name = "checklist_template_id", referencedColumnName = "id") private ChecklistTemplate checklistTemplate; + //</editor-fold> + //<editor-fold desc="Constructors"> public ActivityTemplate() { } public ActivityTemplate(int daysOffset) { this.daysOffset = daysOffset; } + //</editor-fold> - public int getDaysOffset() { - return daysOffset; - } - - public int getNumberInOrder() { - return numberInOrder; - } - + //<editor-fold desc="Properties (Getters and Setters"> @Override public Long getId() { return this.id; } - public String getTitle() { - return this.title; - } - - public String getDescription() { - return this.description; - } - - public ActivityPlanTemplate getActivityPlanTemplate() { - return this.activityPlanTemplate; - } - - public Action getAction() { - return this.action; - } - - public ChecklistTemplate getChecklistTemplate() { - return this.checklistTemplate; - } - public void setId(Long id) { this.id = id; } + public String getTitle() { + return this.title; + } + public void setTitle(String title) { this.title = title; } + public String getDescription() { + return this.description; + } + public void setDescription(String description) { this.description = description; } - public void setActivityPlanTemplate(ActivityPlanTemplate activityPlanTemplate) { - this.activityPlanTemplate = activityPlanTemplate; + public int getDaysOffset() { + return daysOffset; } public void setDaysOffset(int daysOffset) { this.daysOffset = daysOffset; } + public Action getAction() { + return this.action; + } + public void setAction(Action action) { this.action = action; } + public int getNumberInOrder() { + return numberInOrder; + } + public void setNumberInOrder(int numberInOrder) { this.numberInOrder = numberInOrder; } + public ActivityPlanTemplate getActivityPlanTemplate() { + return this.activityPlanTemplate; + } + + public void setActivityPlanTemplate(ActivityPlanTemplate activityPlanTemplate) { + this.activityPlanTemplate = activityPlanTemplate; + } + + public ChecklistTemplate getChecklistTemplate() { + return this.checklistTemplate; + } + public void setChecklistTemplate(ChecklistTemplate checklistTemplate) { this.checklistTemplate = checklistTemplate; } + //</editor-fold> - @Override - public String toString() { - return "ActivityTemplate(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", activityPlanTemplate=" + this.getActivityPlanTemplate() + ", daysOffset=" + this.getDaysOffset() + ", action=" + this.getAction() + ", numberInOrder=" + this.getNumberInOrder() + ", checklistTemplate=" + this.getChecklistTemplate() + ")"; - } - + //<editor-fold desc="Methods Common To All Objects"> @Override public boolean equals(final Object o) { if (o == this) return true; @@ -120,12 +146,24 @@ public class ActivityTemplate extends DomainObject { && Objects.equals(this.getId(), other.getId()); } - protected boolean canEqual(final Object other) { - return other instanceof ActivityTemplate; - } - @Override public int hashCode() { return Objects.hashCode(this.getId()); } -} \ No newline at end of file + + @Override + public String toString() { + return "ActivityTemplate(id=" + this.getId() + ", title=" + this.getTitle() + + ", description=" + this.getDescription() + ", activityPlanTemplate=" + + this.getActivityPlanTemplate() + ", daysOffset=" + this.getDaysOffset() + ", action=" + + this.getAction() + ", numberInOrder=" + this.getNumberInOrder() + ", checklistTemplate=" + + this.getChecklistTemplate() + ")"; + } + //</editor-fold> + + //<editor-fold desc="Other methods"> + protected boolean canEqual(final Object other) { + return other instanceof ActivityTemplate; + } + //</editor-fold> +} diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java b/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java index 3d25b8b1c1..d4c7044f52 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java @@ -1,12 +1,33 @@ package se.su.dsv.scipro.checklist; - +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapKeyJoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; @Entity @Table(name = "checklist") @@ -17,6 +38,7 @@ public class Checklist extends DomainObject { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Basic @Column(nullable = false) private String name; @@ -28,15 +50,26 @@ public class Checklist extends DomainObject { */ @Deprecated @ManyToOne(optional = false) + @JoinColumn(name = "project_id") private Project project; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinTable(name = "checklist_checklist_question", + joinColumns = @JoinColumn(name = "checklist_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "checklist_question_id", referencedColumnName = "id")) private List<ChecklistQuestion> questions = new ArrayList<>(); @ManyToMany + @JoinTable(name = "checklist_checklist_category", + joinColumns = @JoinColumn(name = "checklist_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "checklist_category_id", referencedColumnName = "id")) private List<se.su.dsv.scipro.checklist.ChecklistCategory> categories = new ArrayList<>(); @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "checklist_user_last_open_date", joinColumns = @JoinColumn(name = "checklist_id")) + @Column(name = "last_open_date") + @SuppressWarnings("JpaDataSourceORMInspection") // false warning from IntelliJ for the @MapKeyJoinColumn + @MapKeyJoinColumn(name = "user_id") private Map<User, Date> userLastOpenDate = new HashMap<>(); protected Checklist() { diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java index 05d756e6a1..704f907f40 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java @@ -1,29 +1,54 @@ package se.su.dsv.scipro.checklist; +import java.util.Objects; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; -import java.util.Objects; - @Entity @Table(name = "checklist_answer") public class ChecklistAnswer extends DomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Basic + @Column(name = "answer", nullable = false) @Enumerated(EnumType.STRING) - @Column(nullable = false) private ChecklistAnswerEnum answer; - @ManyToOne(optional = false) - private User user; - + @Basic + @Column(name = "comment") @Lob - @Column private String comment; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (checklist_answer) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected ChecklistAnswer() { } @@ -36,44 +61,45 @@ public class ChecklistAnswer extends DomainObject { this.answer = answer != null ? answer : ChecklistAnswerEnum.NO_ANSWER; } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public ChecklistAnswerEnum getAnswer() { - return this.answer; - } - - public User getUser() { - return this.user; - } - - public String getComment() { - return this.comment; - } - public void setId(Long id) { this.id = id; } + public ChecklistAnswerEnum getAnswer() { + return this.answer; + } + public void setAnswer(ChecklistAnswerEnum answer) { this.answer = answer; } - public void setUser(User user) { - this.user = user; + public String getComment() { + return this.comment; } public void setComment(String comment) { this.comment = comment; } - @Override - public String toString() { - return "ChecklistAnswer(id=" + this.getId() + ", answer=" + this.getAnswer() + ", user=" + this.getUser() + ", comment=" + this.getComment() + ")"; + public User getUser() { + return this.user; } + public void setUser(User user) { + this.user = user; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -83,12 +109,21 @@ public class ChecklistAnswer extends DomainObject { && Objects.equals(this.getId(), other.getId()); } - protected boolean canEqual(final Object other) { - return other instanceof ChecklistAnswer; - } - @Override public int hashCode() { return Objects.hashCode(this.getId()); } + + @Override + public String toString() { + return "ChecklistAnswer(id=" + this.getId() + ", answer=" + this.getAnswer() + ", user=" + this.getUser() + + ", comment=" + this.getComment() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ChecklistAnswer; + } } \ No newline at end of file diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java index 796d0ddeeb..e806794440 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java @@ -4,6 +4,6 @@ public enum ChecklistAnswerEnum { RED, GREEN, YELLOW, - NOT_APLICABLE, + NOT_APPLICABLE, NO_ANSWER } diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java index 1e1893ccda..20a612c25f 100644 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java @@ -9,7 +9,7 @@ import jakarta.persistence.EntityManager; public class ChecklistAnswerServiceImpl extends AbstractServiceImpl<ChecklistAnswer, Long> implements ChecklistAnswerService { @Inject - protected ChecklistAnswerServiceImpl(Provider<EntityManager> em) { + public ChecklistAnswerServiceImpl(Provider<EntityManager> em) { super(em, ChecklistAnswer.class, QChecklistAnswer.checklistAnswer); } } diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java index ed0f76c658..c3589be745 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java @@ -1,13 +1,17 @@ -/** - * - */ package se.su.dsv.scipro.checklist; -import se.su.dsv.scipro.system.DomainObject; - -import jakarta.persistence.*; import java.util.Objects; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import se.su.dsv.scipro.system.DomainObject; + @Entity @Table(name="checklist_category") @Cacheable(true) @@ -16,7 +20,7 @@ public class ChecklistCategory extends DomainObject { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(unique=true) + @Column(name = "category_name", unique = true) private String categoryName; protected ChecklistCategory() { diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java index 9b5883089e..64b595d29e 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.checklist; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java index 337551dc04..3678024780 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java @@ -1,13 +1,26 @@ package se.su.dsv.scipro.checklist; -import se.su.dsv.scipro.system.DomainObject; -import se.su.dsv.scipro.system.User; - -import jakarta.persistence.*; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.Lob; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +import se.su.dsv.scipro.system.DomainObject; +import se.su.dsv.scipro.system.User; + @Entity @Table(name = "checklist_question") @Cacheable(true) @@ -20,13 +33,15 @@ public class ChecklistQuestion extends DomainObject { @Column(nullable = false) private String question; - @Column(nullable = false) + @Basic + @Column(name = "question_number", nullable = false) private int questionNumber; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinTable( - joinColumns = @JoinColumn(name = "checklist_question_id") - ) + name = "checklist_question_checklist_answer", + joinColumns = @JoinColumn(name = "checklist_question_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "checklist_answer_id", referencedColumnName = "id")) private List<ChecklistAnswer> answers = new ArrayList<>(); protected ChecklistQuestion() { diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java index 410c90439a..3fb6407ebc 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.checklist; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java index cba683c25a..9a9a9c234e 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.checklist; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.activityplan.QActivity; import se.su.dsv.scipro.activityplan.QActivityPlan; import se.su.dsv.scipro.project.Project; diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java index 05b09733b1..12ad047041 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java @@ -1,11 +1,27 @@ package se.su.dsv.scipro.checklist; +import jakarta.persistence.Basic; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.ProjectType; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; @Entity @Table(name = "checklist_template") @@ -17,35 +33,42 @@ public class ChecklistTemplate extends DomainObject { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Basic @Column(nullable = false) private String name; @Basic(optional = true) + @Column(name = "description") private String description; - @Column + @Basic + @Column(name = "template_number") private int templateNumber = DEFAULT_TEMPLATE_NUMBER; - @Lob @ElementCollection + @CollectionTable(name = "checklist_template_question", + joinColumns = @JoinColumn(name = "checklist_template_id")) + @Column(name = "question") private List<String> questions = new ArrayList<>(1); @ManyToOne(optional = false) + @JoinColumn(name = "creator_user_id", referencedColumnName = "id") private User creator; @ManyToMany - @JoinTable( - joinColumns = @JoinColumn(name = "checklist_template_id") - ) + @JoinTable(name = "checklist_template_checklist_category", + joinColumns = @JoinColumn(name = "checklist_template_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "checklist_category_id", referencedColumnName = "id")) private List<ChecklistCategory> categories = new ArrayList<>(); @ManyToMany - @JoinTable(name = "checklist_template_ProjectType", + @JoinTable(name = "checklist_template_project_type", joinColumns = {@JoinColumn(name = "checklist_template_id")}, - inverseJoinColumns = {@JoinColumn(name = "projectType_id")}) + inverseJoinColumns = {@JoinColumn(name = "project_type_id")}) private Collection<ProjectType> projectTypes = new HashSet<>(); public ChecklistTemplate() { + } public ChecklistTemplate(String name, User creator) { diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java index 0e43b8c13d..336d0e8b58 100755 --- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.checklist; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.types.dsl.BooleanExpression; import se.su.dsv.scipro.system.Pageable; import se.su.dsv.scipro.project.Project; diff --git a/core/src/main/java/se/su/dsv/scipro/daisyExternal/DaisyExternalModule.java b/core/src/main/java/se/su/dsv/scipro/daisyExternal/DaisyExternalModule.java deleted file mode 100644 index 63de05fdfb..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/daisyExternal/DaisyExternalModule.java +++ /dev/null @@ -1,20 +0,0 @@ -package se.su.dsv.scipro.daisyExternal; - -import com.google.inject.Key; -import com.google.inject.PrivateModule; -import com.google.inject.Scopes; -import com.google.inject.name.Names; -import se.su.dsv.scipro.daisyExternal.http.DaisyAPI; -import se.su.dsv.scipro.daisyExternal.http.DaisyAPIImpl; - -public class DaisyExternalModule extends PrivateModule { - @Override - protected void configure() { - requireBinding(Key.get(String.class, Names.named("daisy.api.url"))); - requireBinding(Key.get(String.class, Names.named("daisy.api.username"))); - requireBinding(Key.get(String.class, Names.named("daisy.api.password"))); - - bind(DaisyAPI.class).to(DaisyAPIImpl.class).in(Scopes.SINGLETON); - expose(DaisyAPI.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/events/EventModule.java b/core/src/main/java/se/su/dsv/scipro/events/EventModule.java deleted file mode 100644 index 61fb042f87..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/events/EventModule.java +++ /dev/null @@ -1,15 +0,0 @@ -package se.su.dsv.scipro.events; - -import com.google.common.eventbus.EventBus; -import com.google.inject.AbstractModule; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EventModule extends AbstractModule { - private static final Logger LOGGER = LoggerFactory.getLogger(EventModule.class); - - @Override - protected void configure() { - bind(EventBus.class).toInstance(new EventBus((throwable, context) -> LOGGER.error("Could not dispatch event: " + context.getSubscriber() + " to " + context.getSubscriberMethod(), throwable))); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java b/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java index 7b4060922b..ac42cab487 100755 --- a/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java +++ b/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java @@ -33,25 +33,40 @@ public class FileDescription extends DomainObject { public static final int FILES_PER_SUBDIRECTORY = 1000; public static final String FILE_ROOT = "/scipro-files"; + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column + @Basic + @Column(name = "name") private String name; - @Column + @Basic + @Column(name = "mime_type") private String mimeType; - @Column - private String identifier; - - @ManyToOne - @JoinColumn(name = "userId") - private User uploader; - + @Basic + @Column(name = "size") private long size; + @Basic + @Column(name = "file_identifier") + private String identifier; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (file_description) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User uploader; + + // ---------------------------------------------------------------------------------- + // JPA lifecycle methods + // ---------------------------------------------------------------------------------- @PostRemove void removeActualData() { try { @@ -63,6 +78,96 @@ public class FileDescription extends DomainObject { } } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMimeType() { + return this.mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + public long getSize() { + return this.size; + } + + public void setSize(long size) { + this.size = size; + } + + public String getIdentifier() { + return this.identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public User getUploader() { + return this.uploader; + } + + public void setUploader(User uploader) { + this.uploader = uploader; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof FileDescription)) return false; + final FileDescription other = (FileDescription) o; + return other.canEqual(this) + && Objects.equals(this.getId(), other.getId()); + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $id = this.getId(); + result = result * PRIME + ($id == null ? 43 : $id.hashCode()); + return result; + } + + // Todo + @Override + public String toString() { + if (name != null) { + return name; + } else { + return super.toString(); + } + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof FileDescription; + } + public Path getPath0() { return FileSystems.getDefault().getPath(FILE_ROOT, getSubdirectory(), Long.toString(id)); } @@ -78,85 +183,4 @@ public class FileDescription extends DomainObject { public InputStream getData() throws IOException { return Files.newInputStream(getPath0()); } - - public String getName() { - return name; - } - - // Todo - @Override - public String toString() { - if (name != null) { - return name; - } else { - return super.toString(); - } - } - - @Override - public Long getId() { - return this.id; - } - - public String getMimeType() { - return this.mimeType; - } - - public String getIdentifier() { - return this.identifier; - } - - public User getUploader() { - return this.uploader; - } - - public long getSize() { - return this.size; - } - - public void setId(Long id) { - this.id = id; - } - - public void setName(String name) { - this.name = name; - } - - public void setMimeType(String mimeType) { - this.mimeType = mimeType; - } - - public void setIdentifier(String identifier) { - this.identifier = identifier; - } - - public void setUploader(User uploader) { - this.uploader = uploader; - } - - public void setSize(long size) { - this.size = size; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof FileDescription)) return false; - final FileDescription other = (FileDescription) o; - return other.canEqual(this) - && Objects.equals(this.getId(), other.getId()); - } - - protected boolean canEqual(final Object other) { - return other instanceof FileDescription; - } - - @Override - public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $id = this.getId(); - result = result * PRIME + ($id == null ? 43 : $id.hashCode()); - return result; - } } diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java b/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java index eccb9da1eb..c649d10bfe 100755 --- a/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.file; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileModule.java b/core/src/main/java/se/su/dsv/scipro/file/FileModule.java deleted file mode 100644 index 82cc9172ea..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/file/FileModule.java +++ /dev/null @@ -1,16 +0,0 @@ -package se.su.dsv.scipro.file; - -import com.google.inject.AbstractModule; - -public class FileModule extends AbstractModule { - @Override - protected void configure() { - bind(FileService.class).to(FileServiceImpl.class); - bind(ProjectFileService.class).to(ProjectFileServiceImpl.class); - bind(ProjectFileRepository.class).to(ProjectFileRepositoryImpl.class); - bind(FileReferenceRepository.class).to(FileReferenceRepositoryImpl.class); - bind(FileDescriptionRepo.class).to(FileDescriptionRepoImpl.class); - - requireBinding(FileStore.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileReference.java b/core/src/main/java/se/su/dsv/scipro/file/FileReference.java index 34f7ce0beb..4858d090db 100644 --- a/core/src/main/java/se/su/dsv/scipro/file/FileReference.java +++ b/core/src/main/java/se/su/dsv/scipro/file/FileReference.java @@ -9,7 +9,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import java.io.Serializable; -import java.util.*; +import java.util.Objects; /** * A reference to a file. @@ -29,7 +29,7 @@ public class FileReference implements Serializable { private Long id; @ManyToOne(cascade = CascadeType.PERSIST) - @JoinColumn(name = "file_description_id") + @JoinColumn(name = "file_description_id", referencedColumnName = "id") private FileDescription fileDescription; public Long getId() { diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java index a942b50e60..3264448133 100644 --- a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.file; -interface FileReferenceRepository { +public interface FileReferenceRepository { FileReference create(FileReference fileReference); void delete(FileReference fileReference); diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java index cacc3f7a16..25e00cf450 100644 --- a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java @@ -1,16 +1,16 @@ package se.su.dsv.scipro.file; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.AbstractRepository; import jakarta.inject.Inject; import jakarta.inject.Provider; import jakarta.persistence.EntityManager; -class FileReferenceRepositoryImpl extends AbstractRepository implements FileReferenceRepository { +public class FileReferenceRepositoryImpl extends AbstractRepository implements FileReferenceRepository { @Inject - FileReferenceRepositoryImpl(final Provider<EntityManager> em) { + public FileReferenceRepositoryImpl(final Provider<EntityManager> em) { super(em); } diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java index 2fe1f634d6..c6643f50ad 100755 --- a/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.file; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.AbstractServiceImpl; import jakarta.inject.Inject; diff --git a/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java b/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java index d63c05d4d0..ba57470626 100644 --- a/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java +++ b/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java @@ -1,71 +1,88 @@ package se.su.dsv.scipro.file; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; -import jakarta.persistence.*; import java.util.Objects; @Entity @Table(name = "project_file") public class ProjectFile extends DomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - private Project project; - + @Basic + @Column(name = "file_source") @Enumerated(EnumType.STRING) private FileSource fileSource = FileSource.FILES; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (project_file) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; + @OneToOne - @JoinColumn(name = "file_reference_id") + @JoinColumn(name = "file_reference_id", referencedColumnName = "id") private FileReference fileReference; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public Project getProject() { - return this.project; - } - - public FileSource getFileSource() { - return this.fileSource; - } - - public FileDescription getFileDescription() { - return this.fileReference.getFileDescription(); - } - public void setId(Long id) { this.id = id; } - public void setProject(Project project) { - this.project = project; + public FileSource getFileSource() { + return this.fileSource; } public void setFileSource(FileSource fileSource) { this.fileSource = fileSource; } - public void setFileReference(FileReference fileReference) { - this.fileReference = fileReference; - } - public FileReference getFileReference() { return this.fileReference; } - @Override - public String toString() { - return "ProjectFile(id=" + this.getId() + ", project=" + this.getProject() + ", fileSource=" + this.getFileSource() + ", fileDescription=" + this.getFileDescription() + ")"; + public void setFileReference(FileReference fileReference) { + this.fileReference = fileReference; } + public Project getProject() { + return this.project; + } + + public void setProject(Project project) { + this.project = project; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -79,12 +96,24 @@ public class ProjectFile extends DomainObject { && Objects.equals(this.getFileDescription(), other.getFileDescription()); } - protected boolean canEqual(final Object other) { - return other instanceof ProjectFile; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getProject(), this.getFileSource(), this.getFileDescription()); } + + @Override + public String toString() { + return "ProjectFile(id=" + this.getId() + ", project=" + this.getProject() + ", fileSource=" + this.getFileSource() + ", fileDescription=" + this.getFileDescription() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ProjectFile; + } + + public FileDescription getFileDescription() { + return this.fileReference.getFileDescription(); + } } diff --git a/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java index e995fd1831..db099d6323 100644 --- a/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.file; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.Pageable; import se.su.dsv.scipro.project.Project; diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java index 461be0f88c..1679e993a0 100755 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java @@ -23,7 +23,15 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; -import java.util.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; @Entity @Table(name = "final_seminar") @@ -35,27 +43,69 @@ public class FinalSeminar extends LazyDeletableDomainObject { public static final int DEFAULT_MAX_PARTICIPANTS = 5; public static final String FINAL_SEMINAR = "finalSeminar"; + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(optional = false) - @QueryInit({"projectType", "headSupervisor"}) - private Project project; - @Basic(optional = false) + @Column(name = "start_date") private Date startDate; @Basic(optional = false) + @Column(name = "room") private String room; + @Basic + @Column(name = "max_opponents") + private int maxOpponents = DEFAULT_MAX_OPPONENTS; + + @Basic + @Column(name = "max_participants") + private int maxParticipants = DEFAULT_MAX_PARTICIPANTS; + + @Enumerated(EnumType.STRING) + @Column(name = "presentation_lang") + private Language presentationLanguage; + + @Basic + @Column(name = "document_upload_date") + private Date documentUploadDate; + @Basic @Column(name = "extra_info") private String extraInfo; @Basic + @Column(name = "creation_reason") + private String creationReason; + + @Basic + @Column(name = "manual_participants") private Boolean manualParticipants = false; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (final_seminar) referencing other tables. + // ---------------------------------------------------------------------------------- + /* + * Cascading delete, set document to nul will delete the filedescription but + * not the actual file. Use FinarSeminarUploadController.deleteSeminarReport + * to delete the document + */ + @OneToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "document_file_reference_id", referencedColumnName = "id") + private FileReference document; + + @OneToOne(optional = false) + @JoinColumn(name = "project_id", referencedColumnName = "id") + @QueryInit({"projectType", "headSupervisor"}) + private Project project; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "final_seminar" + // ---------------------------------------------------------------------------------- @OneToMany(mappedBy = FINAL_SEMINAR, orphanRemoval = true, cascade = CascadeType.ALL) private Set<FinalSeminarActiveParticipation> activeParticipations = new HashSet<>(); @@ -65,28 +115,10 @@ public class FinalSeminar extends LazyDeletableDomainObject { @OneToMany(mappedBy = FINAL_SEMINAR, orphanRemoval = true, cascade = CascadeType.ALL) private Set<FinalSeminarRespondent> respondents = new HashSet<>(); - /* - * Cascading delete, set document to nul will delete the filedescription but - * not the actual file. Use FinarSeminarUploadController.deleteSeminarReport - * to delete the document - */ - @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name = "document_reference_id") - private FileReference document; - - private Date documentUploadDate; - - @Enumerated(EnumType.STRING) - private Language presentationLanguage; - - private int maxOpponents = DEFAULT_MAX_OPPONENTS; - private int maxParticipants = DEFAULT_MAX_PARTICIPANTS; - - @Basic - private String creationReason; - + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- public FinalSeminar() { - } public FinalSeminar(int maxOpponents, int maxParticipants) { @@ -99,6 +131,90 @@ public class FinalSeminar extends LazyDeletableDomainObject { this.project = project; } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public boolean isCancelled() { + return isDeleted(); + } + + public void setCancelled(boolean cancelled) { + setDeleted(cancelled); + } + + public Date getStartDate() { + return this.startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = (Date) startDate.clone(); + } + + public String getRoom() { + return this.room; + } + + public void setRoom(String room) { + this.room = room; + } + + public int getMaxOpponents() { + return this.maxOpponents; + } + + public void setMaxOpponents(int maxOpponents) { + this.maxOpponents = maxOpponents; + } + + public int getMaxParticipants() { + return this.maxParticipants; + } + + public void setMaxParticipants(int maxParticipants) { + this.maxParticipants = maxParticipants; + } + + public Language getPresentationLanguage() { + return this.presentationLanguage; + } + + public void setPresentationLanguage(Language presentationLanguage) { + this.presentationLanguage = presentationLanguage; + } + + public Date getDocumentUploadDate() { + return this.documentUploadDate; + } + + public void setDocumentUploadDate(Date documentUploadDate) { + this.documentUploadDate = documentUploadDate; + } + + public String getExtraInfo() { + return extraInfo; + } + + public void setExtraInfo(String extraInfo) { + this.extraInfo = extraInfo; + } + + public String getCreationReason() { + return this.creationReason; + } + + public void setCreationReason(String creationReason) { + this.creationReason = creationReason; + } + public Boolean getManualParticipants() { return manualParticipants; } @@ -107,21 +223,83 @@ public class FinalSeminar extends LazyDeletableDomainObject { this.manualParticipants = manualParticipants; } - public void setStartDate(Date startDate) { - this.startDate = (Date) startDate.clone(); + public FileReference getDocument() { + return this.document; + } + + public void setDocument(FileReference document) { + this.document = document; } public Project getProject() { return project; } + public void setProject(Project project) { + this.project = project; + } + + public Set<FinalSeminarActiveParticipation> getActiveParticipations() { + return Collections.unmodifiableSet(activeParticipations); + } + public void setActiveParticipations(Collection<FinalSeminarActiveParticipation> activeParticipations) { this.activeParticipations.clear(); this.activeParticipations.addAll(activeParticipations); } - public Set<FinalSeminarActiveParticipation> getActiveParticipations() { - return Collections.unmodifiableSet(activeParticipations); + public Set<FinalSeminarOpposition> getOppositions() { + return Collections.unmodifiableSet(oppositions); + } + + public void setOppositions(Collection<FinalSeminarOpposition> oppositions) { + this.oppositions.clear(); + this.oppositions.addAll(oppositions); + } + + public Set<FinalSeminarRespondent> getRespondents() { + return this.respondents; + } + + public void setRespondents(Set<FinalSeminarRespondent> respondents) { + this.respondents = respondents; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof FinalSeminar)) return false; + final FinalSeminar other = (FinalSeminar) o; + return other.canEqual(this) + && super.equals(o) + && Objects.equals(this.getId(), other.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.getId()); + } + + @Override + public String toString() { + return "FinalSeminar(id=" + this.getId() + ", project=" + this.getProject() + ", startDate=" + + this.getStartDate() + ", room=" + this.getRoom() + ", activeParticipations=" + + this.getActiveParticipations() + ", oppositions=" + this.getOppositions() + + ", respondents=" + this.getRespondents() + ", document=" + this.getDocument() + + ", documentUploadDate=" + this.getDocumentUploadDate() + ", presentationLanguage=" + + this.getPresentationLanguage() + ", maxOpponents=" + this.getMaxOpponents() + + ", maxParticipants=" + this.getMaxParticipants() + ", creationReason=" + + this.getCreationReason() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof FinalSeminar; } public void addActiveParticipant(FinalSeminarActiveParticipation participation) { @@ -132,25 +310,62 @@ public class FinalSeminar extends LazyDeletableDomainObject { this.activeParticipations.remove(participation); } - public void setOppositions(Collection<FinalSeminarOpposition> oppositions) { - this.oppositions.clear(); - this.oppositions.addAll(oppositions); + public void removeActiveParticipant(User user) { + activeParticipations.removeIf(next -> next.getUser().equals(user)); } - public Set<FinalSeminarOpposition> getOppositions() { - return Collections.unmodifiableSet(oppositions); + public Set<User> getActiveParticipants(){ + Set<User> activeParticipants = new HashSet<>(); + for (FinalSeminarActiveParticipation fsap : activeParticipations){ + activeParticipants.add(fsap.getUser()); + } + return activeParticipants; + } + + public Collection<User> getNotGradedActiveParticipations() { + return getNotGradedParticipations(activeParticipations); } public void addOpposition(FinalSeminarOpposition opposition) { this.oppositions.add(opposition); } + public void removeOpposition(FinalSeminarOpposition opposition) { + this.oppositions.remove(opposition); + } + + public Set<User> getOpponents(){ + Set<User> opponents = new HashSet<>(); + for (FinalSeminarOpposition fso : oppositions){ + opponents.add(fso.getUser()); + } + return opponents; + } + + public Collection<User> getNotGradedOpponents() { + return getNotGradedParticipations(oppositions); + } + + public Collection<User> getNotGradedRespondents() { + return getNotGradedParticipations(respondents); + } + + private Collection<User> getNotGradedParticipations(Set<? extends FinalSeminarParticipation> participations) { + List<User> result = new ArrayList<>(); + for (FinalSeminarParticipation participation : participations) { + if(participation.getGrade() == null) { + result.add(participation.getUser()); + } + } + return result; + } + public int getMinOpponents() { - return project.getMinOpponentsOnFinalSeminar(); + return getProject().getMinOpponentsOnFinalSeminar(); } public int getMinActiveParticipants() { - return project.getMinFinalSeminarActiveParticipation(); + return getProject().getMinFinalSeminarActiveParticipation(); } public List<Member> getMembers() { @@ -172,177 +387,10 @@ public class FinalSeminar extends LazyDeletableDomainObject { } public ProjectType getProjectType() { - return project.getProjectType(); + return getProject().getProjectType(); } public String getProjectTitle() { - return project.getTitle(); + return getProject().getTitle(); } - - public void setCancelled(boolean cancelled) { - setDeleted(cancelled); - } - - public boolean isCancelled() { - return isDeleted(); - } - - public void removeOpposition(FinalSeminarOpposition opposition) { - this.oppositions.remove(opposition); - } - - public Collection<User> getNotGradedOpponents() { - return getNotGradedParticipations(oppositions); - } - - public Collection<User> getNotGradedActiveParticipations() { - return getNotGradedParticipations(activeParticipations); - } - - public Collection<User> getNotGradedRespondents() { - return getNotGradedParticipations(respondents); - } - - private Collection<User> getNotGradedParticipations(Set<? extends FinalSeminarParticipation> participations) { - List<User> result = new ArrayList<>(); - for (FinalSeminarParticipation participation : participations) { - if(participation.getGrade() == null) { - result.add(participation.getUser()); - } - } - return result; - } - - public Set<User> getOpponents(){ - Set<User> opponents = new HashSet<>(); - for (FinalSeminarOpposition fso : oppositions){ - opponents.add(fso.getUser()); - } - return opponents; - } - - public Set<User> getActiveParticipants(){ - Set<User> activeParticipants = new HashSet<>(); - for (FinalSeminarActiveParticipation fsap : activeParticipations){ - activeParticipants.add(fsap.getUser()); - } - return activeParticipants; - } - - public void removeActiveParticipant(User user) { - activeParticipations.removeIf(next -> next.getUser().equals(user)); - } - - @Override - public Long getId() { - return this.id; - } - - public Date getStartDate() { - return this.startDate; - } - - public String getRoom() { - return this.room; - } - - public Set<FinalSeminarRespondent> getRespondents() { - return this.respondents; - } - - public FileReference getDocument() { - return this.document; - } - - public Date getDocumentUploadDate() { - return this.documentUploadDate; - } - - public Language getPresentationLanguage() { - return this.presentationLanguage; - } - - public int getMaxOpponents() { - return this.maxOpponents; - } - - public int getMaxParticipants() { - return this.maxParticipants; - } - - public void setId(Long id) { - this.id = id; - } - - public void setProject(Project project) { - this.project = project; - } - - public void setRoom(String room) { - this.room = room; - } - - public void setRespondents(Set<FinalSeminarRespondent> respondents) { - this.respondents = respondents; - } - - public void setDocument(FileReference document) { - this.document = document; - } - - public void setDocumentUploadDate(Date documentUploadDate) { - this.documentUploadDate = documentUploadDate; - } - - public void setPresentationLanguage(Language presentationLanguage) { - this.presentationLanguage = presentationLanguage; - } - - public void setMaxOpponents(int maxOpponents) { - this.maxOpponents = maxOpponents; - } - - public void setMaxParticipants(int maxParticipants) { - this.maxParticipants = maxParticipants; - } - - public void setCreationReason(String creationReason) { - this.creationReason = creationReason; - } - - public String getExtraInfo() { - return extraInfo; - } - - public void setExtraInfo(String extraInfo) { - this.extraInfo = extraInfo; - } - - @Override - public String toString() { - return "FinalSeminar(id=" + this.getId() + ", project=" + this.getProject() + ", startDate=" + this.getStartDate() + ", room=" + this.getRoom() + ", activeParticipations=" + this.getActiveParticipations() + ", oppositions=" + this.getOppositions() + ", respondents=" + this.getRespondents() + ", document=" + this.getDocument() + ", documentUploadDate=" + this.getDocumentUploadDate() + ", presentationLanguage=" + this.getPresentationLanguage() + ", maxOpponents=" + this.getMaxOpponents() + ", maxParticipants=" + this.getMaxParticipants() + ", creationReason=" + this.getCreationReason() + ")"; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof FinalSeminar)) return false; - final FinalSeminar other = (FinalSeminar) o; - return other.canEqual(this) - && super.equals(o) - && Objects.equals(this.getId(), other.getId()); - } - - protected boolean canEqual(final Object other) { - return other instanceof FinalSeminar; - } - - @Override - public int hashCode() { - return Objects.hashCode(this.getId()); - } - - public String getCreationReason() { - return this.creationReason; - } -} \ No newline at end of file +} diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java index 4930b37979..fdc7bf1429 100755 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.finalseminar; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.project.Project; import jakarta.persistence.Cacheable; @@ -9,13 +10,20 @@ import jakarta.persistence.Table; import java.util.Objects; @Entity -@Cacheable(true) @Table(name = "final_seminar_active_participation") +@Cacheable(true) public class FinalSeminarActiveParticipation extends FinalSeminarParticipation { - + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (final_seminar_active_participation) + // referencing other tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = false) + @JoinColumn(name = "project_id", referencedColumnName = "id") private Project project; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Project getProject() { return this.project; } @@ -24,6 +32,9 @@ public class FinalSeminarActiveParticipation extends FinalSeminarParticipation { this.project = project; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -34,13 +45,16 @@ public class FinalSeminarActiveParticipation extends FinalSeminarParticipation { && Objects.equals(this.project, other.project); } - @Override - protected boolean canEqual(final Object other) { - return other instanceof FinalSeminarActiveParticipation; - } - @Override public int hashCode() { return Objects.hash(super.hashCode(), this.getProject()); } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + @Override + protected boolean canEqual(final Object other) { + return other instanceof FinalSeminarActiveParticipation; + } } diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java index 65cf89e756..de9c6cd3a4 100755 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java @@ -13,73 +13,90 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; -import java.util.*; + +import java.util.Objects; @Entity @Table(name="final_seminar_opposition") public class FinalSeminarOpposition extends FinalSeminarParticipation { - public static final int FEEDBACK_LENGTH = 2000; - @ManyToOne(optional = false) - private Project project; - - @OneToOne - @JoinColumn(name = "opponent_report_reference_id") - private FileReference opponentReport; - - @OneToOne(optional = true, orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "finalSeminarOpposition") - private OppositionReport oppositionReport; + private static final int FEEDBACK_LENGTH = 2000; + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Basic + @Column(name = "points") private Integer points; @Basic - @Column(length = FEEDBACK_LENGTH) + @Column(name = "feedback", length = FEEDBACK_LENGTH) private String feedback; - public ProjectType getProjectType() { - return getFinalSeminar().getProject().getProjectType(); - } + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (final_seminar_opposition) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @OneToOne + @JoinColumn(name = "opponent_report_file_reference_id", referencedColumnName = "id") + private FileReference opponentReport; - public void setProject(final Project project) { - this.project = project; - } + @ManyToOne(optional = false) + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; - public Project getProject() { - return this.project; - } - - public FileReference getOpponentReport() { - return this.opponentReport; - } - - public OppositionReport getOppositionReport() { - return this.oppositionReport; - } + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table (final_seminar_opposition) + // ---------------------------------------------------------------------------------- + @OneToOne(optional = true, orphanRemoval = true, cascade = CascadeType.ALL, + mappedBy = "finalSeminarOpposition") + private OppositionReport oppositionReport; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Integer getPoints() { return this.points; } - public String getFeedback() { - return this.feedback; - } - - public void setOpponentReport(FileReference opponentReport) { - this.opponentReport = opponentReport; - } - - public void setOppositionReport(OppositionReport oppositionReport) { - this.oppositionReport = oppositionReport; - } - public void setPoints(Integer points) { this.points = points; } + public String getFeedback() { + return this.feedback; + } + public void setFeedback(String feedback) { this.feedback = feedback; } + public FileReference getOpponentReport() { + return this.opponentReport; + } + + public void setOpponentReport(FileReference opponentReport) { + this.opponentReport = opponentReport; + } + + public Project getProject() { + return this.project; + } + + public void setProject(final Project project) { + this.project = project; + } + + public OppositionReport getOppositionReport() { + return this.oppositionReport; + } + + public void setOppositionReport(OppositionReport oppositionReport) { + this.oppositionReport = oppositionReport; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -90,13 +107,20 @@ public class FinalSeminarOpposition extends FinalSeminarParticipation { && Objects.equals(this.getProject(), other.getProject()); } + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), this.getProject()); + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- @Override protected boolean canEqual(final Object other) { return other instanceof FinalSeminarOpposition; } - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), this.getProject()); + public ProjectType getProjectType() { + return getFinalSeminar().getProject().getProjectType(); } } diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java index 7def75b680..46957a9678 100755 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.finalseminar; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.system.ProjectType; diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java index 43d94e05e8..8d97c21020 100644 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java @@ -1,64 +1,66 @@ package se.su.dsv.scipro.finalseminar; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.Objects; @MappedSuperclass public abstract class FinalSeminarParticipation extends DomainObject { - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(optional = false) - private User user; + @Basic + @Enumerated(EnumType.STRING) + @Column(name = "grade") + private FinalSeminarGrade grade = null; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in tables whose entity class inherits from + // FinalSeminarParticipation class (such as final_seminar_active_participation, + // final_seminar_opposition, final_seminar_respondent) referencing other tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = false) + @JoinColumn(name = "final_seminar_id", referencedColumnName = "id") private FinalSeminar finalSeminar; - @Enumerated(EnumType.STRING) - private FinalSeminarGrade grade = null; + @ManyToOne(optional = false) + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- + protected FinalSeminarParticipation() { + } protected FinalSeminarParticipation(User user, FinalSeminar finalSeminar) { this.user = user; this.finalSeminar = finalSeminar; } - protected FinalSeminarParticipation() { - } - - public boolean isApproved() { - return grade == FinalSeminarGrade.APPROVED; - } - - public boolean hasGrade() { - return (grade != null); - } - - public void setUser(final User user) { - this.user = user; - } - - public void setFinalSeminar(final FinalSeminar finalSeminar) { - this.finalSeminar = finalSeminar; - } - + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public User getUser() { - return this.user; - } - - public FinalSeminar getFinalSeminar() { - return this.finalSeminar; - } - public FinalSeminarGrade getGrade() { return this.grade; } @@ -67,6 +69,29 @@ public abstract class FinalSeminarParticipation extends DomainObject { this.grade = grade; } + public boolean hasGrade() { + return (grade != null); + } + + public FinalSeminar getFinalSeminar() { + return this.finalSeminar; + } + + public void setFinalSeminar(final FinalSeminar finalSeminar) { + this.finalSeminar = finalSeminar; + } + + public User getUser() { + return this.user; + } + + public void setUser(final User user) { + this.user = user; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -77,12 +102,20 @@ public abstract class FinalSeminarParticipation extends DomainObject { && Objects.equals(this.getFinalSeminar(), other.getFinalSeminar()); } - protected boolean canEqual(final Object other) { - return other instanceof FinalSeminarParticipation; - } - @Override public int hashCode() { return Objects.hash(this.getUser(), this.getFinalSeminar()); } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + + protected boolean canEqual(final Object other) { + return other instanceof FinalSeminarParticipation; + } + + public boolean isApproved() { + return grade == FinalSeminarGrade.APPROVED; + } } diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java index f17e41be75..40e72964a7 100644 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.finalseminar; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.persistence.EntityManager; import se.su.dsv.scipro.system.AbstractRepository; @@ -9,7 +9,7 @@ import jakarta.inject.Provider; public class FinalSeminarRepositoryImpl extends AbstractRepository implements FinalSeminarRepository { @Inject - protected FinalSeminarRepositoryImpl(Provider<EntityManager> em) { + public FinalSeminarRepositoryImpl(Provider<EntityManager> em) { super(em); } diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java index 2178db68c1..92bf8ee457 100644 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java @@ -8,17 +8,17 @@ import jakarta.persistence.Entity; import jakarta.persistence.Table; @Entity -@Cacheable(true) @Table(name = "final_seminar_respondent") +@Cacheable(true) public class FinalSeminarRespondent extends FinalSeminarParticipation { + protected FinalSeminarRespondent() { + } + public FinalSeminarRespondent(User student, FinalSeminar finalSeminar) { super(student, finalSeminar); } - protected FinalSeminarRespondent() { - } - public Project getProject() { return getFinalSeminar().getProject(); } diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java index ee7478c33c..f532f0289d 100644 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.finalseminar; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.AbstractServiceImpl; import se.su.dsv.scipro.system.User; @@ -33,6 +34,7 @@ public class FinalSeminarRespondentServiceImpl extends AbstractServiceImpl<Final } @Override + @Transactional public List<FinalSeminarRespondent> findOrCreate(FinalSeminar finalSeminar) { if(finalSeminar.getId() == null) { return new ArrayList<>(); diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java index e3510ddfae..b5514bcd3e 100755 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.finalseminar; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.dsl.BooleanExpression; import jakarta.persistence.EntityManager; diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java index b95f64e994..7a62ea83e9 100644 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java @@ -7,6 +7,7 @@ import java.util.Objects; @Entity @Cacheable(true) +@Table(name = "final_seminar_settings") public class FinalSeminarSettings extends DomainObject { public static final int DEFAULT_DAYS_AHEAD_TO_UPLOAD_THESIS = 10; public static final int DEFAULT_DAYS_AHEAD_TO_REGISTER_OPPOSITION = 3; @@ -22,25 +23,26 @@ public class FinalSeminarSettings extends DomainObject { this.id = id; } - @Basic(optional = false) + @Column(name = "days_ahead_to_create", nullable = false) private int daysAheadToCreate; - @Basic(optional = false) + @Column(name = "days_ahead_to_register_participation", nullable = false) private int daysAheadToRegisterParticipation = DEFAULT_DAYS_AHEAD_TO_REGISTER_PARTICIPATION; - @Basic(optional = false) + @Column(name = "days_ahead_to_register_opposition", nullable = false) private int daysAheadToRegisterOpposition = DEFAULT_DAYS_AHEAD_TO_REGISTER_OPPOSITION; - @Basic(optional = false) + @Column(name = "days_ahead_to_upload_thesis", nullable = false) private int daysAheadToUploadThesis = DEFAULT_DAYS_AHEAD_TO_UPLOAD_THESIS; - @Basic(optional = false) + @Column(name = "thesis_must_be_pdf", nullable = false) private boolean thesisMustBePDF = false; - @Basic(optional = true) + @Column(name = "evaluation_url", nullable = true) private String evaluationURL; @Basic(optional = false) + @Column(name = "opposition_priority_days", nullable = false) private int oppositionPriorityDays; public boolean getThesisMustBePDF() { diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java index 24aa74c59e..c912f35abb 100755 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.finalseminar; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.AbstractServiceImpl; import jakarta.inject.Inject; diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java index 5feff42af2..2613d77c32 100755 --- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.finalseminar; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.su.dsv.scipro.file.*; diff --git a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java index 894e798a5f..818bfc2b0c 100644 --- a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java +++ b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java @@ -21,50 +21,67 @@ import jakarta.persistence.Table; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; -import java.util.*; +import java.util.Date; +import java.util.Objects; @Entity -@Table +@Table(name = "final_thesis") public class FinalThesis extends DomainObject { - public enum Status { - APPROVED, REJECTED, NO_DECISION - } - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(optional = false) - @JoinColumn(name = "document_reference_id") - private FileReference document; + @Basic + @Column(name = "title_sv") + private String swedishTitle; - @ManyToOne(optional = true) - @JoinColumn(name = "text_matching_document_reference_id") - private FileReference textMatchingDocument; + @Basic + @Column(name = "title_en") + private String englishTitle; + + @Basic + @Column(name = "status") + @Enumerated(EnumType.STRING) + private Status status = Status.NO_DECISION; + + @Basic + @Column(name = "date_approved") + private Date dateApproved; + + @Basic + @Column(name = "date_rejected") + private Date dateRejected; + + @Basic + @Column(name = "rejection_comment") + private String rejectionComment; @Basic @Column(name = "text_matching_analysis") private String textMatchingAnalysis; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (final_thesis) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = true) + @JoinColumn(name = "text_matching_document_reference_id", referencedColumnName = "id") + private FileReference textMatchingDocument; + @ManyToOne(optional = false) - @JoinColumn(name = "project_id") + @JoinColumn(name = "document_reference_id", referencedColumnName = "id") + private FileReference document; + + @ManyToOne(optional = false) + @JoinColumn(name = "project_id", referencedColumnName = "id") private Project project; - @Enumerated(EnumType.STRING) - private Status status = Status.NO_DECISION; - - private Date dateApproved; - - private Date dateRejected; - - private String englishTitle; - - private String swedishTitle; - - @Column(name = "rejection_comment") - private String rejectionComment; - + // ---------------------------------------------------------------------------------- + // JPA lifecycle method + // ---------------------------------------------------------------------------------- @PrePersist @PreUpdate void cleanTitle() { @@ -72,6 +89,126 @@ public class FinalThesis extends DomainObject { this.swedishTitle = clean(this.swedishTitle); } + + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getEnglishTitle() { + return this.englishTitle; + } + + public void setEnglishTitle(String englishTitle) { + this.englishTitle = englishTitle; + } + + public String getSwedishTitle() { + return this.swedishTitle; + } + + public void setSwedishTitle(String swedishTitle) { + this.swedishTitle = swedishTitle; + } + + public Status getStatus() { + return this.status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public Date getDateApproved() { + return dateApproved; + } + + public void setDateApproved(Date dateApproved) { + this.dateApproved = dateApproved; + } + + public Date getDateRejected() { + return dateRejected; + } + + public void setDateRejected(Date dateRejected) { + this.dateRejected = dateRejected; + } + + public String getRejectionComment() { + return rejectionComment; + } + + public void setRejectionComment(String rejectionComment) { + this.rejectionComment = rejectionComment; + } + + public String getTextMatchingAnalysis() { + return textMatchingAnalysis; + } + + public void setTextMatchingAnalysis(String textMatchingAnalysis) { + this.textMatchingAnalysis = textMatchingAnalysis; + } + + public FileReference getTextMatchingDocument() { + return this.textMatchingDocument; + } + + public void setTextMatchingDocument(FileReference textMatchingDocument) { + this.textMatchingDocument = textMatchingDocument; + } + + public FileReference getDocument() { + return this.document; + } + + public void setDocument(FileReference fileDescription) { + this.document = fileDescription; + } + + public Project getProject() { + return this.project; + } + + public void setProject(Project project) { + this.project = project; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof FinalThesis)) return false; + final FinalThesis other = (FinalThesis) o; + return other.canEqual(this) + && Objects.equals(this.getDocument(), other.getDocument()) + && Objects.equals(this.getProject(), other.getProject()); + } + + @Override + public int hashCode() { + return Objects.hash(this.getDocument(), this.getProject()); + } + + @Override + public String toString() { + return "FinalThesis(id=" + this.getId() + ", fileDescription=" + this.getDocument() + ", textMatchingDocument=" + this.getTextMatchingDocument() + ", project=" + this.getProject() + ", status=" + this.getStatus() + ", dateApproved=" + this.getDateApproved() + ", dateRejected=" + this.getDateRejected() + ", englishTitle=" + this.getEnglishTitle() + ", swedishTitle=" + this.getSwedishTitle() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- private String clean(String str) { if (str == null) { return null; @@ -83,125 +220,23 @@ public class FinalThesis extends DomainObject { .trim(); } - @Override - public Long getId() { - return this.id; - } - - public FileReference getDocument() { - return this.document; - } - - public FileReference getTextMatchingDocument() { - return this.textMatchingDocument; - } - - public Project getProject() { - return this.project; - } - - public Status getStatus() { - return this.status; - } - - public String getEnglishTitle() { - return this.englishTitle; - } - - public String getSwedishTitle() { - return this.swedishTitle; - } - - public void setId(Long id) { - this.id = id; - } - - public void setDocument(FileReference fileDescription) { - this.document = fileDescription; - } - - public void setTextMatchingDocument(FileReference textMatchingDocument) { - this.textMatchingDocument = textMatchingDocument; - } - - public void setProject(Project project) { - this.project = project; - } - - public void setStatus(Status status) { - this.status = status; - } - - public void setDateApproved(Date dateApproved) { - this.dateApproved = dateApproved; - } - - public void setDateRejected(Date dateRejected) { - this.dateRejected = dateRejected; - } - - public void setEnglishTitle(String englishTitle) { - this.englishTitle = englishTitle; - } - - public void setSwedishTitle(String swedishTitle) { - this.swedishTitle = swedishTitle; - } - - public String getTextMatchingAnalysis() { - return textMatchingAnalysis; - } - - public void setTextMatchingAnalysis(String textMatchingAnalysis) { - this.textMatchingAnalysis = textMatchingAnalysis; - } - - public String getRejectionComment() { - return rejectionComment; - } - - public void setRejectionComment(String rejectionComment) { - this.rejectionComment = rejectionComment; - } - - @Override - public String toString() { - return "FinalThesis(id=" + this.getId() + ", fileDescription=" + this.getDocument() + ", textMatchingDocument=" + this.getTextMatchingDocument() + ", project=" + this.getProject() + ", status=" + this.getStatus() + ", dateApproved=" + this.getDateApproved() + ", dateRejected=" + this.getDateRejected() + ", englishTitle=" + this.getEnglishTitle() + ", swedishTitle=" + this.getSwedishTitle() + ")"; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof FinalThesis)) return false; - final FinalThesis other = (FinalThesis) o; - return other.canEqual(this) - && Objects.equals(this.getDocument(), other.getDocument()) - && Objects.equals(this.getProject(), other.getProject()); - } - protected boolean canEqual(final Object other) { return other instanceof FinalThesis; } - @Override - public int hashCode() { - return Objects.hash(this.getDocument(), this.getProject()); - } - - public boolean isRejected() { - return getStatus() == Status.REJECTED; - } - - public Date getDateRejected() { - return dateRejected; - } - - public Date getDateApproved() { - return dateApproved; - } - public LocalDate getUploadDate() { Instant instant = document.getFileDescription().getDateCreated().toInstant(); return instant.atZone(ZoneId.systemDefault()).toLocalDate(); } + + public boolean isRejected() { + return getStatus() == Status.REJECTED; + } + + // ---------------------------------------------------------------------------------- + // Nested types + // ---------------------------------------------------------------------------------- + public enum Status { + APPROVED, REJECTED, NO_DECISION + } } diff --git a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java index 98b775c07b..f505a3d189 100644 --- a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.finalthesis; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Predicate; import jakarta.persistence.EntityManager; @@ -56,6 +56,7 @@ public class FinalThesisServiceImpl extends AbstractServiceImpl<FinalThesis, Lon } @Override + @Transactional public FinalThesis upload(ProjectFileUpload fileUpload, String englishTitle, String swedishTitle) { ProjectFile fileDescription = storeFinalThesisFile(fileUpload); final FileReference reference = fileService.createReference(fileDescription.getFileDescription()); @@ -133,6 +134,7 @@ public class FinalThesisServiceImpl extends AbstractServiceImpl<FinalThesis, Lon } @Override + @Transactional public void removeApproval(Project project) { setStatus(project, FinalThesis.Status.NO_DECISION); } diff --git a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingModule.java b/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingModule.java deleted file mode 100644 index e567605a8d..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingModule.java +++ /dev/null @@ -1,11 +0,0 @@ -package se.su.dsv.scipro.firstmeeting; - -import com.google.inject.AbstractModule; -import se.su.dsv.scipro.firstmeeting.FirstMeetingReminderWorker.FirstMeetingReminderWorkerSchedule; - -public class FirstMeetingModule extends AbstractModule { - @Override - public void configure() { - bind(FirstMeetingReminderWorkerSchedule.class).asEagerSingleton(); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java index 23d1832201..1ab1e575a8 100644 --- a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.firstmeeting; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.activityplan.Activity; import se.su.dsv.scipro.activityplan.ActivityPlanFacade; import se.su.dsv.scipro.project.Project; @@ -26,6 +27,7 @@ public class FirstMeetingServiceImpl extends AbstractServiceImpl<ProjectFirstMee } @Override + @Transactional public ProjectFirstMeeting schedule(final Project project, final Date date, final String room, final String description) { final Optional<ProjectFirstMeeting> optFirstMeeting = findByProject(project); final ProjectFirstMeeting firstMeeting = optFirstMeeting diff --git a/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java b/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java index acfaa134eb..759f63f781 100644 --- a/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java +++ b/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java @@ -1,37 +1,58 @@ package se.su.dsv.scipro.firstmeeting; import com.querydsl.core.annotations.QueryInit; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.activityplan.Activity; import se.su.dsv.scipro.system.DomainObject; -import jakarta.persistence.*; import java.util.Date; @Entity @Table(name = "project_first_meeting") public final class ProjectFirstMeeting extends DomainObject { + // ---------------------------------------------------------------------------------- + // basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @QueryInit("activityPlan.project") - @OneToOne(optional = false, cascade = CascadeType.ALL) - private Activity activity; - @Basic(optional = false) + @Column(name = "room") private String room; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (project_first_meeting) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @OneToOne(optional = false, cascade = CascadeType.ALL) + @JoinColumn(name = "activity_id", referencedColumnName = "id") + @QueryInit("activityPlan.project") + private Activity activity; + + // ---------------------------------------------------------------------------------- + // constructor + // ---------------------------------------------------------------------------------- protected ProjectFirstMeeting() {} + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- @Override public Long getId() { return id; } - public Date getDate() { - return activity.getDate(); - } - public String getRoom() { return room; } @@ -40,10 +61,6 @@ public final class ProjectFirstMeeting extends DomainObject { this.room = room; } - public String getDescription() { - return activity.getDescription(); - } - Activity getActivity() { return activity; } @@ -51,4 +68,15 @@ public final class ProjectFirstMeeting extends DomainObject { void setActivity(Activity activity) { this.activity = activity; } + + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- + public Date getDate() { + return activity.getDate(); + } + + public String getDescription() { + return activity.getDescription(); + } } diff --git a/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java index 05642970d2..0dae3383bb 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.forum; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; import se.su.dsv.scipro.forum.dataobjects.ForumPost; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumModule.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumModule.java deleted file mode 100644 index 7346fd1166..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/forum/ForumModule.java +++ /dev/null @@ -1,26 +0,0 @@ -package se.su.dsv.scipro.forum; - -import com.google.inject.PrivateModule; - -public class ForumModule extends PrivateModule { - @Override - protected void configure() { - bind(AbstractThreadRepository.class).to(AbstractThreadRepositoryImpl.class); - bind(ForumPostReadStateRepository.class).to(ForumPostReadStateRepositoryImpl.class); - bind(ForumPostRepository.class).to(ForumPostRepositoryImpl.class); - bind(ProjectThreadRepository.class).to(ProjectThreadRepositoryImpl.class); - bind(GroupThreadRepository.class).to(GroupThreadRepositoryImpl.class); - - expose(ProjectThreadRepository.class); - expose(GroupThreadRepository.class); - - bind(ProjectForumService.class).to(ProjectForumServiceImpl.class); - bind(GroupForumService.class).to(GroupForumServiceImpl.class); - - expose(ProjectForumService.class); - expose(GroupForumService.class); - - bind(BasicForumService.class).to(BasicForumServiceImpl.class); - expose(BasicForumService.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java index 4d385c0255..00dd52bb7c 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.forum; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.forum.dataobjects.ForumPost; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java index 909c57693f..862884445c 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.forum; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.persistence.LockModeType; import se.su.dsv.scipro.forum.dataobjects.ForumPost; import se.su.dsv.scipro.forum.dataobjects.ForumPostReadState; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java index 0b39495268..92e3afb1c8 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.forum; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.forum.dataobjects.ForumPost; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java index bed0169c09..0ba81e0b92 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.forum; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.forum.dataobjects.ForumPost; import se.su.dsv.scipro.forum.dataobjects.ForumThread; import se.su.dsv.scipro.forum.dataobjects.GroupThread; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java index 37e0a30d31..2c254d5bd2 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.forum; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.forum.dataobjects.GroupThread; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java index 7ed3e1715c..1825a16197 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.forum; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileSource; import se.su.dsv.scipro.file.ProjectFileService; import se.su.dsv.scipro.forum.dataobjects.ForumPost; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java index b50913b764..cbe28506a1 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.forum; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.forum.dataobjects.ProjectThread; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java index 7740741863..aff80a655f 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.forum.dataobjects; +import jakarta.persistence.Basic; import jakarta.persistence.GenerationType; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.system.LazyDeletableDomainObject; @@ -15,54 +16,51 @@ import jakarta.persistence.Lob; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; -import java.util.*; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; @Entity @Table(name = "forum_post") public class ForumPost extends LazyDeletableDomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Lob + @Basic @Column(name = "content", nullable = false) + @Lob private String content; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (forum_post) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne - @JoinColumn(name = "user", nullable = true) - private User postedBy; - - @ManyToOne - @JoinColumn(name = "thread", nullable = false) + @JoinColumn(name = "thread_id", nullable = false) private ForumThread forumThread; + @ManyToOne + @JoinColumn(name = "user_id", nullable = true) + private User postedBy; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "forum_post" + // ---------------------------------------------------------------------------------- @OneToMany(orphanRemoval = true) - @JoinTable(name = "forum_post_file_description", - joinColumns = {@JoinColumn(name = "forum_post_id")}, + @JoinTable(name = "forum_post_file_reference", + joinColumns = {@JoinColumn(name = "forum_post_id", referencedColumnName = "id")}, inverseJoinColumns = {@JoinColumn(name = "file_reference_id")}) private Set<FileReference> attachments = new HashSet<>(); - public String getSubject() { - return forumThread.getSubject(); - } - - public Set<FileReference> getAttachments() { - return attachments; - } - - public User getPostedBy() { - return postedBy; - } - - public String getContent() { - return content; - } - - public ForumThread getForumThread() { - return forumThread; - } - + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; @@ -72,27 +70,41 @@ public class ForumPost extends LazyDeletableDomainObject { this.id = id; } + public String getContent() { + return content; + } + public void setContent(String content) { this.content = content; } - public void setPostedBy(User postedBy) { - this.postedBy = postedBy; + public ForumThread getForumThread() { + return forumThread; } public void setForumThread(ForumThread forumThread) { this.forumThread = forumThread; } + public User getPostedBy() { + return postedBy; + } + + public void setPostedBy(User postedBy) { + this.postedBy = postedBy; + } + + public Set<FileReference> getAttachments() { + return attachments; + } + public void setAttachments(Set<FileReference> attachments) { this.attachments = attachments; } - @Override - public String toString() { - return "ForumPost(id=" + this.getId() + ", content=" + this.getContent() + ", postedBy=" + this.getPostedBy() + ", forumThread=" + this.getForumThread() + ", attachments=" + this.getAttachments() + ")"; - } - + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -106,10 +118,6 @@ public class ForumPost extends LazyDeletableDomainObject { && Objects.equals(this.getAttachments(), other.getAttachments()); } - protected boolean canEqual(final Object other) { - return other instanceof ForumPost; - } - @Override public int hashCode() { return Objects.hash( @@ -119,4 +127,22 @@ public class ForumPost extends LazyDeletableDomainObject { this.getForumThread(), this.getAttachments()); } + + @Override + public String toString() { + return "ForumPost(id=" + this.getId() + ", content=" + this.getContent() + + ", postedBy=" + this.getPostedBy() + ", forumThread=" + this.getForumThread() + + ", attachments=" + this.getAttachments() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ForumPost; + } + + public String getSubject() { + return forumThread.getSubject(); + } } diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java index 655a3baf41..eff11f8578 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java @@ -1,14 +1,21 @@ package se.su.dsv.scipro.forum.dataobjects; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.io.Serializable; @Entity -@Table(name = "forum_post_read") +@Table(name = "forum_post_read_state") public class ForumPostReadState implements Serializable { + // ---------------------------------------------------------------------------------- + // Basic and embedded JPA-mappings + // ---------------------------------------------------------------------------------- @EmbeddedId private ForumPostReadStateId id; @@ -16,6 +23,9 @@ public class ForumPostReadState implements Serializable { @Column(name = "`read`", nullable = false) private boolean read = false; + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- public ForumPostReadState() { } @@ -23,6 +33,9 @@ public class ForumPostReadState implements Serializable { id = new ForumPostReadStateId(user, post); } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public ForumPostReadStateId getId() { return id; } @@ -39,4 +52,3 @@ public class ForumPostReadState implements Serializable { this.read = read; } } - diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java index c596d98513..818fd9ca86 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java @@ -11,11 +11,11 @@ import java.util.Objects; @Embeddable public class ForumPostReadStateId implements Serializable { @ManyToOne - @JoinColumn(name = "user", nullable = false) + @JoinColumn(name = "user_id", nullable = false) private User user; @ManyToOne - @JoinColumn(name = "post", nullable = false) + @JoinColumn(name = "forum_post_id", nullable = false) private ForumPost post; public ForumPostReadStateId() { diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java index 3068a8fa62..aaeaf4849e 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java @@ -1,9 +1,21 @@ package se.su.dsv.scipro.forum.dataobjects; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.OneToMany; +import jakarta.persistence.PostLoad; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.LazyDeletableDomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -13,17 +25,88 @@ import java.util.Objects; @Inheritance(strategy = InheritanceType.JOINED) public class ForumThread extends LazyDeletableDomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToMany(mappedBy = "forumThread", cascade = CascadeType.ALL, fetch = FetchType.EAGER) - private List<ForumPost> posts = new ArrayList<>(); - @Basic @Column(name = "subject", nullable = false) private String subject; + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "thread" + // ---------------------------------------------------------------------------------- + @OneToMany(mappedBy = "forumThread", cascade = CascadeType.ALL, fetch = FetchType.EAGER) + private List<ForumPost> posts = new ArrayList<>(); + + // ---------------------------------------------------------------------------------- + // JPA-lifecycle method + // ---------------------------------------------------------------------------------- + @PostLoad + void lazyDeletion() { + posts.removeIf(LazyDeletableDomainObject::isDeleted); + } + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public List<ForumPost> getPosts() { + return this.posts; + } + + public void setPosts(List<ForumPost> posts) { + this.posts = posts; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof ForumThread)) return false; + final ForumThread other = (ForumThread) o; + return other.canEqual(this) + && Objects.equals(this.getId(), other.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.getId()); + } + + @Override + public String toString() { + return "ForumThread(id=" + this.getId() + ", subject=" + this.getSubject() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ForumThread; + } + public void addPost(ForumPost post) { posts.add(post); } @@ -32,15 +115,6 @@ public class ForumThread extends LazyDeletableDomainObject { return posts.size(); } - @PostLoad - void lazyDeletion() { - posts.removeIf(LazyDeletableDomainObject::isDeleted); - } - - public String getSubject() { - return subject; - } - public User getCreatedBy(){ return getPosts().get(0).getPostedBy(); } @@ -53,48 +127,4 @@ public class ForumThread extends LazyDeletableDomainObject { } return false; } - - @Override - public Long getId() { - return this.id; - } - - public List<ForumPost> getPosts() { - return this.posts; - } - - public void setId(Long id) { - this.id = id; - } - - public void setPosts(List<ForumPost> posts) { - this.posts = posts; - } - - public void setSubject(String subject) { - this.subject = subject; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof ForumThread)) return false; - final ForumThread other = (ForumThread) o; - return other.canEqual(this) - && Objects.equals(this.getId(), other.getId()); - } - - protected boolean canEqual(final Object other) { - return other instanceof ForumThread; - } - - @Override - public int hashCode() { - return Objects.hashCode(this.getId()); - } - - @Override - public String toString() { - return "ForumThread(id=" + this.getId() + ", subject=" + this.getSubject() + ")"; - } } diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java index 5956a4d6de..ed7d45f410 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java @@ -1,49 +1,70 @@ package se.su.dsv.scipro.forum.dataobjects; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.group.Group; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity -@Table(name = "group_thread") +@Table(name = "project_group_thread") public class GroupThread implements Serializable { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (project_group_thread) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne - @JoinColumn(name = "group_id", nullable = false) + @JoinColumn(name = "project_group_id", referencedColumnName = "id", nullable = false) private Group group; @OneToOne(cascade = CascadeType.ALL, optional = false) - @JoinColumn(name = "thread_id") + @JoinColumn(name = "thread_id", referencedColumnName = "id") private ForumThread forumThread; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } - public Group getGroup() { - return group; - } - - public ForumThread getForumThread() { - return forumThread; - } - public void setId(Long id) { this.id = id; } + public Group getGroup() { + return group; + } + public void setGroup(Group group) { this.group = group; } + public ForumThread getForumThread() { + return forumThread; + } + public void setForumThread(ForumThread forumThread) { this.forumThread = forumThread; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -55,10 +76,6 @@ public class GroupThread implements Serializable { && Objects.equals(this.getForumThread(), other.getForumThread()); } - protected boolean canEqual(final Object other) { - return other instanceof GroupThread; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getGroup(), this.getForumThread()); @@ -66,6 +83,14 @@ public class GroupThread implements Serializable { @Override public String toString() { - return "GroupThread(id=" + this.getId() + ", group=" + this.getGroup() + ", forumThread=" + this.getForumThread() + ")"; + return "GroupThread(id=" + this.getId() + ", group=" + this.getGroup() + ", forumThread=" + + this.getForumThread() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof GroupThread; } } diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java index 32b99a8a84..ba32a9f14f 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java @@ -1,50 +1,70 @@ package se.su.dsv.scipro.forum.dataobjects; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity @Table(name = "project_thread") public class ProjectThread implements Serializable { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(optional = false) - @JoinColumn(name = "thread_id") - private ForumThread forumThread; - + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (project_thread) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = false) - @JoinColumn(name = "project_id") + @JoinColumn(name = "project_id", referencedColumnName = "id") private Project project; + @OneToOne(optional = false) + @JoinColumn(name = "thread_id", referencedColumnName = "id") + private ForumThread forumThread; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } - public Project getProject() { - return project; - } - - public ForumThread getForumThread() { - return forumThread; - } - public void setId(Long id) { this.id = id; } - public void setForumThread(ForumThread forumThread) { - this.forumThread = forumThread; + public Project getProject() { + return project; } public void setProject(Project project) { this.project = project; } + public ForumThread getForumThread() { + return forumThread; + } + + public void setForumThread(ForumThread forumThread) { + this.forumThread = forumThread; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -56,10 +76,6 @@ public class ProjectThread implements Serializable { && Objects.equals(this.getProject(), other.getProject()); } - protected boolean canEqual(final Object other) { - return other instanceof ProjectThread; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getForumThread(), this.getProject()); @@ -67,6 +83,14 @@ public class ProjectThread implements Serializable { @Override public String toString() { - return "ProjectThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() + ", project=" + this.getProject() + ")"; + return "ProjectThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() + + ", project=" + this.getProject() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ProjectThread; } } diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java index 010a5686d6..5cce25c1ca 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java @@ -1,50 +1,69 @@ package se.su.dsv.scipro.forum.dataobjects; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; -import jakarta.persistence.*; import java.util.Objects; @Entity @Table(name = "reviewer_thread") public class ReviewerThread { + // ---------------------------------------------------------------------------------- + // Basic JPA-mapping + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(optional = false) - @JoinColumn(name = "thread_id") - private ForumThread forumThread; - + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (mail_event) referencing other + // tables. + // ---------------------------------------------------------------------------------- @OneToOne - @JoinColumn(name = "project_id", unique = true) + @JoinColumn(name = "project_id", referencedColumnName = "id", unique = true) private Project project; + @OneToOne(optional = false) + @JoinColumn(name = "thread_id", referencedColumnName = "id") + private ForumThread forumThread; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return this.id; } - public ForumThread getForumThread() { - return this.forumThread; - } - - public Project getProject() { - return this.project; - } - public void setId(Long id) { this.id = id; } - public void setForumThread(ForumThread forumThread) { - this.forumThread = forumThread; + public Project getProject() { + return this.project; } public void setProject(Project project) { this.project = project; } + public ForumThread getForumThread() { + return this.forumThread; + } + + public void setForumThread(ForumThread forumThread) { + this.forumThread = forumThread; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -56,10 +75,6 @@ public class ReviewerThread { && Objects.equals(this.getProject(), other.getProject()); } - protected boolean canEqual(final Object other) { - return other instanceof ReviewerThread; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getForumThread(), this.getProject()); @@ -67,6 +82,14 @@ public class ReviewerThread { @Override public String toString() { - return "ReviewerThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() + ", project=" + this.getProject() + ")"; + return "ReviewerThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() + + ", project=" + this.getProject() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ReviewerThread; } } diff --git a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java index 3bc39f38ab..fe2bc877e4 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java @@ -1,26 +1,44 @@ package se.su.dsv.scipro.forum.notifications; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; import se.su.dsv.scipro.forum.dataobjects.ForumPost; import se.su.dsv.scipro.notifications.dataobject.NotificationEvent; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity @Table(name = "forum_notification") class ForumNotification { + // ---------------------------------------------------------------------------------- + // Embedded JPA-mapping + // ---------------------------------------------------------------------------------- @EmbeddedId private Id id = new Id(); + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (forum_notification) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = false) + @JoinColumn(name = "forum_post_id", referencedColumnName = "id") @MapsId("forumPostId") private ForumPost forumPost; @ManyToOne(optional = false) + @JoinColumn(name = "notification_data_id") @MapsId("notificationEventId") private NotificationEvent notificationEvent; + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected ForumNotification() { } // JPA ForumNotification(final ForumPost forumPost, final NotificationEvent notificationEvent) { @@ -28,6 +46,9 @@ class ForumNotification { this.notificationEvent = notificationEvent; } + // ---------------------------------------------------------------------------------- + // Properties (Getters) + // ---------------------------------------------------------------------------------- public ForumPost getForumPost() { return forumPost; } @@ -36,6 +57,9 @@ class ForumNotification { return notificationEvent; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -47,10 +71,6 @@ class ForumNotification { && Objects.equals(this.getNotificationEvent(), other.getNotificationEvent()); } - protected boolean canEqual(final Object other) { - return other instanceof ForumNotification; - } - @Override public int hashCode() { return Objects.hash(this.id, this.getForumPost(), this.getNotificationEvent()); @@ -58,9 +78,20 @@ class ForumNotification { @Override public String toString() { - return "ForumNotification(id=" + this.id + ", forumPost=" + this.getForumPost() + ", notificationEvent=" + this.getNotificationEvent() + ")"; + return "ForumNotification(id=" + this.id + ", forumPost=" + this.getForumPost() + + ", notificationEvent=" + this.getNotificationEvent() + ")"; } + // ---------------------------------------------------------------------------------- + // Other method + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ForumNotification; + } + + // ---------------------------------------------------------------------------------- + // Nested type + // ---------------------------------------------------------------------------------- @Embeddable static class Id implements Serializable { private Long forumPostId; @@ -103,7 +134,8 @@ class ForumNotification { @Override public String toString() { - return "ForumNotification.Id(forumPostId=" + this.getForumPostId() + ", notificationEventId=" + this.getNotificationEventId() + ")"; + return "ForumNotification.Id(forumPostId=" + this.getForumPostId() + ", notificationEventId=" + + this.getNotificationEventId() + ")"; } } } diff --git a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java index b294608351..5b1ff17920 100644 --- a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java +++ b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java @@ -2,7 +2,7 @@ package se.su.dsv.scipro.forum.notifications; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.forum.dataobjects.ForumPost; import se.su.dsv.scipro.forum.ForumPostReadEvent; import se.su.dsv.scipro.forum.NewGroupForumReplyEvent; diff --git a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotificationsModule.java b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotificationsModule.java deleted file mode 100644 index 2a77013615..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotificationsModule.java +++ /dev/null @@ -1,11 +0,0 @@ -package se.su.dsv.scipro.forum.notifications; - -import com.google.inject.AbstractModule; - -public class ForumNotificationsModule extends AbstractModule { - @Override - public void configure() { - bind(ForumNotificationRepository.class).to(ForumNotificationRepositoryImpl.class); - bind(ForumNotifications.class).asEagerSingleton(); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/gdpr/GDPRModule.java b/core/src/main/java/se/su/dsv/scipro/gdpr/GDPRModule.java deleted file mode 100644 index 65a3f3ae8f..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/gdpr/GDPRModule.java +++ /dev/null @@ -1,12 +0,0 @@ -package se.su.dsv.scipro.gdpr; - -import com.google.inject.PrivateModule; - -public class GDPRModule extends PrivateModule { - @Override - protected void configure() { - bind(Reporter.class).to(ZipReporter.class); - - expose(Reporter.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java index b7f7bc0b0b..511fd841b4 100755 --- a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java +++ b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java @@ -14,81 +14,86 @@ public class GeneralSystemSettings extends DomainObject { @Id private Long id = null; - @Basic + @Column(name = "daisy_profile_link_base_url") private String daisyProfileLinkBaseURL; - @Basic + @Column(name = "daisy_select_research_area_url") private String daisySelectResearchAreaURL; @ElementCollection - @CollectionTable(name = "general_system_settings_alarm_recipients") + @CollectionTable(name = "general_system_settings_alarm_recipient", + joinColumns = @JoinColumn(name = "general_system_settings_id", referencedColumnName = "id")) @Column(name = "mail") private List<String> alarmMails = new ArrayList<>(); @ElementCollection - @CollectionTable(name = "general_system_settings_supervisor_change_recipients") + @CollectionTable(name = "general_system_settings_supervisor_change_recipient", + joinColumns = @JoinColumn(name = "general_system_settings_id", referencedColumnName = "id")) @Column(name = "mail") private List<String> supervisorChangeMails = new ArrayList<>(); - @Basic(optional = true) + @Column(name = "project_partner_days_to_live", nullable = true) private int projectPartnerDaysToLive; - @Basic(optional = false) + @Column(name = "mail_notifications", nullable = false) private boolean mailNotifications = true; - @Basic(optional = false) + @Column(name = "mail_from_name", nullable = false) private String mailFromName = "SciPro"; - @Basic(optional = false) + @Column(name = "system_from_mail", nullable = false) private String systemFromMail = "noreply-scipro@dsv.su.se"; - @Basic(optional = false) + @Column(name = "smtp_server", nullable = false) private String smtpServer = "localhost"; + @Column(name = "peer_display_latest_reviews") private boolean peerDisplayLatestReviews = true; - @Basic(optional = false) + @Column(name = "number_of_latest_reviews_displayed", nullable = false) private int numberOfLatestReviewsDisplayed = DEFAULT_NUMER_OF_LATEST_REVIEWS_DISPLAYED; - @Basic(optional = false) + @Column(name = "public_reviews_activated", nullable = false) private boolean publicReviewsActivated = true; - @Basic(optional = false) + @Column(name = "peer_download_enabled", nullable = false) private boolean peerDownloadEnabled = true; - @Basic(optional = false) + @Column(name = "scipro_url", nullable = false) private String sciproURL = "http://localhost:8080/"; - @Basic(optional = false) + @Column(name = "show_single_sign_on", nullable = false) private boolean showSingleSignOn = true; @ElementCollection @Enumerated(EnumType.STRING) - @JoinTable(name = "general_system_settings_system_modules") + @CollectionTable(name = "general_system_settings_system_module", + joinColumns = @JoinColumn(name = "general_system_settings_id", referencedColumnName = "id")) + @Column(name = "system_module") private Set<SystemModule> systemModules = EnumSet.allOf(SystemModule.class); - @Basic(optional = true) + @Column(name = "match_responsible_mail", nullable = true) private String matchResponsibleMail = ""; - @Basic(optional = true) + @Column(name = "reviewer_support_mail", nullable = true) private String reviewerSupportMail; - @Basic(optional = true) + @Column(name = "thesis_support_mail", nullable = true) private String thesisSupportMail; - @Basic(optional = true) + @Column(name = "external_room_booking_url", nullable = true) private String externalRoomBookingURL; - @Basic(optional = true) + @Column(name = "external_getting_started_with_idea_url", nullable = true) private String externalGettingStartedWithIdeaURL; - @Basic(optional = true) + @Column(name = "external_grading_url", nullable = true) private String externalGradingURL; - @Basic(optional = false) + @Column(name = "final_survey_available", nullable = false) private boolean finalSurveyAvailable = false; - @Basic + @Column(name = "active_project_idea_support_mail") private String activeProjectIdeaSupportMail; public GeneralSystemSettings() { diff --git a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java index 1550844b4e..5450f5b837 100755 --- a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.generalsystemsettings; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.AbstractServiceImpl; import jakarta.inject.Inject; diff --git a/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java b/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java index dfe7e5b08b..88160eb8a9 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java @@ -16,20 +16,31 @@ import java.time.Instant; import java.util.Objects; @Entity -@Table(name = "grading_history_approvals") +@Table(name = "grading_history_approval") public class ApprovedEvent { + + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "project_id") - private Project project; - @Temporal(TemporalType.TIMESTAMP) @Column(name = "`when`") private Instant when; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_history_rejections) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "project_id") + private Project project; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } @@ -38,14 +49,6 @@ public class ApprovedEvent { this.id = id; } - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - public Instant getWhen() { return when; } @@ -54,6 +57,17 @@ public class ApprovedEvent { this.when = when; } + public Project getProject() { + return project; + } + + public void setProject(Project project) { + this.project = project; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(Object o) { if (this == o) return true; @@ -70,10 +84,7 @@ public class ApprovedEvent { @Override public String toString() { - return "ApprovedEvent{" + - "id=" + id + - ", project=" + project + - ", when=" + when + - '}'; + return "ApprovedEvent{" + "id=" + id + ", project=" + project + + ", when=" + when + '}'; } } diff --git a/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java index 68b25d1cd0..de3f36ac13 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.grading; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.persistence.EntityManager; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.AbstractRepository; diff --git a/core/src/main/java/se/su/dsv/scipro/grading/GradingModule.java b/core/src/main/java/se/su/dsv/scipro/grading/GradingModule.java deleted file mode 100644 index e67d559b77..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/grading/GradingModule.java +++ /dev/null @@ -1,37 +0,0 @@ -package se.su.dsv.scipro.grading; - -import com.google.inject.Key; -import com.google.inject.PrivateModule; -import com.google.inject.name.Names; -import se.su.dsv.scipro.report.GradingReportServiceImpl; - -public class GradingModule extends PrivateModule { - @Override - protected void configure() { - requireBinding(Key.get(String.class, Names.named("service.grading.url"))); - bind(GradingService.class).to(GradingServiceImpl.class); - - expose(GradingService.class); - - bind(PublicationMetadataRepository.class).to(PublicationMetadataRepositoryImpl.class); - bind(PublicationMetadataService.class).to(PublicationMetadataServiceImpl.class); - expose(PublicationMetadataService.class); - - bind(ExaminerTimelineService.class).to(GradingHistory.class); - expose(ExaminerTimelineService.class); - bind(GradingHistoryEventRepository.class).to(GradingHistoryEventRepositoryImpl.class); - bind(ThesisRejectionHistoryService.class).to(GradingHistory.class); - expose(ThesisRejectionHistoryService.class); - bind(ThesisApprovedHistoryService.class).to(GradingHistory.class); - expose(ThesisApprovedHistoryService.class); - bind(ThesisSubmissionHistoryService.class).to(GradingHistory.class); - expose(ThesisSubmissionHistoryService.class); - - bind(NationalSubjectCategoryRepository.class).to(NationalSubjectCategoryRepositoryImpl.class); - bind(NationalSubjectCategoryService.class).to(NationalSubjectCategoryServiceImpl.class); - expose(NationalSubjectCategoryService.class); - - bind(GradingReportTemplateService.class).to(GradingReportServiceImpl.class); - expose(GradingReportTemplateService.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java index 26323389d8..c2ec2aa67e 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java @@ -12,21 +12,20 @@ import java.util.Objects; @Entity @Table(name = "national_subject_category") public class NationalSubjectCategory { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY) @Column(name = "id") private Long id; @Basic - @Column(name = "external_id") - private Integer externalId; - - @Basic - @Column(name = "swedish_name") + @Column(name = "name_sv") private String swedishName; @Basic - @Column(name = "english_name") + @Column(name = "name_en") private String englishName; @Basic @@ -37,9 +36,19 @@ public class NationalSubjectCategory { @Column(name = "preselected") private boolean preselected; + @Basic + @Column(name = "external_id") + private Integer externalId; + + // ---------------------------------------------------------------------------------- + // Constructor + // ---------------------------------------------------------------------------------- public NationalSubjectCategory() { } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } @@ -48,14 +57,6 @@ public class NationalSubjectCategory { this.id = id; } - public Integer getExternalId() { - return externalId; - } - - public void setExternalId(Integer externalId) { - this.externalId = externalId; - } - public String getSwedishName() { return swedishName; } @@ -88,6 +89,17 @@ public class NationalSubjectCategory { this.preselected = preselected; } + public Integer getExternalId() { + return externalId; + } + + public void setExternalId(Integer externalId) { + this.externalId = externalId; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(Object o) { if (this == o) { diff --git a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java index 2a6d009a47..90c2723739 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.grading; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.persistence.EntityManager; import se.su.dsv.scipro.system.AbstractRepository; diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java index 87b0a82f6c..2fe7236e6c 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java @@ -17,34 +17,44 @@ import java.util.Objects; @Entity @Table(name = "publication_metadata") public class PublicationMetadata { - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(optional = false) - private Project project; - @Basic - @Column(name = "abstract_swedish") + @Column(name = "abstract_sv") private String abstractSwedish; @Basic - @Column(name = "abstract_english") + @Column(name = "abstract_en") private String abstractEnglish; @Basic - @Column(name = "keywords_swedish") + @Column(name = "keywords_sv") private String keywordsSwedish; @Basic - @Column(name = "keywords_english") + @Column(name = "keywords_en") private String keywordsEnglish; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (publication_metadata) referencing + // other tables. + // ---------------------------------------------------------------------------------- @ManyToOne @JoinColumn(name = "national_subject_category_id") private NationalSubjectCategory nationalSubjectCategory;; + @OneToOne(optional = false) + @JoinColumn(name = "project_id") + private Project project; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } @@ -53,14 +63,6 @@ public class PublicationMetadata { this.id = id; } - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - public String getAbstractSwedish() { return abstractSwedish; } @@ -101,19 +103,17 @@ public class PublicationMetadata { this.nationalSubjectCategory = nationalSubjectCategory; } - @Override - public String toString() { - return "PublicationMetadata{" + - "id=" + id + - ", project=" + project + - ", abstractSwedish='" + abstractSwedish + '\'' + - ", abstractEnglish='" + abstractEnglish + '\'' + - ", keywordsSwedish='" + keywordsSwedish + '\'' + - ", keywordsEnglish='" + keywordsEnglish + '\'' + - ", nationalSubjectCategory=" + nationalSubjectCategory + '\'' + - '}'; + public Project getProject() { + return project; } + public void setProject(Project project) { + this.project = project; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(Object o) { return o instanceof PublicationMetadata that && @@ -124,4 +124,15 @@ public class PublicationMetadata { public int hashCode() { return Objects.hashCode(id); } + + @Override + public String toString() { + return "PublicationMetadata{" + "id=" + id + ", project=" + project + + ", abstractSwedish='" + abstractSwedish + '\'' + + ", abstractEnglish='" + abstractEnglish + '\'' + + ", keywordsSwedish='" + keywordsSwedish + '\'' + + ", keywordsEnglish='" + keywordsEnglish + '\'' + + ", nationalSubjectCategory=" + nationalSubjectCategory + '\'' + + '}'; + } } diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java index 05702c1d93..10c37dab9e 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java @@ -2,7 +2,7 @@ package se.su.dsv.scipro.grading; import se.su.dsv.scipro.project.Project; -interface PublicationMetadataRepository { +public interface PublicationMetadataRepository { void save(PublicationMetadata publicationMetadata); PublicationMetadata findByProject(Project project); diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java index f1b2ac5a38..503b62f6ec 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.grading; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.persistence.EntityManager; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.AbstractRepository; @@ -8,9 +8,9 @@ import se.su.dsv.scipro.system.AbstractRepository; import jakarta.inject.Inject; import jakarta.inject.Provider; -class PublicationMetadataRepositoryImpl extends AbstractRepository implements PublicationMetadataRepository { +public class PublicationMetadataRepositoryImpl extends AbstractRepository implements PublicationMetadataRepository { @Inject - PublicationMetadataRepositoryImpl(Provider<EntityManager> em) { + public PublicationMetadataRepositoryImpl(Provider<EntityManager> em) { super(em); } diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java index 26f0e1801b..684e24ae7b 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java @@ -6,11 +6,11 @@ import se.su.dsv.scipro.system.Language; import jakarta.inject.Inject; import java.util.Objects; -class PublicationMetadataServiceImpl implements PublicationMetadataService { +public class PublicationMetadataServiceImpl implements PublicationMetadataService { private final PublicationMetadataRepository publicationMetadataRepository; @Inject - PublicationMetadataServiceImpl(PublicationMetadataRepository publicationMetadataRepository) { + public PublicationMetadataServiceImpl(PublicationMetadataRepository publicationMetadataRepository) { this.publicationMetadataRepository = publicationMetadataRepository; } diff --git a/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java b/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java index 745eaf14a8..d7a24907e3 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java @@ -17,23 +17,35 @@ import java.time.Instant; import java.util.Objects; @Entity -@Table(name = "grading_history_rejections") +@Table(name = "grading_history_rejection") public class RejectionEvent { + + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "project_id") - private Project project; + @Basic + @Column(name = "reason") + private String reason; @Temporal(TemporalType.TIMESTAMP) @Column(name = "`when`") private Instant when; - @Basic - private String reason; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_history_rejections) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "project_id") + private Project project; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } @@ -42,22 +54,6 @@ public class RejectionEvent { this.id = id; } - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - public Instant getWhen() { - return when; - } - - public void setWhen(Instant when) { - this.when = when; - } - public String getReason() { return reason; } @@ -66,6 +62,25 @@ public class RejectionEvent { this.reason = reason; } + public Instant getWhen() { + return when; + } + + public void setWhen(Instant when) { + this.when = when; + } + + public Project getProject() { + return project; + } + + public void setProject(Project project) { + this.project = project; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java b/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java index 664c1e6bcf..fd88070c36 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java @@ -18,27 +18,38 @@ import java.time.Instant; import java.util.Objects; @Entity -@Table(name = "grading_history_submissions") +@Table(name = "grading_history_submission") public class SubmissionEvent { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - @JoinColumn(name = "project_id") - private Project project; - - @ManyToOne - @JoinColumn(name = "author_id") - private User author; - @Temporal(TemporalType.TIMESTAMP) @Column(name = "`when`") private Instant when; @Basic + @Column(name = "corrections") private String corrections; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_history_submission) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; + + @ManyToOne + @JoinColumn(name = "author_user_id", referencedColumnName = "id") + private User author; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } @@ -47,22 +58,6 @@ public class SubmissionEvent { this.id = id; } - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - public User getAuthor() { - return author; - } - - public void setAuthor(User user) { - this.author = user; - } - public Instant getWhen() { return when; } @@ -79,6 +74,25 @@ public class SubmissionEvent { this.corrections = corrections; } + public Project getProject() { + return project; + } + + public void setProject(Project project) { + this.project = project; + } + + public User getAuthor() { + return author; + } + + public void setAuthor(User user) { + this.author = user; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(Object o) { if (this == o) return true; @@ -97,11 +111,8 @@ public class SubmissionEvent { @Override public String toString() { - return "RejectionEvent{" + - "id=" + id + - ", project=" + project + - ", author=" + author + - ", when=" + when + + return "RejectionEvent{" + "id=" + id + ", project=" + project + + ", author=" + author + ", when=" + when + ", corrections='" + corrections + '\'' + '}'; } diff --git a/core/src/main/java/se/su/dsv/scipro/group/Group.java b/core/src/main/java/se/su/dsv/scipro/group/Group.java index c85082e740..11aecf59e8 100644 --- a/core/src/main/java/se/su/dsv/scipro/group/Group.java +++ b/core/src/main/java/se/su/dsv/scipro/group/Group.java @@ -18,30 +18,124 @@ public class Group extends DomainObject { public static final int STRING_MAX_LENGTH = 255; + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(length = STRING_MAX_LENGTH) @Basic(optional = false) + @Column(name = "title", length = STRING_MAX_LENGTH) private String title; @Basic(optional = true) + @Column(name = "description") private String description; + @Basic + @Column(name = "active") + private boolean active = true; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (project_group) referencing other tables. + // ---------------------------------------------------------------------------------- //Creator, should be a supervisor @ManyToOne(optional = false) - @JoinColumn(name = "user_id") + @JoinColumn(name = "user_id", referencedColumnName = "id") private User user; + // ---------------------------------------------------------------------------------- + // @ManyToMany JPA-mappings + // ---------------------------------------------------------------------------------- @ManyToMany - @JoinTable( - name = "project_group_project", - joinColumns = @JoinColumn(name = "project_group_id"), - inverseJoinColumns = @JoinColumn(name = "project_id")) + @JoinTable(name = "project_group_project", + joinColumns = @JoinColumn(name = "project_group_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id")) private Set<Project> projects = new HashSet<>(); - private boolean active = true; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isActive() { + return this.active; + } + + public void setActive(boolean active) { + this.active = active; + } + + public User getUser() { + return this.user; + } + + public void setUser(User user) { + this.user = user; + } + + public Set<Project> getProjects() { + return projects; + } + + public void setProjects(Set<Project> projects) { + this.projects = projects; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof Group)) return false; + final Group other = (Group) o; + return other.canEqual(this) + && Objects.equals(this.getId(), other.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.getId()); + } + + @Override + public String toString() { + return "Group(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + + this.getDescription() + ", user=" + this.getUser() + ", projects=" + + this.getProjects() + ", active=" + this.isActive() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof Group; + } public boolean isAuthor(final User user) { for (Project project : projects) { @@ -58,76 +152,4 @@ public class Group extends DomainObject { .filter(member -> member.getType() != Member.Type.REVIEWER) .toList(); } - - public Set<Project> getProjects() { - return projects; - } - - public String getTitle() { - return title; - } - - @Override - public Long getId() { - return this.id; - } - - public String getDescription() { - return this.description; - } - - public User getUser() { - return this.user; - } - - public boolean isActive() { - return this.active; - } - - public void setId(Long id) { - this.id = id; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setDescription(String description) { - this.description = description; - } - - public void setUser(User user) { - this.user = user; - } - - public void setProjects(Set<Project> projects) { - this.projects = projects; - } - - public void setActive(boolean active) { - this.active = active; - } - - @Override - public String toString() { - return "Group(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", user=" + this.getUser() + ", projects=" + this.getProjects() + ", active=" + this.isActive() + ")"; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof Group)) return false; - final Group other = (Group) o; - return other.canEqual(this) - && Objects.equals(this.getId(), other.getId()); - } - - protected boolean canEqual(final Object other) { - return other instanceof Group; - } - - @Override - public int hashCode() { - return Objects.hashCode(this.getId()); - } -} \ No newline at end of file +} diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java index f5bd35bd82..7a34082b32 100644 --- a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java +++ b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java @@ -1,30 +1,49 @@ package se.su.dsv.scipro.integration.activityfinalseminar; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; + import se.su.dsv.scipro.activityplan.Activity; import se.su.dsv.scipro.finalseminar.FinalSeminar; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity @Table(name = "activity_final_seminar") class ActivityFinalSeminar { + // ---------------------------------------------------------------------------------- + // embedded JPA-mappings + // ---------------------------------------------------------------------------------- @EmbeddedId @AttributeOverride(name = "activityId", column = @Column(name = "activity_id")) @AttributeOverride(name = "finalSeminarId", column = @Column(name = "final_seminar_id")) private Id id = new Id(); + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (activity_final_seminiar) referencing + // other tables. + // ---------------------------------------------------------------------------------- @ManyToOne @MapsId("activityId") - @JoinColumn(name = "activity_id") + @JoinColumn(name = "activity_id", referencedColumnName = "id") private Activity activity; @ManyToOne @MapsId("finalSeminarId") - @JoinColumn(name = "final_seminar_id") + @JoinColumn(name = "final_seminar_id", referencedColumnName = "id") private FinalSeminar finalSeminar; + // ---------------------------------------------------------------------------------- + // constructor + // ---------------------------------------------------------------------------------- protected ActivityFinalSeminar() { // JPA } @@ -34,6 +53,9 @@ class ActivityFinalSeminar { this.finalSeminar = finalSeminar; } + // ---------------------------------------------------------------------------------- + // getters + // ---------------------------------------------------------------------------------- public Id getId() { return this.id; } @@ -46,6 +68,9 @@ class ActivityFinalSeminar { return this.finalSeminar; } + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -57,10 +82,6 @@ class ActivityFinalSeminar { && Objects.equals(this.getFinalSeminar(), other.getFinalSeminar()); } - protected boolean canEqual(final Object other) { - return other instanceof ActivityFinalSeminar; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getActivity(), this.getFinalSeminar()); @@ -71,6 +92,13 @@ class ActivityFinalSeminar { return "ActivityFinalSeminar(id=" + this.getId() + ", activity=" + this.getActivity() + ", finalSeminar=" + this.getFinalSeminar() + ")"; } + protected boolean canEqual(final Object other) { + return other instanceof ActivityFinalSeminar; + } + + // ---------------------------------------------------------------------------------- + // nested class + // ---------------------------------------------------------------------------------- @Embeddable static class Id implements Serializable { private Long activityId; diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarModule.java b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarModule.java deleted file mode 100644 index 0d5d8bf9a4..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarModule.java +++ /dev/null @@ -1,11 +0,0 @@ -package se.su.dsv.scipro.integration.activityfinalseminar; - -import com.google.inject.AbstractModule; - -public class ActivityFinalSeminarModule extends AbstractModule { - @Override - protected void configure() { - bind(FinalSeminarActivityHandler.class).asEagerSingleton(); - bind(ActivityFinalSeminarRepository.class).to(ActivityFinalSeminarRepositoryImpl.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java index 87191121e6..6f1af4098c 100644 --- a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.integration.activityfinalseminar; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.finalseminar.FinalSeminar; diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityForumModule.java b/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityForumModule.java deleted file mode 100644 index c14a655f13..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityForumModule.java +++ /dev/null @@ -1,11 +0,0 @@ -package se.su.dsv.scipro.integration.activityforum; - -import com.google.inject.AbstractModule; - -public class ActivityForumModule extends AbstractModule { - @Override - protected void configure() { - bind(PostActivityUploadToForum.class).asEagerSingleton(); - bind(ActivityThreadRepository.class).to(ActivityThreadRepositoryImpl.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java b/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java index 89d7f0ee43..a890466fc5 100644 --- a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java +++ b/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java @@ -1,27 +1,44 @@ package se.su.dsv.scipro.integration.activityforum; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; + import se.su.dsv.scipro.activityplan.Activity; import se.su.dsv.scipro.forum.dataobjects.ProjectThread; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity @Table(name = "activity_thread") class ActivityThread { + // ---------------------------------------------------------------------------------- + // basic and embedded JPA-mappings + // ---------------------------------------------------------------------------------- @EmbeddedId private Id id = new Id(); - @ManyToOne - @MapsId("threadId") - @JoinColumn(name = "project_thread_id") - private ProjectThread thread; - + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (activity_thread) referencing other tables. + // ---------------------------------------------------------------------------------- @ManyToOne @MapsId("activityId") + @JoinColumn(name = "activity_id", referencedColumnName = "id") private Activity activity; + @ManyToOne + @MapsId("threadId") + @JoinColumn(name = "project_thread_id", referencedColumnName = "id") + private ProjectThread thread; + + // ---------------------------------------------------------------------------------- + // constructor + // ---------------------------------------------------------------------------------- protected ActivityThread() { // JPA } @@ -31,6 +48,9 @@ class ActivityThread { this.activity = activity; } + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- public Id getId() { return this.id; } @@ -43,6 +63,9 @@ class ActivityThread { return this.activity; } + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -54,10 +77,6 @@ class ActivityThread { && Objects.equals(this.getActivity(), other.getActivity()); } - protected boolean canEqual(final Object other) { - return other instanceof ActivityThread; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getThread(), this.getActivity()); @@ -68,6 +87,13 @@ class ActivityThread { return "ActivityThread(id=" + this.getId() + ", thread=" + this.getThread() + ", activity=" + this.getActivity() + ")"; } + protected boolean canEqual(final Object other) { + return other instanceof ActivityThread; + } + + // ---------------------------------------------------------------------------------- + // nested class + // ---------------------------------------------------------------------------------- @Embeddable static class Id implements Serializable { private Long threadId; diff --git a/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java b/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java index 200d362663..a8b99efd4d 100755 --- a/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.mail; +import jakarta.persistence.CollectionTable; import jakarta.persistence.GenerationType; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.system.DomainObject; @@ -19,61 +20,80 @@ import jakarta.persistence.Lob; import jakarta.persistence.ManyToMany; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import java.util.*; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; @Entity @Table(name = "mail_event") @Cacheable(false) public class MailEvent extends DomainObject { public static final int STRING_MAX_LENGTH = 255; + + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @JoinTable( - name = "mail_event_recipients", - joinColumns = @JoinColumn(name = "mail_event_id"), - inverseJoinColumns = @JoinColumn(name = "recipients_id")) - @ManyToMany(fetch = FetchType.EAGER) - private Set<User> recipients = new HashSet<>(); - - @ElementCollection - private Set<String> nonUserRecipients = new HashSet<>(); - - @Column(length = STRING_MAX_LENGTH) @Basic(optional = false) + @Column(name = "subject", length = STRING_MAX_LENGTH) private String subject; - @Column(length = STRING_MAX_LENGTH) @Basic(optional = true) + @Column(name = "from_name", length = STRING_MAX_LENGTH) private String fromName; - @Column(length = STRING_MAX_LENGTH) @Basic(optional = true) + @Column(name = "from_email", length = STRING_MAX_LENGTH) private String fromEmail; - @Lob @Basic(optional = false) + @Column(name = "message_body") + @Lob private String messageBody; @Basic(optional = false) + @Column(name = "sent") private boolean sent = false; @Basic(optional = true) + @Column(name = "message_id") private String messageID; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (mail_event) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = true) - @JoinColumn(name = "attachment_reference_id") + @JoinColumn(name = "attachment_file_reference_id", referencedColumnName = "id") private FileReference attachment; + // ---------------------------------------------------------------------------------- + // @ManyToMany JPA-mappings + // ---------------------------------------------------------------------------------- + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "mail_event_recipient", + joinColumns = @JoinColumn(name = "mail_event_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "recipient_id", referencedColumnName = "id")) + private Set<User> recipients = new HashSet<>(); + + @ElementCollection + @CollectionTable(name = "mail_event_non_user_recipient", + joinColumns = @JoinColumn(name = "mail_event_id", referencedColumnName = "id")) + @Column(name = "non_user_recipient") + private Set<String> nonUserRecipients = new HashSet<>(); + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- public MailEvent() { } - public MailEvent( - final String subject, - final String messageBody, - final User recipient, - final String fromName, + public MailEvent(final String subject, final String messageBody, final User recipient, final String fromName, final String fromEmail) { this.subject = subject; this.messageBody = messageBody; @@ -82,13 +102,8 @@ public class MailEvent extends DomainObject { this.fromEmail = fromEmail; } - public MailEvent( - final String subject, - final String messageBody, - final Collection<User> recipients, - final String fromName, - final String fromEmail - ) { + public MailEvent(final String subject, final String messageBody, final Collection<User> recipients, + final String fromName, final String fromEmail) { this.subject = subject; this.messageBody = messageBody; this.recipients.addAll(recipients); @@ -96,35 +111,124 @@ public class MailEvent extends DomainObject { this.fromEmail = fromEmail; } - public boolean isSent() { - return sent; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; } - public void markSent(final String messageID) { - this.messageID = messageID; - this.sent = true; + public void setId(Long id) { + this.id = id; } - public Set<User> getRecipients() { - return recipients; - } - - public void setMessageBody(String messageBody) { - this.messageBody = messageBody; + public String getSubject() { + return this.subject; } public void setSubject(String subject) { this.subject = subject; } + public String getFromName() { + return this.fromName; + } + public void setFromName(String fromName) { this.fromName = fromName; } + public String getFromEmail() { + return this.fromEmail; + } + public void setFromEmail(String fromEmail) { this.fromEmail = fromEmail; } + public String getMessageBody() { + return this.messageBody; + } + + public void setMessageBody(String messageBody) { + this.messageBody = messageBody; + } + + public boolean isSent() { + return sent; + } + + public void setSent(boolean sent) { + this.sent = sent; + } + + public String getMessageID() { + return this.messageID; + } + + public void setMessageID(String messageID) { + this.messageID = messageID; + } + + public FileReference getAttachment() { + return this.attachment; + } + + public void setAttachment(FileReference attachment) { + this.attachment = attachment; + } + + public Set<User> getRecipients() { + return recipients; + } + + public void setRecipients(Set<User> recipients) { + this.recipients = recipients; + } + + public Set<String> getNonUserRecipients() { + return this.nonUserRecipients; + } + + public void setNonUserRecipients(Set<String> nonUserRecipients) { + this.nonUserRecipients = nonUserRecipients; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof MailEvent)) return false; + final MailEvent other = (MailEvent) o; + return other.canEqual(this) + && Objects.equals(this.getId(), other.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.getId()); + } + + @Override + public String toString() { + return "MailEvent(id=" + this.getId() + ", recipients=" + this.getRecipients() + + ", nonUserRecipients=" + this.getNonUserRecipients() + ", subject=" + + this.getSubject() + ", fromName=" + this.getFromName() + + ", fromEmail=" + this.getFromEmail() + ", messageBody=" + this.getMessageBody() + + ", sent=" + this.isSent() + ", messageID=" + this.getMessageID() + + ", attachment=" + this.getAttachment() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof MailEvent; + } + public void addRecipients(final Iterable<Recipient> recipients) { for (Recipient recipient : recipients) { recipient.accept(new RecipientVisitor<Boolean>() { @@ -141,83 +245,8 @@ public class MailEvent extends DomainObject { } } - @Override - public Long getId() { - return this.id; - } - - public Set<String> getNonUserRecipients() { - return this.nonUserRecipients; - } - - public String getSubject() { - return this.subject; - } - - public String getFromName() { - return this.fromName; - } - - public String getFromEmail() { - return this.fromEmail; - } - - public String getMessageBody() { - return this.messageBody; - } - - public String getMessageID() { - return this.messageID; - } - - public FileReference getAttachment() { - return this.attachment; - } - - public void setId(Long id) { - this.id = id; - } - - public void setRecipients(Set<User> recipients) { - this.recipients = recipients; - } - - public void setNonUserRecipients(Set<String> nonUserRecipients) { - this.nonUserRecipients = nonUserRecipients; - } - - public void setSent(boolean sent) { - this.sent = sent; - } - - public void setMessageID(String messageID) { + public void markSent(final String messageID) { this.messageID = messageID; - } - - public void setAttachment(FileReference attachment) { - this.attachment = attachment; - } - - @Override - public String toString() { - return "MailEvent(id=" + this.getId() + ", recipients=" + this.getRecipients() + ", nonUserRecipients=" + this.getNonUserRecipients() + ", subject=" + this.getSubject() + ", fromName=" + this.getFromName() + ", fromEmail=" + this.getFromEmail() + ", messageBody=" + this.getMessageBody() + ", sent=" + this.isSent() + ", messageID=" + this.getMessageID() + ", attachment=" + this.getAttachment() + ")"; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof MailEvent)) return false; - final MailEvent other = (MailEvent) o; - return other.canEqual(this) - && Objects.equals(this.getId(), other.getId()); - } - - protected boolean canEqual(final Object other) { - return other instanceof MailEvent; - } - - @Override - public int hashCode() { - return Objects.hashCode(this.getId()); + this.sent = true; } } diff --git a/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java b/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java index a5c7f597be..179bffc02c 100644 --- a/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java +++ b/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java @@ -6,7 +6,7 @@ import se.su.dsv.scipro.file.FileDescription; import java.util.Arrays; import java.util.UUID; -class PrintingMailer implements Mailer { +public class PrintingMailer implements Mailer { @Override public MailResult mail(final String fromName, final String fromEmail, final String[] recipients, final String subject, final String message, final FileDescription attachment) { return new MailResult() { diff --git a/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java b/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java index f5e0035fa5..6a91588ff1 100644 --- a/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java +++ b/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.match; -class AllowAllIdeaCreationJudge implements IdeaCreationJudge { +public class AllowAllIdeaCreationJudge implements IdeaCreationJudge { @Override public Decision ruling(Idea idea) { return Decision.allowed(); diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java index 6955d28d2d..d3c7a21e50 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java +++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java @@ -1,17 +1,30 @@ package se.su.dsv.scipro.match; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.ProjectType; -import jakarta.persistence.*; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.*; - @Entity @Cacheable(true) -@Table(name="ApplicationPeriod") +@Table(name="application_period") public class ApplicationPeriod extends DomainObject { @Id @@ -23,17 +36,16 @@ public class ApplicationPeriod extends DomainObject { private String name; - @Basic + @Column(name = "start_date") private LocalDate startDate = LocalDate.now(); - @Basic + @Column(name = "end_date") private LocalDate endDate = LocalDate.now(); - @Basic - @Column(name = "courseStartDate") + @Column(name = "course_start_date") private LocalDateTime courseStartDateTime = LocalDate.now().atTime(8, 0); - @Basic + @Column(name = "course_end_date") private LocalDate courseEndDate; @OneToMany(fetch = FetchType.LAZY, mappedBy = "applicationPeriod", cascade=CascadeType.ALL, orphanRemoval=true) diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java index 717d71f294..82197dc73d 100644 --- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java +++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java @@ -1,15 +1,23 @@ package se.su.dsv.scipro.match; -import se.su.dsv.scipro.system.User; - -import jakarta.persistence.*; import java.io.Serializable; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Objects; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; + +import se.su.dsv.scipro.system.User; + @Entity -@Table(name = "applicationperiodexemption") +@Table(name = "application_period_exemption") public class ApplicationPeriodExemption implements Serializable { public enum Type { SUBMIT_STUDENT_IDEA(true), @@ -39,16 +47,19 @@ public class ApplicationPeriodExemption implements Serializable { @MapsId("applicationPeriodId") @ManyToOne(optional = false) - @JoinColumn(name = "applicationPeriodId") + @JoinColumn(name = "application_period_id") private ApplicationPeriod applicationPeriod; + @Column(name = "end_date") private LocalDate endDate; private String comment; @ManyToOne(optional = false) + @JoinColumn(name = "granted_by_id") private User grantedBy; + @Column(name = "granted_on") private LocalDateTime grantedOn; public ApplicationPeriodExemptionId getApplicationperiodexemptionId() { diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java index 0d9a6f0b91..eac5ccfbc2 100644 --- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java +++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java @@ -1,5 +1,7 @@ package se.su.dsv.scipro.match; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Table; import se.su.dsv.scipro.activityplan.ActivityPlanTemplate; import se.su.dsv.scipro.system.ProjectType; @@ -10,19 +12,23 @@ import jakarta.persistence.MapsId; import java.io.Serializable; @Entity +@Table(name = "application_period_project_type") public class ApplicationPeriodProjectType implements Serializable { @EmbeddedId private ApplicationPeriodProjectTypeId applicationPeriodProjectTypeId = new ApplicationPeriodProjectTypeId(); @MapsId("applicationPeriodId") @ManyToOne + @JoinColumn(name = "application_period_id") private ApplicationPeriod applicationPeriod; @MapsId("projectTypeId") @ManyToOne + @JoinColumn(name = "project_type_id") private ProjectType projectType; @ManyToOne(optional = true) + @JoinColumn(name = "activity_plan_template_id") private ActivityPlanTemplate activityPlanTemplate; protected ApplicationPeriodProjectType() {} diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java index 0156c88bd8..29499c6f0c 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.match; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.Expressions; import se.su.dsv.scipro.system.PageRequest; diff --git a/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java b/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java index 2df0e579c7..4367c24d73 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java +++ b/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java @@ -1,6 +1,16 @@ package se.su.dsv.scipro.match; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + import java.io.Serializable; import java.util.Date; import java.util.Objects; @@ -9,72 +19,92 @@ import java.util.Objects; @Table(name = "idea_first_meeting") @Cacheable(true) public class FirstMeeting implements Serializable { - public static final int LENGTH = 1024; + private static final int LENGTH = 1024; + + // ---------------------------------------------------------------------------------- + // basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Basic(optional = false) - private Date firstMeetingDate; - - @Column(nullable = false, length = LENGTH) - private String room; - - @Column(nullable = true, length = LENGTH) + @Basic + @Column(name = "description", nullable = true, length = LENGTH) private String description; + @Basic(optional = false) + @Column(name = "first_meeting_date") + private Date firstMeetingDate; + + @Basic + @Column(name = "room", nullable = false, length = LENGTH) + private String room; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (idea_first_meeting) referencing other + // tables. + // ---------------------------------------------------------------------------------- @OneToOne(optional = false) + @JoinColumn(name = "idea_id", referencedColumnName = "id") private Idea idea; - public FirstMeeting() { - - } + // ---------------------------------------------------------------------------------- + // constructors + // ---------------------------------------------------------------------------------- + public FirstMeeting() { } public FirstMeeting(Date firstMeetingDate, Idea idea) { this.firstMeetingDate = firstMeetingDate; this.idea = idea; } + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- + public Long getId() { return this.id; } - public Date getFirstMeetingDate() { - return this.firstMeetingDate; - } - - public String getRoom() { - return this.room; - } - - public String getDescription() { - return this.description; - } - - public Idea getIdea() { - return this.idea; - } - public void setId(Long id) { this.id = id; } - public void setFirstMeetingDate(Date firstMeetingDate) { - this.firstMeetingDate = firstMeetingDate; - } - - public void setRoom(String room) { - this.room = room; + public String getDescription() { + return this.description; } public void setDescription(String description) { this.description = description; } + public Date getFirstMeetingDate() { + return this.firstMeetingDate; + } + + public void setFirstMeetingDate(Date firstMeetingDate) { + this.firstMeetingDate = firstMeetingDate; + } + + public String getRoom() { + return this.room; + } + + public void setRoom(String room) { + this.room = room; + } + + public Idea getIdea() { + return this.idea; + } + public void setIdea(Idea idea) { this.idea = idea; } + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -94,11 +124,13 @@ public class FirstMeeting implements Serializable { @Override public int hashCode() { - return Objects.hash(this.getId(), this.getFirstMeetingDate(), this.getRoom(), this.getDescription(), this.getIdea()); + return Objects.hash(this.getId(), this.getFirstMeetingDate(), this.getRoom(), this.getDescription(), + this.getIdea()); } @Override public String toString() { - return "FirstMeeting(id=" + this.getId() + ", firstMeetingDate=" + this.getFirstMeetingDate() + ", room=" + this.getRoom() + ", description=" + this.getDescription() + ", idea=" + this.getIdea() + ")"; + return "FirstMeeting(id=" + this.getId() + ", firstMeetingDate=" + this.getFirstMeetingDate() + ", room=" + + this.getRoom() + ", description=" + this.getDescription() + ", idea=" + this.getIdea() + ")"; } } diff --git a/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java b/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java index 7714a267a9..caa4bab050 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.match; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; diff --git a/core/src/main/java/se/su/dsv/scipro/match/Idea.java b/core/src/main/java/se/su/dsv/scipro/match/Idea.java index 15b457b17b..e2772b539b 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/Idea.java +++ b/core/src/main/java/se/su/dsv/scipro/match/Idea.java @@ -1,103 +1,190 @@ package se.su.dsv.scipro.match; import com.querydsl.core.annotations.QueryInit; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.AttributeOverrides; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.OrderBy; +import jakarta.persistence.PostLoad; +import jakarta.persistence.PostPersist; +import jakarta.persistence.PostUpdate; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; + import se.su.dsv.scipro.data.dataobjects.Member; import se.su.dsv.scipro.project.Project; -import se.su.dsv.scipro.system.*; +import se.su.dsv.scipro.system.DomainObject; +import se.su.dsv.scipro.system.Language; +import se.su.dsv.scipro.system.ProjectType; +import se.su.dsv.scipro.system.ResearchArea; +import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.time.LocalDate; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; @Entity @Table(name = "idea") @Cacheable(true) public class Idea extends DomainObject { + private static final int DESCRIPTION_LENGTH = 4000; + private static final int PREREQUISITES_LENGTH = 4000; + private static final int TITLE_LENGTH = 1024; - public static final int DESCRIPTION_LENGTH = 4000; - public static final int PREREQUISITES_LENGTH = 4000; - public static final int TITLE_LENGTH = 1024; + // ---------------------------------------------------------------------------------- + // basic and embedded JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(optional = false) - private ProjectType projectType; - - @Enumerated(EnumType.STRING) - private Type type; - - @ManyToOne(optional = false) - private User creator; - + @Basic @Column(nullable = true, length = DESCRIPTION_LENGTH) private String description; + @Basic @Column(nullable = true, length = PREREQUISITES_LENGTH) private String prerequisites; - @OneToMany(fetch = FetchType.LAZY, mappedBy = "idea", cascade = CascadeType.ALL, orphanRemoval = true) - @QueryInit({"user", "program"}) - private Set<IdeaParticipation> ideaParticipations = new HashSet<>(); - - @ManyToOne(optional = true) - private ApplicationPeriod applicationPeriod; - + @Basic @Column(nullable = false, length = TITLE_LENGTH) private String title; - @ManyToOne(optional = true) - private ResearchArea researchArea; - - @ElementCollection - @CollectionTable(name = "idea_language") - @Column(name = "language") + @Basic @Enumerated(EnumType.STRING) - private Set<Language> languages = EnumSet.noneOf(Language.class); + private Type type; + + @Basic + @Column(name = "published") + private boolean published = true; + + @Enumerated(EnumType.STRING) + @Column(name = "cached_status") + private Status cachedStatus; + + @Basic + @Column(name = "inactive") + private boolean inactive = false; @Embedded @AttributeOverrides({ - @AttributeOverride(name = "practicalHow", column = @Column(insertable = false, updatable = false)), - @AttributeOverride(name = "literature", column = @Column(insertable = false, updatable = false)), - @AttributeOverride(name = "theoryHow", column = @Column(insertable = false, updatable = false)), - @AttributeOverride(name = "why", column = @Column(insertable = false, updatable = false)), - @AttributeOverride(name = "what", column = @Column(insertable = false, updatable = false)) + @AttributeOverride(name = "practicalHow", column = @Column(name = "practical_how", insertable = false, updatable = false)), + @AttributeOverride(name = "theoryHow", column = @Column(name = "theory_how", insertable = false, updatable = false)), + @AttributeOverride(name = "what", column = @Column(name = "what", insertable = false, updatable = false)), + @AttributeOverride(name = "why", column = @Column(name = "why", insertable = false, updatable = false)), + @AttributeOverride(name = "literature", column = @Column(name = "literature", insertable = false, updatable = false)) }) private Watson watson; @Embedded + @AttributeOverrides({ + @AttributeOverride(name = "literature", column = @Column(name = "literature", insertable = false, updatable = false)), + @AttributeOverride(name = "background", column = @Column(name = "background", insertable = false, updatable = false)), + @AttributeOverride(name = "problem", column = @Column(name = "problem", insertable = false, updatable = false)), + @AttributeOverride(name = "method", column = @Column(name = "method", insertable = false, updatable = false)), + @AttributeOverride(name = "interests", column = @Column(name = "interests", insertable = false, updatable = false)) + }) private TholanderBox tholanderBox = new TholanderBox(); - @ManyToMany - private Set<Keyword> keywords = new HashSet<>(); + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (idea) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = true) + @JoinColumn(name = "application_period_id", referencedColumnName = "id") + private ApplicationPeriod applicationPeriod; + + @ManyToOne(optional = false) + @JoinColumn(name = "creator_user_id", referencedColumnName = "id") + private User creator; + + @OneToOne(optional = true, cascade = CascadeType.ALL) + @JoinColumn(name = "latest_match_id", referencedColumnName = "id") + @QueryInit({"supervisor.user", "supervisor.unit"}) + private Match match; @OneToOne + @JoinColumn(name = "project_id", referencedColumnName = "id") private Project project; - @OneToOne(mappedBy = "idea", orphanRemoval = true, optional = true) - private FirstMeeting firstMeeting; + @ManyToOne(optional = false) + @JoinColumn(name = "project_type_id", referencedColumnName = "id") + private ProjectType projectType; + @ManyToOne(optional = true) + @JoinColumn(name = "research_area_id", referencedColumnName = "id") + private ResearchArea researchArea; + + // ---------------------------------------------------------------------------------- + // @ManyToMany JPA-mappings + // ---------------------------------------------------------------------------------- + + // many-to-many from table "keyword" through table "idea_keyword" + @ManyToMany + @JoinTable(name="idea_keyword", + joinColumns = @JoinColumn(name = "idea_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "keyword_id", referencedColumnName = "id")) + private Set<Keyword> keywords = new HashSet<>(); + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "idea" + // ---------------------------------------------------------------------------------- + + // from table idea_language + @ElementCollection + @CollectionTable(name = "idea_language", + joinColumns = @JoinColumn(name = "idea_id", referencedColumnName = "id")) + @Column(name = "language") + @Enumerated(EnumType.STRING) + private Set<Language> languages = EnumSet.noneOf(Language.class); + + // from table idea_export + @OneToMany(mappedBy = "idea", cascade = CascadeType.ALL) + private List<IdeaExport> exports = new ArrayList<>(); + + // from table idea_student + @OneToMany(fetch = FetchType.LAZY, mappedBy = "idea", cascade = CascadeType.ALL, orphanRemoval = true) + @QueryInit({"user", "program"}) + private Set<IdeaParticipation> ideaParticipations = new HashSet<>(); + + // from table "idea_match" @OneToMany(fetch = FetchType.LAZY, mappedBy = "idea", cascade = CascadeType.ALL) @OrderBy("dateCreated DESC") private List<Match> matchHistory = new ArrayList<>(); - @OneToOne(optional = true, cascade = CascadeType.ALL) - @QueryInit({"supervisor.user", "supervisor.unit"}) - private Match match; - - @Column(name = "published") - private boolean published = true; - - @OneToMany(mappedBy = "idea", cascade = CascadeType.ALL) - private List<IdeaExport> exports = new ArrayList<>(); - - @Enumerated(EnumType.STRING) - private Status cachedStatus; - - @Basic - private boolean inactive = false; + // from table "idea_first_meeting" + @OneToOne(mappedBy = "idea", orphanRemoval = true, optional = true) + private FirstMeeting firstMeeting; + // ---------------------------------------------------------------------------------- + // methods... + // ---------------------------------------------------------------------------------- public Idea copy(User supervisor) { Idea copy = new Idea(); copy.projectType = this.projectType; @@ -448,7 +535,9 @@ public class Idea extends DomainObject { public String toString() { return "Student idea"; } - }, SUPERVISOR { + }, + + SUPERVISOR { @Override public String toString() { return "Supervisor idea"; @@ -463,18 +552,21 @@ public class Idea extends DomainObject { return "Unmatched"; } }, + MATCHED { @Override public String toString() { return "Matched, no project"; } }, + COMPLETED { @Override public String toString() { return "Matched, has project"; } }, + INACTIVE { @Override public String toString() { diff --git a/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java b/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java index 39b00e453a..321ccda22b 100644 --- a/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java +++ b/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java @@ -1,8 +1,18 @@ package se.su.dsv.scipro.match; +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.system.DomainObject; -import jakarta.persistence.*; import java.util.Objects; @Entity @@ -11,56 +21,69 @@ public class IdeaExport extends DomainObject { public enum Result { FAIL, SUCCESS } + // ---------------------------------------------------------------------------------- + // basic and embedded JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Enumerated(EnumType.STRING) - private Result result; - @Basic private String reason; + @Enumerated(EnumType.STRING) + private Result result; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (idea_export) referencing other tables + // ---------------------------------------------------------------------------------- @ManyToOne(optional = false) + @JoinColumn(name = "idea_id", referencedColumnName = "id") private Idea idea; - public boolean wasSuccessful() { - return result == Result.SUCCESS; - } - + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public Result getResult() { - return this.result; - } - - public String getReason() { - return this.reason; - } - - public Idea getIdea() { - return this.idea; - } - public void setId(Long id) { this.id = id; } - public void setResult(Result result) { - this.result = result; + public String getReason() { + return this.reason; } public void setReason(String reason) { this.reason = reason; } + public Result getResult() { + return this.result; + } + + public void setResult(Result result) { + this.result = result; + } + + public Idea getIdea() { + return this.idea; + } + public void setIdea(Idea idea) { this.idea = idea; } + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- + public boolean wasSuccessful() { + return result == Result.SUCCESS; + } + @Override public boolean equals(final Object o) { if (o == this) return true; diff --git a/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java b/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java index 625e38cf8f..7bf357d62f 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java +++ b/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java @@ -1,83 +1,114 @@ package se.su.dsv.scipro.match; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.Program; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Date; import java.util.Objects; @Entity @Table(name = "idea_student") -@AssociationOverrides({ - @AssociationOverride(name = "idea", - joinColumns = @JoinColumn(name = "idea_id")) }) public class IdeaParticipation implements Serializable { - protected IdeaParticipation() { - - } - - public IdeaParticipation(User student, Idea idea) { - this.user = student; - this.idea = idea; - } + // ---------------------------------------------------------------------------------- + // basic and embedded JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - private User user; - - @ManyToOne - private Idea idea; - + @Basic + @Column(name = "date_created") private Date dateCreated = new Date(); + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (idea_student) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "idea_id", referencedColumnName = "id") + private Idea idea; + @ManyToOne(optional = true) + @JoinColumn(name = "program_id", referencedColumnName = "id") private Program program; + @ManyToOne + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- + + // JPA/Hibernate works by create a child class of your entity class with all database + // tricks in it, it therefore requires no-arg constructor to be able to instantiate + // a new instance. + // By creating a protected constructor, JPA/Hibernate still works as expected, but it + // declares the intention that parameters need to be provided when new instances are + // created. + protected IdeaParticipation() { } + + public IdeaParticipation(User student, Idea idea) { + this.user = student; + this.idea = idea; + } + + // ---------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------- public Long getId() { return this.id; } - public User getUser() { - return this.user; - } - - public Idea getIdea() { - return this.idea; - } - - public Date getDateCreated() { - return this.dateCreated; - } - - public Program getProgram() { - return this.program; - } - public void setId(Long id) { this.id = id; } - public void setUser(User user) { - this.user = user; - } - - public void setIdea(Idea idea) { - this.idea = idea; + public Date getDateCreated() { + return this.dateCreated; } public void setDateCreated(Date dateCreated) { this.dateCreated = dateCreated; } + public Idea getIdea() { + return this.idea; + } + + public void setIdea(Idea idea) { + this.idea = idea; + } + + public Program getProgram() { + return this.program; + } + public void setProgram(Program program) { this.program = program; } + public User getUser() { + return this.user; + } + + public void setUser(User user) { + this.user = user; + } + + // ---------------------------------------------------------------------------- + // methods + // ---------------------------------------------------------------------------- @Override public String toString() { return "IdeaParticipation(id=" + this.getId() + ", user=" + this.getUser() + ", idea=" + this.getIdea() + ", dateCreated=" + this.getDateCreated() + ", program=" + this.getProgram() + ")"; diff --git a/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java index 07a468f894..e6be18e1c3 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.match; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.BooleanExpression; @@ -358,7 +358,6 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements } } - @Transactional private Idea acceptIdea0(Idea idea, User creator, Program accepteeProgram, User coAuthor, final ApplicationPeriod applicationPeriod) { Idea localIdea = idea; @@ -442,6 +441,7 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements } @Override + @Transactional public void studentUnselect(final Idea idea, final User student) { unmatch(idea, student, new NotificationSource()); } @@ -490,7 +490,6 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements return returnValue; } - @Transactional private Idea addMatch(User creator, User supervisor, Idea idea, NotificationSource notificationSource) { Match match = new Match(); match.setIdea(idea); diff --git a/core/src/main/java/se/su/dsv/scipro/match/Keyword.java b/core/src/main/java/se/su/dsv/scipro/match/Keyword.java index 320c278981..060efc46b7 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/Keyword.java +++ b/core/src/main/java/se/su/dsv/scipro/match/Keyword.java @@ -1,15 +1,25 @@ package se.su.dsv.scipro.match; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.Table; + import se.su.dsv.scipro.system.LazyDeletableDomainObject; import se.su.dsv.scipro.system.ResearchArea; -import jakarta.persistence.*; - import java.util.HashSet; import java.util.Objects; import java.util.Set; @Entity +@Table(name = "keyword") @Cacheable(true) public class Keyword extends LazyDeletableDomainObject { @@ -19,8 +29,10 @@ public class Keyword extends LazyDeletableDomainObject { private String keyword; - @ManyToMany(fetch = FetchType.EAGER,targetEntity=ResearchArea.class) - @JoinTable(name="Keyword_researcharea") + @ManyToMany(fetch = FetchType.EAGER, targetEntity = ResearchArea.class) + @JoinTable(name="keyword_research_area", + joinColumns = @JoinColumn(name = "keyword_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "research_area_id", referencedColumnName = "id")) private Set<ResearchArea> researchAreas = new HashSet<>(); public Keyword() { diff --git a/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java index 44c702b1aa..9eb0a58232 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.match; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.types.dsl.BooleanExpression; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core/src/main/java/se/su/dsv/scipro/match/Match.java b/core/src/main/java/se/su/dsv/scipro/match/Match.java index ec4bb68099..2408e5058f 100755 --- a/core/src/main/java/se/su/dsv/scipro/match/Match.java +++ b/core/src/main/java/se/su/dsv/scipro/match/Match.java @@ -1,56 +1,85 @@ package se.su.dsv.scipro.match; import com.querydsl.core.annotations.QueryInit; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.Objects; @Entity -@Cacheable(true) @Table(name = "idea_match") +@Cacheable(true) public class Match extends DomainObject { + + // ---------------------------------------------------------------------------------- + // basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(optional = false) - private Idea idea; - - @ManyToOne - @QueryInit({"unit"}) - private User supervisor; - + @Basic @Enumerated(EnumType.STRING) private Idea.Status status; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (idea_match) referencing other tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = true) + @JoinColumn(name = "changed_by_user_id", referencedColumnName = "id") private User changedBy; - public User getSupervisor() { - return supervisor; - } + @ManyToOne(optional = false) + @JoinColumn(name = "idea_id", referencedColumnName = "id") + private Idea idea; + @ManyToOne + @JoinColumn(name = "supervisor_user_id", referencedColumnName = "id") + @QueryInit({"unit"}) + private User supervisor; + + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public Idea getIdea() { - return this.idea; + public void setId(Long id) { + this.id = id; } public Idea.Status getStatus() { return this.status; } + public void setStatus(Idea.Status status) { + this.status = status; + } + public User getChangedBy() { return this.changedBy; } - public void setId(Long id) { - this.id = id; + public void setChangedBy(User changedBy) { + this.changedBy = changedBy; + } + + public Idea getIdea() { + return this.idea; } public void setIdea(Idea idea) { @@ -61,14 +90,13 @@ public class Match extends DomainObject { this.supervisor = supervisor; } - public void setStatus(Idea.Status status) { - this.status = status; - } - - public void setChangedBy(User changedBy) { - this.changedBy = changedBy; + public User getSupervisor() { + return supervisor; } + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -93,6 +121,7 @@ public class Match extends DomainObject { @Override public String toString() { - return "Match(id=" + this.getId() + ", supervisor=" + this.getSupervisor() + ", status=" + this.getStatus() + ", changedBy=" + this.getChangedBy() + ")"; + return "Match(id=" + this.getId() + ", supervisor=" + this.getSupervisor() + ", status=" + this.getStatus() + + ", changedBy=" + this.getChangedBy() + ")"; } } diff --git a/core/src/main/java/se/su/dsv/scipro/match/MatchModule.java b/core/src/main/java/se/su/dsv/scipro/match/MatchModule.java deleted file mode 100644 index 28e19d2295..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/match/MatchModule.java +++ /dev/null @@ -1,26 +0,0 @@ -package se.su.dsv.scipro.match; - -import com.google.inject.AbstractModule; -import com.google.inject.multibindings.OptionalBinder; - -public class MatchModule extends AbstractModule { - @Override - protected void configure() { - OptionalBinder.newOptionalBinder(binder(), IdeaCreationJudge.class) - .setDefault().to(AllowAllIdeaCreationJudge.class); - bind(ProjectStartNotifier.class).asEagerSingleton(); - bind(AddActivityPlanOnProjectStart.class).asEagerSingleton(); - bind(ApplicationPeriodService.class).to(ApplicationPeriodServiceImpl.class); - bind(IdeaService.class).to(IdeaServiceImpl.class); - bind(FirstMeetingRepository.class).to(FirstMeetingRepositoryImpl.class); - bind(KeywordService.class).to(KeywordServiceImpl.class); - bind(MatchService.class).to(MatchServiceImpl.class); - bind(ProgramService.class).to(ProgramServiceImpl.class); - bind(MatchFollowUpService.class).to(MatchFollowUpServiceImpl.class); - bind(TargetService.class).to(TargetServiceImpl.class); - bind(ApplicationPeriodProjectTypeService.class).to(ApplicationPeriodProjectTypeServiceImpl.class); - bind(PreliminaryMatchService.class).to(PreliminaryMatchServiceImpl.class); - bind(IdeaRepository.class).to(IdeaRepositoryImpl.class); - bind(TargetRepository.class).to(TargetRepositoryImpl.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java b/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java index 5845f8f479..4a2b0229ba 100644 --- a/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java +++ b/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java @@ -1,70 +1,98 @@ package se.su.dsv.scipro.match; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.Objects; @Entity @Table(name = "preliminary_match") public class PreliminaryMatch extends DomainObject { + // ---------------------------------------------------------------------------------- + // basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Basic + @Column(name = "comment") + private String comment; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (idea_first_meeting) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne + @JoinColumn(name = "idea_id", referencedColumnName = "id") private Idea idea; @ManyToOne + @JoinColumn(name = "supervisor_user_id", referencedColumnName = "id") private User supervisor; - private String comment; - - // JPA - public PreliminaryMatch() { - } + // ---------------------------------------------------------------------------------- + // constructors + // ---------------------------------------------------------------------------------- + public PreliminaryMatch() { } public PreliminaryMatch(final Idea idea) { this.idea = idea; } + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public Idea getIdea() { - return this.idea; - } - - public User getSupervisor() { - return this.supervisor; - } - - public String getComment() { - return this.comment; - } - public void setId(Long id) { this.id = id; } - public void setIdea(Idea idea) { - this.idea = idea; - } - - public void setSupervisor(User supervisor) { - this.supervisor = supervisor; + public String getComment() { + return this.comment; } public void setComment(String comment) { this.comment = comment; } + public Idea getIdea() { + return this.idea; + } + + public void setIdea(Idea idea) { + this.idea = idea; + } + + public User getSupervisor() { + return this.supervisor; + } + + public void setSupervisor(User supervisor) { + this.supervisor = supervisor; + } + + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- @Override public String toString() { - return "PreliminaryMatch(id=" + this.getId() + ", idea=" + this.getIdea() + ", supervisor=" + this.getSupervisor() + ", comment=" + this.getComment() + ")"; + return "PreliminaryMatch(id=" + this.getId() + ", idea=" + this.getIdea() + ", supervisor=" + + this.getSupervisor() + ", comment=" + this.getComment() + ")"; } @Override diff --git a/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java index e759f53f93..925831af46 100644 --- a/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.match; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.types.dsl.BooleanExpression; import se.su.dsv.scipro.system.PageRequest; import se.su.dsv.scipro.system.Sort; diff --git a/core/src/main/java/se/su/dsv/scipro/match/Target.java b/core/src/main/java/se/su/dsv/scipro/match/Target.java index 2be7fac981..79d88f4514 100644 --- a/core/src/main/java/se/su/dsv/scipro/match/Target.java +++ b/core/src/main/java/se/su/dsv/scipro/match/Target.java @@ -20,12 +20,12 @@ public class Target implements Serializable { @MapsId("applicationPeriodId") @ManyToOne - @JoinColumn(name = "applicationPeriodId") + @JoinColumn(name = "application_period_id") private ApplicationPeriod applicationPeriod; @MapsId("projectTypeId") @ManyToOne - @JoinColumn(name = "projectTypeId") + @JoinColumn(name = "project_type_id") private ProjectType projectType; private int target; diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java b/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java index e43bb892e8..8d8aaaeb33 100644 --- a/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.milestones; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate; diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java index 45bbd74bfb..f72cf1954f 100644 --- a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java +++ b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java @@ -1,39 +1,54 @@ package se.su.dsv.scipro.milestones.dataobjects; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.data.dataobjects.Member; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.Collections; import java.util.List; @Entity @Table(name = "milestone") public class Milestone extends DomainObject { - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) protected long id; - @ManyToOne - private Project project; - - @ManyToOne(optional = true) - private User user; - - @ManyToOne(optional = false) - private MilestoneActivityTemplate activity; - + @Basic @Column(name = "confirmed", nullable = false) private boolean confirmed = false; - @Override - public Long getId() { - return id; - } + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (milestone) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name = "milestone_activity_template_id", referencedColumnName = "id") + private MilestoneActivityTemplate activity; + @ManyToOne + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; + + @ManyToOne(optional = true) + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected Milestone() { } @@ -49,6 +64,15 @@ public class Milestone extends DomainObject { this.activity = activity; } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + + @Override + public Long getId() { + return id; + } + public void setId(Long id) { this.id = id; } @@ -61,14 +85,6 @@ public class Milestone extends DomainObject { this.confirmed = confirmed; } - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - public MilestoneActivityTemplate getActivity() { return activity; } @@ -77,11 +93,22 @@ public class Milestone extends DomainObject { this.activity = activity; } - public List<Member> getMembers() { - return Collections.singletonList(new Member(user, Member.Type.MILESTONE_INDIVIDUAL)); + public Project getProject() { + return project; + } + + public void setProject(Project project) { + this.project = project; } public User getUser() { return this.user; } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + public List<Member> getMembers() { + return Collections.singletonList(new Member(user, Member.Type.MILESTONE_INDIVIDUAL)); + } } diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java index f86421e861..583c558278 100644 --- a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java @@ -1,10 +1,23 @@ package se.su.dsv.scipro.milestones.dataobjects; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.Event; import se.su.dsv.scipro.system.LazyDeletableDomainObject; import se.su.dsv.scipro.system.ProjectType; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Comparator; import java.util.HashSet; @@ -18,42 +31,66 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject { public static final String PEER_REVIEW_ONE = "PEER_REVIEW_ONE"; public static final String PEER_REVIEW_TWO = "PEER_REVIEW_TWO"; + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Basic(optional = false) + @Column(name = "title") private String title; @Basic(optional = true) + @Column(name = "description") private String description; @Enumerated(EnumType.STRING) + @Column(name = "type") private Type type; - @Column(unique = true) + @Basic + @Column(name = "code", unique = true) private String code; + @Basic + @Column(name = "sort_order") + private int sortOrder; + + @Basic + @Column(name = "editable_by_students") + private boolean editableByStudents = false; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (milestone_activity_template) + // referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "milestone_phase_template_id", referencedColumnName = "id", nullable = false) + private MilestonePhaseTemplate milestonePhaseTemplate; + + @OneToOne + @JoinColumn(name = "activated_by_event_name", referencedColumnName = "name") + private Event activatedBy; + + // ---------------------------------------------------------------------------------- + // @ManyToMany JPA-mappings + // ---------------------------------------------------------------------------------- + + // Many-to-Many between table milestone_activity_template and project_type through + // table "milestone_activity_template_project_type". @ManyToMany @JoinTable( - joinColumns = @JoinColumn(name = "milestone_activity_template_id") + name = "milestone_activity_template_project_type", + joinColumns = @JoinColumn(name = "milestone_activity_template_id"), + inverseJoinColumns = @JoinColumn(name = "project_type_id") ) private Set<ProjectType> projectTypes = new HashSet<>(); - @ManyToOne - @JoinColumn(name = "phase", nullable = false) - private MilestonePhaseTemplate milestonePhaseTemplate; - - @Column - private int sortOrder; - - @Column - private boolean editableByStudents = false; - - @OneToOne - @JoinColumn(name = "activatedBy") - private Event activatedBy; - + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- public MilestoneActivityTemplate() { } @@ -67,10 +104,9 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject { this.description = description; } - public void addProjectType(ProjectType projectType) { - projectTypes.add(projectType); - } - + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; @@ -80,79 +116,95 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject { return this.title; } - public String getDescription() { - return this.description; - } - - public Type getType() { - return this.type; - } - - public String getCode() { - return this.code; - } - - public Set<ProjectType> getProjectTypes() { - return this.projectTypes; - } - - public MilestonePhaseTemplate getMilestonePhaseTemplate() { - return this.milestonePhaseTemplate; - } - - public int getSortOrder() { - return this.sortOrder; - } - - public boolean isEditableByStudents() { - return this.editableByStudents; - } - - public Event getActivatedBy() { - return this.activatedBy; - } - public void setTitle(String title) { this.title = title; } + public String getDescription() { + return this.description; + } + public void setDescription(String description) { this.description = description; } + public Type getType() { + return this.type; + } + public void setType(Type type) { this.type = type; } + public String getCode() { + return this.code; + } + public void setCode(String code) { this.code = code; } - public void setMilestonePhaseTemplate(MilestonePhaseTemplate milestonePhaseTemplate) { - this.milestonePhaseTemplate = milestonePhaseTemplate; + public int getSortOrder() { + return this.sortOrder; } public void setSortOrder(int sortOrder) { this.sortOrder = sortOrder; } + public boolean isEditableByStudents() { + return this.editableByStudents; + } + public void setEditableByStudents(boolean editableByStudents) { this.editableByStudents = editableByStudents; } + public MilestonePhaseTemplate getMilestonePhaseTemplate() { + return this.milestonePhaseTemplate; + } + + public void setMilestonePhaseTemplate(MilestonePhaseTemplate milestonePhaseTemplate) { + this.milestonePhaseTemplate = milestonePhaseTemplate; + } + + public Event getActivatedBy() { + return this.activatedBy; + } + public void setActivatedBy(Event activatedBy) { this.activatedBy = activatedBy; } + public Set<ProjectType> getProjectTypes() { + return this.projectTypes; + } + public void setProjectTypes(Set<ProjectType> projectTypes) { this.projectTypes = projectTypes; } - public static class BySortOrderComparator implements Comparator<MilestoneActivityTemplate>, Serializable { + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + public void addProjectType(ProjectType projectType) { + projectTypes.add(projectType); + } + + public boolean isAutomatic() { + return code != null || activatedBy != null; + } + + // ---------------------------------------------------------------------------------- + // Nested classes and types + // ---------------------------------------------------------------------------------- + public static class BySortOrderComparator implements Comparator<MilestoneActivityTemplate>, + Serializable { @Override public int compare(MilestoneActivityTemplate o1, MilestoneActivityTemplate o2) { int sortOrderResult = o1.sortOrder - o2.sortOrder; - int phaseSortOrderResult = o1.milestonePhaseTemplate.getSortOrder() - o2.getMilestonePhaseTemplate().getSortOrder(); + int phaseSortOrderResult = o1.milestonePhaseTemplate.getSortOrder() - + o2.getMilestonePhaseTemplate().getSortOrder(); if (phaseSortOrderResult == 0) { return sortOrderResult; @@ -175,8 +227,4 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject { return asString; } } - - public boolean isAutomatic() { - return code != null || activatedBy != null; - } } diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java index 3078dd4d24..34b29d2fe4 100644 --- a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java @@ -1,31 +1,41 @@ package se.su.dsv.scipro.milestones.dataobjects; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.LazyDeletableDomainObject; -import jakarta.persistence.*; import java.util.Objects; @Entity @Table(name = "milestone_phase_template") public class MilestonePhaseTemplate extends LazyDeletableDomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) protected long id; - @Override - public Long getId() { - return id; - } - @Basic(optional = false) + @Column(name = "title") private String title; @Basic(optional = true) + @Column(name = "description") private String description; - @Column(name = "sortOrder") + @Basic + @Column(name = "sort_order") private int sortOrder; + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- public MilestonePhaseTemplate() { } @@ -41,37 +51,47 @@ public class MilestonePhaseTemplate extends LazyDeletableDomainObject { this.sortOrder = sortOrder; } - public String getTitle() { - return this.title; - } - - public String getDescription() { - return this.description; - } - - public int getSortOrder() { - return this.sortOrder; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return id; } public void setId(long id) { this.id = id; } + public String getTitle() { + return this.title; + } + public void setTitle(String title) { this.title = title; } + public String getDescription() { + return this.description; + } + public void setDescription(String description) { this.description = description; } + public int getSortOrder() { + return this.sortOrder; + } + public void setSortOrder(int sortOrder) { this.sortOrder = sortOrder; } - @Override - public String toString() { - return "MilestonePhaseTemplate(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", sortOrder=" + this.getSortOrder() + ")"; + // ---------------------------------------------------------------------------------- + // Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof MilestonePhaseTemplate; } @Override @@ -86,12 +106,13 @@ public class MilestonePhaseTemplate extends LazyDeletableDomainObject { && this.getSortOrder() == other.getSortOrder(); } - protected boolean canEqual(final Object other) { - return other instanceof MilestonePhaseTemplate; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getTitle(), this.getDescription(), this.getSortOrder()); } + + @Override + public String toString() { + return "MilestonePhaseTemplate(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", sortOrder=" + this.getSortOrder() + ")"; + } } diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java b/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java index d19f65687a..e70062e7b1 100644 --- a/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java +++ b/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java @@ -61,7 +61,7 @@ public class MilestoneActivator { int minimumActiveParticipationsToBeGraded = event.getProject() .getProjectType() .getProjectTypeSettings() - .getMinimumActiveParticipationsToBeGraded(); + .getMinActiveParticipationsToBeGraded(); if (completedParticipations >= minimumActiveParticipationsToBeGraded) { activateIndividualMilestone(Set.of("ParticipationGradingEvent"), event.getProject(), event.getStudent()); } else { diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java index f5bd91a316..197e947bda 100644 --- a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.milestones.service.impl; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.Sort; import se.su.dsv.scipro.milestones.dataobjects.MilestonePhaseTemplate; import se.su.dsv.scipro.milestones.dataobjects.QMilestonePhaseTemplate; diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java index 70c69ddef2..f7b5b8c447 100644 --- a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java @@ -4,6 +4,7 @@ import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.Pageable; import se.su.dsv.scipro.milestones.dataobjects.Milestone; import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate; @@ -54,6 +55,7 @@ public class MilestoneServiceImpl extends AbstractServiceImpl<Milestone, Long> i } @Override + @Transactional public void setConfirmed(Project project, MilestoneActivityTemplate activity, boolean confirmed) { if (confirmed) { for (MilestoneActivityTemplate earlierActivity : getEarlierIncompleteProjectMilestoneActivities(project, activity)) { @@ -84,6 +86,7 @@ public class MilestoneServiceImpl extends AbstractServiceImpl<Milestone, Long> i } @Override + @Transactional public void setConfirmed(Project project, User student, MilestoneActivityTemplate activity, boolean confirmed) { if (!project.hasModule(ProjectModule.MILESTONES)) { diff --git a/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java b/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java index b12335ead6..639da2f1f5 100755 --- a/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java +++ b/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java @@ -1,24 +1,29 @@ package se.su.dsv.scipro.nonworkperiod; -import jakarta.persistence.GenerationType; -import se.su.dsv.scipro.system.DomainObject; - import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Table; +import se.su.dsv.scipro.system.DomainObject; + import java.time.LocalDate; import java.util.Objects; @Entity @Cacheable(true) +@Table(name = "non_work_day_period") public class NonWorkDayPeriod extends DomainObject { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "start_date") private LocalDate startDate; + @Column(name = "end_date") private LocalDate endDate; private String comment; diff --git a/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java index 126470035e..58cb33dbc1 100755 --- a/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java @@ -1,6 +1,7 @@ package se.su.dsv.scipro.notes; import com.querydsl.core.types.dsl.BooleanExpression; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.AbstractServiceImpl; import se.su.dsv.scipro.system.User; @@ -20,6 +21,7 @@ public class NoteServiceImpl extends AbstractServiceImpl<Note, Long> implements } @Override + @Transactional public Note getNote(User user) { Note note = findOne(hasUser(user)); if (note == null){ diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java index 8bd1a88a13..0a4a6e08f4 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java @@ -1,6 +1,5 @@ package se.su.dsv.scipro.notifications; -import com.google.inject.ProvisionException; import se.su.dsv.scipro.data.dataobjects.Member; import se.su.dsv.scipro.finalseminar.FinalSeminar; import se.su.dsv.scipro.group.Group; @@ -94,7 +93,7 @@ public class NotificationControllerImpl implements NotificationController { try { return currentUserProvider.get().get(); } - catch (ProvisionException ignored) { + catch (RuntimeException ignored) { return null; } } diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationModule.java b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationModule.java deleted file mode 100644 index 507ca4bcab..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationModule.java +++ /dev/null @@ -1,28 +0,0 @@ -package se.su.dsv.scipro.notifications; - -import com.google.inject.PrivateModule; -import se.su.dsv.scipro.notifications.interfaces.NotificationMailFormatter; -import se.su.dsv.scipro.notifications.interfaces.impl.NotificationMailFormatterImpl; - -public class NotificationModule extends PrivateModule { - - public static final String NOTIFICATION_RELATIVE_PAGE_URL = "notification"; - - @Override - protected void configure() { - bind(Notifications.class).asEagerSingleton(); - - bind(NotificationService.class).to(NotificationServiceImpl.class); - expose(NotificationService.class); - - bind(NotificationEventRepository.class).to(NotificationEventRepositoryImpl.class); - bind(NotificationEventService.class).to(NotificationEventServiceImpl.class); - expose(NotificationEventService.class); - - bind(NotificationMailFormatter.class).to(NotificationMailFormatterImpl.class); - expose(NotificationMailFormatter.class); - bind(NotificationController.class).to(NotificationControllerImpl.class); - expose(NotificationController.class); - } - -} diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java index 826991801f..5bbe68093e 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.notifications; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Predicate; import se.su.dsv.scipro.system.Pageable; @@ -50,6 +50,7 @@ public class NotificationServiceImpl extends AbstractServiceImpl<Notification,Lo } @Override + @Transactional public void setRead(User user, NotificationEvent notificationEvent, boolean read) { Iterable<Notification> notifications = findAll( QNotification.notification.notificationEvent.eq(notificationEvent) @@ -62,6 +63,7 @@ public class NotificationServiceImpl extends AbstractServiceImpl<Notification,Lo } @Override + @Transactional @SuppressWarnings("unchecked") // This looks so wrong but a List<Notification> is what we actually get // during runtime, see SCIPRO-167935. Reflection so awesome... diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java index 3fd7e4a0ac..f738fbf6c8 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java @@ -1,5 +1,7 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; import se.su.dsv.scipro.system.DomainObject; import jakarta.persistence.Entity; @@ -13,6 +15,8 @@ public class CustomEvent extends NotificationEvent { IDEA_DELETED } + @Basic + @Column(name = "event") @Enumerated(EnumType.STRING) private CustomEvent.Event event; diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java index fa25851094..079c0cb09a 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.group.Group; import se.su.dsv.scipro.system.DomainObject; @@ -11,37 +14,40 @@ import jakarta.persistence.ManyToOne; @Entity public class GroupEvent extends NotificationEvent { - public void setEvent(Event event) { - this.event = event; - } - public enum Event { MESSAGE_THREAD_CREATED, MESSAGE_THREAD_REPLY } + @Basic + @Column(name = "event") + @Enumerated(EnumType.STRING) + private Event event; + + @ManyToOne + @JoinColumn(name = "project_group_id", referencedColumnName = "id") + private Group group; + + public GroupEvent() { + super(Notification.Type.GROUP); + } + + @Override + public Enum getEvent() { + return event; + } + + public void setEvent(Event event) { + this.event = event; + } + public Group getGroup() { return group; } - @ManyToOne - private Group group; - - @Enumerated(EnumType.STRING) - private Event event; - - public GroupEvent() { - super(Notification.Type.GROUP); - } - public void setGroup(Group group) { this.group = group; } - @Override - public Enum getEvent() { - return event; - } - @Override protected String getEntityTitle() { return group.getTitle(); diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java index 8ef2b2d070..54df3b315e 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.match.Idea; import se.su.dsv.scipro.system.DomainObject; @@ -11,18 +14,29 @@ import jakarta.persistence.ManyToOne; @Entity public class IdeaEvent extends NotificationEvent { - public enum Event { STATUS_CHANGE, PARTNER_ACCEPT, ADDED_AS_PARTNER, FIRST_MEETING, REMOVED_AS_PARTNER, EXPORTED_FAIL } - @ManyToOne - private Idea idea; - + @Basic + @Column(name = "event") @Enumerated(EnumType.STRING) private Event event; + @ManyToOne + @JoinColumn(name = "idea_id", referencedColumnName = "id") + private Idea idea; + + @Override + public Event getEvent() { + return event; + } + + public void setEvent(Event event) { + this.event = event; + } + public IdeaEvent() { super(Notification.Type.IDEA); } @@ -35,15 +49,6 @@ public class IdeaEvent extends NotificationEvent { this.idea = idea; } - @Override - public Event getEvent() { - return event; - } - - public void setEvent(Event event) { - this.event = event; - } - @Override public String getEntityTitle() { return idea.getTitle(); diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java index 9e4c1bf5a9..f84a47be57 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.milestones.dataobjects.Milestone; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; @@ -17,24 +20,64 @@ public class MileStoneEvent extends NotificationEvent { MILESTONE_CONFIRMED, MILESTONE_REVOKED } - @ManyToOne - private Milestone milestone; - + @Basic + @Column(name = "event") @Enumerated(EnumType.STRING) private Event event; + @ManyToOne + @JoinColumn(name = "milestone_id", referencedColumnName = "id") + private Milestone milestone; + public MileStoneEvent() { super(Notification.Type.MILESTONE); } @Override - public Project getProject() { - return milestone.getProject(); + public Enum getEvent() { + return event; + } + + public void setEvent(Event event) { + this.event = event; + } + + public Milestone getMilestone() { + return this.milestone; + } + + public void setMilestone(Milestone milestone) { + this.milestone = milestone; } @Override - public Enum getEvent() { - return event; + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof MileStoneEvent)) return false; + final MileStoneEvent other = (MileStoneEvent) o; + return other.canEqual(this) + && super.equals(o) + && Objects.equals(this.getMilestone(), other.getMilestone()) + && Objects.equals(this.getEvent(), other.getEvent()); + } + + @Override + public int hashCode() { + return Objects.hash(this.getMilestone(), this.getEvent()); + } + + @Override + public String toString() { + return "MileStoneEvent(milestone=" + this.getMilestone() + ", event=" + this.getEvent() + ")"; + } + + protected boolean canEqual(final Object other) { + return other instanceof MileStoneEvent; + } + + @Override + public Project getProject() { + return milestone.getProject(); } @Override @@ -51,41 +94,4 @@ public class MileStoneEvent extends NotificationEvent { public DomainObject getEntity() { return milestone; } - - public Milestone getMilestone() { - return this.milestone; - } - - public void setMilestone(Milestone milestone) { - this.milestone = milestone; - } - - public void setEvent(Event event) { - this.event = event; - } - - @Override - public String toString() { - return "MileStoneEvent(milestone=" + this.getMilestone() + ", event=" + this.getEvent() + ")"; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof MileStoneEvent)) return false; - final MileStoneEvent other = (MileStoneEvent) o; - return other.canEqual(this) - && super.equals(o) - && Objects.equals(this.getMilestone(), other.getMilestone()) - && Objects.equals(this.getEvent(), other.getEvent()); - } - - protected boolean canEqual(final Object other) { - return other instanceof MileStoneEvent; - } - - @Override - public int hashCode() { - return Objects.hash(this.getMilestone(), this.getEvent()); - } } diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java index 073be08b40..5102db88cd 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java @@ -1,41 +1,59 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; - @Entity +@Table(name = "notification") public class Notification extends DomainObject { - - public enum Type { - PROJECT, IDEA, FINAL_SEMINAR, PEER, MILESTONE, - GROUP, FORUM, CUSTOM - } - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Basic(optional = false) - private boolean unread = true; - - @Basic(optional = false) + @Column(name = "mailed") private boolean mailed = false; + @Basic(optional = false) + @Column(name = "unread") + private boolean unread = true; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (notification) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne(cascade = CascadeType.ALL) - @JoinColumn(name = "notificationData_id") + @JoinColumn(name = "notification_data_id", referencedColumnName = "id") private NotificationEvent notificationEvent; @ManyToOne + @JoinColumn(name = "user_id", referencedColumnName = "id") private User user; + // ---------------------------------------------------------------------------------- + // Constructor + // ---------------------------------------------------------------------------------- public Notification() { - } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return id; @@ -45,6 +63,14 @@ public class Notification extends DomainObject { this.id = id; } + public boolean isMailed() { + return mailed; + } + + public void setMailed(boolean mailed) { + this.mailed = mailed; + } + public boolean isUnread() { return unread; } @@ -69,14 +95,9 @@ public class Notification extends DomainObject { this.user = user; } - public boolean isMailed() { - return mailed; - } - - public void setMailed(boolean mailed) { - this.mailed = mailed; - } - + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- public String getTitle() { return getNotificationEvent().getTitle(); } @@ -108,4 +129,12 @@ public class Notification extends DomainObject { public User getCausedBy() { return getNotificationEvent().getCausedBy(); } + + // ---------------------------------------------------------------------------------- + // Nested type + // ---------------------------------------------------------------------------------- + public enum Type { + PROJECT, IDEA, FINAL_SEMINAR, PEER, MILESTONE, + GROUP, FORUM, CUSTOM + } } diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java index 1aac89eca6..6eb2f15ef4 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java @@ -1,55 +1,70 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.Collection; @Entity +@Table(name = "notification_data") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) -@Table(name = "NotificationData") +@DiscriminatorColumn(name = "subclass") public abstract class NotificationEvent extends DomainObject { - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) protected long id; + @Basic + @Column(name = "type") @Enumerated(EnumType.STRING) protected Notification.Type type; - @OneToMany(mappedBy = "notificationEvent", cascade = CascadeType.ALL, orphanRemoval = true) - private Collection<Notification> notifications; - @Basic(optional = true) + @Column(name = "source") private String source; @Basic(optional = true) + @Column(name = "additional_source") private String additionalSource; - + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (notification_data) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = true) + @JoinColumn(name = "caused_by_user_id", referencedColumnName = "id") private User causedBy; - public abstract Enum getEvent(); - - /** - * The title of the entity this event is about. - * - * @return a human readable title - */ - protected abstract String getEntityTitle(); - - /** - * Return true if there is an entity backing this event. - * Used to determine if this event was about a deletion, or has since been deleted. - */ - public abstract boolean hasEntity(); - - public abstract DomainObject getEntity(); + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "notification_data" + // ---------------------------------------------------------------------------------- + @OneToMany(mappedBy = "notificationEvent", cascade = CascadeType.ALL, orphanRemoval = true) + private Collection<Notification> notifications; + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected NotificationEvent() { } @@ -58,6 +73,9 @@ public abstract class NotificationEvent extends DomainObject { this.type = type; } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return id; @@ -75,14 +93,6 @@ public abstract class NotificationEvent extends DomainObject { this.type = type; } - public Collection<Notification> getNotifications() { - return notifications; - } - - public void setNotifications(Collection<Notification> notifications) { - this.notifications = notifications; - } - public String getSource() { return source; } @@ -91,8 +101,12 @@ public abstract class NotificationEvent extends DomainObject { this.source = source; } - public String getTitle() { - return hasEntity() ? getEntityTitle() : "[Deleted entity]"; + public String getAdditionalSource() { + return additionalSource; + } + + public void setAdditionalSource(String additionalSource) { + this.additionalSource = additionalSource; } public User getCausedBy() { @@ -103,6 +117,41 @@ public abstract class NotificationEvent extends DomainObject { this.causedBy = user; } + public Collection<Notification> getNotifications() { + return notifications; + } + + public void setNotifications(Collection<Notification> notifications) { + this.notifications = notifications; + } + + // ---------------------------------------------------------------------------------- + // Abstract methods to be implemented by subclasses + // ---------------------------------------------------------------------------------- + /** + * The title of the entity this event is about. + * + * @return a human readable title + */ + protected abstract String getEntityTitle(); + + /** + * Return true if there is an entity backing this event. + * Used to determine if this event was about a deletion, or has since been deleted. + */ + public abstract boolean hasEntity(); + + public abstract DomainObject getEntity(); + + public abstract Enum getEvent(); + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + public String getTitle() { + return hasEntity() ? getEntityTitle() : "[Deleted entity]"; + } + /** * Override this method if the event has an association with a {@link Project}. * @@ -111,12 +160,4 @@ public abstract class NotificationEvent extends DomainObject { public Project getProject() { return null; } - - public String getAdditionalSource() { - return additionalSource; - } - - public void setAdditionalSource(String additionalSource) { - this.additionalSource = additionalSource; - } } diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java index 17272c9768..8ca7f15e9e 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.peer.PeerReview; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; @@ -12,22 +15,31 @@ import jakarta.persistence.ManyToOne; @Entity public class PeerEvent extends NotificationEvent { - public enum Event { REVIEW_COMPLETED, REVIEW_COMMENT, REVIEW_ACCEPTED, REQUEST_DELETED, - REQUEST_EXPIRED } - - @ManyToOne - private PeerReview review; + public enum Event { + REVIEW_COMPLETED, REVIEW_COMMENT, REVIEW_ACCEPTED, REQUEST_DELETED, + REQUEST_EXPIRED + } + @Basic + @Column(name = "event") @Enumerated(EnumType.STRING) private Event event; + @ManyToOne + @JoinColumn(name = "peer_review_id", referencedColumnName = "id") + private PeerReview review; + public PeerEvent() { super(Notification.Type.PEER); } @Override - public Project getProject() { - return review.getProject(); + public Event getEvent() { + return event; + } + + public void setEvent(Event event) { + this.event = event; } public PeerReview getReview() { @@ -39,12 +51,8 @@ public class PeerEvent extends NotificationEvent { } @Override - public Event getEvent() { - return event; - } - - public void setEvent(Event event) { - this.event = event; + public Project getProject() { + return review.getProject(); } @Override diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java index 37355d4d44..72f6dac062 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.peer.PeerRequest; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; @@ -12,10 +15,13 @@ import jakarta.persistence.ManyToOne; @Entity public class PeerRequestEvent extends NotificationEvent { + @Basic + @Column(name = "event") @Enumerated(EnumType.STRING) private PeerEvent.Event event; @ManyToOne + @JoinColumn(name = "peer_request_id", referencedColumnName = "id") private PeerRequest request; public PeerRequestEvent() { diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java index c8c3e51032..ae72d48f16 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; @@ -19,29 +22,24 @@ public class ProjectEvent extends NotificationEvent { FINAL_SEMINAR_APPROVAL_APPROVED, FINAL_SEMINAR_APPROVAL_REJECTED, ROUGH_DRAFT_APPROVAL_REQUESTED, ROUGH_DRAFT_APPROVAL_APPROVED, ROUGH_DRAFT_APPROVAL_REJECTED, REVIEWER_GRADING_REPORT_SUBMITTED, ONE_YEAR_PASSED_FROM_LATEST_ANNUAL_REVIEW, SUPERVISOR_GRADING_INITIAL_ASSESSMENT_DONE, - EXPORTED_SUCCESS, REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, FIRST_MEETING, OPPOSITION_FAILED, PARTICIPATION_APPROVED, COMPLETED, - PARTICIPATION_FAILED + EXPORTED_SUCCESS, REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, FIRST_MEETING, OPPOSITION_FAILED, + PARTICIPATION_APPROVED, COMPLETED, PARTICIPATION_FAILED, REFLECTION_IMPROVEMENTS_REQUESTED, + REFLECTION_IMPROVEMENTS_SUBMITTED } - @ManyToOne - private Project project; - + @Basic + @Column(name = "event") @Enumerated(EnumType.STRING) private Event event; + @ManyToOne + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; + public ProjectEvent() { super(Notification.Type.PROJECT); } - @Override - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - @Override public Event getEvent() { return event; @@ -51,6 +49,15 @@ public class ProjectEvent extends NotificationEvent { this.event = event; } + @Override + public Project getProject() { + return project; + } + + public void setProject(Project project) { + this.project = project; + } + @Override public String getEntityTitle() { return project.getTitle(); diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java index a5b2989c19..c95ec8bf05 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; @@ -10,29 +13,24 @@ import jakarta.persistence.ManyToOne; @Entity public class ProjectForumEvent extends NotificationEvent { - @ManyToOne - private Project project; - - @Enumerated(EnumType.STRING) - private Event event; - - public void setProject(Project project) { - this.project = project; - } public enum Event { NEW_FORUM_POST, NEW_FORUM_POST_COMMENT, NEW_REVIEWER_INTERACTION } + @Basic + @Column(name = "event") + @Enumerated(EnumType.STRING) + private Event event; + + @ManyToOne + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; + public ProjectForumEvent() { super(Notification.Type.FORUM); } - @Override - public Project getProject() { - return this.project; - } - @Override public Event getEvent() { return event; @@ -42,6 +40,15 @@ public class ProjectForumEvent extends NotificationEvent { this.event = event; } + @Override + public Project getProject() { + return this.project; + } + + public void setProject(Project project) { + this.project = project; + } + @Override protected String getEntityTitle() { return project.getTitle(); @@ -56,5 +63,4 @@ public class ProjectForumEvent extends NotificationEvent { public DomainObject getEntity() { return project; } - } diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java index 46951edcc3..dedad4ca0a 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java @@ -1,5 +1,8 @@ package se.su.dsv.scipro.notifications.dataobject; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.JoinColumn; import se.su.dsv.scipro.finalseminar.FinalSeminar; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; @@ -12,27 +15,24 @@ import jakarta.persistence.ManyToOne; @Entity public class SeminarEvent extends NotificationEvent { - public enum Event { CREATED, ROOM_CHANGED, DATE_CHANGED, OPPOSITION_CHANGED, PARTICIPATION_CHANGED, THESIS_UPLOADED, THESIS_UPLOADED_OPPONENT, - OPPOSITION_REPORT_UPLOADED, THESIS_DELETED, THESIS_UPLOAD_REMIND, CANCELLED} - - @ManyToOne - private FinalSeminar seminar; + public enum Event { CREATED, ROOM_CHANGED, DATE_CHANGED, OPPOSITION_CHANGED, + PARTICIPATION_CHANGED, THESIS_UPLOADED, THESIS_UPLOADED_OPPONENT, + OPPOSITION_REPORT_UPLOADED, THESIS_DELETED, THESIS_UPLOAD_REMIND, CANCELLED + } + @Basic + @Column(name = "event") @Enumerated(EnumType.STRING) private Event event; + @ManyToOne + @JoinColumn(name = "final_seminar_id", referencedColumnName = "id") + private FinalSeminar seminar; + public SeminarEvent() { super(Notification.Type.FINAL_SEMINAR); } - public FinalSeminar getSeminar() { - return seminar; - } - - public void setSeminar(FinalSeminar seminar) { - this.seminar = seminar; - } - @Override public Event getEvent() { return event; @@ -42,6 +42,14 @@ public class SeminarEvent extends NotificationEvent { this.event = event; } + public FinalSeminar getSeminar() { + return seminar; + } + + public void setSeminar(FinalSeminar seminar) { + this.seminar = seminar; + } + @Override public String getEntityTitle() { return seminar.getProject().getTitle(); diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java index cdf67a52d4..b8aeadcb99 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java @@ -8,7 +8,6 @@ import se.su.dsv.scipro.finalseminar.FinalSeminar; import se.su.dsv.scipro.finalseminar.FinalSeminarService; import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettings; import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; -import se.su.dsv.scipro.notifications.NotificationModule; import se.su.dsv.scipro.notifications.dataobject.*; import se.su.dsv.scipro.notifications.interfaces.NotificationMailFormatter; import se.su.dsv.scipro.project.Project; @@ -158,7 +157,7 @@ public class NotificationMailFormatterImpl implements NotificationMailFormatter private String getAbsoluteURL(final Notification notification) { final String baseUrl = systemSettingsService.getGeneralSystemSettingsInstance().getSciproURL(); long id = notification.getNotificationEvent().getId(); - return baseUrl + "/" + NotificationModule.NOTIFICATION_RELATIVE_PAGE_URL + "?id=" + id; + return baseUrl + "/" + "notification" + "?id=" + id; } String makeProperty(Object... parts) { diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties b/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties index a972eac30e..c5cb11b76a 100755 --- a/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties +++ b/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties @@ -85,6 +85,13 @@ PROJECT.PARTICIPATION_APPROVED.body = Your active participation on {0} has been PROJECT.PARTICIPATION_FAILED.title = Your active participation on {1} did not meet the minimum requirements. PROJECT.PARTICIPATION_FAILED.body = Your active participation did not meet the minimum requirements set, and you will \ have to be an active participant on a different final seminar to pass this step. +PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.title = Reflection improvements requested +PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.body = The supervisor has deemed that the reflection submitted does not meet \ + the minimum requirements and has requested improvements. Please log into SciPro and submit a new reflection. \ + Their comments can be seen below:\n\n{0} +PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.title = Reflection improvements submitted +PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.body = The reflection improvements have been submitted. \ + \n\n{0} FORUM.NEW_FORUM_POST.title = Forum post: {2} FORUM.NEW_FORUM_POST.body = New forum post submitted:<br /><br />{0} diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java b/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java index 65af5aaa5c..7e20fa7ffb 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java @@ -1,14 +1,21 @@ package se.su.dsv.scipro.notifications.settings.entities; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; + import se.su.dsv.scipro.notifications.dataobject.Notification; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; - @Entity @Table(name = "notification_delivery_configuration", uniqueConstraints = { - @UniqueConstraint(name = "one_setting_per_user", columnNames = {"type", "event", "method", "user_id"}) + @UniqueConstraint(name = "uk_one_setting_per_user", columnNames = {"type", "event", "method", "user_id"}) }) public class DeliveryConfiguration extends Configuration { diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java index 285b9f6c0a..75f7624ac6 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.notifications.settings.service; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.notifications.dataobject.Notification; import se.su.dsv.scipro.notifications.dataobject.Notification.Type; import se.su.dsv.scipro.notifications.settings.entities.DeliveryConfiguration; diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java index 37befe6c34..596c2e3821 100644 --- a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.notifications.settings.service; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.data.dataobjects.Member; import se.su.dsv.scipro.notifications.dataobject.Notification; import se.su.dsv.scipro.notifications.settings.entities.QReceiverConfiguration; diff --git a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthModule.java b/core/src/main/java/se/su/dsv/scipro/oauth/OAuthModule.java deleted file mode 100644 index bce825afe1..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthModule.java +++ /dev/null @@ -1,25 +0,0 @@ -package se.su.dsv.scipro.oauth; - -import com.google.inject.PrivateModule; -import com.google.inject.Provides; - -import jakarta.inject.Named; - -public class OAuthModule extends PrivateModule { - @Override - protected void configure() { - bind(OAuthService.class).to(OAuthServiceImpl.class); - - expose(OAuthService.class); - } - - @Provides - OAuthSettings settings( - @Named("oauth.uri") String uri, - @Named("oauth.redirectUri") String redirectUri, - @Named("oauth.clientId") String clientId, - @Named("oauth.clientSecret") String clientSecret) - { - return new OAuthSettings(uri, redirectUri, clientId, clientSecret); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java b/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java index a8b41b8648..2a20bcf204 100644 --- a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java +++ b/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java @@ -1,4 +1,4 @@ package se.su.dsv.scipro.oauth; -record OAuthSettings(String uri, String redirectUri, String clientId, String clientSecret) { +public record OAuthSettings(String uri, String redirectUri, String clientId, String clientSecret) { } diff --git a/core/src/main/java/se/su/dsv/scipro/peer/Answer.java b/core/src/main/java/se/su/dsv/scipro/peer/Answer.java index fd7b4b0ca4..bf40f7d72e 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/Answer.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/Answer.java @@ -1,80 +1,115 @@ package se.su.dsv.scipro.peer; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.checklist.ChecklistAnswerEnum; import se.su.dsv.scipro.system.DomainObject; -import jakarta.persistence.*; import java.util.Objects; @Entity @Table(name="answer") @Cacheable(true) public class Answer extends DomainObject { + // ---------------------------------------------------------------------------------- + // basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - + + @Basic(optional = false) + @Column(name = "question") + private String question; + + @Enumerated(EnumType.STRING) + @Column(name = "answer", nullable=false) + private ChecklistAnswerEnum answer = ChecklistAnswerEnum.NO_ANSWER; + + @Basic(optional=true) + @Lob + @Column(name = "motivation") + private String motivation; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (answer) referencing other tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional=false) + @JoinColumn(name = "peer_review_id", referencedColumnName = "id") private PeerReview peerReview; - @Basic(optional = false) - private String question; - - @Lob - @Basic(optional=true) - private String motivation; - - @Enumerated(EnumType.STRING) - @Column(nullable=false) - private ChecklistAnswerEnum answer = ChecklistAnswerEnum.NO_ANSWER; - + // ---------------------------------------------------------------------------------- + // constructors + // ---------------------------------------------------------------------------------- public Answer() {} + public Answer(PeerReview peerReview, String question){ this.peerReview = peerReview; this.question = question; } + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public PeerReview getPeerReview() { - return this.peerReview; - } - - public String getQuestion() { - return this.question; - } - - public String getMotivation() { - return this.motivation; - } - - public ChecklistAnswerEnum getAnswer() { - return this.answer; - } - public void setId(Long id) { this.id = id; } - public void setPeerReview(PeerReview peerReview) { - this.peerReview = peerReview; + public String getQuestion() { + return this.question; } public void setQuestion(String question) { this.question = question; } - public void setMotivation(String motivation) { - this.motivation = motivation; + public ChecklistAnswerEnum getAnswer() { + return this.answer; } public void setAnswer(ChecklistAnswerEnum answer) { this.answer = answer; } + public String getMotivation() { + return this.motivation; + } + + public void setMotivation(String motivation) { + this.motivation = motivation; + } + + public PeerReview getPeerReview() { + return this.peerReview; + } + + public void setPeerReview(PeerReview peerReview) { + this.peerReview = peerReview; + } + + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof Answer; + } + @Override public boolean equals(final Object o) { if (o == this) return true; @@ -84,10 +119,6 @@ public class Answer extends DomainObject { && Objects.equals(this.getId(), other.getId()); } - protected boolean canEqual(final Object other) { - return other instanceof Answer; - } - @Override public int hashCode() { return Objects.hashCode(this.getId()); @@ -95,6 +126,7 @@ public class Answer extends DomainObject { @Override public String toString() { - return "Answer(id=" + this.getId() + ", question=" + this.getQuestion() + ", motivation=" + this.getMotivation() + ", answer=" + this.getAnswer() + ")"; + return "Answer(id=" + this.getId() + ", question=" + this.getQuestion() + ", motivation=" + + this.getMotivation() + ", answer=" + this.getAnswer() + ")"; } } diff --git a/core/src/main/java/se/su/dsv/scipro/peer/Comment.java b/core/src/main/java/se/su/dsv/scipro/peer/Comment.java index 32d3fe771d..bb5c68db96 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/Comment.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/Comment.java @@ -1,9 +1,19 @@ package se.su.dsv.scipro.peer; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Comparator; @@ -16,12 +26,16 @@ public class Comment extends DomainObject { private Long id; @ManyToOne(optional = false) + @JoinColumn(name = "creator_user_id", referencedColumnName = "id") private User creator; + @Basic + @Column(name = "comment") @Lob private String comment; @ManyToOne(optional = false) + @JoinColumn(name = "comment_thread_id", referencedColumnName = "id") private CommentThread commentThread; protected Comment() { diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java index db26096621..63723ecf16 100644 --- a/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java @@ -10,7 +10,7 @@ import java.util.List; public class CommentServiceImpl extends AbstractServiceImpl<Comment, Long> implements CommentService { @Inject - protected CommentServiceImpl(Provider<EntityManager> em) { + public CommentServiceImpl(Provider<EntityManager> em) { super(em, Comment.class, QComment.comment1); } diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java index d90511945c..803fb375af 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java @@ -8,7 +8,9 @@ import java.util.Set; import java.util.TreeSet; @Entity -@Table(name = "comment_thread", uniqueConstraints = {@UniqueConstraint(columnNames = {"commentableKey", "commentableId"})}) +@Table(name = "comment_thread", + uniqueConstraints = {@UniqueConstraint(name = "uk_comment_thread_id_key", + columnNames = {"commentable_key", "commentable_id"})}) @Cacheable(true) public class CommentThread extends DomainObject { @@ -16,11 +18,10 @@ public class CommentThread extends DomainObject { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Basic(optional = false) - @Column(length = 191) + @Column(name = "commentable_key", length = 191, nullable = false) private String commentableKey; - @Basic(optional = false) + @Column(name = "commentable_id", nullable = false) private Long commentableId; @OneToMany(mappedBy = "commentThread", orphanRemoval = true, cascade = CascadeType.ALL, targetEntity = Comment.class) diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java index 025bb02da1..8210abd3c5 100644 --- a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.peer; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java index 82d1e68e53..604e36b9a5 100644 --- a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.peer; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.inject.Inject; diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerModule.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerModule.java deleted file mode 100644 index 0fdd05980c..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/peer/PeerModule.java +++ /dev/null @@ -1,13 +0,0 @@ -package se.su.dsv.scipro.peer; - -import com.google.inject.AbstractModule; -import com.google.inject.multibindings.Multibinder; -import se.su.dsv.scipro.system.Lifecycle; - -public class PeerModule extends AbstractModule { - @Override - protected void configure() { - Multibinder.newSetBinder(binder(), Lifecycle.class) - .addBinding().to(PeerWorkerSchedules.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java index 5582001f6a..aa6b178072 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.peer; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.su.dsv.scipro.file.FileReference; @@ -152,7 +152,7 @@ public class PeerPortalImpl implements PeerPortal, PerformReviewService { } @Override - @Transactional(ignore = {TooShortCommentException.class, MissingAnswerException.class}) + @Transactional(dontRollbackOn = {TooShortCommentException.class, MissingAnswerException.class}) public void submit(PeerReview review, Optional<FileUpload> upload) { review.submit(); final Optional<FileReference> fileDescription = storePeerReviewFileUpload(upload); diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java index 8bf04b8d37..addf9fff54 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java @@ -1,7 +1,20 @@ package se.su.dsv.scipro.peer; import com.querydsl.core.annotations.QueryInit; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import se.su.dsv.scipro.checklist.ChecklistTemplate; import se.su.dsv.scipro.data.dataobjects.Member; import se.su.dsv.scipro.file.FileReference; @@ -10,57 +23,138 @@ import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.Language; import se.su.dsv.scipro.system.User; -import jakarta.persistence.Basic; -import jakarta.persistence.Cacheable; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.Lob; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; @Entity @Table(name = "peer_request") @Cacheable(true) public class PeerRequest extends DomainObject { + // ---------------------------------------------------------------------------------- + // basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Lob @Basic(optional = true) + @Lob + @Column(name = "comment") private String comment; - @ManyToOne(optional = false) - @QueryInit({"headSupervisor", "projectType"}) - private Project project; - - @ManyToOne(optional = false) - private User requester; - - @ManyToOne(optional = false) - @JoinColumn(name = "file_reference_id") - private FileReference file; - - @ManyToOne(optional = true) - private ChecklistTemplate checklistTemplate; + @Enumerated(EnumType.STRING) + @Column(name = "status", nullable = false) + private RequestStatus status = RequestStatus.WAITING; @Enumerated(EnumType.STRING) private Language language; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (peer_request) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = true) + @JoinColumn(name = "checklist_template_id", referencedColumnName = "id") + private ChecklistTemplate checklistTemplate; + + @ManyToOne(optional = false) + @JoinColumn(name = "file_reference_id", referencedColumnName = "id") + private FileReference file; + + @ManyToOne(optional = false) + @JoinColumn(name = "project_id", referencedColumnName = "id") + @QueryInit({"headSupervisor", "projectType"}) + private Project project; + + @ManyToOne(optional = false) + @JoinColumn(name = "requester_user_id", referencedColumnName = "id") + private User requester; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "peer_request" + // ---------------------------------------------------------------------------------- @OneToMany(mappedBy = "peerRequest") private List<PeerReview> peerReviews = new ArrayList<>(1); - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private RequestStatus status = RequestStatus.WAITING; + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; + } + public void setId(Long id) { + this.id = id; + } + + public String getComment() { + return this.comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public RequestStatus getStatus() { + return this.status; + } + + public void setStatus(RequestStatus status) { + this.status = status; + } + + public Language getLanguage() { + return this.language; + } + + public void setLanguage(Language language) { + this.language = language; + } + + public ChecklistTemplate getChecklistTemplate() { + return this.checklistTemplate; + } + + public void setChecklistTemplate(ChecklistTemplate checklistTemplate) { + this.checklistTemplate = checklistTemplate; + } + + public FileReference getFile() { + return this.file; + } + + public void setFile(FileReference file) { + this.file = file; + } + + public Project getProject() { + return this.project; + } + + public void setProject(Project project) { + this.project = project; + } + + public User getRequester() { + return this.requester; + } + + public void setRequester(User requester) { + this.requester = requester; + } + + public List<PeerReview> getPeerReviews() { + return this.peerReviews; + } + + public void setPeerReviews(List<PeerReview> peerReviews) { + this.peerReviews = peerReviews; + } + + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- public List<Member> getMembers() { List<Member> members = project.getMembers(); @@ -80,77 +174,8 @@ public class PeerRequest extends DomainObject { return null; } - @Override - public Long getId() { - return this.id; - } - - public String getComment() { - return this.comment; - } - - public Project getProject() { - return this.project; - } - - public User getRequester() { - return this.requester; - } - - public FileReference getFile() { - return this.file; - } - - public ChecklistTemplate getChecklistTemplate() { - return this.checklistTemplate; - } - - public Language getLanguage() { - return this.language; - } - - public List<PeerReview> getPeerReviews() { - return this.peerReviews; - } - - public RequestStatus getStatus() { - return this.status; - } - - public void setId(Long id) { - this.id = id; - } - - public void setComment(String comment) { - this.comment = comment; - } - - public void setProject(Project project) { - this.project = project; - } - - public void setRequester(User requester) { - this.requester = requester; - } - - public void setFile(FileReference file) { - this.file = file; - } - - public void setChecklistTemplate(ChecklistTemplate checklistTemplate) { - this.checklistTemplate = checklistTemplate; - } - - public void setLanguage(Language language) { - this.language = language; - } - - public void setPeerReviews(List<PeerReview> peerReviews) { - this.peerReviews = peerReviews; - } - - public void setStatus(RequestStatus status) { - this.status = status; + protected boolean canEqual(final Object other) { + return other instanceof PeerRequest; } @Override @@ -162,10 +187,6 @@ public class PeerRequest extends DomainObject { && Objects.equals(this.getId(), other.getId()); } - protected boolean canEqual(final Object other) { - return other instanceof PeerRequest; - } - @Override public int hashCode() { return Objects.hashCode(this.getId()); @@ -173,6 +194,9 @@ public class PeerRequest extends DomainObject { @Override public String toString() { - return "PeerRequest(id=" + this.getId() + ", comment=" + this.getComment() + ", project=" + this.getProject() + ", requester=" + this.getRequester() + ", file=" + this.getFile() + ", checklistTemplate=" + this.getChecklistTemplate() + ", language=" + this.getLanguage() + ", status=" + this.getStatus() + ")"; + return "PeerRequest(id=" + this.getId() + ", comment=" + this.getComment() + ", project=" + + this.getProject() + ", requester=" + this.getRequester() + ", file=" + this.getFile() + + ", checklistTemplate=" + this.getChecklistTemplate() + ", language=" + this.getLanguage() + + ", status=" + this.getStatus() + ")"; } } diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java index d6ca147c68..1a5c7439ff 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.peer; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java index b79394efd6..ad77dcfe22 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.peer; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.dsl.BooleanExpression; import se.su.dsv.scipro.system.Pageable; diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java index e721778e38..7ce7378d1d 100755 --- a/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java +++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java @@ -1,6 +1,24 @@ package se.su.dsv.scipro.peer; import com.querydsl.core.annotations.QueryInit; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.OrderBy; +import jakarta.persistence.Table; + import se.su.dsv.scipro.checklist.ChecklistAnswerEnum; import se.su.dsv.scipro.data.dataobjects.Member; import se.su.dsv.scipro.file.FileReference; @@ -8,7 +26,6 @@ import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -23,41 +40,140 @@ public class PeerReview extends DomainObject implements Commentable { public enum ReviewStatus { IN_PROGRESS, COMPLETED, EXPIRED } - + + // ---------------------------------------------------------------------------------- + // basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - + + @Basic + @Lob + @Column(name = "comment") + private String comment; + + @Enumerated(EnumType.STRING) + @Column(name = "status") + private ReviewStatus status = ReviewStatus.IN_PROGRESS; + + @Basic(optional = false) + @Column(name = "deadline") + private Date deadline; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (peer_review) referencing other tables. + // ---------------------------------------------------------------------------------- + @OneToOne(optional=true, orphanRemoval = true, cascade = CascadeType.ALL) + @JoinColumn(name = "file_reference_id", referencedColumnName = "id") + private FileReference file; + + @ManyToOne(optional=false) + @JoinColumn(name = "peer_request_id", referencedColumnName = "id") + @QueryInit({"project.headSupervisor", "requester.user", "language", "checklistTemplate"}) + private PeerRequest peerRequest; + + @ManyToOne(optional=false) + @JoinColumn(name = "project_id", referencedColumnName = "id") + @QueryInit({"headSupervisor", "projectType"}) + private Project project; + @ManyToOne(optional=false) + @JoinColumn(name = "reviewer_user_id", referencedColumnName = "id") @QueryInit("*.*") private User reviewer; - - @ManyToOne(optional=false) - @QueryInit({"headSupervisor", "projectType"}) - private Project project; - - @ManyToOne(optional=false) - @QueryInit({"project.headSupervisor","requester.user", "language", "checklistTemplate"}) - private PeerRequest peerRequest; - + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "peer_review" + // ---------------------------------------------------------------------------------- @OneToMany(mappedBy="peerReview", orphanRemoval=true, cascade=CascadeType.ALL) @OrderBy("id") private List<Answer> answers = new ArrayList<>(); - @OneToOne(optional=true, orphanRemoval = true, cascade = CascadeType.ALL) - @JoinColumn(name = "file_reference_id") - private FileReference file; - - @Lob - private String comment; + // ---------------------------------------------------------------------------------- + // getters and setters + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; + } - @Enumerated(EnumType.STRING) - private ReviewStatus status = ReviewStatus.IN_PROGRESS; + public void setId(Long id) { + this.id = id; + } - @Basic(optional = false) - private Date deadline; + public String getComment() { + return this.comment; + } - @Override + public void setComment(String comment) { + this.comment = comment; + } + + public ReviewStatus getStatus() { + return status; + } + + public void setStatus(ReviewStatus status) { + this.status = status; + } + + public Date getDeadline() { + return this.deadline; + } + + public void setDeadline(Date deadline) { + this.deadline = deadline; + } + + public FileReference getFile() { + return this.file; + } + + public void setFile(FileReference file) { + this.file = file; + } + + public PeerRequest getPeerRequest() { + return this.peerRequest; + } + + public void setPeerRequest(PeerRequest peerRequest) { + this.peerRequest = peerRequest; + } + + public Project getProject() { + return this.project; + } + + public void setProject(Project project) { + this.project = project; + } + + public User getReviewer() { + return this.reviewer; + } + + public void setReviewer(User reviewer) { + this.reviewer = reviewer; + } + + public List<Answer> getAnswers() { + return this.answers; + } + + public void setAnswers(List<Answer> answers) { + this.answers = answers; + } + + public void addAnswer(String question) { + this.answers.add(new Answer(this, question)); + } + + // ---------------------------------------------------------------------------------- + // other methods + // ---------------------------------------------------------------------------------- + @Override public final String getCommentKey() { return PeerReview.class.getCanonicalName(); } @@ -73,10 +189,6 @@ public class PeerReview extends DomainObject implements Commentable { return new Date().after(getDeadline()); } - public ReviewStatus getStatus() { - return status; - } - public boolean isExpired() { return status == ReviewStatus.EXPIRED; } @@ -97,90 +209,12 @@ public class PeerReview extends DomainObject implements Commentable { setStatus(isLate() ? ReviewStatus.EXPIRED : ReviewStatus.COMPLETED); } - private static boolean isEmpty(String s) { - return s == null || s.isBlank(); - } - public void expire() { status = ReviewStatus.EXPIRED; } - public void addAnswer(String question) { - this.answers.add(new Answer(this, question)); - } - - @Override - public Long getId() { - return this.id; - } - - public User getReviewer() { - return this.reviewer; - } - - public Project getProject() { - return this.project; - } - - public PeerRequest getPeerRequest() { - return this.peerRequest; - } - - public List<Answer> getAnswers() { - return this.answers; - } - - public FileReference getFile() { - return this.file; - } - - public String getComment() { - return this.comment; - } - - public Date getDeadline() { - return this.deadline; - } - - public void setId(Long id) { - this.id = id; - } - - public void setReviewer(User reviewer) { - this.reviewer = reviewer; - } - - public void setProject(Project project) { - this.project = project; - } - - public void setPeerRequest(PeerRequest peerRequest) { - this.peerRequest = peerRequest; - } - - public void setAnswers(List<Answer> answers) { - this.answers = answers; - } - - public void setFile(FileReference file) { - this.file = file; - } - - public void setComment(String comment) { - this.comment = comment; - } - - public void setStatus(ReviewStatus status) { - this.status = status; - } - - public void setDeadline(Date deadline) { - this.deadline = deadline; - } - - @Override - public String toString() { - return "PeerReview(id=" + this.getId() + ", reviewer=" + this.getReviewer() + ", project=" + this.getProject() + ", peerRequest=" + this.getPeerRequest() + ", answers=" + this.getAnswers() + ", file=" + this.getFile() + ", comment=" + this.getComment() + ", status=" + this.getStatus() + ", deadline=" + this.getDeadline() + ")"; + protected boolean canEqual(final Object other) { + return other instanceof PeerReview; } @Override @@ -192,12 +226,23 @@ public class PeerReview extends DomainObject implements Commentable { && Objects.equals(this.getId(), other.getId()); } - protected boolean canEqual(final Object other) { - return other instanceof PeerReview; + @Override + public int hashCode() { + return Objects.hashCode(this.getId()); } @Override - public int hashCode() { - return Objects.hashCode(this.getId()); + public String toString() { + return "PeerReview(id=" + this.getId() + ", reviewer=" + this.getReviewer() + ", project=" + + this.getProject() + ", peerRequest=" + this.getPeerRequest() + ", answers=" + this.getAnswers() + + ", file=" + this.getFile() + ", comment=" + this.getComment() + ", status=" + this.getStatus() + + ", deadline=" + this.getDeadline() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Static helper methods + // ---------------------------------------------------------------------------------- + private static boolean isEmpty(String s) { + return s == null || s.isBlank(); } } diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java index b21bd32fe9..d72913163d 100755 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.plagiarism; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileDescription; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismModule.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismModule.java deleted file mode 100644 index 3f862ea21c..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismModule.java +++ /dev/null @@ -1,11 +0,0 @@ -package se.su.dsv.scipro.plagiarism; - -import com.google.inject.AbstractModule; - -public class PlagiarismModule extends AbstractModule { - @Override - protected void configure() { - bind(PlagiarismControl.class).to(PlagiarismControlImpl.class); - bind(PlagiarismRequestRepository.class).to(PlagiarismRequestRepositoryImpl.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java index 3356526223..1aece5bd51 100644 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java +++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java @@ -11,46 +11,61 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; -import java.util.*; + +import java.util.Objects; @Entity @Table(name = "plagiarism_request") class PlagiarismRequest { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (plagiarism_request) referencing other + // tables. + // ---------------------------------------------------------------------------------- @OneToOne(optional = false) - @JoinColumn(name = "document_reference_id") + @JoinColumn(name = "document_file_reference_id", referencedColumnName = "id") private FileReference document; @ManyToOne + @JoinColumn(name = "receiver_user_id", referencedColumnName = "id") private User receiver; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return this.id; } - public FileReference getDocument() { - return this.document; - } - - public User getReceiver() { - return this.receiver; - } - public void setId(Long id) { this.id = id; } + public FileReference getDocument() { + return this.document; + } + public void setDocument(FileReference fileDescription) { this.document = fileDescription; } + public User getReceiver() { + return this.receiver; + } + public void setReceiver(User receiver) { this.receiver = receiver; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -62,10 +77,6 @@ class PlagiarismRequest { && Objects.equals(this.getReceiver(), other.getReceiver()); } - protected boolean canEqual(final Object other) { - return other instanceof PlagiarismRequest; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getDocument(), this.getReceiver()); @@ -73,6 +84,14 @@ class PlagiarismRequest { @Override public String toString() { - return "PlagiarismRequest(id=" + this.getId() + ", fileDescription=" + this.getDocument() + ", receiver=" + this.getReceiver() + ")"; + return "PlagiarismRequest(id=" + this.getId() + ", fileDescription=" + this.getDocument() + + ", receiver=" + this.getReceiver() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other method + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof PlagiarismRequest; } } diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java index 774dfdda3a..5a5f58f929 100644 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java @@ -36,7 +36,7 @@ public class UrkundApiImpl implements UrkundApi { private final FileService fileService; @Inject - UrkundApiImpl(final UrkundSettingsRepository urkundSettingsRepository, FileService fileService) { + public UrkundApiImpl(final UrkundSettingsRepository urkundSettingsRepository, FileService fileService) { this.urkundSettingsRepository = urkundSettingsRepository; this.fileService = fileService; objectMapper = new ObjectMapper(); diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundModule.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundModule.java deleted file mode 100644 index 573a3a5559..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundModule.java +++ /dev/null @@ -1,26 +0,0 @@ -package se.su.dsv.scipro.plagiarism.urkund; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Scopes; -import se.su.dsv.scipro.sukat.Sukat; - -import jakarta.persistence.EntityManager; - -public class UrkundModule extends AbstractModule { - @Override - protected void configure() { - bind(UrkundService.class).to(UrkundServiceImpl.class); - bind(UrkundSubmissionRepository.class).to(UrkundSubmissionRepositoryImpl.class); - bind(UrkundApi.class).to(UrkundApiImpl.class).in(Scopes.SINGLETON); - bind(UrkundSettingsRepository.class).to(UrkundSettingsRepositoryImpl.class); - - requireBinding(EntityManager.class); - requireBinding(Sukat.class); - } - - @Provides - public UrkundSettings urkundSettings(UrkundSettingsRepository urkundSettingsRepository) { - return urkundSettingsRepository.getSettings(); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java index 8eac423c9b..e83125690b 100644 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.plagiarism.urkund; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileDescription; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java index 74716b4e56..fa97b51a46 100644 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java +++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java @@ -1,9 +1,11 @@ package se.su.dsv.scipro.plagiarism.urkund; import jakarta.persistence.Basic; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; + import java.util.Objects; @Entity @@ -15,12 +17,15 @@ public class UrkundSettings { private long id = ID; @Basic + @Column(name = "enabled") private boolean enabled = false; @Basic + @Column(name = "username") private String username; @Basic + @Column(name = "password") private String password; public boolean isEnabled() { @@ -70,6 +75,7 @@ public class UrkundSettings { @Override public String toString() { - return "UrkundSettings(id=" + this.id + ", enabled=" + this.isEnabled() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ")"; + return "UrkundSettings(id=" + this.id + ", enabled=" + this.isEnabled() + ", username=" + + this.getUsername() + ", password=" + this.getPassword() + ")"; } } diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java index 594dd691fc..87580259a7 100644 --- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java +++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java @@ -17,139 +17,159 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import java.time.Instant; -import java.util.*; +import java.util.Objects; @Entity @Table(name = "urkund_submission") public class UrkundSubmission extends DomainObject { - - public enum State { - SUBMISSION_FAILED, SUBMITTED, REJECTED, ACCEPTED, ANALYZED, ERROR; - - public boolean isFinal() { - return !(this == SUBMITTED || this == ACCEPTED); - } - } - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne - private User receiver; + @Basic + @Column(name = "submitted_date", nullable = false) + private Instant submitted; @Basic - private String analysisAddress; - - @Column(nullable = false) + @Column(name = "state", nullable = false) @Enumerated(EnumType.STRING) private State state; - @Column(nullable = false) - private Instant submitted; - - @Column(nullable = false) + @Basic + @Column(name = "next_poll_date", nullable = false) private Instant nextPoll; - @Column(nullable = false) + @Basic + @Column(name = "polling_delay", nullable = false) @Enumerated(EnumType.STRING) private PollingDelay pollingDelay = PollingDelay.FIRST; - @OneToOne(optional = false) - @JoinColumn(name = "document_reference_id") - private FileReference document; - @Basic(optional = false) + @Column(name = "message") private String message; @Basic + @Column(name = "report_url") private String reportUrl; @Basic + @Column(name = "significance") private Float significance; + @Basic + @Column(name = "analysis_address") + private String analysisAddress; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (urkund_submission) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @OneToOne(optional = false) + @JoinColumn(name = "document_file_reference_id", referencedColumnName = "id") + private FileReference document; + + @ManyToOne + @JoinColumn(name = "receiver_user_id", referencedColumnName = "id") + private User receiver; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public String getAnalysisAddress() { - return this.analysisAddress; - } - - public State getState() { - return this.state; - } - - public Instant getSubmitted() { - return this.submitted; - } - - public FileReference getDocument() { - return this.document; - } - - public String getMessage() { - return this.message; - } - - public String getReportUrl() { - return this.reportUrl; - } - - public Float getSignificance() { - return this.significance; - } - - @Override - public String toString() { - return "UrkundSubmission(id=" + this.getId() + ", receiver=" + this.getReceiver() + ", analysisAddress=" + this.getAnalysisAddress() + ", state=" + this.getState() + ", submitted=" + this.getSubmitted() + ", nextPoll=" + this.getNextPoll() + ", pollingDelay=" + this.getPollingDelay() + ", fileDescription=" + this.getDocument() + ", message=" + this.getMessage() + ", reportUrl=" + this.getReportUrl() + ", significance=" + this.getSignificance() + ")"; - } - void setId(Long id) { this.id = id; } - void setReceiver(User receiver) { - this.receiver = receiver; - } - - void setAnalysisAddress(String analysisAddress) { - this.analysisAddress = analysisAddress; - } - - void setState(State state) { - this.state = state; + public Instant getSubmitted() { + return this.submitted; } void setSubmitted(Instant submitted) { this.submitted = submitted; } + public State getState() { + return this.state; + } + + void setState(State state) { + this.state = state; + } + + Instant getNextPoll() { + return this.nextPoll; + } + void setNextPoll(Instant nextPoll) { this.nextPoll = nextPoll; } + PollingDelay getPollingDelay() { + return this.pollingDelay; + } + void setPollingDelay(PollingDelay pollingDelay) { this.pollingDelay = pollingDelay; } - void setDocument(FileReference fileDescription) { - this.document = fileDescription; + public String getMessage() { + return this.message; } void setMessage(String message) { this.message = message; } + public String getReportUrl() { + return this.reportUrl; + } + void setReportUrl(String reportUrl) { this.reportUrl = reportUrl; } + public Float getSignificance() { + return this.significance; + } + void setSignificance(Float significance) { this.significance = significance; } + public String getAnalysisAddress() { + return this.analysisAddress; + } + + void setAnalysisAddress(String analysisAddress) { + this.analysisAddress = analysisAddress; + } + + public FileReference getDocument() { + return this.document; + } + + void setDocument(FileReference fileDescription) { + this.document = fileDescription; + } + + User getReceiver() { + return this.receiver; + } + + void setReceiver(User receiver) { + this.receiver = receiver; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -170,10 +190,6 @@ public class UrkundSubmission extends DomainObject { && Objects.equals(this.getSignificance(), other.getSignificance()); } - protected boolean canEqual(final Object other) { - return other instanceof UrkundSubmission; - } - @Override public int hashCode() { return Objects.hash( @@ -190,15 +206,31 @@ public class UrkundSubmission extends DomainObject { this.getSignificance()); } - User getReceiver() { - return this.receiver; + @Override + public String toString() { + return "UrkundSubmission(id=" + this.getId() + ", receiver=" + this.getReceiver() + + ", analysisAddress=" + this.getAnalysisAddress() + ", state=" + + this.getState() + ", submitted=" + this.getSubmitted() + + ", nextPoll=" + this.getNextPoll() + ", pollingDelay=" + this.getPollingDelay() + + ", fileDescription=" + this.getDocument() + ", message=" + this.getMessage() + + ", reportUrl=" + this.getReportUrl() + ", significance=" + this.getSignificance() + ")"; } - Instant getNextPoll() { - return this.nextPoll; + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof UrkundSubmission; } - PollingDelay getPollingDelay() { - return this.pollingDelay; + // ---------------------------------------------------------------------------------- + // Nested type + // ---------------------------------------------------------------------------------- + public enum State { + SUBMISSION_FAILED, SUBMITTED, REJECTED, ACCEPTED, ANALYZED, ERROR; + + public boolean isFinal() { + return !(this == SUBMITTED || this == ACCEPTED); + } } } diff --git a/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java b/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java index 679ba53157..6bf6f2bd19 100755 --- a/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java +++ b/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java @@ -1,14 +1,10 @@ package se.su.dsv.scipro.profiles; -import jakarta.inject.Inject; -import jakarta.inject.Named; - public class CurrentProfile { private String currentProfileString; - @Inject - public void setCurrentProfileString(@Named("profile") String currentProfileString) { + public void setCurrentProfileString(String currentProfileString) { this.currentProfileString = currentProfileString; } diff --git a/core/src/main/java/se/su/dsv/scipro/project/Author.java b/core/src/main/java/se/su/dsv/scipro/project/Author.java index c3094e697c..96ec7ce284 100644 --- a/core/src/main/java/se/su/dsv/scipro/project/Author.java +++ b/core/src/main/java/se/su/dsv/scipro/project/Author.java @@ -1,26 +1,45 @@ package se.su.dsv.scipro.project; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapsId; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.io.Serializable; import java.util.Objects; @Entity @Table(name = "project_user") public class Author { + // ---------------------------------------------------------------------------------- + // Embedded JPA-mapping + // ---------------------------------------------------------------------------------- @EmbeddedId private AuthorPK authorPK; - @ManyToOne(optional = false) - @JoinColumn(name = "project_id", nullable = false) - @MapsId("projectId") - private Project project; + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- + @Basic(optional = true) + @Column(name = "reflection") + private String reflection; - @ManyToOne(optional = false) - @JoinColumn(name = "user_id", nullable = false) - @MapsId("userId") - private User user; + @Basic + @Enumerated(EnumType.STRING) + @Column(name = "reflection_status") + private ReflectionStatus reflectionStatus = ReflectionStatus.NOT_SUBMITTED; + + @Basic + @Column(name = "reflection_comment_by_supervisor") + private String reflectionSupervisorComment; /** * If this author wants to be notified when a final seminar created @@ -36,15 +55,29 @@ public class Author { @Column(name = "subscribed_to_final_seminar_notifications", nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE") private boolean subscribedToFinalSeminarNotifications; - @Basic(optional = true) - private String reflection; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (project_user) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name = "project_id", nullable = false) + @MapsId("projectId") + private Project project; - public Project getProject() { - return project; + @ManyToOne(optional = false) + @JoinColumn(name = "user_id", nullable = false) + @MapsId("userId") + private User user; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + public String getReflection() { + return reflection; } - public User getUser() { - return user; + public void setReflection(String reflection) { + this.reflection = reflection; } public boolean isSubscribedToFinalSeminarNotifications() { @@ -55,14 +88,33 @@ public class Author { this.subscribedToFinalSeminarNotifications = subscribedToFinalSeminarNotifications; } - public String getReflection() { - return reflection; + public Project getProject() { + return project; } - public void setReflection(String reflection) { - this.reflection = reflection; + public User getUser() { + return user; } + public ReflectionStatus getReflectionStatus() { + return reflectionStatus; + } + + public void setReflectionStatus(ReflectionStatus reflectionStatus) { + this.reflectionStatus = reflectionStatus; + } + + public void setReflectionSupervisorComment(String reflectionSupervisorComment) { + this.reflectionSupervisorComment = reflectionSupervisorComment; + } + + public String getReflectionSupervisorComment() { + return reflectionSupervisorComment; + } + + // ---------------------------------------------------------------------------------- + // Nested class + // ---------------------------------------------------------------------------------- @Embeddable public static class AuthorPK implements Serializable { private Long projectId; diff --git a/core/src/main/java/se/su/dsv/scipro/project/Project.java b/core/src/main/java/se/su/dsv/scipro/project/Project.java index 9429d2cbfc..569d1da4a7 100755 --- a/core/src/main/java/se/su/dsv/scipro/project/Project.java +++ b/core/src/main/java/se/su/dsv/scipro/project/Project.java @@ -1,13 +1,51 @@ package se.su.dsv.scipro.project; import com.querydsl.core.annotations.QueryInit; +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MapKeyJoinColumn; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; + import se.su.dsv.scipro.data.dataobjects.Member; import se.su.dsv.scipro.reusable.SciProUtilities; -import se.su.dsv.scipro.system.*; +import se.su.dsv.scipro.system.DegreeType; +import se.su.dsv.scipro.system.DomainObject; +import se.su.dsv.scipro.system.Language; +import se.su.dsv.scipro.system.ProjectModule; +import se.su.dsv.scipro.system.ProjectType; +import se.su.dsv.scipro.system.ResearchArea; +import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.time.LocalDate; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.stream.Collectors; @Entity @@ -18,17 +56,30 @@ public class Project extends DomainObject { public static final String NO_CO_SUPERVISOR = "No co-supervisor"; public static final int TITLE_MAX_LENGTH = 255; + public static ITitle builder() { + return new Builder(); + } + + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(unique = true) - private Integer identifier; - - @Column(length = TITLE_MAX_LENGTH) @Basic(optional = false) + @Column(name = "title", length = TITLE_MAX_LENGTH) private String title; + @Basic + @Column(name = "credits") + private int credits; + + @Basic + @Column(name = "language") + @Enumerated(EnumType.STRING) + private Language language; + @Basic(optional = false) @Column(name = "start_date", nullable = false) private LocalDate startDate; @@ -37,61 +88,91 @@ public class Project extends DomainObject { @Column(name = "expected_end_date") private LocalDate expectedEndDate; - @ManyToMany - @JoinTable(name = "project_user", inverseJoinColumns = @JoinColumn(name = "user_id")) - private Set<User> projectParticipants = new TreeSet<>(new User.ByNameComparator()); - - @ManyToMany - @JoinTable(name = "project_reviewer", inverseJoinColumns = @JoinColumn(name = "user_id")) - private Set<User> reviewers = new TreeSet<>(new User.ByNameComparator()); - - @ManyToMany - @JoinTable(name = "project_cosupervisor", inverseJoinColumns = @JoinColumn(name = "user_id")) - private Set<User> coSupervisors = new TreeSet<>(new User.ByNameComparator()); - - @ManyToOne(optional = false) - @QueryInit({"unit"}) - @JoinColumn(name = "supervisor_id") - private User headSupervisor; - + @Basic + @Column(name = "project_status") @Enumerated(EnumType.STRING) private ProjectStatus projectStatus = ProjectStatus.ACTIVE; + @Basic + @Column(name = "final_seminar_rule_exmpt") + private boolean finalSeminarRuleExempted = false; + + @Basic + @Column(name = "state_of_mind") @Enumerated(EnumType.STRING) private StateOfMind stateOfMind = StateOfMind.FINE; @Basic(optional = true) - private Date stateOfMindDate; - - @Basic(optional = true) + @Column(name = "state_of_mind_reason") private String stateOfMindReason; - @ManyToOne(optional = false) - private ProjectType projectType; - - @Embedded - @AttributeOverride(name = "name", column = @Column(name = "externalOrganization")) - private ExternalOrganization externalOrganization; - - @Column(name = "fs_rule_exmpt") - private boolean finalSeminarRuleExempted = false; + @Basic(optional = true) + @Column(name = "state_of_mind_date") + private Date stateOfMindDate; @Basic - private int credits; + @Column(name = "daisy_identifier", unique = true) + private Integer identifier; + + // ---------------------------------------------------------------------------------- + // Embedded JPA-mapping + // ---------------------------------------------------------------------------------- + @Embedded + @AttributeOverride(name = "name", column = @Column(name = "external_organization")) + private ExternalOrganization externalOrganization; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (opposition_report) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name = "project_type_id", referencedColumnName = "id") + private ProjectType projectType; @ManyToOne(optional = true) + @JoinColumn(name = "research_area_id", referencedColumnName = "id") private ResearchArea researchArea; - @Enumerated(EnumType.STRING) - private Language language; + @ManyToOne(optional = false) + @JoinColumn(name = "supervisor_id", referencedColumnName = "id") + @QueryInit({"unit"}) + private User headSupervisor; + // ---------------------------------------------------------------------------------- + // @ManyToMany JPA-mappings + // ---------------------------------------------------------------------------------- + @ManyToMany + @JoinTable(name = "project_user", + joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")) + private Set<User> projectParticipants = new TreeSet<>(new User.ByNameComparator()); + + @ManyToMany + @JoinTable(name = "project_reviewer", + joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")) + private Set<User> reviewers = new TreeSet<>(new User.ByNameComparator()); + + @ManyToMany + @JoinTable(name = "project_cosupervisor", + joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")) + private Set<User> coSupervisors = new TreeSet<>(new User.ByNameComparator()); + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "project" + // ---------------------------------------------------------------------------------- @ElementCollection(fetch = FetchType.LAZY) - @CollectionTable(name = "project_user_note", joinColumns = @JoinColumn(name = "project_id")) + @CollectionTable(name = "project_user_note", + joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id")) @Column(name = "note") @SuppressWarnings("JpaDataSourceORMInspection") // false warning from IntelliJ for the @MapKeyJoinColumn @MapKeyJoinColumn(name = "user_id") private Map<User, String> userNotes = new HashMap<>(); + // ---------------------------------------------------------------------------------- + // JPA Lifecycle Methods + // ---------------------------------------------------------------------------------- @PrePersist @PreUpdate void cleanTitle() { @@ -101,12 +182,67 @@ public class Project extends DomainObject { title = title.trim(); } - public Map<User, String> getUserNotes() { - return userNotes; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; } - public void setUserNotes(Map<User, String> userNotes) { - this.userNotes = userNotes; + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return SciProUtilities.cleanString(title); + } + + public void setTitle(String title) { + this.title = title; + } + + public int getCredits() { + return this.credits; + } + + public void setCredits(int credits) { + this.credits = credits; + } + + public Language getLanguage() { + return this.language; + } + + public void setLanguage(Language language) { + this.language = language; + } + + public LocalDate getStartDate() { + return startDate; + } + + public void setStartDate(LocalDate startDate) { + this.startDate = startDate; + } + + public LocalDate getExpectedEndDate() { + return this.expectedEndDate; + } + + public void setExpectedEndDate(LocalDate expectedEndDate) { + this.expectedEndDate = expectedEndDate; + } + + public ProjectStatus getProjectStatus() { + return this.projectStatus; + } + + public void setProjectStatus(ProjectStatus projectStatus) { + this.projectStatus = projectStatus; + if (projectStatus == ProjectStatus.COMPLETED) { + this.stateOfMind = StateOfMind.FINE; + } } public boolean isFinalSeminarRuleExempted() { @@ -117,53 +253,20 @@ public class Project extends DomainObject { this.finalSeminarRuleExempted = finalSeminarRuleExempted; } - public User getHeadSupervisor() { - return headSupervisor; + public StateOfMind getStateOfMind() { + return this.stateOfMind; } - public ProjectType getProjectType() { - return projectType; + public void setStateOfMind(StateOfMind stateOfMind) { + this.stateOfMind = stateOfMind; } - public SortedSet<User> getCoSupervisors() { - TreeSet<User> s = new TreeSet<>(new User.ByNameComparator()); - s.addAll(coSupervisors); - return Collections.unmodifiableSortedSet(s); + public String getStateOfMindReason() { + return this.stateOfMindReason; } - public void setCoSupervisors(Collection<User> coSupervisors) { - this.coSupervisors.clear(); - this.coSupervisors.addAll(coSupervisors); - } - - public void addCoSupervisor(User coSupervisor) { - coSupervisors.add(coSupervisor); - } - - public SortedSet<User> getReviewers() { - TreeSet<User> s = new TreeSet<>(new User.ByNameComparator()); - s.addAll(reviewers); - return Collections.unmodifiableSortedSet(s); - } - - public void setReviewers(Collection<User> reviewers) { - this.reviewers.clear(); - this.reviewers.addAll(reviewers); - } - - public void addReviewer(User reviewer) { - reviewers.add(reviewer); - } - - public void removeReviewer(User reviewer) { - reviewers.remove(reviewer); - } - - public void setProjectStatus(ProjectStatus projectStatus) { - this.projectStatus = projectStatus; - if (projectStatus == ProjectStatus.COMPLETED) { - this.stateOfMind = StateOfMind.FINE; - } + public void setStateOfMindReason(String stateOfMindReason) { + this.stateOfMindReason = stateOfMindReason; } public Date getStateOfMindDate() { @@ -176,8 +279,44 @@ public class Project extends DomainObject { : new Date(stateOfMindDate.getTime()); } - public String getTitle() { - return SciProUtilities.cleanString(title); + public Integer getIdentifier() { + return this.identifier; + } + + public void setIdentifier(Integer identifier) { + this.identifier = identifier; + } + + public ExternalOrganization getExternalOrganization() { + return this.externalOrganization; + } + + public void setExternalOrganization(ExternalOrganization externalOrganization) { + this.externalOrganization = externalOrganization; + } + + public ProjectType getProjectType() { + return projectType; + } + + public void setProjectType(ProjectType projectType) { + this.projectType = projectType; + } + + public ResearchArea getResearchArea() { + return this.researchArea; + } + + public void setResearchArea(ResearchArea researchArea) { + this.researchArea = researchArea; + } + + public User getHeadSupervisor() { + return headSupervisor; + } + + public void setHeadSupervisor(User headSupervisor) { + this.headSupervisor = headSupervisor; } public SortedSet<User> getProjectParticipants() { @@ -191,11 +330,91 @@ public class Project extends DomainObject { this.projectParticipants.addAll(projectParticipants); } + public SortedSet<User> getReviewers() { + TreeSet<User> s = new TreeSet<>(new User.ByNameComparator()); + s.addAll(reviewers); + return Collections.unmodifiableSortedSet(s); + } + + public void setReviewers(Collection<User> reviewers) { + this.reviewers.clear(); + this.reviewers.addAll(reviewers); + } + + public SortedSet<User> getCoSupervisors() { + TreeSet<User> s = new TreeSet<>(new User.ByNameComparator()); + s.addAll(coSupervisors); + return Collections.unmodifiableSortedSet(s); + } + + public void setCoSupervisors(Collection<User> coSupervisors) { + this.coSupervisors.clear(); + this.coSupervisors.addAll(coSupervisors); + } + + public Map<User, String> getUserNotes() { + return userNotes; + } + + public void setUserNotes(Map<User, String> userNotes) { + this.userNotes = userNotes; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof Project)) return false; + final Project other = (Project) o; + return other.canEqual(this) + && Objects.equals(this.getId(), other.getId()); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.getId()); + } + + @Override + public String toString() { + return "Project(id=" + this.getId() + ", identifier=" + this.getIdentifier() + + ", title=" + this.getTitle() + ", projectParticipants=" + this.getProjectParticipants() + + ", headSupervisor=" + this.getHeadSupervisor() + ", projectType=" + + this.getProjectType() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + + protected boolean canEqual(final Object other) { + return other instanceof Project; + } + public void addProjectParticipant(User s) { projectParticipants.add(s); } - //TODO remove this method + public boolean isParticipant(User user) { + for (User s : projectParticipants) { + if (s.equals(user)) { + return true; + } + } + return false; + } + + public void addReviewer(User reviewer) { + reviewers.add(reviewer); + } + + public void removeReviewer(User reviewer) { + reviewers.remove(reviewer); + } + + // TODO remove this method public User getReviewer() { if (reviewers.isEmpty()) { return null; @@ -204,6 +423,14 @@ public class Project extends DomainObject { } } + public String getReviewerName() { + return getReviewer() != null ? getReviewer().getFullName() : NO_REVIEWER; + } + + public void addCoSupervisor(User coSupervisor) { + coSupervisors.add(coSupervisor); + } + public List<Member> getMembers() { List<Member> members = new ArrayList<>(); @@ -240,23 +467,10 @@ public class Project extends DomainObject { return externalOrganization != null; } - public boolean isParticipant(User user) { - for (User s : projectParticipants) { - if (s.equals(user)) { - return true; - } - } - return false; - } - public String getSupervisorName() { return getHeadSupervisor().getFullName(); } - public String getReviewerName() { - return getReviewer() != null ? getReviewer().getFullName() : NO_REVIEWER; - } - public DegreeType getProjectTypeDegreeType() { return getProjectType().getDegreeType(); } @@ -289,10 +503,6 @@ public class Project extends DomainObject { return getProjectType().hasModule(projectModule); } - public static ITitle builder() { - return new Builder(); - } - public boolean isSupervisor(User user) { return headSupervisor != null && headSupervisor.equals(user); } @@ -319,125 +529,9 @@ public class Project extends DomainObject { return Objects.requireNonNullElse(language, getProjectType().getDefaultLanguage()); } - @Override - public Long getId() { - return this.id; - } - - public Integer getIdentifier() { - return this.identifier; - } - - public LocalDate getExpectedEndDate() { - return this.expectedEndDate; - } - - public ProjectStatus getProjectStatus() { - return this.projectStatus; - } - - public StateOfMind getStateOfMind() { - return this.stateOfMind; - } - - public String getStateOfMindReason() { - return this.stateOfMindReason; - } - - public ExternalOrganization getExternalOrganization() { - return this.externalOrganization; - } - - public int getCredits() { - return this.credits; - } - - public ResearchArea getResearchArea() { - return this.researchArea; - } - - public Language getLanguage() { - return this.language; - } - - public void setId(Long id) { - this.id = id; - } - - public void setIdentifier(Integer identifier) { - this.identifier = identifier; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setExpectedEndDate(LocalDate expectedEndDate) { - this.expectedEndDate = expectedEndDate; - } - - public void setHeadSupervisor(User headSupervisor) { - this.headSupervisor = headSupervisor; - } - - public void setStateOfMind(StateOfMind stateOfMind) { - this.stateOfMind = stateOfMind; - } - - public void setStateOfMindReason(String stateOfMindReason) { - this.stateOfMindReason = stateOfMindReason; - } - - public void setProjectType(ProjectType projectType) { - this.projectType = projectType; - } - - public void setExternalOrganization(ExternalOrganization externalOrganization) { - this.externalOrganization = externalOrganization; - } - - public void setCredits(int credits) { - this.credits = credits; - } - - public void setResearchArea(ResearchArea researchArea) { - this.researchArea = researchArea; - } - - public void setLanguage(Language language) { - this.language = language; - } - - public LocalDate getStartDate() { - return startDate; - } - - public void setStartDate(LocalDate startDate) { - this.startDate = startDate; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof Project)) return false; - final Project other = (Project) o; - return other.canEqual(this) - && Objects.equals(this.getId(), other.getId()); - } - - protected boolean canEqual(final Object other) { - return other instanceof Project; - } - - @Override - public int hashCode() { - return Objects.hashCode(this.getId()); - } - - @Override - public String toString() { - return "Project(id=" + this.getId() + ", identifier=" + this.getIdentifier() + ", title=" + this.getTitle() + ", projectParticipants=" + this.getProjectParticipants() + ", headSupervisor=" + this.getHeadSupervisor() + ", projectType=" + this.getProjectType() + ")"; - } + // ---------------------------------------------------------------------------------- + // Nested classes and interfaces + // ---------------------------------------------------------------------------------- private static class Builder implements ITitle, IProjectType, IStartDate, IBuild { private final Project instance = new Project(); diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java index 9a2862ae63..ada1db066b 100644 --- a/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java @@ -10,7 +10,7 @@ import jakarta.persistence.EntityManager; public class ProjectPeopleStatisticsServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectPeopleStatisticsService { @Inject - protected ProjectPeopleStatisticsServiceImpl(Provider<EntityManager> em) { + public ProjectPeopleStatisticsServiceImpl(Provider<EntityManager> em) { super(em, Project.class, QProject.project); } diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java index 43892156ca..a1c985044f 100755 --- a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.project; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.JpaRepository; import se.su.dsv.scipro.system.QueryDslPredicateExecutor; import se.su.dsv.scipro.system.User; diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java index f8dfb462bd..8211412568 100644 --- a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.project; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.GenericRepo; import se.su.dsv.scipro.system.User; diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java index 617f39e795..e52cae2397 100755 --- a/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.project; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.BooleanExpression; diff --git a/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java b/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java new file mode 100644 index 0000000000..92b94cd7b6 --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java @@ -0,0 +1,7 @@ +package se.su.dsv.scipro.project; + +public enum ReflectionStatus { + NOT_SUBMITTED, + SUBMITTED, + IMPROVEMENTS_NEEDED +} diff --git a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java index 0afe97861e..643956fe8e 100755 --- a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java +++ b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java @@ -1,15 +1,26 @@ package se.su.dsv.scipro.projectpartner; +import java.util.Objects; + +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.match.ApplicationPeriod; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.ProjectType; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; -import java.util.Objects; - @Entity -@Table(name="projectPartner") +@Table(name="project_partner") @Cacheable(true) public class ProjectPartner extends DomainObject { @Id @@ -20,17 +31,19 @@ public class ProjectPartner extends DomainObject { private User user; @ManyToOne(optional = false) + @JoinColumn(name = "project_type_id") private ProjectType projectType; @ManyToOne(optional = false) + @JoinColumn(name = "application_period_id") private ApplicationPeriod applicationPeriod; @Lob - @Basic(optional=false) + @Column(name = "info_text", nullable=false) private String infotext; @Basic(optional = false) - @Column(nullable = false, name = "active") + @Column(name = "active", nullable = false) private boolean active = true; public ProjectPartner(User user){ diff --git a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java index 63dada7bf6..a437f162d5 100644 --- a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.projectpartner; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.system.AbstractRepository; import jakarta.inject.Inject; diff --git a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java index 3b39364a33..5af5e3a0a7 100644 --- a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.projectpartner; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.jpa.JPAExpressions; import se.su.dsv.scipro.system.Pageable; diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java b/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java new file mode 100644 index 0000000000..898d961a2c --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java @@ -0,0 +1,22 @@ +package se.su.dsv.scipro.reflection; + +public sealed interface Reflection { + boolean isSubmittable(); + + record NotSubmitted() implements Reflection { + @Override + public boolean isSubmittable() { return true; } + } + + record Submitted(String reflection) implements Reflection { + @Override + public boolean isSubmittable() { + return false; + } + } + + record ImprovementsNeeded(String oldReflection, String commentBySupervisor) implements Reflection { + @Override + public boolean isSubmittable() { return true; } + } +} diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java new file mode 100644 index 0000000000..07d8811f99 --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java @@ -0,0 +1,7 @@ +package se.su.dsv.scipro.reflection; + +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.system.User; + +public record ReflectionImprovementsRequestedEvent(Project project, User author, String supervisorComment) { +} diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java new file mode 100644 index 0000000000..ce43d5eed4 --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java @@ -0,0 +1,10 @@ +package se.su.dsv.scipro.reflection; + +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.system.User; + +/** + * This event may be triggered by the supervisor if they edit the reflection after requesting improvements. + */ +public record ReflectionImprovementsSubmittedEvent(Project project, User author, String reflection) { +} diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionModule.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionModule.java deleted file mode 100644 index 872fd7d8dd..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionModule.java +++ /dev/null @@ -1,13 +0,0 @@ -package se.su.dsv.scipro.reflection; - -import com.google.inject.AbstractModule; -import se.su.dsv.scipro.finalseminar.AuthorRepository; - -public class ReflectionModule extends AbstractModule { - @Override - protected void configure() { - requireBinding(AuthorRepository.class); - - bind(ReflectionService.class).to(ReflectionServiceImpl.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java index b4a206bf76..139dc9a6d9 100644 --- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java +++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java @@ -14,4 +14,15 @@ public interface ReflectionService { * @return the reflection, or {@code null} if none has been submitted */ String getSubmittedReflection(Project project, User author); + + /** + * Used by the supervisor when the currently submitted reflection does not meet the minimum requirements. + * This is done individually by author. + * + * @param author the author whose reflection does not meet the minimum requirements. + * @param supervisorComment feedback provided by the supervisor so the author knows what to improve. + */ + void requestNewReflection(Project project, User author, String supervisorComment); + + Reflection getReflection(Project project, User author); } diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java index ccd23a6244..73d934ca32 100644 --- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java @@ -1,22 +1,32 @@ package se.su.dsv.scipro.reflection; -import com.google.inject.persist.Transactional; +import com.google.common.eventbus.EventBus; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.finalseminar.AuthorRepository; import se.su.dsv.scipro.finalseminar.FinalSeminarService; import se.su.dsv.scipro.project.Author; import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.project.ReflectionStatus; import se.su.dsv.scipro.system.User; import jakarta.inject.Inject; -class ReflectionServiceImpl implements ReflectionService { +import java.util.Optional; + +public class ReflectionServiceImpl implements ReflectionService { private final AuthorRepository authorRepository; private final FinalSeminarService finalSeminarService; + private final EventBus eventBus; @Inject - ReflectionServiceImpl(AuthorRepository authorRepository, FinalSeminarService finalSeminarService) { + public ReflectionServiceImpl( + AuthorRepository authorRepository, + FinalSeminarService finalSeminarService, + EventBus eventBus) + { this.authorRepository = authorRepository; this.finalSeminarService = finalSeminarService; + this.eventBus = eventBus; } @Override @@ -25,10 +35,13 @@ class ReflectionServiceImpl implements ReflectionService { } @Override - public boolean hasToFillInReflection(Project project, User author) { - boolean noReflectionSubmitted = authorRepository.findByProjectAndUser(project, author) - .map(Author::getReflection) - .isEmpty(); + public boolean hasToFillInReflection(Project project, User user) { + Optional<Author> optionalAuthor = authorRepository.findByProjectAndUser(project, user); + if (optionalAuthor.isEmpty()) { + return false; + } + Author author = optionalAuthor.get(); + boolean noReflectionSubmitted = author.getReflectionStatus() != ReflectionStatus.SUBMITTED; return hasReachedReflectionProcess(project) && noReflectionSubmitted; } @@ -36,7 +49,13 @@ class ReflectionServiceImpl implements ReflectionService { @Transactional public void submitReflection(Project project, User user, String reflection) { authorRepository.findByProjectAndUser(project, user) - .ifPresent(author -> author.setReflection(reflection)); + .ifPresent(author -> { + if (author.getReflectionStatus() == ReflectionStatus.IMPROVEMENTS_NEEDED) { + eventBus.post(new ReflectionImprovementsSubmittedEvent(project, user, reflection)); + } + author.setReflection(reflection); + author.setReflectionStatus(ReflectionStatus.SUBMITTED); + }); } @Override @@ -45,4 +64,32 @@ class ReflectionServiceImpl implements ReflectionService { .map(Author::getReflection) .orElse(null); } + + @Override + @Transactional + public void requestNewReflection(Project project, User user, String supervisorComment) { + authorRepository.findByProjectAndUser(project, user) + .ifPresent(author -> { + author.setReflectionStatus(ReflectionStatus.IMPROVEMENTS_NEEDED); + author.setReflectionSupervisorComment(supervisorComment); + }); + eventBus.post(new ReflectionImprovementsRequestedEvent(project, user, supervisorComment)); + } + + @Override + public Reflection getReflection(Project project, User author) { + return authorRepository.findByProjectAndUser(project, author) + .map(this::toReflection) + .orElseGet(Reflection.NotSubmitted::new); + } + + private Reflection toReflection(Author author) { + return switch (author.getReflectionStatus()) { + case SUBMITTED -> new Reflection.Submitted(author.getReflection()); + case IMPROVEMENTS_NEEDED -> new Reflection.ImprovementsNeeded( + author.getReflection(), + author.getReflectionSupervisorComment()); + default -> new Reflection.NotSubmitted(); + }; + } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java b/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java index 7fd640236b..e9d80f2699 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java +++ b/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java @@ -1,12 +1,12 @@ package se.su.dsv.scipro.report; -import jakarta.persistence.GenerationType; -import se.su.dsv.scipro.system.DomainObject; - import jakarta.persistence.Basic; +import jakarta.persistence.Column; import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.MappedSuperclass; +import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.Language; import java.io.Serializable; @@ -15,19 +15,28 @@ import java.util.Objects; @MappedSuperclass public abstract class AbstractCriterion extends DomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Basic(optional = false) + @Basic + @Column(name = "title_sv", nullable = false) private String title; - @Basic(optional = false) + @Basic + @Column(name = "title_en", nullable = false) private String titleEn; - @Basic(optional = false) + @Basic + @Column(name = "sort_order", nullable = false) private Integer sortOrder; + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected AbstractCriterion() { } @@ -37,6 +46,9 @@ public abstract class AbstractCriterion extends DomainObject { this.sortOrder = sortOrder; } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; @@ -50,14 +62,13 @@ public abstract class AbstractCriterion extends DomainObject { return titleEn; } - public String getTitle(Language language) { - return language == Language.ENGLISH ? getTitleEn() : getTitle(); - } - public Integer getSortOrder() { return this.sortOrder; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -71,10 +82,6 @@ public abstract class AbstractCriterion extends DomainObject { && Objects.equals(this.getSortOrder(), other.getSortOrder()); } - protected boolean canEqual(final Object other) { - return other instanceof AbstractCriterion; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getTitle(), this.getTitleEn(), this.getSortOrder()); @@ -85,6 +92,20 @@ public abstract class AbstractCriterion extends DomainObject { return "AbstractCriterion(id=" + this.getId() + ", title=" + this.getTitle() + ", titleEn=" + this.getTitleEn() + ", sortOrder=" + this.getSortOrder() + ")"; } + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof AbstractCriterion; + } + + public String getTitle(Language language) { + return language == Language.ENGLISH ? getTitleEn() : getTitle(); + } + + // ---------------------------------------------------------------------------------- + // Embedded class + // ---------------------------------------------------------------------------------- public static class BySortOrderComparator implements Comparator<AbstractCriterion>, Serializable { @Override public int compare(AbstractCriterion o1, AbstractCriterion o2) { diff --git a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java index 64d2f0433b..81b55d0982 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java +++ b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java @@ -8,7 +8,109 @@ import jakarta.persistence.MappedSuperclass; @MappedSuperclass public abstract class AbstractGradingCriterion extends AbstractCriterion { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- + @Basic(optional = false) + @Column(name = "points_required_to_pass", nullable = false) + protected int pointsRequiredToPass; + @Basic + @Column(name = "fx") + private boolean fx = true; + + @Basic + @Column(name = "flag") + @Enumerated(EnumType.STRING) + private Flag flag; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- + protected AbstractGradingCriterion() { + + } + + protected AbstractGradingCriterion(String title, String titleEn, int sortOrder, int pointsRequiredToPass) { + super(title, titleEn, sortOrder); + this.pointsRequiredToPass = pointsRequiredToPass; + } + + protected AbstractGradingCriterion(String title, String titleEn, Integer sortOrder, int pointsRequiredToPass, + Flag flag) { + this(title, titleEn, sortOrder, pointsRequiredToPass); + this.flag = flag; + } + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + public int getPointsRequiredToPass() { + return this.pointsRequiredToPass; + } + + public boolean isFx() { + return this.fx; + } + + public void setFx(boolean fx) { + this.fx = fx; + } + + public Flag getFlag() { + return flag; + } + + public void setFlag(Flag flag) { + this.flag = flag; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof AbstractGradingCriterion)) return false; + final AbstractGradingCriterion other = (AbstractGradingCriterion) o; + return other.canEqual(this) + && super.equals(o) + && this.getPointsRequiredToPass() == other.getPointsRequiredToPass() + && this.isFx() == other.isFx(); + } + + @Override + public int hashCode() { + final int PRIME = 59; + int result = super.hashCode(); + result = result * PRIME + this.getPointsRequiredToPass(); + result = result * PRIME + (this.isFx() ? 79 : 97); + return result; + } + + @Override + public String toString() { + return "AbstractGradingCriterion(pointsRequiredToPass=" + this.getPointsRequiredToPass() + + ", fx=" + this.isFx() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + @Override + protected boolean canEqual(final Object other) { + return other instanceof AbstractGradingCriterion; + } + + public abstract boolean isProjectCriterion(); + + public abstract boolean isIndividualCriterion(); + + public abstract int getMaxPoints(); + + // ---------------------------------------------------------------------------------- + // Nested type + // ---------------------------------------------------------------------------------- public enum Flag { /** * Criterion marked with this flag will add extra functionality related @@ -25,91 +127,4 @@ public abstract class AbstractGradingCriterion extends AbstractCriterion { */ OPPOSITION } - - @Basic(optional = false) - protected int pointsRequiredToPass; - - @Basic - private boolean fx = true; - - @Basic - @Column(name = "flag") - @Enumerated(EnumType.STRING) - private Flag flag; - - protected AbstractGradingCriterion() { - - } - - protected AbstractGradingCriterion(String title, String titleEn, int sortOrder, int pointsRequiredToPass) { - super(title, titleEn, sortOrder); - this.pointsRequiredToPass = pointsRequiredToPass; - } - - protected AbstractGradingCriterion( - String title, - String titleEn, - Integer sortOrder, - int pointsRequiredToPass, - Flag flag) - { - this(title, titleEn, sortOrder, pointsRequiredToPass); - this.flag = flag; - } - - public abstract boolean isProjectCriterion(); - - public abstract boolean isIndividualCriterion(); - - public abstract int getMaxPoints(); - - public int getPointsRequiredToPass() { - return this.pointsRequiredToPass; - } - - public boolean isFx() { - return this.fx; - } - - public Flag getFlag() { - return flag; - } - - public void setFlag(Flag flag) { - this.flag = flag; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof AbstractGradingCriterion)) return false; - final AbstractGradingCriterion other = (AbstractGradingCriterion) o; - return other.canEqual(this) - && super.equals(o) - && this.getPointsRequiredToPass() == other.getPointsRequiredToPass() - && this.isFx() == other.isFx(); - } - - @Override - protected boolean canEqual(final Object other) { - return other instanceof AbstractGradingCriterion; - } - - @Override - public int hashCode() { - final int PRIME = 59; - int result = super.hashCode(); - result = result * PRIME + this.getPointsRequiredToPass(); - result = result * PRIME + (this.isFx() ? 79 : 97); - return result; - } - - @Override - public String toString() { - return "AbstractGradingCriterion(pointsRequiredToPass=" + this.getPointsRequiredToPass() + ", fx=" + this.isFx() + ")"; - } - - public void setFx(boolean fx) { - this.fx = fx; - } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java index ae653266ac..29e423d0f2 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java +++ b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java @@ -1,70 +1,86 @@ package se.su.dsv.scipro.report; -import se.su.dsv.scipro.system.DomainObject; - -import jakarta.persistence.*; -import se.su.dsv.scipro.system.Language; - import java.util.Objects; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import se.su.dsv.scipro.system.DomainObject; + +import se.su.dsv.scipro.system.Language; + @MappedSuperclass -public abstract class AbstractGradingCriterionPoint extends DomainObject implements Comparable<AbstractGradingCriterionPoint> { +public abstract class AbstractGradingCriterionPoint extends DomainObject + implements Comparable<AbstractGradingCriterionPoint> { public static final int DESCRIPTION_LENGTH = 600; + + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Basic(optional = false) + @Column(name = "point") private Integer point; @Basic - @Column(length = DESCRIPTION_LENGTH) + @Column(name = "description_sv", length = DESCRIPTION_LENGTH) private String description; @Basic - @Column(length = DESCRIPTION_LENGTH) + @Column(name = "description_en", length = DESCRIPTION_LENGTH) private String descriptionEn; + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- public AbstractGradingCriterionPoint() { } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return id; } - public Integer getPoint() { - return this.point; - } - - public String getDescription() { - return this.description; - } - - public String getDescriptionEn() { - return descriptionEn; - } - - public String getDescription(Language language) { - return language == Language.ENGLISH ? getDescriptionEn() : getDescription(); - } - public void setId(Long id) { this.id = id; } + public Integer getPoint() { + return this.point; + } + public void setPoint(Integer point) { this.point = point; } + public String getDescription() { + return this.description; + } + public void setDescription(String description) { this.description = description; } + public String getDescriptionEn() { + return descriptionEn; + } + public void setDescriptionEn(String descriptionEn) { this.descriptionEn = descriptionEn; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects and Comparable + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -78,10 +94,6 @@ public abstract class AbstractGradingCriterionPoint extends DomainObject impleme && Objects.equals(this.getDescriptionEn(), other.getDescriptionEn()); } - protected boolean canEqual(final Object other) { - return other instanceof AbstractGradingCriterionPoint; - } - @Override public int hashCode() { return Objects.hash(super.hashCode(), this.getId(), this.getPoint(), this.getDescription(), this.getDescriptionEn()); @@ -91,4 +103,15 @@ public abstract class AbstractGradingCriterionPoint extends DomainObject impleme public String toString() { return "AbstractGradingCriterionPoint(id=" + this.getId() + ", point=" + this.getPoint() + ", description=" + this.getDescription() + ", descriptionEn=" + this.getDescriptionEn() + ")"; } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof AbstractGradingCriterionPoint; + } + + public String getDescription(Language language) { + return language == Language.ENGLISH ? getDescriptionEn() : getDescription(); + } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java b/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java index 3ec5ea0ac4..53c135a971 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java +++ b/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java @@ -6,16 +6,23 @@ import jakarta.persistence.CascadeType; import jakarta.persistence.JoinColumn; import jakarta.persistence.MappedSuperclass; import jakarta.persistence.OneToOne; -import java.util.*; +import java.util.Objects; @MappedSuperclass public abstract class AttachmentReport extends Report { + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in table of children class (OppositionReport) + // referencing other tables. + // ---------------------------------------------------------------------------------- @OneToOne(optional = true, cascade = CascadeType.ALL) - @JoinColumn(name = "attachment_reference_id") + @JoinColumn(name = "attachment_file_reference_id", referencedColumnName = "id") private FileReference attachment; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public FileReference getAttachment() { return this.attachment; } @@ -24,6 +31,9 @@ public abstract class AttachmentReport extends Report { this.attachment = attachment; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -34,14 +44,16 @@ public abstract class AttachmentReport extends Report { && Objects.equals(this.attachment, other.attachment); } - @Override - protected boolean canEqual(final Object other) { - return other instanceof AttachmentReport; - } - @Override public int hashCode() { return Objects.hash(super.hashCode(), this.attachment); } + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + @Override + protected boolean canEqual(final Object other) { + return other instanceof AttachmentReport; + } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/Criterion.java b/core/src/main/java/se/su/dsv/scipro/report/Criterion.java index de823bdb5c..63978c9170 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/Criterion.java +++ b/core/src/main/java/se/su/dsv/scipro/report/Criterion.java @@ -1,6 +1,11 @@ package se.su.dsv.scipro.report; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.Language; import java.util.Objects; @@ -8,26 +13,34 @@ import java.util.Objects; @Entity @Table(name = "criterion") public class Criterion extends AbstractCriterion { - public static final int DESCRIPTION_LENGTH = 2000; - @ManyToOne(optional = false) - private Report report; - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Basic - @Column - private String feedback; - - @Basic - @Column(length = DESCRIPTION_LENGTH) + @Column(name = "description_sv", length = DESCRIPTION_LENGTH) private String description; @Basic - @Column(length = DESCRIPTION_LENGTH) + @Column(name = "description_en", length = DESCRIPTION_LENGTH) private String descriptionEn; - protected Criterion() { + @Basic + @Column(name = "feedback") + private String feedback; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (criterion) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name ="report_id", referencedColumnName = "id") + private Report report; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- + protected Criterion() { } Criterion(Report report, String title, String titleEn, String description, String descriptionEn, int sortOrder) { @@ -41,22 +54,9 @@ public class Criterion extends AbstractCriterion { this(report, gradingCriterionTemplate.getTitle(), gradingCriterionTemplate.getTitleEn(), gradingCriterionTemplate.getDescription(), gradingCriterionTemplate.getDescriptionEn(), gradingCriterionTemplate.getSortOrder()); } - public void setFeedback(final String feedback) { - this.feedback = feedback; - } - - public boolean isFilledOut() { - return feedback != null && !feedback.isEmpty(); - } - - public Report getReport() { - return this.report; - } - - public String getFeedback() { - return this.feedback; - } - + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public String getDescription() { return this.description; } @@ -65,10 +65,21 @@ public class Criterion extends AbstractCriterion { return this.descriptionEn; } - public String getDescription(Language language) { - return language == Language.ENGLISH ? getDescriptionEn() : getDescription(); + public String getFeedback() { + return this.feedback; } + public void setFeedback(final String feedback) { + this.feedback = feedback; + } + + public Report getReport() { + return this.report; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -82,11 +93,6 @@ public class Criterion extends AbstractCriterion { && Objects.equals(this.getDescriptionEn(), other.getDescriptionEn()); } - @Override - protected boolean canEqual(final Object other) { - return other instanceof Criterion; - } - @Override public int hashCode() { return Objects.hash(this.getReport(), this.getFeedback(), this.getDescription(), this.getDescriptionEn()); @@ -94,6 +100,24 @@ public class Criterion extends AbstractCriterion { @Override public String toString() { - return "Criterion(report=" + this.getReport() + ", feedback=" + this.getFeedback() + ", description=" + this.getDescription() + ", descriptionEn=" + this.getDescriptionEn() + ")"; + return "Criterion(report=" + this.getReport() + ", feedback=" + this.getFeedback() + + ", description=" + this.getDescription() + ", descriptionEn=" + + this.getDescriptionEn() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + @Override + protected boolean canEqual(final Object other) { + return other instanceof Criterion; + } + + public String getDescription(Language language) { + return language == Language.ENGLISH ? getDescriptionEn() : getDescription(); + } + + public boolean isFilledOut() { + return feedback != null && !feedback.isEmpty(); } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java b/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java index 49d6b60097..385d4941f3 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.report; +import jakarta.persistence.Basic; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -8,18 +9,26 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; @Entity -@Table(name = "grading_report_template_grade_limits") +@Table(name = "grading_report_template_grade_limit") public class GradeLimit { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Basic @Column(name = "grade") private String grade; + @Basic @Column(name = "lower_limit") private int lowerLimit; + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java index aad898db4c..10ea7059b0 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java @@ -1,30 +1,57 @@ package se.su.dsv.scipro.report; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Entity; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @Entity -@DiscriminatorColumn(name = "type") +@Table(name = "grading_criterion") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "type") public abstract class GradingCriterion extends AbstractGradingCriterion { public static final int FEEDBACK_LENGTH = 2000; - @ManyToOne(optional = false) - private GradingReport gradingReport; - - @OneToMany(mappedBy = "gradingCriterion", orphanRemoval = true, cascade = CascadeType.PERSIST) - private List<GradingCriterionPoint> gradingCriterionPoints = new ArrayList<>(); - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Basic + @Column(name = "points") private Integer points; @Basic - @Column(length = FEEDBACK_LENGTH) + @Column(name = "feedback", length = FEEDBACK_LENGTH) private String feedback; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_criterion) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name = "grading_report_id", referencedColumnName = "id") + private GradingReport gradingReport; + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "grading_criterion" + // ---------------------------------------------------------------------------------- + @OneToMany(mappedBy = "gradingCriterion", orphanRemoval = true, cascade = CascadeType.PERSIST) + private List<GradingCriterionPoint> gradingCriterionPoints = new ArrayList<>(); + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected GradingCriterion() { // JPA } @@ -41,6 +68,71 @@ public abstract class GradingCriterion extends AbstractGradingCriterion { } } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + public Integer getPoints() { + return this.points; + } + + public void setPoints(Integer points) { + this.points = points; + } + + public String getFeedback() { + return this.feedback; + } + + public void setFeedback(String feedback) { + this.feedback = feedback; + } + + public List<GradingCriterionPoint> getGradingCriterionPoints() { + return this.gradingCriterionPoints; + } + + public GradingReport getGradingReport() { + return this.gradingReport; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof GradingCriterion)) return false; + final GradingCriterion other = (GradingCriterion) o; + return other.canEqual(this) + && super.equals(o) + && Objects.equals(this.getGradingReport(), other.getGradingReport()) + && Objects.equals(this.getPoints(), other.getPoints()) + && Objects.equals(this.getFeedback(), other.getFeedback()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), this.getGradingReport(), this.getPoints(), this.getFeedback()); + } + + @Override + public String toString() { + return "GradingCriterion(gradingReport=" + this.getGradingReport() + ", points=" + this.getPoints() + + ", feedback=" + this.getFeedback() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + @Override + protected boolean canEqual(final Object other) { + return other instanceof GradingCriterion; + } + + public boolean isPassFail() { + return getMaxPoints() == 1 && getPointsRequiredToPass() == 1; + } + public boolean meetsMinimumPointRequirement() { return Objects.requireNonNullElse(getPoints(), 0) >= getPointsRequiredToPass(); } @@ -57,59 +149,4 @@ public abstract class GradingCriterion extends AbstractGradingCriterion { public int getMaxPoints() { return Collections.max(gradingCriterionPoints).getPoint(); } - - public GradingReport getGradingReport() { - return this.gradingReport; - } - - public Integer getPoints() { - return this.points; - } - - public String getFeedback() { - return this.feedback; - } - - public List<GradingCriterionPoint> getGradingCriterionPoints() { - return this.gradingCriterionPoints; - } - - public void setPoints(Integer points) { - this.points = points; - } - - public void setFeedback(String feedback) { - this.feedback = feedback; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof GradingCriterion)) return false; - final GradingCriterion other = (GradingCriterion) o; - return other.canEqual(this) - && super.equals(o) - && Objects.equals(this.getGradingReport(), other.getGradingReport()) - && Objects.equals(this.getPoints(), other.getPoints()) - && Objects.equals(this.getFeedback(), other.getFeedback()); - } - - @Override - protected boolean canEqual(final Object other) { - return other instanceof GradingCriterion; - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), this.getGradingReport(), this.getPoints(), this.getFeedback()); - } - - @Override - public String toString() { - return "GradingCriterion(gradingReport=" + this.getGradingReport() + ", points=" + this.getPoints() + ", feedback=" + this.getFeedback() + ")"; - } - - public boolean isPassFail() { - return getMaxPoints() == 1 && getPointsRequiredToPass() == 1; - } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java index 5c8734af9b..6c516f95b4 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java @@ -1,37 +1,39 @@ package se.su.dsv.scipro.report; import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import java.util.Objects; @Entity -@Table(name = "GradingCriterionPoint") +@Table(name = "grading_criterion_point") public class GradingCriterionPoint extends AbstractGradingCriterionPoint { - + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_criterion_point) referencing other + // tables. + // ---------------------------------------------------------------------------------- @ManyToOne(optional = false) + @JoinColumn(name = "grading_criterion_id", referencedColumnName = "id") private GradingCriterion gradingCriterion; + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- public GradingCriterionPoint() { } - public GradingCriterionPoint( - final Integer point, - final String description, - final String descriptionEn, - final GradingCriterion gradingCriterion) - { + public GradingCriterionPoint(final Integer point, final String description, + final String descriptionEn, final GradingCriterion gradingCriterion) { setPoint(point); setDescription(description); setDescriptionEn(descriptionEn); this.gradingCriterion = gradingCriterion; } - @Override - public int compareTo(AbstractGradingCriterionPoint abstractGradingCriterionPoint) { - return this.getPoint().compareTo(abstractGradingCriterionPoint.getPoint()); - } - + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public GradingCriterion getGradingCriterion() { return this.gradingCriterion; } @@ -40,9 +42,12 @@ public class GradingCriterionPoint extends AbstractGradingCriterionPoint { this.gradingCriterion = gradingCriterion; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects and Comparable + // ---------------------------------------------------------------------------------- @Override - public String toString() { - return "GradingCriterionPoint(gradingCriterion=" + this.getGradingCriterion() + ")"; + public int compareTo(AbstractGradingCriterionPoint abstractGradingCriterionPoint) { + return this.getPoint().compareTo(abstractGradingCriterionPoint.getPoint()); } @Override @@ -55,13 +60,22 @@ public class GradingCriterionPoint extends AbstractGradingCriterionPoint { && Objects.equals(this.getGradingCriterion(), other.getGradingCriterion()); } + @Override + public int hashCode() { + return Objects.hashCode(this.getGradingCriterion()); + } + + @Override + public String toString() { + return "GradingCriterionPoint(gradingCriterion=" + this.getGradingCriterion() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- @Override protected boolean canEqual(final Object other) { return other instanceof GradingCriterionPoint; } - @Override - public int hashCode() { - return Objects.hashCode(this.getGradingCriterion()); - } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java index 88708ddf1d..a41785948a 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java @@ -1,8 +1,10 @@ package se.su.dsv.scipro.report; import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; + import java.util.Objects; @Entity @@ -10,6 +12,7 @@ import java.util.Objects; public class GradingCriterionPointTemplate extends AbstractGradingCriterionPoint { @ManyToOne(optional = false) + @JoinColumn(name = "grading_criterion_template_id", nullable = false) private GradingCriterionTemplate gradingCriterionTemplate; @Override diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java index 6feaee5bd8..92ab7539dc 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java @@ -1,18 +1,29 @@ package se.su.dsv.scipro.report; -import jakarta.persistence.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; +import jakarta.persistence.CascadeType; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Entity; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + @Entity -@DiscriminatorColumn(name = "type", length = GradingCriterionTemplate.LENGTH) -@Inheritance(strategy = InheritanceType.SINGLE_TABLE) @Table(name = "grading_criterion_template") +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "type", length = GradingCriterionTemplate.LENGTH) public abstract class GradingCriterionTemplate extends AbstractGradingCriterion { public static final int LENGTH = 64; + @ManyToOne(optional = false) + @JoinColumn(name = "grading_report_template_id") private GradingReportTemplate gradingReportTemplate; @OneToMany(mappedBy = "gradingCriterionTemplate", orphanRemoval = true, cascade = CascadeType.ALL) diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java index 0c036ede48..6957cae4d5 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java @@ -1,11 +1,19 @@ package se.su.dsv.scipro.report; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.Language; import se.su.dsv.scipro.system.ProjectType; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; @@ -13,6 +21,7 @@ import java.util.List; import java.util.stream.Collectors; @Entity +@Table(name = "grading_report") public abstract class GradingReport extends Report { public record Grade(String name) { @@ -27,40 +36,51 @@ public abstract class GradingReport extends Report { public enum State { INITIAL, REVIEWING, FINALIZED } + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- + @Basic + @Column(name = "state") @Enumerated(EnumType.STRING) private State state = State.INITIAL; - @ManyToOne(optional = false) - private Project project; - - @OneToMany(mappedBy = "gradingReport", cascade = {CascadeType.ALL}) - private List<GradingCriterion> gradingCriteria = new ArrayList<>(); - @Basic @Column(name = "date_submitted_to_examiner") private Instant dateSubmittedToExaminer; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_report) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + private Project project; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "grading_report" + // ---------------------------------------------------------------------------------- + @OneToMany(mappedBy = "gradingReport", cascade = {CascadeType.ALL}) + private List<GradingCriterion> gradingCriteria = new ArrayList<>(); + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected GradingReport() { // JPA } - @Override - public void submit() { - super.submit(); - setState(State.FINALIZED); - setDateSubmittedToExaminer(Instant.now()); - } - - public Project getProject() { - return project; - } - GradingReport(Project project) { this.project = project; } - void addCriterion(GradingCriterion criterion) { - gradingCriteria.add(criterion); + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + public State getState() { + return state; + } + + public void setState(final State state) { + this.state = state; } public Instant getDateSubmittedToExaminer(){ @@ -71,12 +91,8 @@ public abstract class GradingReport extends Report { this.dateSubmittedToExaminer = dateSubmittedToExaminer; } - public State getState() { - return state; - } - - public void setState(final State state) { - this.state = state; + public Project getProject() { + return project; } public List<GradingCriterion> getGradingCriteria() { @@ -84,6 +100,21 @@ public abstract class GradingReport extends Report { return Collections.unmodifiableList(gradingCriteria); } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public String toString() { + return "GradingReport(state=" + this.getState() + ", project=" + this.getProject() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + void addCriterion(GradingCriterion criterion) { + gradingCriteria.add(criterion); + } + public String getProjectTitle() { return project.getTitle(); } @@ -112,7 +143,9 @@ public abstract class GradingReport extends Report { } @Override - public String toString() { - return "GradingReport(state=" + this.getState() + ", project=" + this.getProject() + ")"; + public void submit() { + super.submit(); + setState(State.FINALIZED); + setDateSubmittedToExaminer(Instant.now()); } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java index 6f9b1a9824..876d3a4010 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.report; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition; import se.su.dsv.scipro.grading.GradingBasis; import se.su.dsv.scipro.grading.GradingReportTemplateService; @@ -48,6 +48,7 @@ public class GradingReportServiceImpl implements GradingReportTemplateService, G } @Override + @Transactional public boolean updateOppositionCriteria(SupervisorGradingReport report, FinalSeminarOpposition opposition) { for (GradingCriterion gradingCriterion : report.getIndividualCriteria()) { boolean isOppositionCriterion = gradingCriterion.getFlag() == GradingCriterion.Flag.OPPOSITION; @@ -133,6 +134,7 @@ public class GradingReportServiceImpl implements GradingReportTemplateService, G } @Override + @Transactional public List<SupervisorGradingReport> getSupervisorGradingReports(Project project) { List<SupervisorGradingReport> gradingReports = new ArrayList<>(); for (User user : project.getProjectParticipants()) { diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java index cc106b6c95..55fe04823b 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java @@ -1,17 +1,28 @@ package se.su.dsv.scipro.report; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.OrderBy; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.ProjectType; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; - import java.time.LocalDate; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -19,18 +30,16 @@ import java.util.Objects; @Table(name = "grading_report_template") public class GradingReportTemplate extends DomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne(optional = false) - private ProjectType projectType; - - @OneToMany(mappedBy = "gradingReportTemplate", cascade = {CascadeType.ALL}, orphanRemoval = true) - private Collection<GradingCriterionTemplate> criteria = new HashSet<>(); - - @Temporal(TemporalType.DATE) + @Basic @Column(name = "valid_from") + @Temporal(TemporalType.DATE) private LocalDate validFrom; @Basic @@ -41,10 +50,28 @@ public class GradingReportTemplate extends DomainObject { @Column(name = "failing_grade") private String failingGrade; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_report_template) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @OneToOne(optional = false) + @JoinColumn(name = "project_type_id", referencedColumnName = "id") + private ProjectType projectType; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "grading_report_template" + // ---------------------------------------------------------------------------------- + @OneToMany(mappedBy = "gradingReportTemplate", cascade = {CascadeType.ALL}, orphanRemoval = true) + @OrderBy("sortOrder ASC") + private List<GradingCriterionTemplate> criteria = new ArrayList<>(); + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "grading_report_template_id") + @JoinColumn(name = "grading_report_template_id", referencedColumnName = "id") private Collection<GradeLimit> gradeLimits = new ArrayList<>(); + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected GradingReportTemplate() { } @@ -57,43 +84,9 @@ public class GradingReportTemplate extends DomainObject { this.validFrom = validFrom; } - public SupervisorGradingReport createSupervisorReport(Project project, User student) { - if (!this.projectType.equals(project.getProjectType())) { - throw new IllegalArgumentException("Project has a different project class than this template"); - } - return new SupervisorGradingReportFactory().using(criteria).create(project, student); - } - - public OppositionReport createOppositionReport(FinalSeminarOpposition finalSeminarOpposition) { - return new OppositionReport(this, finalSeminarOpposition); - } - - public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) { - return addProjectCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null); - } - - public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates, AbstractGradingCriterion.Flag flag) { - GradingCriterionTemplate gradingCriterionTemplate = new ProjectGradingCriterionTemplate(this, criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates); - gradingCriterionTemplate.setFlag(flag); - criteria.add(gradingCriterionTemplate); - return gradingCriterionTemplate; - } - - public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) { - return addIndividualCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null); - } - - public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates, AbstractGradingCriterion.Flag flag) { - GradingCriterionTemplate gradingCriterionTemplate = new IndividualGradingCriterionTemplate(this, criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates); - gradingCriterionTemplate.setFlag(flag); - criteria.add(gradingCriterionTemplate); - return gradingCriterionTemplate; - } - - public Collection<GradingCriterionTemplate> getCriteria() { - return criteria; - } - + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; @@ -107,14 +100,6 @@ public class GradingReportTemplate extends DomainObject { this.validFrom = validFrom; } - public ProjectType getProjectType() { - return projectType; - } - - public void setProjectType(ProjectType projectType) { - this.projectType = projectType; - } - public String getNote() { return note; } @@ -131,6 +116,18 @@ public class GradingReportTemplate extends DomainObject { this.failingGrade = failingGrade; } + public ProjectType getProjectType() { + return projectType; + } + + public void setProjectType(ProjectType projectType) { + this.projectType = projectType; + } + + public Collection<GradingCriterionTemplate> getCriteria() { + return criteria; + } + public Collection<GradeLimit> getGradeLimits() { return gradeLimits; } @@ -139,6 +136,9 @@ public class GradingReportTemplate extends DomainObject { this.gradeLimits = gradeLimits; } + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -148,10 +148,6 @@ public class GradingReportTemplate extends DomainObject { && Objects.equals(this.id, other.id); } - protected boolean canEqual(final Object other) { - return other instanceof GradingReportTemplate; - } - @Override public int hashCode() { return Objects.hashCode(this.id); @@ -159,6 +155,56 @@ public class GradingReportTemplate extends DomainObject { @Override public String toString() { - return "GradingReportTemplate(id=" + this.id + ", projectType=" + this.projectType + ", validFrom=" + this.validFrom + ")"; + return "GradingReportTemplate(id=" + this.id + ", projectType=" + this.projectType + ", validFrom=" + + this.validFrom + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + public SupervisorGradingReport createSupervisorReport(Project project, User student) { + if (!this.projectType.equals(project.getProjectType())) { + throw new IllegalArgumentException("Project has a different project class than this template"); + } + return new SupervisorGradingReportFactory().using(criteria).create(project, student); + } + + public OppositionReport createOppositionReport(FinalSeminarOpposition finalSeminarOpposition) { + return new OppositionReport(this, finalSeminarOpposition); + } + + public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass, + List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) { + return addProjectCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null); + } + + public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass, + List<GradingCriterionPointTemplate> gradingCriterionPointTemplates, + AbstractGradingCriterion.Flag flag) { + GradingCriterionTemplate gradingCriterionTemplate = new ProjectGradingCriterionTemplate(this, + criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates); + gradingCriterionTemplate.setFlag(flag); + criteria.add(gradingCriterionTemplate); + return gradingCriterionTemplate; + } + + public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass, + List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) { + return addIndividualCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null); + } + + public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass, + List<GradingCriterionPointTemplate> gradingCriterionPointTemplates, + AbstractGradingCriterion.Flag flag) { + GradingCriterionTemplate gradingCriterionTemplate = new IndividualGradingCriterionTemplate(this, + criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates); + gradingCriterionTemplate.setFlag(flag); + criteria.add(gradingCriterionTemplate); + return gradingCriterionTemplate; + } + + + protected boolean canEqual(final Object other) { + return other instanceof GradingReportTemplate; } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java index 8cf96941a1..7eec180ce5 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java @@ -1,8 +1,8 @@ package se.su.dsv.scipro.report; -import com.google.inject.persist.Transactional; import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.JPQLQuery; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.grading.GradingReportTemplateUpdate; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.GenericRepo; diff --git a/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java b/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java index 5775a6db0b..426e393399 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java +++ b/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java @@ -1,10 +1,17 @@ package se.su.dsv.scipro.report; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition; import se.su.dsv.scipro.system.Language; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -15,56 +22,57 @@ import java.util.stream.Collectors; @Table(name = "opposition_report") public class OppositionReport extends AttachmentReport { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- + @Basic + @Column(name = "thesis_summary") + private String thesisSummary; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (opposition_report) referencing other + // tables. + // ---------------------------------------------------------------------------------- @OneToOne(optional = false) + @JoinColumn(name = "final_seminar_opposition_id", referencedColumnName = "id") private FinalSeminarOpposition finalSeminarOpposition; + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "opposition_report" + // ---------------------------------------------------------------------------------- @OneToMany(mappedBy = "report", cascade = {CascadeType.ALL}) private List<Criterion> oppositionCriteria = new ArrayList<>(); - @Basic - @Column - private String thesisSummary; - - + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected OppositionReport() { - } - public OppositionReport(GradingReportTemplate gradingReportTemplate, FinalSeminarOpposition finalSeminarOpposition) { + public OppositionReport(GradingReportTemplate gradingReportTemplate, + FinalSeminarOpposition finalSeminarOpposition) { this.finalSeminarOpposition = finalSeminarOpposition; createCriteriaFromTemplate(gradingReportTemplate); } - private void createCriteriaFromTemplate(GradingReportTemplate gradingReportTemplate) { - for (GradingCriterionTemplate template : gradingReportTemplate.getCriteria()) { - if (template.isProjectCriterion()) { - oppositionCriteria.add(new Criterion(this, template)); - } - } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + public String getThesisSummary() { + return this.thesisSummary; } - public List<Criterion> getCriteria() { - oppositionCriteria.sort(new AbstractCriterion.BySortOrderComparator()); - return Collections.unmodifiableList(oppositionCriteria); + public void setThesisSummary(String thesisSummary) { + this.thesisSummary = thesisSummary; } - @Override - public boolean isFinished() { - if (thesisSummaryIsEmpty()) { - return false; - } - for (Criterion criterion : oppositionCriteria) { - if (!criterion.isFilledOut()) { - return false; - } - } - return true; - } - - private boolean thesisSummaryIsEmpty() { - return thesisSummary == null || thesisSummary.isEmpty(); + public FinalSeminarOpposition getFinalSeminarOpposition() { + return this.finalSeminarOpposition; } + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- public User getUser() { return finalSeminarOpposition.getUser(); } @@ -110,15 +118,33 @@ public class OppositionReport extends AttachmentReport { return finalSeminarOpposition.getUser().getLastName(); } - public FinalSeminarOpposition getFinalSeminarOpposition() { - return this.finalSeminarOpposition; + private void createCriteriaFromTemplate(GradingReportTemplate gradingReportTemplate) { + for (GradingCriterionTemplate template : gradingReportTemplate.getCriteria()) { + if (template.isProjectCriterion()) { + oppositionCriteria.add(new Criterion(this, template)); + } + } } - public String getThesisSummary() { - return this.thesisSummary; + public List<Criterion> getCriteria() { + oppositionCriteria.sort(new AbstractCriterion.BySortOrderComparator()); + return Collections.unmodifiableList(oppositionCriteria); } - public void setThesisSummary(String thesisSummary) { - this.thesisSummary = thesisSummary; + @Override + public boolean isFinished() { + if (thesisSummaryIsEmpty()) { + return false; + } + for (Criterion criterion : oppositionCriteria) { + if (!criterion.isFilledOut()) { + return false; + } + } + return true; + } + + private boolean thesisSummaryIsEmpty() { + return thesisSummary == null || thesisSummary.isEmpty(); } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java index 417e7a15bf..231fe6f692 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.report; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition; diff --git a/core/src/main/java/se/su/dsv/scipro/report/Report.java b/core/src/main/java/se/su/dsv/scipro/report/Report.java index dd1437fc18..da88711b3b 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/Report.java +++ b/core/src/main/java/se/su/dsv/scipro/report/Report.java @@ -1,48 +1,36 @@ package se.su.dsv.scipro.report; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.Table; import se.su.dsv.scipro.system.DomainObject; -import jakarta.persistence.*; import java.util.Objects; @Entity @Table(name = "report") @Inheritance(strategy = InheritanceType.JOINED) public abstract class Report extends DomainObject { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Basic(optional = false) + @Column(name = "submitted") private boolean submitted = false; - public abstract boolean isFinished(); - - public void submit() { - if (!isFinished()) { - throw new IllegalStateException("Report is not finished: you need to score and give feedback to every criteria"); - } - submitted = true; - } - - @Override - public boolean equals(final Object o) { - if (o == this) return true; - if (!(o instanceof Report)) return false; - final Report other = (Report) o; - return other.canEqual(this) - && Objects.equals(this.id, other.id); - } - - protected boolean canEqual(final Object other) { - return other instanceof Report; - } - - @Override - public int hashCode() { - return Objects.hashCode(this.id); - } - + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; @@ -55,4 +43,37 @@ public abstract class Report extends DomainObject { public void setSubmitted(boolean submitted) { this.submitted = submitted; } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- + @Override + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof Report)) return false; + final Report other = (Report) o; + return other.canEqual(this) + && Objects.equals(this.id, other.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(this.id); + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof Report; + } + + public abstract boolean isFinished(); + + public void submit() { + if (!isFinished()) { + throw new IllegalStateException("Report is not finished: you need to score and give feedback to every criteria"); + } + submitted = true; + } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java index f8ba6bd969..a0f324029f 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.report; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; import se.su.dsv.scipro.file.FileUpload; @@ -22,12 +22,14 @@ public class ReportServiceImpl extends AbstractServiceImpl<Report, Long> impleme } @Override + @Transactional public AttachmentReport submit(AttachmentReport report) { report.submit(); return save(report); } @Override + @Transactional public void save(AttachmentReport report, Optional<FileUpload> fileUpload) { storeReportFile(report, fileUpload); save(report); diff --git a/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java b/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java index b3e682dfba..59b4bca6b8 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java +++ b/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java @@ -1,26 +1,24 @@ package se.su.dsv.scipro.report; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import se.su.dsv.scipro.project.Project; -import se.su.dsv.scipro.system.User; - import jakarta.persistence.Basic; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.system.User; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @Entity +@Table(name = "supervisor_grading_report") public class SupervisorGradingReport extends GradingReport { - - private static final Logger LOG = LoggerFactory.getLogger(SupervisorGradingReport.class); - - @ManyToOne(optional = false) - private User user; - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Basic @Column(name = "rejection_comment") private String rejectionComment; @@ -33,6 +31,17 @@ public class SupervisorGradingReport extends GradingReport { @Column(name = "motivation") private String motivation; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (grading_criterion) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected SupervisorGradingReport() { // JPA } @@ -42,6 +51,40 @@ public class SupervisorGradingReport extends GradingReport { this.user = user; } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + public User getUser() { + return this.user; + } + + public String getRejectionComment() { + return rejectionComment; + } + + public void setRejectionComment(String rejectionComment) { + this.rejectionComment = rejectionComment; + } + + public String getRejectionCommentFeedback() { + return rejectionCommentFeedback; + } + + public void setRejectionCommentFeedback(String rejectionCommentFeedback) { + this.rejectionCommentFeedback = rejectionCommentFeedback; + } + + public String getMotivation() { + return motivation; + } + + public void setMotivation(String motivation) { + this.motivation = motivation; + } + + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- public List<GradingCriterion> getProjectCriteria() { List<GradingCriterion> result = new ArrayList<>(); for (GradingCriterion criterion : getGradingCriteria()) { @@ -82,34 +125,6 @@ public class SupervisorGradingReport extends GradingReport { return true; } - public User getUser() { - return this.user; - } - - public String getRejectionComment() { - return rejectionComment; - } - - public void setRejectionComment(String rejectionComment) { - this.rejectionComment = rejectionComment; - } - - public String getRejectionCommentFeedback() { - return rejectionCommentFeedback; - } - - public void setRejectionCommentFeedback(String rejectionCommentFeedback) { - this.rejectionCommentFeedback = rejectionCommentFeedback; - } - - public String getMotivation() { - return motivation; - } - - public void setMotivation(String motivation) { - this.motivation = motivation; - } - public boolean hasProvidedOverallMotivation() { return getMotivation() != null && !getMotivation().isBlank(); } diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java b/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java index cc255a893e..6d3fb25f16 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java @@ -20,51 +20,73 @@ import se.su.dsv.scipro.system.User; import java.time.Instant; import java.time.LocalDate; -import java.util.*; +import java.util.Date; +import java.util.Optional; @Entity -@Table(name = "Decision") +@Table(name = "decision") public class Decision { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Basic + @Column(name = "status") @Enumerated(EnumType.STRING) private Status status = Status.UNDECIDED; - @OneToOne(optional = false) - @JoinColumn(name = "thesis_reference_id") - private FileReference thesis; - @Basic + @Column(name = "reason") private String reason; @Basic + @Column(name = "comment") private String comment; - @OneToOne(optional = true) - @JoinColumn(name = "attachment_reference_id") - private FileReference attachment; - + @Basic + @Column(name = "requested_date") @Temporal(TemporalType.TIMESTAMP) private Date requested; - @Temporal(TemporalType.TIMESTAMP) - private Date deadline; - + @Basic + @Column(name = "decision_date") @Temporal(TemporalType.TIMESTAMP) private Date decisionDate; - @ManyToOne(optional = false) - private ReviewerApproval reviewerApproval; - - @ManyToOne - @JoinColumn(name = "assigned_reviewer_id") - private User assignedReviewer; + @Basic + @Column(name = "deadline") + @Temporal(TemporalType.TIMESTAMP) + private Date deadline; + @Basic @Column(name = "assigned_reviewer_date") private LocalDate reviewerAssignedAt; + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (decision) referencing other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne + @JoinColumn(name = "assigned_reviewer_id", referencedColumnName = "id") + private User assignedReviewer; + + @OneToOne(optional = true) + @JoinColumn(name = "attachment_reference_id", referencedColumnName = "id") + private FileReference attachment; + + @ManyToOne(optional = false) + @JoinColumn(name = "reviewer_approval_id", referencedColumnName = "id") + private ReviewerApproval reviewerApproval; + + @OneToOne(optional = false) + @JoinColumn(name = "thesis_reference_id", referencedColumnName = "id") + private FileReference thesis; + + // ---------------------------------------------------------------------------------- + // Constructors + // ---------------------------------------------------------------------------------- protected Decision() {} // JPA Decision(ReviewerApproval reviewerApproval, final FileReference thesis, final String comment, final Date deadline) { @@ -79,6 +101,9 @@ public class Decision { this.comment = comment; } + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- public Long getId() { return id; } @@ -87,14 +112,6 @@ public class Decision { this.id = id; } - public FileReference getThesis() { - return thesis; - } - - public ReviewerApproval getReviewerApproval() { - return reviewerApproval; - } - public Status getStatus() { return status; } @@ -107,10 +124,6 @@ public class Decision { return comment; } - public Optional<FileReference> getAttachment() { - return Optional.ofNullable(attachment); - } - public Date getRequested() { return requested; } @@ -127,14 +140,6 @@ public class Decision { this.deadline = deadline; } - public User getAssignedReviewer() { - return assignedReviewer; - } - - public void setAssignedReviewer(User assignedReviewer) { - this.assignedReviewer = assignedReviewer; - } - public LocalDate getReviewerAssignedAt() { return reviewerAssignedAt; } @@ -143,6 +148,29 @@ public class Decision { this.reviewerAssignedAt = reviewerAssignedAt; } + public User getAssignedReviewer() { + return assignedReviewer; + } + + public void setAssignedReviewer(User assignedReviewer) { + this.assignedReviewer = assignedReviewer; + } + + public Optional<FileReference> getAttachment() { + return Optional.ofNullable(attachment); + } + + public ReviewerApproval getReviewerApproval() { + return reviewerApproval; + } + + public FileReference getThesis() { + return thesis; + } + + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- void approve(final String reason, final Optional<FileReference> attachment) { decide(Status.APPROVED, reason, attachment); } diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java index 5d8e123342..fec755260c 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.reviewing; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; import se.su.dsv.scipro.file.FileUpload; diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java index 736c9d4120..9a5239e570 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java @@ -27,7 +27,7 @@ import static com.querydsl.core.types.dsl.Expressions.anyOf; public class ProjectFinalSeminarStatisticsServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectFinalSeminarStatisticsService { @Inject - protected ProjectFinalSeminarStatisticsServiceImpl(Provider<EntityManager> em) { + public ProjectFinalSeminarStatisticsServiceImpl(Provider<EntityManager> em) { super(em, Project.class, QProject.project); } diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java index 25c63338aa..cdad680797 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java @@ -1,6 +1,8 @@ package se.su.dsv.scipro.reviewing; import jakarta.persistence.GenerationType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Table; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; @@ -13,31 +15,61 @@ import jakarta.persistence.Id; import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.OrderBy; -import java.util.*; + +import java.util.Collections; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; @Entity +@Table(name = "reviewer_approval") @DiscriminatorColumn(name = "type", length = 64) public abstract class ReviewerApproval extends DomainObject { - @OneToOne(optional = false) - protected Project project; - - @OneToMany(mappedBy = "reviewerApproval", cascade = CascadeType.ALL) - @OrderBy("requested desc") - protected List<Decision> decisions = new LinkedList<>(); - + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - public abstract Step getStep(); + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (reviewer_approval) referencing other + // tables. + // ---------------------------------------------------------------------------------- + @OneToOne(optional = false) + @JoinColumn(name = "project_id", referencedColumnName = "id") + protected Project project; - public FileReference getCurrentThesis() { - return getCurrentDecision().getThesis(); + // ---------------------------------------------------------------------------------- + // JPA-mappings of other tables referencing to this table "reviewer_approval" + // ---------------------------------------------------------------------------------- + @OneToMany(mappedBy = "reviewerApproval", cascade = CascadeType.ALL) + @OrderBy("requested desc") + protected List<Decision> decisions = new LinkedList<>(); + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- + @Override + public Long getId() { + return this.id; } public Project getProject(){return this.project;} + // ---------------------------------------------------------------------------------- + // Other methods + // ---------------------------------------------------------------------------------- + public abstract Step getStep(); + public Decision getCurrentDecision() { + return decisions.get(0); + } + + public FileReference getCurrentThesis() { + return getCurrentDecision().getThesis(); + } public Status getCurrentStatus() { return getCurrentDecision().getStatus(); @@ -63,10 +95,6 @@ public abstract class ReviewerApproval extends DomainObject { getCurrentDecision().reject(reason, attachment); } - public Decision getCurrentDecision() { - return decisions.get(0); - } - public void addNewThesis(final FileReference thesis, final String comment, final Date deadline) { if (getCurrentStatus() != Status.REJECTED) { throw new IllegalStateException(); @@ -86,17 +114,15 @@ public abstract class ReviewerApproval extends DomainObject { return getCurrentStatus() == Status.APPROVED; } - @Override - public Long getId() { - return this.id; + public Date getCurrentDeadline() { + return getCurrentDecision().getDeadline(); } + // ---------------------------------------------------------------------------------- + // Nested types. + // ---------------------------------------------------------------------------------- public enum Step { ROUGH_DRAFT_APPROVAL, FINAL_SEMINAR_APPROVAL } - - public Date getCurrentDeadline() { - return getCurrentDecision().getDeadline(); - } } diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java index c758523db5..08e67aa38b 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.reviewing; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.project.ProjectService; import se.su.dsv.scipro.project.ReviewerAssignedEvent; @@ -25,7 +25,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Stream; -class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAssignmentService { +public class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAssignmentService { private final ReviewerTargetRepository reviewerTargetRepository; private final DecisionRepository decisionRepository; private final UserService userService; @@ -33,7 +33,7 @@ class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAs private final EventBus eventBus; @Inject - ReviewerCapacityServiceImpl( + public ReviewerCapacityServiceImpl( ReviewerTargetRepository reviewerTargetRepository, DecisionRepository decisionRepository, UserService userService, diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java index 3b200eac44..044ada8fb5 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java @@ -13,13 +13,13 @@ public class ReviewerDeadlineSettings extends DomainObject { @Id private Long id = null; - @Basic(optional = false) + @Column(name = "rough_draft_approval", nullable = false) private int roughDraftApproval = 5; - @Basic(optional = false) + @Column(name = "final_seminar_approval", nullable = false) private int finalSeminarApproval = 2; - @Basic(optional = false) + @Column(name = "final_grading", nullable = false) private int finalGrading = 5; public ReviewerDeadlineSettings() { diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java index 0094b9e7dc..e95b191bb8 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.reviewing; -interface ReviewerDeadlineSettingsRepository { +public interface ReviewerDeadlineSettingsRepository { ReviewerDeadlineSettings findOne(long instanceId); ReviewerDeadlineSettings save(ReviewerDeadlineSettings entity); diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java index bcaf1e434e..6839c0cac5 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java @@ -6,12 +6,12 @@ import se.su.dsv.scipro.system.AbstractRepository; import jakarta.inject.Inject; import jakarta.inject.Provider; -class ReviewerDeadlineSettingsRepositoryImpl +public class ReviewerDeadlineSettingsRepositoryImpl extends AbstractRepository implements ReviewerDeadlineSettingsRepository { @Inject - ReviewerDeadlineSettingsRepositoryImpl(Provider<EntityManager> em) { + public ReviewerDeadlineSettingsRepositoryImpl(Provider<EntityManager> em) { super(em); } diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java index e52d28d078..3f0db387dd 100755 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.reviewing; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.inject.Inject; diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java index 0079e40a2b..f0e62aacc6 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.reviewing; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.forum.Attachment; import se.su.dsv.scipro.forum.BasicForumService; import se.su.dsv.scipro.forum.dataobjects.ForumPost; @@ -49,6 +49,7 @@ public class ReviewerInteractionServiceImpl implements ReviewerInteractionServic } @Override + @Transactional public ForumPost reply(final Project project, final User user, final String content, final Set<Attachment> attachments) { ReviewerThread reviewerThread = getReviewerThread(project); ForumPost reply = forumService.createReply(reviewerThread.getForumThread(), user, content, attachments); diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java index 4a8b145f2e..29803d920f 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java @@ -1,5 +1,6 @@ package se.su.dsv.scipro.reviewing; +import jakarta.persistence.Basic; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -10,7 +11,6 @@ import jakarta.persistence.Table; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import java.time.LocalDate; import java.util.Objects; @Entity @@ -20,22 +20,26 @@ public class ReviewerTarget extends DomainObject { @GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY) private Long id; - @ManyToOne(optional = false) - @JoinColumn(name = "reviewer_id", nullable = false) - private User reviewer; - + @Basic @Column(name = "year", nullable = false) private int year; + @Basic @Column(name = "spring", nullable = false) private int spring; + @Basic @Column(name = "autumn", nullable = false) private int autumn; + @Basic @Column(name = "note") private String note; + @ManyToOne(optional = false) + @JoinColumn(name = "reviewer_user_id", referencedColumnName = "id", nullable = false) + private User reviewer; + @Override public Long getId() { return id; diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java index 985ae1934b..ba1b9b961c 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.reviewing; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.persistence.EntityManager; import se.su.dsv.scipro.system.AbstractRepository; import se.su.dsv.scipro.system.User; diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingModule.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingModule.java deleted file mode 100644 index 9a0d1d53f7..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingModule.java +++ /dev/null @@ -1,25 +0,0 @@ -package se.su.dsv.scipro.reviewing; - -import com.google.inject.AbstractModule; -import se.su.dsv.scipro.file.FileService; - -import jakarta.persistence.EntityManager; - -public class ReviewingModule extends AbstractModule { - @Override - protected void configure() { - requireBinding(FileService.class); - requireBinding(EntityManager.class); - bind(ReviewerThreadRepository.class).to(ReviewerThreadRepositoryImpl.class); - bind(ReviewerInteractionService.class).to(ReviewerInteractionServiceImpl.class); - bind(FinalSeminarApprovalService.class).to(FinalSeminarApprovalServiceImpl.class); - bind(MyReviewService.class).to(ReviewingServiceImpl.class); - bind(ReviewerDecisionService.class).to(ReviewingServiceImpl.class); - bind(RoughDraftApprovalService.class).to(RoughDraftApprovalServiceImpl.class); - bind(ReviewerDeadlineSettingsService.class).to(ReviewerDeadlineSettingsServiceImpl.class); - bind(ReviewerDeadlineSettingsRepository.class).to(ReviewerDeadlineSettingsRepositoryImpl.class); - bind(ReviewerDeadlineFollowupService.class).to(ReviewerDeadlineFollowupServiceImpl.class); - bind(ReviewerCapacityService.class).to(ReviewerCapacityServiceImpl.class); - bind(ReviewerAssignmentService.class).to(ReviewerCapacityServiceImpl.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java index 9087510e37..b56e733c68 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java @@ -7,6 +7,7 @@ import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.LiteralExpression; import com.querydsl.jpa.impl.JPAQuery; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; import se.su.dsv.scipro.file.FileUpload; @@ -92,6 +93,7 @@ public class ReviewingServiceImpl extends AbstractServiceImpl<ReviewerApproval, } @Override + @Transactional public void reject(final ReviewerApproval reviewerApproval, final String reason, final Optional<FileUpload> feedback) { Optional<FileReference> feedbackFile = store(feedback); reviewerApproval.reject(reason, feedbackFile); @@ -106,6 +108,7 @@ public class ReviewingServiceImpl extends AbstractServiceImpl<ReviewerApproval, } @Override + @Transactional public void approve(final ReviewerApproval process, final String reason, final Optional<FileUpload> feedback) { Optional<FileReference> feedbackFile = store(feedback); process.approve(reason, feedbackFile); diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java index fea26c83d6..f7a4365b24 100644 --- a/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java @@ -1,7 +1,7 @@ package se.su.dsv.scipro.reviewing; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.file.FileReference; import se.su.dsv.scipro.file.FileService; import se.su.dsv.scipro.file.FileUpload; diff --git a/core/src/main/java/se/su/dsv/scipro/security/auth/AuthenticationModule.java b/core/src/main/java/se/su/dsv/scipro/security/auth/AuthenticationModule.java deleted file mode 100644 index 3598358043..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/security/auth/AuthenticationModule.java +++ /dev/null @@ -1,15 +0,0 @@ -package se.su.dsv.scipro.security.auth; - -import com.google.inject.AbstractModule; -import com.google.inject.multibindings.Multibinder; - -public class AuthenticationModule extends AbstractModule { - @Override - protected void configure() { - bind(AuthenticationService.class).to(AuthenticationServiceImpl.class); - - Multibinder<AuthenticationProvider> authenticationProviders - = Multibinder.newSetBinder(binder(), AuthenticationProvider.class); - authenticationProviders.addBinding().to(LocalAuthentication.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java index ac863a2afa..e88c4b289b 100644 --- a/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java +++ b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java @@ -1,5 +1,26 @@ package se.su.dsv.scipro.settings.dataobjects; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.Objects; + +import jakarta.persistence.Basic; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + import se.su.dsv.scipro.project.ProjectStatus; import se.su.dsv.scipro.project.ProjectTeamMemberRoles; import se.su.dsv.scipro.security.auth.roles.Roles; @@ -7,12 +28,6 @@ import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.ProjectType; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Objects; - @Entity @Table(name = "user_profile") public class UserProfile extends DomainObject { @@ -24,40 +39,46 @@ public class UserProfile extends DomainObject { @OneToOne(optional = false) private User user; - @Basic(optional = true) - private String skypeId; - - @Basic(optional = true) - private String phoneNumber; - - @Basic(optional = true) + @Column(name = "other_info", nullable = true) private String otherInfo; - @Basic(optional = false) + @Column(name = "phone_number", nullable = true) + private String phoneNumber; + + @Column(name = "skype_id", nullable = true) + private String skypeId; + + @Column(name = "mail_compilation", nullable = false) private boolean mailCompilation = false; + @Column(name = "default_supervisor_filter", nullable = false) + private boolean defaultSupervisorFilter = true; + + @Enumerated(EnumType.STRING) + @Column(name = "selected_role") + private Roles selectedRole; + @ElementCollection @Enumerated(EnumType.STRING) + @CollectionTable(name = "user_profile_default_project_status_filter", + joinColumns = @JoinColumn(name = "user_profile_id", referencedColumnName = "id")) + @Column(name = "default_project_status_filter") private Collection<ProjectStatus> defaultProjectStatusFilter = EnumSet.of(ProjectStatus.ACTIVE); @ElementCollection @Enumerated(EnumType.STRING) + @CollectionTable(name = "user_profile_default_project_team_member_roles_filter", + joinColumns = @JoinColumn(name = "user_profile_id", referencedColumnName = "id")) + @Column(name = "default_project_team_member_roles_filter") private Collection<ProjectTeamMemberRoles> defaultProjectTeamMemberRolesFilter = EnumSet.of(ProjectTeamMemberRoles.CO_SUPERVISOR); - @Basic(optional = false) - private boolean defaultSupervisorFilter = true; - @ManyToMany - @JoinTable( - name = "user_profile_ProjectType", - joinColumns = {@JoinColumn(name = "user_profile_id")} + @JoinTable(name = "user_profile_project_type", + joinColumns = @JoinColumn(name = "user_profile_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "project_type_id", referencedColumnName = "id") ) private Collection<ProjectType> defaultProjectTypeFilter = new ArrayList<>(); - @Basic - @Enumerated(EnumType.STRING) - private Roles selectedRole; - @Basic @Enumerated(EnumType.STRING) @Column(name = "supervisor_project_note_display") diff --git a/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java index a89512dab1..992aa54888 100644 --- a/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.springdata.serviceimpls; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.security.auth.roles.Roles; import se.su.dsv.scipro.settings.dataobjects.QUserProfile; import se.su.dsv.scipro.settings.dataobjects.UserProfile; @@ -38,11 +38,13 @@ public class UserProfileServiceImpl extends AbstractServiceImpl<UserProfile, Lon } @Override + @Transactional public Roles findSelectedRole(User user) { return findByUser(user).getSelectedRole(); } @Override + @Transactional public void setSelectedRole(User user, Roles role) { UserProfile profile = findByUser(user); profile.setSelectedRole(role); diff --git a/core/src/main/java/se/su/dsv/scipro/sukat/SukatModule.java b/core/src/main/java/se/su/dsv/scipro/sukat/SukatModule.java deleted file mode 100644 index 544a17ec39..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/sukat/SukatModule.java +++ /dev/null @@ -1,10 +0,0 @@ -package se.su.dsv.scipro.sukat; - -import com.google.inject.AbstractModule; - -public class SukatModule extends AbstractModule { - @Override - protected void configure() { - bind(Sukat.class).to(LDAP.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/survey/Question.java b/core/src/main/java/se/su/dsv/scipro/survey/Question.java index 4097ad1283..4c2d6e4a73 100644 --- a/core/src/main/java/se/su/dsv/scipro/survey/Question.java +++ b/core/src/main/java/se/su/dsv/scipro/survey/Question.java @@ -1,11 +1,23 @@ package se.su.dsv.scipro.survey; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Table; + import java.io.Serializable; import java.util.LinkedList; import java.util.List; @Entity +@Table(name = "question") public class Question implements Serializable { public enum Type { TEXT, SINGLE_CHOICE, MULTIPLE_CHOICE, GROUP_HEADING } @@ -20,6 +32,9 @@ public class Question implements Serializable { private String text; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "question_choices", + joinColumns = @JoinColumn(name = "question_id", referencedColumnName = "id")) + @Column(name = "choices") private List<String> choices = new LinkedList<>(); private Type type = Type.TEXT; diff --git a/core/src/main/java/se/su/dsv/scipro/survey/Survey.java b/core/src/main/java/se/su/dsv/scipro/survey/Survey.java index 01b44b7e1d..9c9621ec02 100644 --- a/core/src/main/java/se/su/dsv/scipro/survey/Survey.java +++ b/core/src/main/java/se/su/dsv/scipro/survey/Survey.java @@ -1,14 +1,23 @@ package se.su.dsv.scipro.survey; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.io.Serializable; import java.util.LinkedList; import java.util.List; @Entity +@Table(name = "survey") public class Survey implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java b/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java index 0deab2b69b..f8d94e7ab9 100644 --- a/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java +++ b/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java @@ -6,7 +6,7 @@ import java.util.Set; import java.util.TreeSet; @Entity -@Table +@Table(name = "survey_answer") public class SurveyAnswer implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -21,6 +21,9 @@ public class SurveyAnswer implements Serializable { private String answer; @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "survey_answer_multiple_answers", + joinColumns = @JoinColumn(name = "survey_answer_id", referencedColumnName = "id")) + @Column(name = "multiple_answers") private Set<String> multipleAnswers = new TreeSet<>(); public Survey getSurvey() { diff --git a/core/src/main/java/se/su/dsv/scipro/survey/SurveyModule.java b/core/src/main/java/se/su/dsv/scipro/survey/SurveyModule.java deleted file mode 100644 index 54a6c83c92..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/survey/SurveyModule.java +++ /dev/null @@ -1,17 +0,0 @@ -package se.su.dsv.scipro.survey; - -import com.google.inject.AbstractModule; -import se.su.dsv.scipro.finalthesis.FinalThesisService; - -import jakarta.persistence.EntityManager; - -public class SurveyModule extends AbstractModule { - @Override - protected void configure() { - requireBinding(EntityManager.class); - requireBinding(FinalThesisService.class); - bind(SurveyRepository.class).to(SurveyRepositoryImpl.class); - bind(QuestionRepository.class).to(QuestionRepositoryImpl.class); - bind(SurveyService.class).to(SurveyServiceImpl.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java index ecb7c22070..386c771880 100644 --- a/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.survey; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.finalthesis.FinalThesisService; import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettings; import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; diff --git a/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java index 748940900e..f6d52a414b 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.EntityPathBase; import com.querydsl.core.types.dsl.Expressions; diff --git a/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java b/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java index bb414d678c..ebcdbb5627 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java +++ b/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java @@ -8,10 +8,10 @@ import java.util.Objects; @MappedSuperclass public abstract class DomainObject implements Serializable { - @Basic(optional=false) + @Column(name = "date_created", nullable = false) private Date dateCreated = new Date(); - @Basic(optional = false) + @Column(name = "last_modified", nullable = false) private Date lastModified = new Date(); @Version diff --git a/core/src/main/java/se/su/dsv/scipro/system/Event.java b/core/src/main/java/se/su/dsv/scipro/system/Event.java index 76abc8f2bb..be417ccb9a 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/Event.java +++ b/core/src/main/java/se/su/dsv/scipro/system/Event.java @@ -1,22 +1,36 @@ package se.su.dsv.scipro.system; import jakarta.persistence.Basic; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.Table; + import java.io.Serializable; import java.util.Objects; @Entity +@Table(name = "event") public class Event implements Serializable { + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- @Id private String name; @Basic + @Column(name = "description") private String description; + // ---------------------------------------------------------------------------------- + // Constructor + // ---------------------------------------------------------------------------------- protected Event() { } + // ---------------------------------------------------------------------------------- + // Properties (Getters) + // ---------------------------------------------------------------------------------- public String getName() { return this.name; } @@ -25,6 +39,13 @@ public class Event implements Serializable { return this.description; } + // ---------------------------------------------------------------------------------- + // Other Methods + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof Event; + } + @Override public boolean equals(final Object o) { if (o == this) return true; @@ -34,10 +55,6 @@ public class Event implements Serializable { && Objects.equals(this.getName(), other.getName()); } - protected boolean canEqual(final Object other) { - return other instanceof Event; - } - @Override public int hashCode() { return Objects.hashCode(this.getName()); @@ -45,6 +62,7 @@ public class Event implements Serializable { @Override public String toString() { - return "Event(name=" + this.getName() + ", description=" + this.getDescription() + ")"; + return "Event(name=" + this.getName() + ", description=" + + this.getDescription() + ")"; } } diff --git a/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java b/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java index 852eac7bbb..008e47babe 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java +++ b/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java @@ -1,9 +1,18 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + import java.util.Objects; @Entity +@Table(name = "external_resource") public class ExternalResource { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -16,6 +25,7 @@ public class ExternalResource { private String url; @ManyToOne(optional = false) + @JoinColumn(name = "project_type_id") private ProjectType relevantFor; public ExternalResource() {} // JPA diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java b/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java index ad0f13494d..b326a9c967 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; @Transactional public interface FooterAddressRepo extends JpaRepository<FooterAddress, Long>, QueryDslPredicateExecutor<FooterAddress> { diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java b/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java index 7676611142..68a84f622f 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java +++ b/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java @@ -13,6 +13,7 @@ public class FooterLink extends DomainObject { private Long id; @Enumerated(EnumType.STRING) + @Column(name = "footer_column") private FooterColumn footerColumn; @Basic(optional = false) diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java index bd0c349289..8994ba19ae 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import java.util.List; import java.util.Optional; diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java index 327b83accc..901a487f84 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.inject.Inject; import java.util.List; diff --git a/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java b/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java index 2a42a60a0e..07ae33135f 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.EntityPathBase; import com.querydsl.core.types.dsl.Expressions; diff --git a/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java index 0c58d7f4d5..e14516ffb9 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.inject.Inject; diff --git a/core/src/main/java/se/su/dsv/scipro/system/Password.java b/core/src/main/java/se/su/dsv/scipro/system/Password.java index 32dd434660..8cc600ed24 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/Password.java +++ b/core/src/main/java/se/su/dsv/scipro/system/Password.java @@ -1,11 +1,18 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + import java.util.Arrays; import java.util.Objects; @Entity -@Table +@Table(name = "password") public class Password extends LazyDeletableDomainObject { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java b/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java index 32d5c4c4f9..53dfe5d7a8 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; @Transactional diff --git a/core/src/main/java/se/su/dsv/scipro/system/Program.java b/core/src/main/java/se/su/dsv/scipro/system/Program.java index 2c23655ccc..f2aba4587d 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/Program.java +++ b/core/src/main/java/se/su/dsv/scipro/system/Program.java @@ -1,10 +1,16 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; import java.util.Objects; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + @Entity -@Table(name = "Program") +@Table(name = "program") public class Program extends DomainObject { @Id @@ -12,13 +18,13 @@ public class Program extends DomainObject { @Column(name = "id") private Long id; - @Column(name = "externalId") + @Column(name = "external_id") private Integer externalId; - @Column(name = "name") + @Column(name = "name_sv") private String name; - @Column(name = "nameEn", nullable = true) + @Column(name = "name_en", nullable = true) private String nameEn; @Column(name = "code") diff --git a/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java b/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java index 0d3bd00f2c..b3f8849870 100644 --- a/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java +++ b/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java @@ -1,12 +1,29 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; import java.util.EnumSet; import java.util.Objects; import java.util.Set; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + @Entity @Cacheable(true) +@Table(name = "project_type") public class ProjectType extends LazyDeletableDomainObject { public static final DegreeType MASTER = DegreeType.MASTER; public static final DegreeType BACHELOR = DegreeType.BACHELOR; @@ -26,7 +43,7 @@ public class ProjectType extends LazyDeletableDomainObject { private ProjectTypeSettings projectTypeSettings = new ProjectTypeSettings(this); @Enumerated(EnumType.STRING) - @Column(nullable = false) + @Column(name = "degree_type", nullable = false) private DegreeType degreeType = DegreeType.NONE; @Lob @@ -34,7 +51,9 @@ public class ProjectType extends LazyDeletableDomainObject { @ElementCollection @Enumerated(EnumType.STRING) - @JoinTable(name = "project_type_project_modules") + @CollectionTable(name = "project_type_project_module", + joinColumns = @JoinColumn(name = "project_type_id", referencedColumnName = "id")) + @Column(name = "project_module") private Set<ProjectModule> projectModules = EnumSet.allOf(ProjectModule.class); @Basic(optional = false) diff --git a/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java b/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java index f83d626f1b..2c64d6629d 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java +++ b/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java @@ -1,68 +1,84 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; + import java.util.Objects; @Entity -@Table(name="project_type_settings") @Cacheable(true) +@Table(name="project_type_settings") public class ProjectTypeSettings extends DomainObject { - public ProjectTypeSettings(){} - - public ProjectTypeSettings(ProjectType projectType){ - this.projectType = projectType; - } + public static final int DEFAULT_NUM_DAYS_BETWEEN_REVIEWS_ON_SAME_PROJECT = 7; + public static final int DEFAULT_NUM_DAYS_TO_SUBMIT_PEER_REVIEW = 3; + public static final int DEFAULT_NUM_DAYS_BEFORE_CANCELLED_PEERS = 90; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToOne(optional = false) + @JoinColumn(name = "project_type_id") private ProjectType projectType; - @Basic(optional=false) - private int minAuthors = 1; - @Basic(optional=false) - private int maxAuthors = 2; - - @Basic(optional=false) - private int maxFinalSeminarActiveParticipation; - @Basic(optional=false) - private int maxOpponentsOnFinalSeminar; - @Basic(optional=false) - private int minFinalSeminarActiveParticipation; - @Basic(optional=false) - private int minOpponentsOnFinalSeminar; - - private int minimumOppositionsToBeGraded = 0; - private int minimumActiveParticipationsToBeGraded = 0; - - public static final int DEFAULT_NUM_DAYS_BETWEEN_REVIEWS_ON_SAME_PROJECT = 7; - public static final int DEFAULT_NUM_DAYS_TO_SUBMIT_PEER_REVIEW = 3; - public static final int DEFAULT_NUM_DAYS_BEFORE_CANCELLED_PEERS = 90; - /* * Defines the time span between reviews on the same project */ - @Basic(optional = false) + @Column(name = "num_days_between_peer_reviews_on_same_project", nullable = false) private int numDaysBetweenPeerReviewsOnSameProject = DEFAULT_NUM_DAYS_BETWEEN_REVIEWS_ON_SAME_PROJECT; - + /* * Defines the number of days between accepting a review and the deadline for review submission */ - @Basic(optional = false) + @Column(name = "num_days_to_submit_peer_review", nullable = false) private int numDaysToSubmitPeerReview = DEFAULT_NUM_DAYS_TO_SUBMIT_PEER_REVIEW; /* * Defines the number of days between accepting a review and the deadline for review submission */ - @Basic(optional = false) + @Column(name = "num_days_before_peer_gets_cancelled", nullable = false) private int numDaysBeforePeerGetsCancelled = DEFAULT_NUM_DAYS_BEFORE_CANCELLED_PEERS; - @Basic + @Column(name = "min_authors", nullable = false) + private int minAuthors = 1; + + @Column(name = "max_authors", nullable = false) + private int maxAuthors = 2; + + @Column(name = "max_final_seminar_active_participation", nullable = false) + private int maxFinalSeminarActiveParticipation; + + @Column(name = "max_opponents_on_final_seminar", nullable = false) + private int maxOpponentsOnFinalSeminar; + + @Column(name = "min_final_seminar_active_participation", nullable = false) + private int minFinalSeminarActiveParticipation; + + @Column(name = "min_opponents_on_final_seminar", nullable = false) + private int minOpponentsOnFinalSeminar; + + @Column(name = "min_oppositions_to_be_graded") + private int minOppositionsToBeGraded = 0; + + @Column(name = "min_active_participations_to_be_graded") + private int minActiveParticipationsToBeGraded = 0; + @Column(name = "review_process_information_url_for_supervisor") private String reviewProcessInformationUrl; + public ProjectTypeSettings(){} + + public ProjectTypeSettings(ProjectType projectType){ + this.projectType = projectType; + } + @Override public Long getId() { return this.id; @@ -152,20 +168,20 @@ public class ProjectTypeSettings extends DomainObject { this.numDaysBeforePeerGetsCancelled = numDaysBeforePeerGetsCancelled; } - public int getMinimumOppositionsToBeGraded() { - return minimumOppositionsToBeGraded; + public int getMinOppositionsToBeGraded() { + return minOppositionsToBeGraded; } - public void setMinimumOppositionsToBeGraded(int minimumOppositionsToBeGraded) { - this.minimumOppositionsToBeGraded = minimumOppositionsToBeGraded; + public void setMinOppositionsToBeGraded(int minimumOppositionsToBeGraded) { + this.minOppositionsToBeGraded = minimumOppositionsToBeGraded; } - public int getMinimumActiveParticipationsToBeGraded() { - return minimumActiveParticipationsToBeGraded; + public int getMinActiveParticipationsToBeGraded() { + return minActiveParticipationsToBeGraded; } - public void setMinimumActiveParticipationsToBeGraded(int minimumActiveParticipationsToBeGraded) { - this.minimumActiveParticipationsToBeGraded = minimumActiveParticipationsToBeGraded; + public void setMinActiveParticipationsToBeGraded(int minimumActiveParticipationsToBeGraded) { + this.minActiveParticipationsToBeGraded = minimumActiveParticipationsToBeGraded; } public String getReviewProcessInformationUrl() { diff --git a/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java b/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java index 11a8bb041f..01e994645b 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java +++ b/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java @@ -1,14 +1,22 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + import java.util.Objects; @Entity -@Table(name = "researcharea") +@Table(name = "research_area") @Cacheable(true) public class ResearchArea extends LazyDeletableDomainObject { - public static final int STRING_MAX_LENGTH = 255; + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java index 76dc29c854..3c75c66915 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java @@ -3,6 +3,8 @@ package se.su.dsv.scipro.system; import jakarta.inject.Inject; import jakarta.inject.Provider; import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; + import java.util.Comparator; import java.util.List; @@ -13,6 +15,7 @@ public class ResearchAreaServiceImpl extends AbstractServiceImpl<ResearchArea,Lo } @Override + @Transactional public ResearchArea updateExternalResearchArea(Long identifier, String name, final boolean active) { ResearchArea ra = new ResearchArea(); if (identifier != null) { diff --git a/core/src/main/java/se/su/dsv/scipro/system/Unit.java b/core/src/main/java/se/su/dsv/scipro/system/Unit.java index acc2b2793c..404baee063 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/Unit.java +++ b/core/src/main/java/se/su/dsv/scipro/system/Unit.java @@ -1,6 +1,13 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + import java.util.Objects; @Entity @@ -17,11 +24,10 @@ public class Unit extends DomainObject { @Column(unique = true) private Integer identifier; - @Column(length = STRING_MAX_LENGTH) - @Basic(optional = false) + @Column(nullable = false, length = STRING_MAX_LENGTH) private String title; - @Basic(optional = true) + @Column(name = "match_responsible", nullable = true) private String matchResponsible; public String getMatchResponsible() { diff --git a/core/src/main/java/se/su/dsv/scipro/system/User.java b/core/src/main/java/se/su/dsv/scipro/system/User.java index 1ee2da3877..9addbde052 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/User.java +++ b/core/src/main/java/se/su/dsv/scipro/system/User.java @@ -1,10 +1,32 @@ package se.su.dsv.scipro.system; -import se.su.dsv.scipro.security.auth.roles.Roles; +import jakarta.persistence.Basic; +import jakarta.persistence.Cacheable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; -import jakarta.persistence.*; import java.io.Serializable; -import java.util.*; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import se.su.dsv.scipro.security.auth.roles.Roles; @Entity @Table(name = "user") @@ -18,9 +40,10 @@ public class User extends LazyDeletableDomainObject { @Column(unique = true) private Integer identifier; - @Basic(optional = false) + @Column(name = "first_name", nullable = false) private String firstName; - @Basic(optional = false) + + @Column(name = "last_name", nullable = false) private String lastName; // Mapped to a generated column to allow sorting UserColumn in DataTables @@ -35,14 +58,15 @@ public class User extends LazyDeletableDomainObject { // If you wish to test specific sort orders then add specific methods that sort // by firstName, lastName instead. @SuppressWarnings("unused") - @Basic - @Column(insertable = false, updatable = false) + @Column(name = "full_name", insertable = false, updatable = false) private String fullName; - @Basic(optional = false) + @Column(name = "email_address", nullable = false) private String emailAddress; + @Basic(optional = false) private boolean deceased = false; + @Basic(optional = false) @Column(name = "active_as_supervisor") private boolean activeAsSupervisor = false; @@ -64,20 +88,22 @@ public class User extends LazyDeletableDomainObject { private Set<Program> programs = new HashSet<>(); @ElementCollection - @CollectionTable(name = "user_languages") + @CollectionTable(name = "user_language") @Column(name = "language") @Enumerated(EnumType.STRING) private Set<Language> languages = EnumSet.noneOf(Language.class); @ManyToMany - @JoinTable(name = "user_research_area", inverseJoinColumns = @JoinColumn(name = "research_area_id")) + @JoinTable(name = "user_research_area", + joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "research_area_id", referencedColumnName = "id")) private Set<ResearchArea> researchAreas = new HashSet<>(); @OneToOne(optional = true) private Unit unit; - @Basic @Enumerated(EnumType.STRING) + @Column(name = "degree_type") private DegreeType degreeType = ProjectType.UNKNOWN; public Unit getUnit() { diff --git a/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java b/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java index 1a227078e1..9831c44da1 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.system; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.security.auth.roles.Roles; import java.util.Collection; diff --git a/core/src/main/java/se/su/dsv/scipro/system/Username.java b/core/src/main/java/se/su/dsv/scipro/system/Username.java index e4836b5070..5da461d2b6 100755 --- a/core/src/main/java/se/su/dsv/scipro/system/Username.java +++ b/core/src/main/java/se/su/dsv/scipro/system/Username.java @@ -1,17 +1,26 @@ package se.su.dsv.scipro.system; -import jakarta.persistence.*; +import jakarta.persistence.Cacheable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; + import java.util.Objects; @Entity +@Table(name="username", uniqueConstraints={@UniqueConstraint(name = "uk_username", columnNames={"username"})}) @Cacheable(true) -@Table(name="username", uniqueConstraints={@UniqueConstraint(columnNames={"username"})}) public class Username extends DomainObject { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Basic(optional=false) + @Column(name = "username", nullable = false) private String username; @ManyToOne(optional=false) diff --git a/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java b/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java index aeeff1631a..ee96eb8884 100644 --- a/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java +++ b/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java @@ -1,84 +1,103 @@ package se.su.dsv.scipro.thesislink; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import se.su.dsv.scipro.project.Project; import se.su.dsv.scipro.system.DomainObject; import se.su.dsv.scipro.system.User; -import jakarta.persistence.*; import java.util.Objects; @Entity -@Table(name = "externallink") +@Table(name = "external_link") public class ExternalLink extends DomainObject { public static final int MAX_CHARS = 255; - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne(optional = false) - private Project project; - - @Column(nullable = false, length = MAX_CHARS) - private String url = ""; - - @ManyToOne(optional = false) - private User user; - - @Column(nullable = true, length = MAX_CHARS) - private String description = ""; - public static IProject builder() { return new Builder(); } + // ---------------------------------------------------------------------------------- + // Basic JPA-mappings + // ---------------------------------------------------------------------------------- + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Basic + @Column(name = "url", nullable = false, length = MAX_CHARS) + private String url = ""; + + @Column(name = "description", nullable = true, length = MAX_CHARS) + private String description = ""; + + // ---------------------------------------------------------------------------------- + // JPA-mappings of foreign keys in this table (external_link) referencing + // other tables. + // ---------------------------------------------------------------------------------- + @ManyToOne(optional = false) + @JoinColumn(name = "project_id", referencedColumnName = "id") + private Project project; + + @ManyToOne(optional = false) + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + // ---------------------------------------------------------------------------------- + // Properties (Getters and Setters) + // ---------------------------------------------------------------------------------- @Override public Long getId() { return this.id; } - public Project getProject() { - return this.project; - } - - public String getUrl() { - return this.url; - } - - public User getUser() { - return this.user; - } - - public String getDescription() { - return this.description; - } - public void setId(Long id) { this.id = id; } - public void setProject(Project project) { - this.project = project; + public String getUrl() { + return this.url; } public void setUrl(String url) { this.url = url; } - public void setUser(User user) { - this.user = user; + public String getDescription() { + return this.description; } public void setDescription(String description) { this.description = description; } - @Override - public String toString() { - return "ExternalLink(id=" + this.getId() + ", project=" + this.getProject() + ", url=" + this.getUrl() + ", user=" + this.getUser() + ", description=" + this.getDescription() + ")"; + public Project getProject() { + return this.project; } + public void setProject(Project project) { + this.project = project; + } + + public User getUser() { + return this.user; + } + + public void setUser(User user) { + this.user = user; + } + + // ---------------------------------------------------------------------------------- + // Methods Common To All Objects + // ---------------------------------------------------------------------------------- @Override public boolean equals(final Object o) { if (o == this) return true; @@ -92,15 +111,28 @@ public class ExternalLink extends DomainObject { && Objects.equals(this.getDescription(), other.getDescription()); } - protected boolean canEqual(final Object other) { - return other instanceof ExternalLink; - } - @Override public int hashCode() { return Objects.hash(this.getId(), this.getProject(), this.getUrl(), this.getUser(), this.getDescription()); } + @Override + public String toString() { + return "ExternalLink(id=" + this.getId() + ", project=" + this.getProject() + + ", url=" + this.getUrl() + ", user=" + this.getUser() + ", description=" + + this.getDescription() + ")"; + } + + // ---------------------------------------------------------------------------------- + // Other method + // ---------------------------------------------------------------------------------- + protected boolean canEqual(final Object other) { + return other instanceof ExternalLink; + } + + // ---------------------------------------------------------------------------------- + // Nested types + // ---------------------------------------------------------------------------------- private static class Builder implements IProject, IURL, IUser, IBuild { private ExternalLink instance = new ExternalLink(); diff --git a/core/src/main/java/se/su/dsv/scipro/war/PluginConfiguration.java b/core/src/main/java/se/su/dsv/scipro/war/PluginConfiguration.java new file mode 100644 index 0000000000..a111714130 --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/war/PluginConfiguration.java @@ -0,0 +1,4 @@ +package se.su.dsv.scipro.war; + +public interface PluginConfiguration { +} diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java index 751b6c8831..5c721b2ffe 100755 --- a/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java +++ b/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java @@ -1,6 +1,5 @@ package se.su.dsv.scipro.workerthreads; -import com.google.inject.persist.UnitOfWork; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,9 +22,7 @@ public abstract class AbstractWorker implements Worker { private WorkerData wd = null; private Date lastSuccessfulRun = new Date(0); private boolean successfulWorker = true; - private Provider<EntityManager> emProvider; - private EntityTransaction transaction; - private UnitOfWork unitOfWork; + private WorkerTransactionManager txManager; /** * Subclasses must be annotated with @Component or similar annotation in order for autowiring of dependencies to work @@ -39,22 +36,13 @@ public abstract class AbstractWorker implements Worker { } @Inject - public void setTxManager(Provider<EntityManager> em) { - this.emProvider = em; - } - - @Inject - public void setUnitOfWork(UnitOfWork unitOfWork) { - this.unitOfWork = unitOfWork; + public void setTxManager(WorkerTransactionManager txManager) { + this.txManager = txManager; } @Override public void run() { - unitOfWork.begin(); - EntityManager em = emProvider.get(); try { - transaction = em.getTransaction(); - wd = workerDataService.getWorkerDataByName(getName()); if (wd != null) { lastSuccessfulRun = wd.getLastSuccessfulRun(); @@ -80,9 +68,7 @@ public abstract class AbstractWorker implements Worker { setSuccessfulWorker(false); } finally { - if (transaction.isActive() && em.isOpen()) { - transaction.rollback(); - } + txManager.rollbackIfActive(); } // in case a job crashes or clears the cache (so the entity is detached) @@ -95,10 +81,7 @@ public abstract class AbstractWorker implements Worker { saveWorkerData(); } finally { - if (transaction.isActive() && em.isOpen()) { - transaction.rollback(); - } - unitOfWork.end(); + txManager.rollbackIfActive(); } } @@ -148,15 +131,15 @@ public abstract class AbstractWorker implements Worker { protected abstract void doWork(); protected void beginTransaction() { - transaction.begin(); + txManager.begin(); } protected void commitTransaction() { - transaction.commit(); + txManager.commit(); } protected void rollbackTransaction() { - transaction.rollback(); + txManager.rollback(); } } diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java index 4827139331..59fefc8d63 100755 --- a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java +++ b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java @@ -7,7 +7,7 @@ import java.util.Date; import java.util.Objects; @Entity -@Table(name="worker_data") +@Table(name = "worker_data") @Cacheable(true) public class WorkerData extends DomainObject { public WorkerData() { @@ -18,13 +18,13 @@ public class WorkerData extends DomainObject { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(unique=true, nullable=false) + @Column(unique = true, nullable = false) private String name; - @Column(nullable=false) - private Date lastRun=new Date(); + @Column(nullable = false, name = "last_run") + private Date lastRun = new Date(); - @Column(nullable=false) + @Column(nullable = false, name = "last_successful_run") private Date lastSuccessfulRun; @PreUpdate diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerModule.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerModule.java deleted file mode 100644 index 370d486d83..0000000000 --- a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerModule.java +++ /dev/null @@ -1,31 +0,0 @@ -package se.su.dsv.scipro.workerthreads; - -import com.google.inject.AbstractModule; -import com.google.inject.Scopes; -import com.google.inject.multibindings.Multibinder; -import se.su.dsv.scipro.mail.MailEventWorker; -import se.su.dsv.scipro.projectpartner.RemoveFulfilledPartnerAdsWorker; -import se.su.dsv.scipro.system.Lifecycle; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; - -public class WorkerModule extends AbstractModule { - private static final int NUMBER_OF_WORKER_THREADS = 4; - - @Override - protected void configure() { - Multibinder.newSetBinder(binder(), Lifecycle.class).addBinding().to(SchedulerImpl.class); - bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS)); - bind(Scheduler.class).to(SchedulerImpl.class).in(Scopes.SINGLETON); - bind(TemporaryWorkerScheduler.class).asEagerSingleton(); - bind(WorkerDataService.class).to(WorkerDataServiceImpl.class); - bind(ThesisUploadDeadlineWorker.class); - bind(ManualMatchRemindWorker.class); - bind(MailEventWorker.class); - bind(NotificationCompilationWorker.class); - bind(ThesisUploadReminderWorker.class); - bind(IdeaExportWorker.class); - bind(RemoveFulfilledPartnerAdsWorker.class); - } -} diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerTransactionManager.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerTransactionManager.java new file mode 100644 index 0000000000..1ff2b458d4 --- /dev/null +++ b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerTransactionManager.java @@ -0,0 +1,20 @@ +package se.su.dsv.scipro.workerthreads; + +public interface WorkerTransactionManager { + void rollbackIfActive(); + + /** + * @throws IllegalStateException if a transaction is already active + */ + void begin(); + + /** + * @throws IllegalStateException if a transaction is not active + */ + void commit(); + + /** + * @throws IllegalStateException if a transaction is not active + */ + void rollback(); +} diff --git a/core/src/main/resources/db/migration/V390__longer_titles_in_final_thesis.sql b/core/src/main/resources/db/migration/V390__longer_titles_in_final_thesis.sql new file mode 100644 index 0000000000..3edeeb923b --- /dev/null +++ b/core/src/main/resources/db/migration/V390__longer_titles_in_final_thesis.sql @@ -0,0 +1,3 @@ +-- Match what project.title allows +ALTER TABLE `FinalThesis` MODIFY `englishTitle` LONGTEXT NULL; +ALTER TABLE `FinalThesis` MODIFY `swedishTitle` LONGTEXT NULL; diff --git a/core/src/main/resources/db/migration/V391__harmonize_table_attribute_name.sql b/core/src/main/resources/db/migration/V391__harmonize_table_attribute_name.sql new file mode 100644 index 0000000000..15c116c0ff --- /dev/null +++ b/core/src/main/resources/db/migration/V391__harmonize_table_attribute_name.sql @@ -0,0 +1,3222 @@ +/* + * Step 1: Remove obsolete tables + */ + +drop table plugin_settings; +drop table turnitincheck; + +alter table TurnitinSettings_expirationMails drop foreign key FK_lji32bekgobx76otvw7syu4hb; +drop table TurnitinSettings_expirationMails; + +drop table TurnitinSettings; + +/* + * Step 2: DomainObject related classes and tables. + * + * Many entity classes inherit directly or indirectly from abstract super class DomainObject. Two attributes + * dateCreated and lastModified, have changed mapping to column name with snake case, date_created and last_modified. + * This change affects many, many tables, which are to be managed at first. + */ + +-- table: ActivityPlan + +alter table `ActivityPlan` rename column `dateCreated` to `date_created`; +alter table `ActivityPlan` rename column `lastModified` to `last_modified`; + +-- table: ActivityPlanTemplate + +alter table `ActivityPlanTemplate` rename column `dateCreated` to `date_created`; +alter table `ActivityPlanTemplate` rename column `lastModified` to `last_modified`; + +-- table: ActivityTemplate + +alter table `ActivityTemplate` rename column `dateCreated` to `date_created`; +alter table `ActivityTemplate` rename column `lastModified` to `last_modified`; + +-- table: file_description + +alter table `file_description` rename column `dateCreated` to `date_created`; +alter table `file_description` rename column `lastModified` to `last_modified`; + +-- table: answer + +alter table `answer` rename column `dateCreated` to `date_created`; +alter table `answer` rename column `lastModified` to `last_modified`; + +-- table: ApplicationPeriod + +alter table `ApplicationPeriod` rename column `dateCreated` to `date_created`; +alter table `ApplicationPeriod` rename column `lastModified` to `last_modified`; + +-- table: checklist + +alter table `checklist` rename column `dateCreated` to `date_created`; +alter table `checklist` rename column `lastModified` to `last_modified`; + +-- table: checklist_answer + +alter table `checklist_answer` rename column `dateCreated` to `date_created`; +alter table `checklist_answer` rename column `lastModified` to `last_modified`; + +-- table: checklist_category + +alter table `checklist_category` rename column `dateCreated` to `date_created`; +alter table `checklist_category` rename column `lastModified` to `last_modified`; + +-- table: checklist_question + +alter table `checklist_question` rename column `dateCreated` to `date_created`; +alter table `checklist_question` rename column `lastModified` to `last_modified`; + +-- table: checklist_template + +alter table `checklist_template` rename column `dateCreated` to `date_created`; +alter table `checklist_template` rename column `lastModified` to `last_modified`; + +-- table: comment + +alter table `comment` rename column `dateCreated` to `date_created`; +alter table `comment` rename column `lastModified` to `last_modified`; + +-- table: externallink + +alter table `externallink` rename column `dateCreated` to `date_created`; +alter table `externallink` rename column `lastModified` to `last_modified`; + +-- table: comment_thread + +alter table `comment_thread` rename column `dateCreated` to `date_created`; +alter table `comment_thread` rename column `lastModified` to `last_modified`; + +-- table: FinalSeminarSettings + +alter table `FinalSeminarSettings` rename column `dateCreated` to `date_created`; +alter table `FinalSeminarSettings` rename column `lastModified` to `last_modified`; + +-- table: FinalThesis + +alter table `FinalThesis` rename column `dateCreated` to `date_created`; +alter table `FinalThesis` rename column `lastModified` to `last_modified`; + +-- table: footer_address + +alter table `footer_address` rename column `dateCreated` to `date_created`; +alter table `footer_address` rename column `lastModified` to `last_modified`; + +-- table: footer_link + +alter table `footer_link` rename column `dateCreated` to `date_created`; +alter table `footer_link` rename column `lastModified` to `last_modified`; + +-- table: general_system_settings + +alter table `general_system_settings` rename column `dateCreated` to `date_created`; +alter table `general_system_settings` rename column `lastModified` to `last_modified`; + +-- table: grading_report_template + +alter table `grading_report_template` rename column `dateCreated` to `date_created`; +alter table `grading_report_template` rename column `lastModified` to `last_modified`; + +-- table: project_group + +alter table `project_group` rename column `dateCreated` to `date_created`; +alter table `project_group` rename column `lastModified` to `last_modified`; + +-- table: idea + +alter table `idea` rename column `dateCreated` to `date_created`; +alter table `idea` rename column `lastModified` to `last_modified`; + +-- table: idea_export + +alter table `idea_export` rename column `dateCreated` to `date_created`; +alter table `idea_export` rename column `lastModified` to `last_modified`; + +-- table: mail_event + +alter table `mail_event` rename column `dateCreated` to `date_created`; +alter table `mail_event` rename column `lastModified` to `last_modified`; + +-- table: idea_match + +alter table `idea_match` rename column `dateCreated` to `date_created`; +alter table `idea_match` rename column `lastModified` to `last_modified`; + +-- table: milestone + +alter table `milestone` rename column `dateCreated` to `date_created`; +alter table `milestone` rename column `lastModified` to `last_modified`; + +-- table: NonWorkDayPeriod + +alter table `NonWorkDayPeriod` rename column `dateCreated` to `date_created`; +alter table `NonWorkDayPeriod` rename column `lastModified` to `last_modified`; + +-- table: note + +alter table `note` rename column `dateCreated` to `date_created`; +alter table `note` rename column `lastModified` to `last_modified`; + +-- table: Notification + +alter table `Notification` rename column `dateCreated` to `date_created`; +alter table `Notification` rename column `lastModified` to `last_modified`; + +-- table: NotificationData + +alter table `NotificationData` rename column `dateCreated` to `date_created`; +alter table `NotificationData` rename column `lastModified` to `last_modified`; + +-- table: peer_request + +alter table `peer_request` rename column `dateCreated` to `date_created`; +alter table `peer_request` rename column `lastModified` to `last_modified`; + +-- table: peer_review + +alter table `peer_review` rename column `dateCreated` to `date_created`; +alter table `peer_review` rename column `lastModified` to `last_modified`; + +-- table: preliminary_match + +alter table `preliminary_match` rename column `dateCreated` to `date_created`; +alter table `preliminary_match` rename column `lastModified` to `last_modified`; + +-- table: Program + +alter table `Program` rename column `dateCreated` to `date_created`; +alter table `Program` rename column `lastModified` to `last_modified`; + +-- table: project + +alter table `project` rename column `dateCreated` to `date_created`; +alter table `project` rename column `lastModified` to `last_modified`; + +-- table: project_file + +alter table `project_file` rename column `dateCreated` to `date_created`; +alter table `project_file` rename column `lastModified` to `last_modified`; + +-- table: project_first_meeting + +alter table `project_first_meeting` rename column `dateCreated` to `date_created`; +alter table `project_first_meeting` rename column `lastModified` to `last_modified`; + +-- table: projectPartner + +alter table `projectPartner` rename column `dateCreated` to `date_created`; +alter table `projectPartner` rename column `lastModified` to `last_modified`; + +-- table: project_type_settings + +alter table `project_type_settings` rename column `dateCreated` to `date_created`; +alter table `project_type_settings` rename column `lastModified` to `last_modified`; + +-- table: reviewer_deadline_settings + +alter table `reviewer_deadline_settings` rename column `dateCreated` to `date_created`; +alter table `reviewer_deadline_settings` rename column `lastModified` to `last_modified`; + +-- table: reviewer_target + +alter table `reviewer_target` rename column `dateCreated` to `date_created`; +alter table `reviewer_target` rename column `lastModified` to `last_modified`; + +-- table: unit + +alter table `unit` rename column `dateCreated` to `date_created`; +alter table `unit` rename column `lastModified` to `last_modified`; + +-- table: urkund_submission + +alter table `urkund_submission` rename column `dateCreated` to `date_created`; +alter table `urkund_submission` rename column `lastModified` to `last_modified`; + +-- table: username + +alter table `username` rename column `dateCreated` to `date_created`; +alter table `username` rename column `lastModified` to `last_modified`; + +-- table: user_profile + +alter table `user_profile` rename column `dateCreated` to `date_created`; +alter table `user_profile` rename column `lastModified` to `last_modified`; + +-- table: worker_data + +alter table `worker_data` rename column `dateCreated` to `date_created`; +alter table `worker_data` rename column `lastModified` to `last_modified`; + +-- table: criterion + +alter table `criterion` rename column `dateCreated` to `date_created`; +alter table `criterion` rename column `lastModified` to `last_modified`; + +-- table: grading_criterion_template + +alter table `grading_criterion_template` rename column `dateCreated` to `date_created`; +alter table `grading_criterion_template` rename column `lastModified` to `last_modified`; + +-- table: GradingCriterion + +alter table `GradingCriterion` rename column `dateCreated` to `date_created`; +alter table `GradingCriterion` rename column `lastModified` to `last_modified`; + +-- table: GradingCriterionPoint + +alter table `GradingCriterionPoint` rename column `dateCreated` to `date_created`; +alter table `GradingCriterionPoint` rename column `lastModified` to `last_modified`; + +-- table: grading_criterion_point_template + +alter table `grading_criterion_point_template` rename column `dateCreated` to `date_created`; +alter table `grading_criterion_point_template` rename column `lastModified` to `last_modified`; + +-- table: ReviewerApproval + +alter table `ReviewerApproval` rename column `dateCreated` to `date_created`; +alter table `ReviewerApproval` rename column `lastModified` to `last_modified`; + +-- table: final_seminar_active_participation + +alter table `final_seminar_active_participation` rename column `dateCreated` to `date_created`; +alter table `final_seminar_active_participation` rename column `lastModified` to `last_modified`; + +-- table: final_seminar_opposition + +alter table `final_seminar_opposition` rename column `dateCreated` to `date_created`; +alter table `final_seminar_opposition` rename column `lastModified` to `last_modified`; + +-- table: final_seminar_respondent + +alter table `final_seminar_respondent` rename column `dateCreated` to `date_created`; +alter table `final_seminar_respondent` rename column `lastModified` to `last_modified`; + +-- table: report + +alter table `report` rename column `dateCreated` to `date_created`; +alter table `report` rename column `lastModified` to `last_modified`; + +-- table: notification_delivery_configuration + +alter table `notification_delivery_configuration` rename column `dateCreated` to `date_created`; +alter table `notification_delivery_configuration` rename column `lastModified` to `last_modified`; + +-- table: notification_receiver_configuration + +alter table `notification_receiver_configuration` rename column `dateCreated` to `date_created`; +alter table `notification_receiver_configuration` rename column `lastModified` to `last_modified`; + +-- table: Activity + +alter table `Activity` rename column `dateCreated` to `date_created`; +alter table `Activity` rename column `lastModified` to `last_modified`; + +-- table: final_seminar + +alter table `final_seminar` rename column `dateCreated` to `date_created`; +alter table `final_seminar` rename column `lastModified` to `last_modified`; + +-- table: forum_post + +alter table `forum_post` rename column `dateCreated` to `date_created`; +alter table `forum_post` rename column `lastModified` to `last_modified`; + +-- table: thread + +alter table `thread` rename column `dateCreated` to `date_created`; +alter table `thread` rename column `lastModified` to `last_modified`; + +-- table: Keyword + +alter table `Keyword` rename column `dateCreated` to `date_created`; +alter table `Keyword` rename column `lastModified` to `last_modified`; + +-- table: milestone_activity_template + +alter table `milestone_activity_template` rename column `dateCreated` to `date_created`; +alter table `milestone_activity_template` rename column `lastModified` to `last_modified`; + +-- table: milestone_phase_template + +alter table `milestone_phase_template` rename column `dateCreated` to `date_created`; +alter table `milestone_phase_template` rename column `lastModified` to `last_modified`; + +-- table: Password + +alter table `Password` rename column `dateCreated` to `date_created`; +alter table `Password` rename column `lastModified` to `last_modified`; + +-- table: ProjectType + +alter table `ProjectType` rename column `dateCreated` to `date_created`; +alter table `ProjectType` rename column `lastModified` to `last_modified`; + +-- table: researcharea + +alter table `researcharea` rename column `dateCreated` to `date_created`; +alter table `researcharea` rename column `lastModified` to `last_modified`; + +-- table: user + +alter table `user` rename column `dateCreated` to `date_created`; +alter table `user` rename column `lastModified` to `last_modified`; + +/* + * Step 3: standalone tables + */ + +-- table: worker_data + +alter table `worker_data` rename column `lastRun` to `last_run`; +alter table `worker_data` rename column `lastSuccessfulRun` to `last_successful_run`; + +-- table: footer_link + +alter table `footer_link` rename column `footerColumn` to `footer_column`; + +-- table: NonWorkDayPeriod + +alter table `NonWorkDayPeriod` rename column `endDate` to `end_date`; +alter table `NonWorkDayPeriod` rename column `startDate` to `start_date`; + +rename table `NonWorkDayPeriod` to `non_work_day_period`; + +-- table: reviewer_deadline_settings + +alter table `reviewer_deadline_settings` rename column `roughDraftApproval` to `rough_draft_approval`; +alter table `reviewer_deadline_settings` rename column `finalSeminarApproval` to `final_seminar_approval`; +alter table `reviewer_deadline_settings` rename column `finalGrading` to `final_grading`; + +-- table: final_seminar_settings + +alter table `FinalSeminarSettings` rename column `daysAheadToCreate` to `days_ahead_to_create`; +alter table `FinalSeminarSettings` rename column `daysAheadToRegisterParticipation` to `days_ahead_to_register_participation`; +alter table `FinalSeminarSettings` rename column `daysAheadToRegisterOpposition` to `days_ahead_to_register_opposition`; +alter table `FinalSeminarSettings` rename column `daysAheadToUploadThesis` to `days_ahead_to_upload_thesis`; +alter table `FinalSeminarSettings` rename column `thesisMustBePDF` to `thesis_must_be_pdf`; +alter table `FinalSeminarSettings` rename column `evaluationURL` to `evaluation_url`; +alter table `FinalSeminarSettings` rename column `oppositionPriorityDays` to `opposition_priority_days`; + +rename table `FinalSeminarSettings` to `final_seminar_settings`; + +/* + * Step 4: general_system_settings and three related tables. + */ + +-- table: general_system_settings_system_module + +alter table `general_system_settings_system_modules` drop foreign key `general_system_settings_system_modules_ibfk_1`; +alter table `general_system_settings_system_modules` drop key `GeneralSystemSettings_id`; +alter table `general_system_settings_system_modules` drop primary key; + +alter table `general_system_settings_system_modules` rename column `GeneralSystemSettings_id` to `general_system_settings_id`; +alter table `general_system_settings_system_modules` rename column `systemModules` to `system_module`; + +rename table `general_system_settings_system_modules` to `general_system_settings_system_module`; + +alter table `general_system_settings_system_module` add primary key (general_system_settings_id, system_module); + +alter table `general_system_settings_system_module` + add constraint fk_general_system_settings_system_module_id + foreign key (general_system_settings_id) references general_system_settings (id) + on delete cascade on update cascade; + +-- table: general_system_settings_supervisor_change_recipient + +alter table `general_system_settings_supervisor_change_recipients` drop foreign key `FK7DA712D52AC37675`; +alter table `general_system_settings_supervisor_change_recipients` drop key `FK7DA712D52AC37675`; + +alter table `general_system_settings_supervisor_change_recipients` rename column `GeneralSystemSettings_id` to `general_system_settings_id`; + +rename table `general_system_settings_supervisor_change_recipients` to `general_system_settings_supervisor_change_recipient`; + +alter table `general_system_settings_supervisor_change_recipient` add primary key (general_system_settings_id, mail); + +alter table `general_system_settings_supervisor_change_recipient` + add constraint fk_general_system_settings_supervisor_change_recipient_id + foreign key (general_system_settings_id) references general_system_settings (id) + on delete cascade on update cascade; + +-- table: general_system_settings_alarm_recipient + +alter table `general_system_settings_alarm_recipients` drop foreign key `FK3C9272B2AC37675`; +alter table `general_system_settings_alarm_recipients` drop key `FK3C9272B2AC37675`; + +alter table `general_system_settings_alarm_recipients` rename column `GeneralSystemSettings_id` to `general_system_settings_id`; + +rename table `general_system_settings_alarm_recipients` to `general_system_settings_alarm_recipient`; + +alter table `general_system_settings_alarm_recipient` add primary key (general_system_settings_id, mail); + +alter table `general_system_settings_alarm_recipient` + add constraint fk_general_system_settings_alarm_recipient_id + foreign key (general_system_settings_id) references general_system_settings (id) + on delete cascade on update cascade; + +-- table: general_system_settings + +alter table `general_system_settings` rename column `daisyProfileLinkBaseURL` to `daisy_profile_link_base_url`; +alter table `general_system_settings` rename column `daisySelectResearchAreaURL` to `daisy_select_research_area_url`; +alter table `general_system_settings` rename column `projectPartnerDaysToLive` to `project_partner_days_to_live`; +alter table `general_system_settings` rename column `mailNotifications` to `mail_notifications`; +alter table `general_system_settings` rename column `mailFromName` to `mail_from_name`; +alter table `general_system_settings` rename column `systemFromMail` to `system_from_mail`; +alter table `general_system_settings` rename column `smtpServer` to `smtp_server`; +alter table `general_system_settings` rename column `peerDisplayLatestReviews` to `peer_display_latest_reviews`; +alter table `general_system_settings` rename column `numberOfLatestReviewsDisplayed` to `number_of_latest_reviews_displayed`; +alter table `general_system_settings` rename column `publicReviewsActivated` to `public_reviews_activated`; +alter table `general_system_settings` rename column `peerDownloadEnabled` to `peer_download_enabled`; +alter table `general_system_settings` rename column `sciproURL` to `scipro_url`; +alter table `general_system_settings` rename column `showSingleSignOn` to `show_single_sign_on`; +alter table `general_system_settings` rename column `matchResponsibleMail` to `match_responsible_mail`; +alter table `general_system_settings` rename column `reviewerSupportMail` to `reviewer_support_mail`; +alter table `general_system_settings` rename column `thesisSupportMail` to `thesis_support_mail`; +alter table `general_system_settings` rename column `externalRoomBookingURL` to `external_room_booking_url`; +alter table `general_system_settings` rename column `externalGettingStartedWithIdeaURL` to `external_getting_started_with_idea_url`; +alter table `general_system_settings` rename column `externalGradingURL` to `external_grading_url`; +alter table `general_system_settings` rename column `finalSurveyAvailable` to `final_survey_available`; +alter table `general_system_settings` rename column `activeProjectIdeaSupportMail` to `active_project_idea_support_mail`; + +/* + * Step 5: table user and related tables. + * + * Table user is one of four fundamental tables (other three: project, file_reference, ProjectType). All four + * tables have many foreign keys referenced to them. + * + * Related tables of table user are the tables which have no relationship with other three fundamental tables. Their + * foreign key references end at table user. + */ + +-- table: Program and user_program + +alter table `user_program` drop foreign key `user_program_program_id`; +alter table `user_program` drop key `user_program_program_id`; + +alter table `user_program` drop foreign key `user_program_user_id`; + +rename table `Program` to `program`; + +alter table `program` rename column `externalId` to `external_id`; +alter table `program` rename column `name` to `name_sv`; +alter table `program` rename column `nameEn` to `name_en`; + +alter table `user_program` + add constraint fk_user_program_program_id + foreign key (program_id) references program (id) + on delete cascade on update cascade; + +alter table `user_program` + add constraint fk_user_program_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: note + +alter table `note` drop foreign key `note_ibfk_1`; +alter table `note` drop key `user_id`; + +alter table `note` + add constraint fk_note_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: comment and comment_thread + +alter table `comment` drop foreign key `FK38A5EE5FE44F4DBE`; +alter table `comment` drop foreign key `FK38A5EE5F45F802F5`; +alter table `comment` drop key `FK38A5EE5FE44F4DBE`; +alter table `comment` drop key `FK38A5EE5F45F802F5`; + +alter table `comment_thread` drop key `UK_s0ve8ppa3snl8i1wocqwiuwn2`; +alter table `comment_thread` drop key `commentableKey`; + +alter table comment_thread rename column `commentableId` to `commentable_id`; +alter table comment_thread rename column `commentableKey` to `commentable_key`; + +alter table `comment_thread` add constraint uk_comment_thread_id_key unique(commentable_id, commentable_key); + +alter table comment rename column `commentThread_id` to `comment_thread_id`; +alter table comment rename column `creator_id` to `creator_user_id`; + +alter table `comment` + add constraint fk_comment_creator_user_id + foreign key (creator_user_id) references user (id) + on delete cascade on update cascade; + +alter table `comment` + add constraint fk_comment_comment_thread_id + foreign key (comment_thread_id) references comment_thread (id) + on delete cascade on update cascade; + +-- table: reviewer_target + +alter table `reviewer_target` drop foreign key `FK_ReviewerTarget_ReviewerId`; +alter table `reviewer_target` drop key `UK_ReviewerTarget_ReviewerId_Year`; + +alter table `reviewer_target` rename column `reviewer_id` to `reviewer_user_id`; + +alter table `reviewer_target` add constraint uk_reviewer_target_reviewer_user_id_year unique(reviewer_user_id, year); + +alter table `reviewer_target` + add constraint fk_reviewer_target_reviewer_user_id + foreign key (reviewer_user_id) references user (id) + on delete cascade on update cascade; + +-- table: notification_delivery_configuration + +alter table `notification_delivery_configuration` drop foreign key `FK7B2EE5BF895349BF`; +alter table `notification_delivery_configuration` drop key `FK7B2EE5BF895349BF`; +alter table `notification_delivery_configuration` drop key `one_setting_per_user`; + +alter table `notification_delivery_configuration` add constraint uk_one_setting_per_user unique(type, event, method, user_id); + +alter table `notification_delivery_configuration` + add constraint fk_notification_delivery_configuration_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: username + +alter table `username` drop foreign key `FK_17moq4bksxe30ihucce3jovdc`; +alter table `username` drop key `FK_17moq4bksxe30ihucce3jovdc`; +alter table `username` drop key `username_must_be_unique`; + +alter table `username` add constraint uk_username unique(username); + +alter table `username` + add constraint fk_username_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: user_role + +alter table `user_role` drop foreign key `user_role_user_id`; + +alter table `user_role` + add constraint fk_user_role_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: user_languages + +alter table `user_languages` drop foreign key `user_languages_user_id`; +alter table `user_languages` drop key `user_languages_user_id`; + +rename table `user_languages` to `user_language`; + +alter table `user_language` + add constraint fk_user_language_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +/* + * table: user, unit and Password + */ + +alter table `user` drop foreign key `FK_hpmviec1b7vdg23xtxsalwxw8`; +alter table `user` drop key `FK_hpmviec1b7vdg23xtxsalwxw8`; + +alter table `user` drop foreign key `user_unit_id`; +alter table `user` drop key `user_unit_id`; + +alter table `user` drop key `identifier`; +alter table `user` drop key `deleted_index`; + +-- rename columns in table user + +alter table `user` rename column `emailAddress` to `email_address`; +alter table `user` rename column `firstName` to `first_name`; +alter table `user` rename column `lastName` to `last_name`; +alter table `user` rename column `fullName` to `full_name`; +alter table `user` rename column `degreeType` to `degree_type`; + +alter table `user` add constraint uk_user_identifier unique(identifier); +create index idx_user_deleted on user(deleted); + +-- table: unit + +alter table `unit` drop key `identifier`; + +alter table `unit` rename column `matchResponsible` to `match_responsible`; + +alter table `unit` add constraint uk_unit_identifier unique(identifier); + +-- add FK from user to unit + +alter table `user` + add constraint fk_user_unit_id + foreign key (unit_id) references unit (id) + on delete cascade on update cascade; + +-- table: Password + +alter table `Password` drop foreign key `FK_43erxladp39q03wrco68hi9iq`; +alter table `Password` drop key `FK_43erxladp39q03wrco68hi9iq`; +alter table `Password` drop key `FK4C641EBB895349BF`; +alter table `Password` drop key `deleted_index`; +alter table `Password` drop key `UK_43erxladp39q03wrco68hi9iq`; +alter table `Password` drop key `user_id`; + +rename table `Password` to `password`; + +alter table `password` add constraint uk_password_user_id unique(user_id); +create index idx_password_deleted on password(deleted); + +alter table `password` + add constraint fk_password_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- add FK from user till password + +alter table `user` + add constraint fk_user_password_id + foreign key (password_id) references password (id) + on delete cascade on update cascade; + +-- table: user_profile + +alter table `user_profile` drop foreign key `FK_user_profile_user`; +alter table `user_profile` drop key `FK487E2135895349BF`; +alter table `user_profile` drop key `UK_ebc21hy5j7scdvcjt0jy6xxrv`; +alter table `user_profile` drop key `user_id`; + +alter table `user_profile` rename column `otherInfo` to `other_info`; +alter table `user_profile` rename column `phoneNumber` to `phone_number`; +alter table `user_profile` rename column `skypeId` to `skype_id`; +alter table `user_profile` rename column `mailCompilation` to `mail_compilation`; +alter table `user_profile` drop column `threadedForum`; +alter table `user_profile` rename column `defaultSupervisorFilter` to `default_supervisor_filter`; +alter table `user_profile` rename column `selectedRole` to `selected_role`; + +alter table `user_profile` add constraint uk_user_profile_user_id unique(user_id); + +alter table `user_profile` + add constraint fk_user_profile_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: user_profile_default_project_status_filter + +alter table `UserProfile_defaultProjectStatusFilter` drop foreign key `FK_user_profile_project_status_user_profile`; +alter table `UserProfile_defaultProjectStatusFilter` drop key `FK_icub74l6htav89sx85ar4qcqg`; + +rename table `UserProfile_defaultProjectStatusFilter` to `user_profile_default_project_status_filter`; + +alter table `user_profile_default_project_status_filter` rename column `UserProfile_id` to `user_profile_id`; +alter table `user_profile_default_project_status_filter` rename column `defaultProjectStatusFilter` to `default_project_status_filter`; + +alter table `user_profile_default_project_status_filter` + add constraint fk_user_profile_default_project_status_filter_user_profile_id + foreign key (user_profile_id) references user_profile (id) + on delete cascade on update cascade; + +-- table: user_profile_default_project_team_member_roles_filter + +alter table `UserProfile_defaultProjectTeamMemberRolesFilter` drop foreign key `FK_user_profile_role_user_profile`; +alter table `UserProfile_defaultProjectTeamMemberRolesFilter` drop key `FK_ibub74l6htav89sx85ar4qcqg`; + +rename table `UserProfile_defaultProjectTeamMemberRolesFilter` to `user_profile_default_project_team_member_roles_filter`; + +alter table `user_profile_default_project_team_member_roles_filter` rename column `UserProfile_id` to `user_profile_id`; +alter table `user_profile_default_project_team_member_roles_filter` rename column `defaultProjectTeamMemberRolesFilter` to `default_project_team_member_roles_filter`; + +alter table `user_profile_default_project_team_member_roles_filter` + add constraint fk_up_dp_tm_roles_filter_user_profile_id + foreign key (user_profile_id) references user_profile (id) + on delete cascade on update cascade; + +/* + * Step 6: table ProjectType and related tables. + * + * Table ProjectType is one of four fundamental tables (other three: project, file_reference, user). All four + * tables have many foreign keys referenced to them. + * + * Table ProjectType has 12 foreign keys referenced to it, this part is the most complex part of this refactoring. + */ + +-- table: user_profile_ProjectType, except foreign key to coming table project_type + +alter table `user_profile_ProjectType` drop foreign key `FK_user_profile_project_type_user_profile`; +alter table `user_profile_ProjectType` drop foreign key `FK_76s8320kw3w7bxp6lw7pmawfh`; +alter table `user_profile_ProjectType` drop key `FK_2blea2vk0b5cvgxjo1fy4p2j0`; +alter table `user_profile_ProjectType` drop key `FK_76s8320kw3w7bxp6lw7pmawfh`; + +rename table `user_profile_ProjectType` to `user_profile_project_type`; + +alter table `user_profile_project_type` rename column `defaultProjectTypeFilter_id` to `project_type_id`; + +alter table `user_profile_project_type` + add constraint fk_user_profile_project_type_user_profile_id + foreign key (user_profile_id) references user_profile (id) + on delete cascade on update cascade; + +-- table: ExternalResource, except foreign key to coming table project_type + +alter table `ExternalResource` drop foreign key `ExternalResource_ProjectType_relevantFor`; +alter table `ExternalResource` drop key `ExternalResource_ProjectType_relevantFor`; + +rename table `ExternalResource` to `external_resource`; + +alter table `external_resource` rename column `relevantFor_id` to `project_type_id`; + +-- table: project_type_project_modules, except foreign key to coming table project_type + +alter table `project_type_project_modules` drop foreign key `FK_4attsf1e22qpveesgl6o9b7lg`; +alter table `project_type_project_modules` drop key `FK_4attsf1e22qpveesgl6o9b7lg`; +alter table `project_type_project_modules` drop primary key; + +rename table `project_type_project_modules` to `project_type_project_module`; + +alter table `project_type_project_module` rename column `ProjectType_id` to `project_type_id`; +alter table `project_type_project_module` rename column `projectModules` to `project_module`; + +alter table `project_type_project_module` add primary key (project_type_id, project_module); + +-- table: project_type_settings, except foreign key to coming table project_type + +alter table `project_type_settings` drop foreign key `FK_project_class_settings_projectType`; +alter table `project_type_settings` drop key `FK_oxqyb1t8jo7cq2fx8j9slvloa`; +alter table `project_type_settings` drop key `UK_project_class_settings_projectType`; + +alter table `project_type_settings` rename column `numDaysBetweenPeerReviewsOnSameProject` to `num_days_between_peer_reviews_on_same_project`; +alter table `project_type_settings` rename column `numDaysToSubmitPeerReview` to `num_days_to_submit_peer_review`; +alter table `project_type_settings` rename column `projectType_id` to `project_type_id`; +alter table `project_type_settings` rename column `numDaysBeforePeerGetsCancelled` to `num_days_before_peer_gets_cancelled`; +alter table `project_type_settings` rename column `minAuthors` to `min_authors`; +alter table `project_type_settings` rename column `maxAuthors` to `max_authors`; +alter table `project_type_settings` rename column `maxFinalSeminarActiveParticipation` to `max_final_seminar_active_participation`; +alter table `project_type_settings` rename column `maxOpponentsOnFinalSeminar` to `max_opponents_on_final_seminar`; +alter table `project_type_settings` rename column `minFinalSeminarActiveParticipation` to `min_final_seminar_active_participation`; +alter table `project_type_settings` rename column `minOpponentsOnFinalSeminar` to `min_opponents_on_final_seminar`; +alter table `project_type_settings` rename column `minimumOppositionsToBeGraded` to `min_oppositions_to_be_graded`; +alter table `project_type_settings` rename column `minimumActiveParticipationsToBeGraded` to `min_active_participations_to_be_graded`; + +alter table `project_type_settings` add constraint uk_project_type_settings_project_type_id unique(project_type_id); + +-- table: grading_report_template, except foreign key to coming table project_type + +alter table `grading_report_template` drop foreign key `FK_grading_report_template_projectType`; +alter table `grading_report_template` drop key `FK_qovbb9ql33oaxprfr01w7ss9u`; +alter table `grading_report_template` drop key `UK_only_one_template_per_date_and_type`; + +alter table `grading_report_template` change `projectType_id` `project_type_id` bigint(20) not null after `failing_grade`; + +alter table `grading_report_template` add constraint uk_grading_report_template_project_type_id_valid_from unique(project_type_id, valid_from); + +-- table: grading_report_template_grade_limits + +alter table `grading_report_template_grade_limits` drop foreign key `FK_grade_limit_grading_report_template `; +alter table `grading_report_template_grade_limits` drop key `UK_one_grade_per_template`; + +rename table `grading_report_template_grade_limits` to `grading_report_template_grade_limit`; + +alter table `grading_report_template_grade_limit` change `grading_report_template_id` `grading_report_template_id` bigint(20) default null after `lower_limit`; + +alter table `grading_report_template_grade_limit` add constraint uk_grt_gl_grading_report_template_id_grade unique (grading_report_template_id, grade); + +alter table `grading_report_template_grade_limit` + add constraint fk_grt_gl_grading_report_template_id + foreign key (grading_report_template_id) references grading_report_template (id) + on delete cascade on update cascade; + +/* >>> START: table grading_criterion_template, GradingCriterion and criterion share same JPA MappedSuperclass, must be handled together. */ + +-- table: criterion (partially, only rename three columns, since this table criterion shares same +-- JPA MappedSuperclass AbstractCriterion with grading_criterion_template, and GradingCriterion + +alter table `criterion` rename column `title` to `title_sv`; +alter table `criterion` rename column `titleEn` to `title_en`; +alter table `criterion` rename column `sortOrder` to `sort_order`; + +-- table: GradingCriterion (partially, only rename four columns, since this table GradingCriterion shares same +-- JPA MappedSuperclass AbstractCriterion and AbstractGradingCriterion with grading_criterion_template. + +alter table `GradingCriterion` rename column `title` to `title_sv`; +alter table `GradingCriterion` rename column `titleEn` to `title_en`; +alter table `GradingCriterion` rename column `sortOrder` to `sort_order`; +alter table `GradingCriterion` rename column `pointsRequiredToPass` to `points_required_to_pass`; + +-- table: grading_criterion_template + +alter table `grading_criterion_template` drop foreign key `FK_b37xw6uyfj98ff2tsn5t8x5q`; +alter table `grading_criterion_template` drop key `FK_b37xw6uyfj98ff2tsn5t8x5q`; + +alter table `grading_criterion_template` rename column `title` to `title_sv`; +alter table `grading_criterion_template` rename column `titleEn` to `title_en`; +alter table `grading_criterion_template` rename column `sortOrder` to `sort_order`; +alter table `grading_criterion_template` rename column `pointsRequiredToPass` to `points_required_to_pass`; +alter table `grading_criterion_template` rename column `gradingReportTemplate_id` to `grading_report_template_id`; + +alter table `grading_criterion_template` + add constraint fk_gct_grading_report_template_id + foreign key (grading_report_template_id) references grading_report_template (id) + on delete cascade on update cascade; + +/* >>> END: */ + +/* >>> START: table grading_criterion_point_template and GradingCriterionPoint share same JPA MappedSuperclass, must be handled together. */ + +-- table: GradingCriterionPoint (partially, only rename two columns since this table and grading_criterion_pint_template +-- shares same MappedSuperclass AbstractGradingCriterionPoint. + +alter table `GradingCriterionPoint` rename column `description` to `description_sv`; +alter table `GradingCriterionPoint` rename column `descriptionEn` to `description_en`; + +-- table: grading_criterion_point_template + +alter table `grading_criterion_point_template` drop foreign key `FK_gradingCriterionTemplate_id`; +alter table `grading_criterion_point_template` drop key `FK_gradingCriterionTemplate_id`; + +alter table `grading_criterion_point_template` rename column `description` to `description_sv`; +alter table `grading_criterion_point_template` rename column `descriptionEn` to `description_en`; +alter table `grading_criterion_point_template` rename column `gradingCriterionTemplate_id` to `grading_criterion_template_id`; + +alter table `grading_criterion_point_template` + add constraint fk_gc_pt_grading_criterion_template_id + foreign key (grading_criterion_template_id) references grading_criterion_template (id) + on delete cascade on update cascade; + +/* >>> END: */ + +-- table: checklist_template_ProjectType, except foreign key to coming table project_type + +alter table `checklist_template_ProjectType` drop foreign key `FK_checklist_template_projectType_id`; +alter table `checklist_template_ProjectType` drop foreign key `FK_checklist_template_degree_level_checklist_template_id`; +alter table `checklist_template_ProjectType` drop key `FK_checklist_template_projectType_id`; +alter table `checklist_template_ProjectType` drop primary key; + +rename table `checklist_template_ProjectType` to `checklist_template_project_type`; + +alter table `checklist_template_project_type` rename column `projectType_id` to `project_type_id`; + +alter table `checklist_template_project_type` add primary key (checklist_template_id, project_type_id); + +alter table `checklist_template_project_type` + add constraint fk_ct_pt_checklist_template_id + foreign key (checklist_template_id) references checklist_template (id) + on delete cascade on update cascade; + +-- table: milestone_activity_template_ProjectType, except foreign key to coming table project_type + +alter table `milestone_activity_template_ProjectType` drop foreign key `FKFB3FC75180E42A0F`; +alter table `milestone_activity_template_ProjectType` drop foreign key `FKFB3FC75157F6B071`; +alter table `milestone_activity_template_ProjectType` drop key `FKFB3FC75180E42A0F`; +alter table `milestone_activity_template_ProjectType` drop key `FKFB3FC75157F6B071`; +alter table `milestone_activity_template_ProjectType` drop primary key; + +rename table `milestone_activity_template_ProjectType` to `milestone_activity_template_project_type`; + +alter table `milestone_activity_template_project_type` rename column `projectTypes_id` to `project_type_id`; + +alter table `milestone_activity_template_project_type` add primary key (`milestone_activity_template_id`, `project_type_id`); + +alter table `milestone_activity_template_project_type` + add constraint fk_ma_tpt_milestone_activity_template_id + foreign key (milestone_activity_template_id) references milestone_activity_template (id) + on delete cascade on update cascade; + +-- table: idea, we only remove foreign key from idea to ProjectType and rename the column projectType_id here. +-- This table has many related tables and will be fixed later. + +alter table `idea` drop foreign key `FK_idea_projectType`; +alter table `idea` drop key `FK_idea_projectType`; + +alter table `idea` rename column `projectType_id` to `project_type_id`; + +-- table: project, we only remove foreign key from project to ProjectType and rename the column projectType_id here. +-- This table has many related tables and will be fixed later. + +alter table `project` drop foreign key `FK_project_projectType`; +alter table `project` drop key `FKED904B19B2B6081F`; + +alter table `project` rename column `projectType_id` to `project_type_id`; + +/* + * Table target, projectPartner and ApplicationPeriodProjectType has not only foreign key referencing table ProjectType, + * but also foreign key referencing table ApplicationPeriod. Table ApplicationPeriodProjectType references to + * ActivityPlanTemplate as well. + * + * Table ActivityTemplate, ActivityPlanTemplate, ApplicationPeriod using camel case naming convention, + * ApplicationPeriod has a related table, applicationperiodexemption, and they all need to + * fixed as well, before ProjectType can be fixed. A foreign key from table idea to ApplicationPeriod needs to be removed + * before table ApplicationPeriod can be fixed. + * + * Removal of foreign keys and renaming of columns and table name must be fixed in following order: + * + * 1. target, projectPartner, ApplicationPeriodProjectType + * 2. ActivityTemplate and ActivityPlanTemplate + * 3. ApplicationPeriod, applicationperiodexcemption, and idea as well + * + * Foreign keys will be then added in reverse order, it's like a stack pop. + */ + +-- >>> STACK PUSH: 1st table group: target, projectPartner, ApplicationPeriodProjectType + +-- table: target, except foreign key to coming table project_type, and application_period + +alter table `target` drop foreign key `target_user_id`; +alter table `target` drop foreign key `FKCB7E7191A520201Eb`; +alter table `target` drop foreign key `FKCB7E7191790761A4b`; +alter table `target` drop key `FKCB7E7191A520201E`; +alter table `target` drop key `FKCB7E7191790761A4`; +alter table `target` drop primary key; + +alter table `target` rename column `applicationPeriodId` to `application_period_id`; +alter table `target` rename column `projectTypeId` to `project_type_id`; + +alter table `target` add primary key (application_period_id, project_type_id, user_id); + +alter table `target` + add constraint fk_target_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: projectPartner, except foreign key to coming table project_type, and application_period + +alter table `projectPartner` drop foreign key `FK_project_partner_project_type`; +alter table `projectPartner` drop foreign key `FK_ProjectPartner_ApplicationPeriod_applicationPeriod`; +alter table `projectPartner` drop foreign key `FK1882B6F895349BF`; +alter table `projectPartner` drop key `FK_ProjectPartner_ApplicationPeriod_applicationPeriod`; +alter table `projectPartner` drop key `FK_project_partner_project_type`; +alter table `projectPartner` drop key `FK1882B6F895349BF`; + +rename table `projectPartner` to `project_partner`; + +alter table `project_partner` rename column `infotext` to `info_text`; +alter table `project_partner` rename column `projectType_id` to `project_type_id`; +alter table `project_partner` rename column `applicationPeriod_id` to `application_period_id`; + +alter table `project_partner` + add constraint fk_project_partner_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: ApplicationPeriodProjectType, except foreign key to coming table application_period, project_type and activity_plan_template. + +alter table `ApplicationPeriodProjectType` drop foreign key `FK_hqebt63rl2mhogp66dy5m7upo`; +alter table `ApplicationPeriodProjectType` drop foreign key `FK_546usee339qh4g5otguwka3hi`; +alter table `ApplicationPeriodProjectType` drop foreign key `FK_3ku67jvegs1xxh8ykk023i7sb`; +alter table `ApplicationPeriodProjectType` drop key `FK_3ku67jvegs1xxh8ykk023i7sb`; +alter table `ApplicationPeriodProjectType` drop key `FK_546usee339qh4g5otguwka3hi`; +alter table `ApplicationPeriodProjectType` drop key `FK_hqebt63rl2mhogp66dy5m7upo`; +alter table `ApplicationPeriodProjectType` drop primary key; + +rename table `ApplicationPeriodProjectType` to `application_period_project_type`; + +alter table `application_period_project_type` rename column `applicationPeriod_id` to `application_period_id`; +alter table `application_period_project_type` rename column `projectType_id` to `project_type_id`; +alter table `application_period_project_type` rename column `activityPlanTemplate_id` to `activity_plan_template_id`; + +alter table `application_period_project_type` add primary key (application_period_id, project_type_id); + +-- >>> STACK PUSH: 2nd table group: ActivityPlanTemplate and ActivityTemplate + +-- table: ActivityTemplate, except foreign key to coming table activity_plan_template + +alter table `ActivityTemplate` drop foreign key `FK_ca5bhq3i6p2g292fo5l4fqtf`; +alter table `ActivityTemplate` drop foreign key `FK_activity_template_checklist_template`; +alter table `ActivityTemplate` drop key `FKD4434665C5FC509F`; +alter table `ActivityTemplate` drop key `FK_ca5bhq3i6p2g292fo5l4fqtf`; +alter table `ActivityTemplate` drop key `FK_667ye6la0yb5obk64v21knimn`; + +rename table `ActivityTemplate` to `activity_template`; + +alter table `activity_template` rename column `numberInOrder` to `number_in_order`; +alter table `activity_template` rename column `activityPlanTemplate_id` to `activity_plan_template_id`; +alter table `activity_template` rename column `daysOffset` to `days_offset`; +alter table `activity_template` rename column `checkListTemplate_id` to `checklist_template_id`; + +alter table `activity_template` + add constraint fk_activity_template_checklist_template_id + foreign key (checklist_template_id) references checklist_template (id) + on delete set null on update cascade; + +-- table: ActivityPlanTemplate (at this stage, no any foreign key is referenced to ActivityPlanTemplate) + +alter table `ActivityPlanTemplate` drop foreign key `FK_rgwf80yvcy2msbb6g80bae10p`; +alter table `ActivityPlanTemplate` drop key `FK_rgwf80yvcy2msbb6g80bae10p`; +alter table `ActivityPlanTemplate` drop key `FKACCF6522E44F4DBE`; + +rename table `ActivityPlanTemplate` to `activity_plan_template`; + +alter table `activity_plan_template` rename column `isSysAdminTemplate` to `is_sys_admin_template`; +alter table `activity_plan_template` rename column `creator_id` to `creator_user_id`; + +alter table `activity_plan_template` + add constraint fk_activity_plan_template_creator_user_id + foreign key (creator_user_id) references user (id) + on delete cascade on update cascade; + +-- Add back all foreign key references to activity_plan_template + +-- add foreign key reference from activity_template to activity_plan_template +alter table `activity_template` + add constraint fk_activity_template_activity_plan_template_id + foreign key (activity_plan_template_id) references activity_plan_template (id) + on delete cascade on update cascade; + +-- add foreign key reference from application_period_project_type to activity_plan_template +alter table `application_period_project_type` + add constraint fk_ap_pt_activity_plan_template_id + foreign key (activity_plan_template_id) references activity_plan_template (id) + on delete cascade on update cascade; + +-- >>> STACK POP: 2nd table group (ActivityPlanTemplate and ActivityTemplate) is done!!! + +-- >>> STACK PUSH: 3rd table group: ApplicationPeriod, applicationperiodexemption, idea + +-- table: applicationperiodexeption, except foreign key reference to coming table application_period + +alter table `applicationperiodexemption` drop foreign key `fk_application_period_exemption_user`; +alter table `applicationperiodexemption` drop foreign key `fk_application_period_exemption_application_period`; +alter table `applicationperiodexemption` drop foreign key `FK_4p3he5fymtmdgbkl3xwrodq36`; +alter table `applicationperiodexemption` drop key `i_user_application_period`; +alter table `applicationperiodexemption` drop key `i_application_period`; +alter table `applicationperiodexemption` drop key `i_user`; +alter table `applicationperiodexemption` drop key `FK_4p3he5fymtmdgbkl3xwrodq36`; +alter table `applicationperiodexemption` drop primary key; + +rename table `applicationperiodexemption` to `application_period_exemption`; + +alter table `application_period_exemption` rename column `endDate` to `end_date`; +alter table `application_period_exemption` rename column `grantedBy_id` to `granted_by_id`; +alter table `application_period_exemption` rename column `grantedOn` to `granted_on`; +alter table `application_period_exemption` rename column `applicationPeriodId` to `application_period_id`; + +alter table `application_period_exemption` add primary key (`application_period_id`,`user_id`,`type`); + +alter table `application_period_exemption` + add constraint fk_ape_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +alter table `application_period_exemption` + add constraint fk_ape_granted_by_id + foreign key (granted_by_id) references user (id) + on delete cascade on update cascade; + +-- table: idea, we only remove foreign key from idea to ApplicationPeriod and rename the column applicationPeriod_id here. +-- This table has many related tables and will be fixed later. + +alter table `idea` drop foreign key `FK6E051897BEC322C1`; +alter table `idea` drop key `FK6E051897BEC322C1`; + +alter table `idea` rename column `applicationPeriod_id` to `application_period_id`; + +-- table: ApplicationPeriod (at this stage, no any foreign key is referenced to ApplicationPeriod) + +rename table `ApplicationPeriod` to `application_period`; + +alter table `application_period` rename column `endDate` to `end_date`; +alter table `application_period` rename column `startDate` to `start_date`; +alter table `application_period` rename column `courseStartDate` to `course_start_date`; +alter table `application_period` rename column `courseEndDate` to `course_end_date`; + +-- Add back all foreign key references to application_period, since table application_period is ready + +-- add back foreign key reference from ide to application_period +alter table `idea` + add constraint fk_idea_application_period_id + foreign key (application_period_id) references application_period (id) + on delete cascade on update cascade; + +-- add back foreign key reference from application_period_exemption to application_period +alter table `application_period_exemption` + add constraint fk_ape_application_period_id + foreign key (application_period_id) references application_period (id) + on delete cascade on update cascade; + +-- >>> STACK POP: 3rd table group: ApplicationPeriod, applicationperiodexemption, idea is done!!! + +-- add back foreign key reference from application_period_project_type to application_period +alter table `application_period_project_type` + add constraint fk_ap_pt_application_period_id + foreign key (application_period_id) references application_period (id) + on delete cascade on update cascade; + +-- add back foreign key reference from project_partner to application_period +alter table `project_partner` + add constraint fk_project_partner_application_period_id + foreign key (application_period_id) references application_period (id) + on delete cascade on update cascade; + +-- add back foreign key reference from target to application_period +alter table `target` + add constraint fk_target_application_period_id + foreign key (application_period_id) references application_period (id) + on delete cascade on update cascade; + +-- table: ProjectType (finally!! at this stage, no any foreign key is referenced to ProjectType) + +rename table `ProjectType` to `project_type`; + +alter table `project_type` rename column `degreeType` to `degree_type`; + +-- Add back all foreign key references to project_type + +-- add back foreign key reference from application_period_project_type to project_type +alter table `application_period_project_type` + add constraint fk_ap_pt_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from project_partner to project_type +alter table `project_partner` + add constraint fk_project_partner_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from target to project_type +alter table `target` + add constraint fk_target_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- >>> STACK POP: 1st table group: target, projectPartner, ApplicationPeriodProjectType is done!!! + +-- add back foreign key reference from project to project_type +alter table `project` + add constraint fk_project_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from idea to project_type +alter table `idea` + add constraint fk_idea_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from milestone_activity_template_project_type to project_type +alter table `milestone_activity_template_project_type` + add constraint fk_ma_tpt_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from checklist_template_project_type to project_type +alter table `checklist_template_project_type` + add constraint fk_ct_pt_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from grading_report_template to project_type +alter table `grading_report_template` + add constraint fk_grading_report_template_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from project_type_settings to project_type +alter table `project_type_settings` + add constraint fk_project_type_settings_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from project_type_project_module to project_type +alter table `project_type_project_module` + add constraint fk_project_type_project_module_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from external_resource to project_type +alter table `external_resource` + add constraint fk_external_resource_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +-- add back foreign key reference from user_profile_project_type to project_type. +alter table `user_profile_project_type` + add constraint fk_user_profile_project_type_project_type_id + foreign key (project_type_id) references project_type (id) + on delete cascade on update cascade; + +/* + * Step 7: checklist related tables + */ + +-- table: checklist_checklist_question + +alter table `checklist_checklist_question` drop foreign key `FKC77ED98C64F9D54`; +alter table `checklist_checklist_question` drop foreign key `FKC77ED981F327355`; +alter table `checklist_checklist_question` drop key `FKC77ED981F327355`; +alter table `checklist_checklist_question` drop key `FKC77ED98C64F9D54`; +alter table `checklist_checklist_question` drop key `UK_o5ndj9lydqv17attv7uf8wlr`; +alter table `checklist_checklist_question` drop key `questions_id`; +alter table `checklist_checklist_question` drop primary key; + +alter table `checklist_checklist_question` rename column `questions_id` to `checklist_question_id`; + +alter table `checklist_checklist_question` add primary key (checklist_id, checklist_question_id); + +alter table `checklist_checklist_question` add constraint uk_ccq_checklist_question_id unique(checklist_question_id); + +alter table `checklist_checklist_question` + add constraint fk_ccq_checklist_question_id + foreign key (checklist_question_id) references checklist_question (id) + on delete cascade on update cascade; + +alter table `checklist_checklist_question` + add constraint fk_ccq_checklist_id + foreign key (checklist_id) references checklist (id) + on delete cascade on update cascade; + +-- table: Checklist_userLastOpenDate + +alter table `Checklist_userLastOpenDate` drop foreign key `FKF7E07AB26D025A9`; +alter table `Checklist_userLastOpenDate` drop foreign key `FKF7E07AB21F327355`; +alter table `Checklist_userLastOpenDate` drop key `FKF7E07AB26D025A9`; +alter table `Checklist_userLastOpenDate` drop key `FKF7E07AB21F327355`; +alter table `Checklist_userLastOpenDate` drop primary key; + +rename table `Checklist_userLastOpenDate` to `checklist_user_last_open_date`; + +alter table `checklist_user_last_open_date` rename column `CheckList_id` to `checklist_id`; +alter table `checklist_user_last_open_date` rename column `userLastOpenDate` to `last_open_date`; +alter table `checklist_user_last_open_date` rename column `userLastOpenDate_KEY` to `user_id`; + +alter table `checklist_user_last_open_date` add primary key (checklist_id, user_id); + +alter table `checklist_user_last_open_date` + add constraint fk_cu_lod_checklist_id + foreign key (checklist_id) references checklist(id) + on delete cascade on update cascade; + +alter table `checklist_user_last_open_date` + add constraint fk_cu_lod_user_id + foreign key (user_id) references user(id) + on delete cascade on update cascade; + +-- table: checklist_checklist_category + +alter table `checklist_checklist_category` drop foreign key `FK54F86EB08725F1D`; +alter table `checklist_checklist_category` drop foreign key `FK54F86EB01F327355`; +alter table `checklist_checklist_category` drop key `FK54F86EB08725F1D`; +alter table `checklist_checklist_category` drop key `FK54F86EB01F327355`; + +alter table `checklist_checklist_category` rename column `categories_id` to `checklist_category_id`; + +alter table `checklist_checklist_category` + add constraint fk_cca_checklist_id + foreign key (checklist_id) references checklist (id) + on delete cascade on update cascade; + +alter table `checklist_checklist_category` + add constraint fk_cca_checklist_category_id + foreign key (checklist_category_id) references checklist_category (id) + on delete cascade on update cascade; + +-- table: checklist_category + +alter table `checklist_category` drop key `categoryName`; +alter table `checklist_category` rename column `categoryName` to `category_name`; + +alter table `checklist_category` add constraint uk_checklist_category_category_name unique(category_name); + +-- table: checklist + +alter table `checklist` drop foreign key `FK_checklist_project`; +alter table `checklist` drop key `I_checkList_activity`; + +alter table `checklist` + add constraint fk_checklist_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- table : checklist_question_checklist_answer + +alter table `checklist_question_checklist_answer` drop foreign key `FK86395A5787D18D44`; +alter table `checklist_question_checklist_answer` drop foreign key `FK86395A574BFBD702`; +alter table `checklist_question_checklist_answer` drop key `FK86395A574BFBD702`; +alter table `checklist_question_checklist_answer` drop key `UK_47is0po5b69467hxbgr4a2gph`; +alter table `checklist_question_checklist_answer` drop key `answers_id`; + +alter table `checklist_question_checklist_answer` rename column `answers_id` to `checklist_answer_id`; + +alter table `checklist_question_checklist_answer` add constraint uk_cq_ca_checklist_answer_id unique(checklist_answer_id); + +alter table `checklist_question_checklist_answer` + add constraint fk_cq_ca_checklist_answer_id + foreign key (checklist_answer_id) references checklist_answer (id) + on delete cascade on update cascade; + +alter table `checklist_question_checklist_answer` + add constraint fk_cq_ca_checklist_question_id + foreign key (checklist_question_id) references checklist_question (id) + on delete cascade on update cascade; + +-- table: checklist_answer + +alter table `checklist_answer` drop foreign key `FK49936477895349BF`; +alter table `checklist_answer` drop key `FK49936477895349BF`; + +alter table `checklist_answer` + add constraint fk_checklist_answer_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- update to NOT_APPLICABLE because of typo in code +update `checklist_answer` set answer = 'NOT_APPLICABLE' where answer = 'NOT_APLICABLE'; +update `answer` set answer = 'NOT_APPLICABLE' where answer = 'NOT_APLICABLE'; + +-- table: checklist_question + +alter table `checklist_question` rename column `questionNumber` to `question_number`; + +-- table: ChecklistTemplate_questions + +alter table `ChecklistTemplate_questions` drop foreign key `FK872F7C0E869F0235`; +alter table `ChecklistTemplate_questions` drop key `FK872F7C0E869F0235`; + +rename table `ChecklistTemplate_questions` to `checklist_template_question`; + +alter table `checklist_template_question` rename column `CheckListTemplate_id` to `checklist_template_id`; +alter table `checklist_template_question` rename column `questions` to `question`; + +alter table `checklist_template_question` + add constraint fk_ctq_checklist_template_id + foreign key (checklist_template_id) references checklist_template (id) + on delete cascade on update cascade; + +-- table: checklist_template_checklist_category + +alter table `checklist_template_checklist_category` drop foreign key `FK4E82F4438725F1D`; +alter table `checklist_template_checklist_category` drop foreign key `FK4E82F44372B51E82`; +alter table `checklist_template_checklist_category` drop key `FK4E82F4438725F1D`; +alter table `checklist_template_checklist_category` drop key `FK4E82F44372B51E82`; + +alter table `checklist_template_checklist_category` rename column `categories_id` to `checklist_category_id`; + +alter table `checklist_template_checklist_category` + add constraint fk_ct_cc_checklist_template_id + foreign key (checklist_template_id) references checklist_template (id) + on delete cascade on update cascade; + +alter table `checklist_template_checklist_category` + add constraint fk_ct_cc_checklist_category_id + foreign key (checklist_category_id) references checklist_category (id) + on delete cascade on update cascade; + +-- table: checklist_template + +alter table `checklist_template` drop foreign key `FK14DA6F3E44F4DBE`; +alter table `checklist_template` drop key `FK14DA6F3E44F4DBE`; + +alter table `checklist_template` rename column `creator_id` to `creator_user_id`; +alter table `checklist_template` rename column `templateNumber` to `template_number`; + +alter table `checklist_template` + add constraint fk_checklist_template_creator_user_id + foreign key (creator_user_id) references user (id) + on delete cascade on update cascade; + +/* + * Step 8: Survey related related tables + */ + +-- table: SurveyAnswer_multipleAnswers, except foreign key to coming table survey_answer + +alter table `SurveyAnswer_multipleAnswers` drop foreign key `FK_SA`; +alter table `SurveyAnswer_multipleAnswers` drop key `FK_SA`; + +rename table `SurveyAnswer_multipleAnswers` to `survey_answer_multiple_answers`; + +alter table `survey_answer_multiple_answers` rename column `SurveyAnswer_id` to `survey_answer_id`; +alter table `survey_answer_multiple_answers` rename column `multipleAnswers` to `multiple_answers`; + +-- table: SurveyAnswer, except foreign key to coming table survey and question + +alter table `SurveyAnswer` drop foreign key `FK_answer_question`; +alter table `SurveyAnswer` drop foreign key `FK_answer_survey`; +alter table `SurveyAnswer` drop key `FK_answer_question`; +alter table `SurveyAnswer` drop key `FK_answer_survey`; + +rename table `SurveyAnswer` to `survey_answer`; + +-- add back foreign key reference from survey_answer_multiple_answers to survey_answer + +alter table `survey_answer_multiple_answers` + add constraint fk_sama_survey_answer_id + foreign key (survey_answer_id) references survey_answer (id) + on delete cascade on update cascade; + +-- table: Question_choices, except foreign key to coming table question + +alter table `Question_choices` drop foreign key `FK_question_choices_question`; +alter table `Question_choices` drop key `FK_question_choices_question`; + +rename table `Question_choices` to `question_choices`; + +-- table: Question + +rename table `Question` to `question`; + +-- add back foreign key reference from question_choices to question + +alter table `question_choices` + add constraint fk_question_choices_question_id + foreign key (question_id) references question (id) + on delete cascade on update cascade; + +-- add back foreign key references from survey_answer to question + +alter table `survey_answer` + add constraint fk_survey_answer_question_id + foreign key (question_id) references question (id) + on delete cascade on update cascade; + +-- table: survey + +alter table `Survey` drop foreign key `FK_survey_project`; +alter table `Survey` drop key `FK_survey_project`; +alter table `Survey` drop foreign key `FK_survey_user`; +alter table `Survey` drop key `FK_survey_user`; + +rename table `Survey` to `survey`; + +alter table `survey` + add constraint fk_survey_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `survey` + add constraint fk_survey_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- add back foreign key references from survey_answer to survey + +alter table `survey_answer` + add constraint fk_survey_answer_survey_id + foreign key (survey_id) references survey (id) + on delete cascade on update cascade; + +/* + * Step 9: Keyword and Research Area related tables + */ + +-- table: Keyword_researcharea, except foreign keys to coming table keyword and research_area + +alter table `Keyword_researcharea` drop foreign key `FKF8C66F5E98ED461`; +alter table `Keyword_researcharea` drop key `FKF8C66F5E98ED461`; +alter table `Keyword_researcharea` drop foreign key `FKF8C66F5E6F20ECBC`; +alter table `Keyword_researcharea` drop key `FKF8C66F5E6F20ECBC`; + +rename table `Keyword_researcharea` to `keyword_research_area`; + +alter table `keyword_research_area` rename column `Keyword_id` to `keyword_id`; +alter table `keyword_research_area` rename column `researchAreas_id` to `research_area_id`; + +-- table: idea_Keyword + +alter table `idea_Keyword` drop foreign key `FK3707EE21AE316F00`; +alter table `idea_Keyword` drop key `FK3707EE21AE316F00`; +alter table `idea_Keyword` drop foreign key `FK3707EE21BD1521C1`; + +alter table `idea_Keyword` drop primary key; + +rename table `idea_Keyword` to `idea_keyword`; + +alter table `idea_keyword` rename column `keywords_id` to `keyword_id`; + +alter table `idea_keyword` add primary key (idea_id, keyword_id); + +alter table `idea_keyword` + add constraint fk_idea_keyword_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +-- table: keyword + +alter table `Keyword` drop key `deleted_index`; + +rename table `Keyword` to `keyword`; + +create index idx_keyword_deleted on keyword (deleted); + +-- add back foreign key reference from table idea_keyword to table keyword + +alter table `idea_keyword` + add constraint fk_idea_keyword_keyword_id + foreign key (keyword_id) references keyword (id) + on delete cascade on update cascade; + +-- add back foreign key reference from table keyword_research_area to table keyword + +alter table `keyword_research_area` + add constraint fk_kra_keyword_id + foreign key (keyword_id) references keyword (id) + on delete cascade on update cascade; + +-- table: user_research_area + +alter table `user_research_area` drop foreign key `user_research_area_user_id`; +alter table `user_research_area` drop foreign key `user_research_area_research_area_id`; +alter table `user_research_area` drop key `user_research_area_research_area_id`; + +alter table `user_research_area` + add constraint fk_ura_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- drop foreign key from idea to table researcharea before we can proceed with that table, +-- change foreign key column name as well + +alter table `idea` drop foreign key `FK6E0518974E257FBF`; +alter table `idea` drop key `FK6E0518974E257FBF`; + +alter table `idea` rename column `researchArea_id` to `research_area_id`; + +-- drop foreign key from project to table researcharea before we can proceed with that table, +-- change foreign key column name as well + +alter table `project` drop foreign key `FK_research_area_id`; +alter table `project` drop key `FK_research_area_id`; + +alter table `project` rename column `researchArea_id` to `research_area_id`; + +-- table: researcharea + +alter table `researcharea` drop key `deleted_index`; +alter table `researcharea` drop key `identifier`; + +rename table `researcharea` to `research_area`; + +create index idx_research_area_deleted on research_area (deleted); + +alter table `research_area` add constraint uk_research_area_identifier unique (identifier); + +-- add back foreign key reference from table project to table research_area + +alter table `project` + add constraint fk_project_research_area_id + foreign key (research_area_id) references research_area (id) + on delete cascade on update cascade; + +-- add back foreign key reference from table idea to table research_area + +alter table `idea` + add constraint fk_idea_research_area_id + foreign key (research_area_id) references research_area (id) + on delete cascade on update cascade; + +-- add back foreign key reference from table user_research_area to table research_area + +alter table `user_research_area` + add constraint fk_ura_research_area_id + foreign key (research_area_id) references research_area (id) + on delete cascade on update cascade; + +-- add back foreign key reference from table keyword_research_area to table research_area + +alter table `keyword_research_area` + add constraint fk_kra_research_area_id + foreign key (research_area_id) references research_area (id) + on delete cascade on update cascade; + +/* + * Step 10: idea related tables + */ + +-- table: idea + +alter table `idea` drop foreign key `FK6E051897B9431B73`; +alter table `idea` drop foreign key `FK6E051897C1813915`; +alter table `idea` drop foreign key `FK6E051897E44F4DBE`; + +alter table `idea` drop key `FK6E051897C1813915`; +alter table `idea` drop key `FK6E051897B9431B73`; +alter table `idea` drop key `FK6E051897E44F4DBE`; + +alter table `idea` drop key `UK_only_one_idea_per_project`; + +alter table `idea` change `published` `published` bit(1) not null default b'1' after `type`; +alter table `idea` change `cachedStatus` `cached_status` varchar(255) default null after `published`; +alter table `idea` change `inactive` `inactive` tinyint(1) not null default 0 after `cached_status`; + +alter table `idea` change `practicalHow` `practical_how` longtext default null after `inactive`; +alter table `idea` change `theoryHow` `theory_how` longtext default null after `practical_how`; +alter table `idea` change `literature` `literature` longtext default null after `why`; + +alter table `idea` change `background` `background` longtext default null after `literature`; +alter table `idea` change `problem` `problem` longtext default null after `background`; +alter table `idea` change `method` `method` longtext default null after `problem`; +alter table `idea` change `interests` `interests` longtext default null after `method`; + +alter table `idea` rename column `creator_id` to `creator_user_id`; +alter table `idea` rename column `match_id` to `latest_match_id`; + +alter table `idea` add constraint uk_idea_project_id unique(project_id); + +alter table `idea` + add constraint fk_idea_creator_user_id + foreign key (creator_user_id) references user (id) + on delete cascade on update cascade; + +alter table `idea` + add constraint fk_idea_latest_match_id + foreign key (latest_match_id) references idea_match (id) + on delete cascade on update cascade; + +alter table `idea` + add constraint fk_idea_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- table: idea_language + +alter table `idea_language` drop foreign key `FK_idea_language_idea`; +alter table `idea_language` drop key `FK_idea_language_idea`; + +alter table `idea_language` + add constraint fk_idea_language_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +-- table: idea_export + +alter table `idea_export` drop foreign key `FK68FA705CFCDADF61`; +alter table `idea_export` drop key `FK68FA705CFCDADF61`; + +alter table `idea_export` + add constraint fk_idea_export_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +-- table: idea_first_meeting + +alter table `idea_first_meeting` drop foreign key `FK9393AA04FCDADF61`; +alter table `idea_first_meeting` drop key `FK9393AA04FCDADF61`; + +alter table `idea_first_meeting` drop key `UK_k4m4tupnikallbq3cq3llvlmk`; +alter table `idea_first_meeting` drop key `idea_id`; + +alter table `idea_first_meeting` rename column `firstMeetingDate` to `first_meeting_date`; +alter table `idea_first_meeting` change `room` `room` longtext not null after `first_meeting_date`; + +alter table `idea_first_meeting` + add constraint fk_idea_first_meeting_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +alter table `idea_first_meeting` + add constraint uk_idea_first_meeting_idea_id unique(idea_id); + +-- table: idea_match + +alter table `idea_match` drop foreign key `FK87EA481DFCDADF61`; +alter table `idea_match` drop foreign key `FK87EA481DA89FFB7F`; +alter table `idea_match` drop foreign key `idea_match_supervisor_id`; + +alter table `idea_match` drop key `FK87EA481DFCDADF61`; +alter table `idea_match` drop key `FK87EA481DA89FFB7F`; +alter table `idea_match` drop key `idea_match_supervisor_id`; + +alter table `idea_match` rename column `changedBy_id` to `changed_by_user_id`; +alter table `idea_match` rename column `supervisor_id` to `supervisor_user_id`; + +alter table `idea_match` + add constraint fk_idea_match_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +alter table `idea_match` + add constraint fk_idea_match_changed_by_user_id + foreign key (changed_by_user_id) references user (id) + on delete cascade on update cascade; + +alter table `idea_match` + add constraint fk_idea_match_supervisor_user_id + foreign key (supervisor_user_id) references user (id) + on delete cascade on update cascade; + +-- table: preliminary_match + +alter table `preliminary_match` drop foreign key `FK_preliminary_match_supervisor`; +alter table `preliminary_match` drop foreign key `FK_preliminary_match_idea`; + +alter table `preliminary_match` drop key `FK_preliminary_match_supervisor`; +alter table `preliminary_match` drop key `FK_preliminary_match_idea`; + +alter table `preliminary_match` change `comment` `comment` mediumtext default null after `version`; +alter table `preliminary_match` rename column `supervisor_id` to `supervisor_user_id`; + +alter table `preliminary_match` + add constraint fk_preliminary_match_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +alter table `preliminary_match` + add constraint fk_preliminary_match_supervisor_user_id + foreign key (supervisor_user_id) references user (id) + on delete cascade on update cascade; + +-- table: idea_student + +alter table `idea_student` drop foreign key `idea_student_user_id`; +alter table `idea_student` drop foreign key `FK9458BA93FCDADF61`; + +alter table `idea_student` drop key `idea_student_user_id`; +alter table `idea_student` drop key `FK9458BA93FCDADF61`; +alter table `idea_student` drop key `FK_c5py593l4g261jdkuvwdmcmgj`; + +alter table `idea_student` rename column `dateCreated` to `date_created`; +alter table `idea_student` change `id` `id` bigint(20) not null auto_increment first; + +alter table `idea_student` + add constraint fk_idea_student_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +alter table `idea_student` + add constraint fk_idea_student_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +/* + * Step 11: activity related tables + * + * Some tables of this group of tables need to be renamed. Because of how foreign keys reference to each other + * between them, the order and behavior of how the tables will be fixed looks like stack again. + * + * 1. Remove references from activity_final_seminar, activity_thread, project_first_meeting to activity, + * the fix these three tables, but wait to later before foreign keys are added back to becoming activity table. + * 2. Remove reference from Activity to ActivtyPlan, and fix table Activity, without adding back foreign key to + * becoming activity_plan table. + * 3. Fix ActivityPlan table, rename it to activity_plan. + * 4. Add back foreign key reference from activity to activity_plan + * 5. Add back foreign key reference from activity_final_seminar, activity_thread, project_first_meeting to + * activity table. + */ + +-- table: activity_final_seminar, except foreign key to becoming table activity + +alter table `activity_final_seminar` drop foreign key `activity_final_seminar_ibfk_2`; +alter table `activity_final_seminar` drop foreign key `activity_final_seminar_ibfk_1`; + +alter table `activity_final_seminar` drop key `activity_id`; + +alter table `activity_final_seminar` + add constraint fk_afs_final_seminar_id + foreign key (final_seminar_id) references final_seminar (id) + on delete cascade on update cascade; + +-- table: activity_thread, except foreign key to becoming table activity + +alter table `activity_thread` drop foreign key `FK_activity_thread_project_thread`; +alter table `activity_thread` drop foreign key `FK_activity_thread_activity`; + +alter table `activity_thread` drop key `FK_activity_thread_project_thread`; + +alter table `activity_thread` + add constraint fk_activity_thread_project_thread_id + foreign key (project_thread_id) references project_thread (id) + on delete cascade on update cascade; + +-- table: project_first_meeting, except foreign key to becoming table activity + +alter table `project_first_meeting` drop foreign key `FK_project_first_meeting_activity`; + +alter table `project_first_meeting` drop key `FK_project_first_meeting_activity`; + +alter table `project_first_meeting` change `room` `room` longtext not null after `version`; + +alter table `project_first_meeting` change `activity_id` `activity_id` bigint(20) not null after `room`; + +-- table: activity + +alter table `Activity` drop foreign key `FK_Activity_file_upload`; +alter table `Activity` drop foreign key `FK_Activity_ActivityPlan`; +alter table `Activity` drop foreign key `FK_activity_checkList`; + +alter table `Activity` drop key `FK_Activity_file_upload`; +alter table `Activity` drop key `activityTemplate_id_index`; +alter table `Activity` drop key `deleted_index`; +alter table `Activity` drop key `UK_activity_checkList`; + +rename table `Activity` to `activity`; + +alter table `activity` change `title` `title` varchar(500) not null after `deleted`; +alter table `activity` change `action` `action` varchar(64) not null default 'none' after `description`; +alter table `activity` change `editable` `editable` bit(1) not null default b'1' after `action`; + +alter table `activity` rename column `activityTemplate_id` to `activity_plan_id`; +alter table `activity` rename column `file_upload_reference_id` to `upload_file_reference_id`; + +alter table `activity` add constraint uk_activity_checklist_id unique (checklist_id); +create index idx_activity_deleted on activity(deleted); + +alter table `activity` + add constraint `fk_activity_checklist_id` + foreign key (checklist_id) references checklist (id) + on delete cascade on update cascade ; + +alter table `activity` + add constraint `fk_activity_upload_file_reference_id` + foreign key (upload_file_reference_id) references file_reference (id) + on delete cascade on update cascade ; + +-- table: ActivityPlan + +alter table `ActivityPlan` drop foreign key `fk_ActivityPlan_project_B`; +alter table `ActivityPlan` drop key `project_id`; + +rename table `ActivityPlan` to `activity_plan`; + +alter table `activity_plan` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `activity_plan` change `startDate` `start_date` datetime default null after `version`; + +alter table `activity_plan` add constraint uk_activity_plan_project_id unique (project_id); + +alter table `activity_plan` + add constraint `fk_activity_plan_project_id` + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- add foreign key reference from activity to activity_plan + +alter table `activity` + add constraint fk_activity_activity_plan_id + foreign key (activity_plan_id) references activity_plan (id) + on delete cascade on update cascade; + +-- Add back all foreign key references to activity + +-- add foreign key reference from project_first_meeting to activity + +alter table `project_first_meeting` + add constraint fk_project_first_meeting_activity_id + foreign key (activity_id) references activity (id) + on delete cascade on update cascade; + +-- add foreign key reference from activity_thread to activity + +alter table `activity_thread` + add constraint fk_activity_thread_activity_id + foreign key (activity_id) references activity (id) + on delete cascade on update cascade; + +-- add foreign key reference from activity_final_seminar to activity + +alter table `activity_final_seminar` + add constraint fk_afs_activity_id + foreign key (activity_id) references activity (id) + on delete cascade on update cascade; + +/* + * Step 12: Peer Review related tables + */ + +-- table: peer_request + +alter table `peer_request` drop foreign key `FK_peer_request_checklist_template`; +alter table `peer_request` drop foreign key `FK_peer_request_file`; +alter table `peer_request` drop foreign key `FK_ppnisfed4ipbg17rts8vbuqt8`; +alter table `peer_request` drop foreign key `peer_request_reviewer_id`; + +alter table `peer_request` drop key `FK_peer_request_file`; +alter table `peer_request` drop key `FK_ppnisfed4ipbg17rts8vbuqt8`; +alter table `peer_request` drop key `peer_request_reviewer_id`; +alter table `peer_request` drop key `FK514488B2869F0235`; +alter table `peer_request` drop key `FK514488B2C1813915`; + +alter table `peer_request` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `peer_request` change `language` `language` varchar(255) not null after `status`; + +alter table `peer_request` rename column `checkListTemplate_id` to `checklist_template_id`; +alter table `peer_request` rename column `requester_id` to `requester_user_id`; + +alter table `peer_request` change `checklist_template_id` `checklist_template_id` bigint(20) default null after `language`; +alter table `peer_request` change `file_reference_id` `file_reference_id` bigint(20) not null after `checklist_template_id`; + +alter table `peer_request` + add constraint fk_peer_request_checklist_template_id + foreign key (checklist_template_id) references checklist_template (id) + on delete set null on update cascade; + +alter table `peer_request` + add constraint fk_peer_request_file_reference_id + foreign key (file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `peer_request` + add constraint fk_peer_request_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `peer_request` + add constraint fk_peer_request_requester_user_id + foreign key (requester_user_id) references user (id) + on delete cascade on update cascade; + +-- table: peer_review + +alter table `peer_review` drop foreign key `peer_review_reviewer_id`; +alter table `peer_review` drop foreign key `FK_n5wj0qsev5cf8acm0xhfrqlpg`; +alter table `peer_review` drop foreign key `FK_9ke7armwg3tfnghmschgo011f`; +alter table `peer_review` drop foreign key `FK_peer_review_file`; + +alter table `peer_review` drop key `peer_review_reviewer_id`; +alter table `peer_review` drop key `FK_n5wj0qsev5cf8acm0xhfrqlpg`; +alter table `peer_review` drop key `FKB00C90D5C1813915`; +alter table `peer_review` drop key `FK_9ke7armwg3tfnghmschgo011f`; +alter table `peer_review` drop key `FKB00C90D5CEE8709B`; +alter table `peer_review` drop key `FK_peer_review_file`; + +alter table `peer_review` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `peer_review` change `status` `status` varchar(255) not null after `comment`; +alter table `peer_review` change `deadline` `deadline` datetime not null after `status`; + +alter table `peer_review` change `file_reference_id` `file_reference_id` bigint(20) default null after `deadline`; +alter table `peer_review` change `peerRequest_id` `peer_request_id` bigint(20) not null; +alter table `peer_review` change `reviewer_id` `reviewer_user_id` bigint(20) not null; + +alter table `peer_review` + add constraint fk_peer_review_file_reference_id + foreign key (file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `peer_review` + add constraint fk_peer_review_peer_request_id + foreign key (peer_request_id) references peer_request (id) + on delete cascade on update cascade; + +alter table `peer_review` + add constraint fk_peer_review_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `peer_review` + add constraint fk_peer_review_reviewer_user_id + foreign key (reviewer_user_id) references user (id) + on delete cascade on update cascade; + +-- table: answer + +alter table `answer` drop foreign key `FK_64r70sbiishrkuj1vn87vo53k`; + +alter table `answer` drop key `FK_64r70sbiishrkuj1vn87vo53k`; +alter table `answer` drop key `FKABCA3FBE2C41A959`; + +alter table `answer` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `answer` change `question` `question` longtext not null after `version`; +alter table `answer` change `answer` `answer` varchar(255) not null after `question`; + +alter table `answer` rename column `peerReview_id` to `peer_review_id`; + +alter table `answer` + add constraint fk_answer_peer_review_id + foreign key (peer_review_id) references peer_review (id) + on delete cascade on update cascade; + +/* + * Step 13: Milestone related tables + */ + +-- table: milestone + +alter table `milestone` drop foreign key `FKC0841970667E5A5E`; +alter table `milestone` drop foreign key `FKC0841970C1813915`; +alter table `milestone` drop foreign key `milestone_user_id`; + +alter table `milestone` drop key `FKC0841970667E5A5E`; +alter table `milestone` drop key `FKC0841970C1813915`; +alter table `milestone` drop key `milestone_user_id`; + +alter table `milestone` rename column `activity_id` to `milestone_activity_template_id`; + +alter table `milestone` + add constraint fk_milestone_milestone_activity_template_id + foreign key (milestone_activity_template_id) references milestone_activity_template (id) + on delete cascade on update cascade; + +alter table `milestone` + add constraint fk_milestone_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `milestone` + add constraint fk_milestone_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: milestone_activity_template, except foreign key to becoming table event + +alter table `milestone_activity_template` drop foreign key `milestone_activity_template_ibfk_1`; +alter table `milestone_activity_template` drop foreign key `FK42DAA8FE233E1A72`; + +alter table `milestone_activity_template` drop key `milestone_activity_template_ibfk_1`; +alter table `milestone_activity_template` drop key `FK42DAA8FE233E1A72`; +alter table `milestone_activity_template` drop key `deleted_index`; +alter table `milestone_activity_template` drop key `code`; + +alter table `milestone_activity_template` change `description` `description` varchar(255) default null after `title`; +alter table `milestone_activity_template` change `sortOrder` `sort_order` int(11) default null; +alter table `milestone_activity_template` change `editableByStudents` `editable_by_students` bit(1) not null default b'0' after `sort_order`; + +alter table `milestone_activity_template` change `phase` `milestone_phase_template_id` bigint(20) not null; +alter table `milestone_activity_template` change `activatedBy` `activated_by_event_name` varchar(191) default null; + +alter table `milestone_activity_template` add constraint uk_milestone_activity_template_code unique(code); + +create index idx_milestone_activity_template_deleted on milestone_activity_template (deleted); + +alter table `milestone_activity_template` + add constraint fk_mat_milestone_phase_template_id + foreign key (milestone_phase_template_id) references milestone_phase_template (id) + on delete cascade on update cascade; + +-- table: event + +rename table `Event` to `event`; + +-- add foreign key reference from milestone_activity_template to event +alter table `milestone_activity_template` + add constraint fk_mat_activated_by_event_name + foreign key (activated_by_event_name) references event (name) + on delete cascade on update cascade; + +-- table: milestone_phase_template + +alter table `milestone_phase_template` drop key `deleted_index`; + +alter table `milestone_phase_template` change `description` `description` varchar(255) default null after `title`; + +alter table `milestone_phase_template` rename column `sortOrder` to `sort_order`; + +create index idx_milestone_phase_template_deleted on milestone_phase_template (deleted); + +/* + * Step 14: Final Seminar related tables + */ + +-- table: final_seminar + +alter table `final_seminar` drop foreign key `FK_rv1p7wl0dnj25saiarmk55yvr`; +alter table `final_seminar` drop foreign key `FK_final_seminar_document_reference`; + +alter table `final_seminar` drop key `FK_final_seminar_document_reference`; +alter table `final_seminar` drop key `FK_rv1p7wl0dnj25saiarmk55yvr`; +alter table `final_seminar` drop key `deleted_index`; +alter table `final_seminar` drop key `FK49900D28C1813915`; + +alter table `final_seminar` drop key `UK_rv1p7wl0dnj25saiarmk55yvr`; + +alter table `final_seminar` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `final_seminar` change `deleted` `deleted` tinyint(1) not null after `version`; + +alter table `final_seminar` change `startDate` `start_date` datetime not null after `deleted`; +alter table `final_seminar` change `room` `room` varchar(255) not null after start_date; +alter table `final_seminar` change `maxOpponents` `max_opponents` int(11) not null after `room`; +alter table `final_seminar` change `maxParticipants` `max_participants` int(11) not null after `max_opponents`; +alter table `final_seminar` change `presentationLanguage` `presentation_lang` varchar(255) not null after `max_participants`; +alter table `final_seminar` change `documentUploadDate` `document_upload_date` datetime default null after `presentation_lang`; +alter table `final_seminar` change `extra_info` `extra_info` text default null after `document_upload_date`; +alter table `final_seminar` change `creationReason` `creation_reason` mediumtext default null after `extra_info`; +alter table `final_seminar` change `manualParticipants` `manual_participants` tinyint(1) not null default 0 after `creation_reason`; +alter table `final_seminar` change `project_id` `project_id` bigint(20) not null after `document_reference_id`; + +alter table `final_seminar` rename column `document_reference_id` to `document_file_reference_id`; + +alter table `final_seminar` add constraint uk_final_seminar_project_id unique(project_id); + +create index idx_final_seminar_deleted on final_seminar (deleted); + +alter table `final_seminar` + add constraint fk_final_seminar_document_file_reference_id + foreign key (document_file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `final_seminar` + add constraint fk_final_seminar_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- table: final_seminar_active_participation + +alter table `final_seminar_active_participation` drop foreign key `final_seminar_active_participation_user_id`; +alter table `final_seminar_active_participation` drop foreign key `FK_mk920fce29yhjgv33wr69fe8a`; +alter table `final_seminar_active_participation` drop foreign key `FK_3si3rx7tv6ke9oeiq0hts3lm0`; + +alter table `final_seminar_active_participation` drop key `FK35AB727FF583C69F`; +alter table `final_seminar_active_participation` drop key `FK35AB727FC1813915`; +alter table `final_seminar_active_participation` drop key `FK_mk920fce29yhjgv33wr69fe8a`; +alter table `final_seminar_active_participation` drop key `FK_3si3rx7tv6ke9oeiq0hts3lm0`; +alter table `final_seminar_active_participation` drop key `final_seminar_active_participation_user_id`; + +alter table `final_seminar_active_participation` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `final_seminar_active_participation` change `grade` `grade` varchar(20) default null after `version`; + +alter table `final_seminar_active_participation` rename column `finalSeminar_id` to `final_seminar_id`; + +alter table `final_seminar_active_participation` + add constraint fk_fsap_final_seminar_id + foreign key (final_seminar_id) references final_seminar (id) + on delete cascade on update cascade; + +alter table `final_seminar_active_participation` + add constraint fk_fsap_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +alter table `final_seminar_active_participation` + add constraint fk_fsap_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- table: final_seminar_opposition + +alter table `final_seminar_opposition` drop foreign key `FK_62i59u7j6x5ma0iydx9no6m4i`; +alter table `final_seminar_opposition` drop foreign key `FK_final_seminar_opposition_report`; +alter table `final_seminar_opposition` drop foreign key `FK_hilhyo3tgq89pm27i4pxjaua`; +alter table `final_seminar_opposition` drop foreign key `final_seminar_opposition_user_id`; + +alter table `final_seminar_opposition` drop key `FK8CD13581F583C69F`; +alter table `final_seminar_opposition` drop key `FK8CD13581C1813915`; +alter table `final_seminar_opposition` drop key `FK_62i59u7j6x5ma0iydx9no6m4i`; +alter table `final_seminar_opposition` drop key `FK_hilhyo3tgq89pm27i4pxjaua`; +alter table `final_seminar_opposition` drop key `final_seminar_opposition_user_id`; +alter table `final_seminar_opposition` drop key `FK_final_seminar_opposition_report`; + +alter table `final_seminar_opposition` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `final_seminar_opposition` change `finalSeminar_id` `final_seminar_id` bigint(20) not null after `feedback`; +alter table `final_seminar_opposition` change `opponent_report_reference_id` + `opponent_report_file_reference_id` bigint(20) default null after `final_seminar_id`; +alter table `final_seminar_opposition` change `project_id` `project_id` bigint(20) not null + after `opponent_report_file_reference_id`; + +alter table `final_seminar_opposition` + add constraint fk_fso_final_seminar_id + foreign key (final_seminar_id) references final_seminar (id) + on delete cascade on update cascade; + +alter table `final_seminar_opposition` + add constraint fk_fso_opponent_report_file_reference_id + foreign key (opponent_report_file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `final_seminar_opposition` + add constraint fk_fso_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `final_seminar_opposition` + add constraint fk_fso_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: final_seminar_respondent + +alter table `final_seminar_respondent` drop foreign key `final_seminar_respondent_user_id`; +alter table `final_seminar_respondent` drop foreign key `FK_final_seminar_respondent_id`; + +alter table `final_seminar_respondent` drop key `FK_final_seminar_respondent_id`; +alter table `final_seminar_respondent` drop key `final_seminar_respondent_user_id`; + +alter table `final_seminar_respondent` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `final_seminar_respondent` change `grade` `grade` varchar(20) default null after `version`; +alter table `final_seminar_respondent` change `finalSeminar_id` `final_seminar_id` bigint(20) not null after `grade`; + +alter table `final_seminar_respondent` + add constraint fk_fsr_final_seminar_id + foreign key (final_seminar_id) references final_seminar (id) + on delete cascade on update cascade; + +alter table `final_seminar_respondent` + add constraint fk_fsr_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +/* + * Step 14: Report and Criterion related tables + */ + +-- table: report + +alter table `report` change `submitted` `submitted` tinyint(1) not null default 0 after `version`; + +-- table: opposition_report + +alter table `opposition_report` drop foreign key `opposition_report_ibfk_1`; +alter table `opposition_report` drop foreign key `FK_opposition_report_seminar_opposition`; +alter table `opposition_report` drop foreign key `FK_opposition_report_attachment`; + +alter table `opposition_report` drop key `FK_opposition_report_attachment`; +alter table `opposition_report` drop key `FK_opposition_report_seminar_opposition`; + +alter table `opposition_report` drop key `UK_one_report_per_opponent`; + +alter table `opposition_report` change `thesisSummary` `thesis_summary` longtext default null after `id`; + +alter table `opposition_report` change `attachment_reference_id` `attachment_file_reference_id` + bigint(20) default null after `thesis_summary`; + +alter table `opposition_report` change `finalSeminarOpposition_id` `final_seminar_opposition_id` + bigint(20) not null after `attachment_file_reference_id`; + +alter table `opposition_report` add constraint uk_or_final_seminar_opposition_id + unique(final_seminar_opposition_id); + +alter table `opposition_report` + add constraint fk_or_id + foreign key (id) references report (id) + on delete cascade on update cascade; + +alter table `opposition_report` + add constraint fk_or_attachment_file_reference_id + foreign key (attachment_file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `opposition_report` + add constraint fk_or_final_seminar_opposition_id + foreign key (final_seminar_opposition_id) references final_seminar_opposition (id) + on delete cascade on update cascade; + +-- table: criterion + +alter table `criterion` drop foreign key `FK_criterion_report`; + +alter table `criterion` drop key `FK_criterion_report`; + +alter table `criterion` change `title_sv` `title_sv` varchar(255) not null after `version`; +alter table `criterion` change `title_en` `title_en` varchar(255) not null default '' after `title_sv`; +alter table `criterion` change `description` `description_sv` varchar(2000) default null after `title_en`; +alter table `criterion` change `descriptionEn` `description_en` varchar(2000) default null after `description_sv`; +alter table `criterion` change `feedback` `feedback` longtext default null after `description_en`; +alter table `criterion` change `report_id` `report_id` bigint(20) not null after `sort_order`; + +alter table `criterion` + add constraint fk_criterion_report_id + foreign key (report_id) references report (id) + on delete cascade on update cascade; + +-- table: GradingCriterionPoint, except foreign key to becoming table grading_criterion + +alter table `GradingCriterionPoint` drop foreign key `FK_GradingCriterion_id`; + +alter table `GradingCriterionPoint` drop key `FK_GradingCriterion_id`; + +alter table `GradingCriterionPoint` change `GradingCriterion_id` `grading_criterion_id` bigint(20) not null + after `description_en`; + +rename table `GradingCriterionPoint` to `grading_criterion_point`; + +-- table: GradingCriterion, except foreign key to becoming table grading_report + +alter table `GradingCriterion` drop foreign key `FK_k2ynx2lcpdl969alj5nt3f7xx`; + +alter table `GradingCriterion` drop key `FK_k2ynx2lcpdl969alj5nt3f7xx`; + +alter table `GradingCriterion` change `title_sv` `title_sv` varchar(255) not null after `version`; +alter table `GradingCriterion` change `title_en` `title_en` varchar(255) not null default '' after `title_sv`; +alter table `GradingCriterion` change `type` `type` varchar(64) not null after `title_en`; +alter table `GradingCriterion` change `points_required_to_pass` `points_required_to_pass` int(11) not null after `type`; +alter table `GradingCriterion` change `feedback` `feedback` longtext default null after `points`; +alter table `GradingCriterion` change `gradingReport_id` `grading_report_id` bigint(20) not null after `flag`; + +rename table `GradingCriterion` to `grading_criterion`; + +-- add foreign key reference from grading_criterion_point to grading_criterion + +alter table `grading_criterion_point` + add constraint fk_gcp_grading_criterion_id + foreign key (grading_criterion_id) references grading_criterion (id) + on delete cascade on update cascade; + +-- table: SupervisorGradingReport, except foreign key to becoming table grading_report + +alter table `SupervisorGradingReport` drop foreign key `supervisor_grading_report_user_id`; +alter table `SupervisorGradingReport` drop foreign key `FK_cwxdypciob8dmndx5elwi3fe5`; + +alter table `SupervisorGradingReport` drop key `supervisor_grading_report_user_id`; +alter table `SupervisorGradingReport` drop key `FK_cwxdypciob8dmndx5elwi3fe5`; + +rename table `SupervisorGradingReport` to `supervisor_grading_report`; + +alter table `supervisor_grading_report` + add constraint fk_sgr_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: ReviewerGradingReport, except foreign key to becoming table grading_report + +alter table `ReviewerGradingReport` drop foreign key `FK_axsaeqbamfc41dhih1s62g998`; + +alter table `ReviewerGradingReport` drop key `FK_axsaeqbamfc41dhih1s62g998`; + +rename table `ReviewerGradingReport` to `reviewer_grading_report`; + +-- table: GradingReport + +alter table `GradingReport` drop foreign key `GradingReport_ibfk_1`; +alter table `GradingReport` drop foreign key `FK_6ygpk1qq218jgwuuyx0bp6vui`; + +alter table `GradingReport` drop key `FK_6ygpk1qq218jgwuuyx0bp6vui`; + +rename table `GradingReport` to `grading_report`; + +alter table `grading_report` + add constraint fk_grading_report_id + foreign key (id) references report (id) + on delete cascade on update cascade; + +alter table `grading_report` + add constraint fk_grading_report_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- add foreign key reference from reviewer_grading_report to grading_report + +alter table `reviewer_grading_report` + add constraint fk_reviewer_grading_report_id + foreign key (id) references grading_report (id) + on delete cascade on update cascade; + +-- add foreign key reference from supervisor_grading_report to grading_report + +alter table `supervisor_grading_report` + add constraint fk_sgr_id + foreign key (id) references grading_report (id) + on delete cascade on update cascade; + +-- add foreign key reference from grading_criterion to grading_report + +alter table `grading_criterion` + add constraint fk_grading_criterion_grading_report_id + foreign key (grading_report_id) references grading_report (id) + on delete cascade on update cascade; + +/* + * Step 15: project and related tables + */ + +-- table: project + +alter table `project` drop foreign key `project_supervisor_id`; +alter table `project` drop key `project_supervisor_id`; +alter table `project` drop key `identifier`; + +alter table `project` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `project` change `title` `title` longtext not null after `version`; +alter table `project` change `credits` `credits` int(11) not null default 0 after `title`; +alter table `project` change `language` `language` varchar(255) default null after credits; +alter table `project` change `start_date` `start_date` date not null after language; +alter table `project` change `expected_end_date` `expected_end_date` date default null after `start_date`; +alter table `project` change `externalOrganization` `external_organization` varchar(255) default null after `expected_end_date`; +alter table `project` change `projectStatus` `project_status` varchar(255) default null after `external_organization`; +alter table `project` change `fs_rule_exmpt` `final_seminar_rule_exmpt` bit(1) not null default b'0' after `project_status`; +alter table `project` change `stateOfMind` `state_of_mind` varchar(255) default null after `final_seminar_rule_exmpt`; +alter table `project` change `stateOfMindReason` `state_of_mind_reason` varchar(255) default null after `state_of_mind`; +alter table `project` change `stateOfMindDate` `state_of_mind_date` datetime default null after `state_of_mind_reason`; +alter table `project` change `identifier` `daisy_identifier` bigint(20) default null after `state_of_mind_date`; +alter table `project` change `supervisor_id` `supervisor_id` bigint(20) not null after `research_area_id`; + +alter table `project` add constraint uk_project_daisy_identifier unique(daisy_identifier); + +alter table `project` + add constraint fk_project_supervisor_id + foreign key (supervisor_id) references user (id) + on delete cascade on update cascade; + +-- table: grading_history_rejections + +alter table `grading_history_rejections` drop foreign key `FK_grading_history_rejections_project`; + +alter table `grading_history_rejections` drop key `FK_grading_history_rejections_project`; + +alter table `grading_history_rejections` change `reason` `reason` text not null after `id`; +alter table `grading_history_rejections` change `when` `when` timestamp not null default '0000-00-00 00:00:00' after `reason`; + +rename table `grading_history_rejections` to `grading_history_rejection`; + +alter table `grading_history_rejection` + add constraint fk_grading_history_rejections_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- table: grading_history_approvals + +alter table `grading_history_approvals` drop foreign key `FK_grading_history_approvals_project`; + +alter table `grading_history_approvals` drop key `FK_grading_history_approvals_project`; + +alter table `grading_history_approvals` change `when` `when` timestamp not null default '0000-00-00 00:00:00' after `id`; + +rename table `grading_history_approvals` to `grading_history_approval`; + +alter table `grading_history_approval` + add constraint fk_grading_history_approval_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- table: national_subject_category + +alter table `national_subject_category` drop key `U_national_subject_category_external_id`; + +alter table `national_subject_category` change `swedish_name` `name_sv` varchar(255) not null after `id`; +alter table `national_subject_category` change `english_name` `name_en` varchar(255) not null after `name_sv`; +alter table `national_subject_category` change `external_id` `external_id` int(11) not null after `preselected`; + +alter table `national_subject_category` + add constraint uk_national_subject_category_external_id unique(external_id); + +-- table: publication_metadata + +alter table `publication_metadata` drop foreign key `FK_publication_metadata_project`; +alter table `publication_metadata` drop foreign key `FK_publication_metadata_national_subject_category`; + +alter table `publication_metadata` drop key `FK_publication_metadata_project`; +alter table `publication_metadata` drop key `FK_publication_metadata_national_subject_category`; + +alter table `publication_metadata` change `project_id` `project_id` bigint(20) not null after `national_subject_category_id`; + +alter table `publication_metadata` change `abstract_swedish` `abstract_sv` text default null after `id`; +alter table `publication_metadata` change `abstract_english` `abstract_en` text default null after `abstract_sv`; +alter table `publication_metadata` change `keywords_swedish` `keywords_sv` text default null after `abstract_en`; +alter table `publication_metadata` change `keywords_english` `keywords_en` text default null after `keywords_sv`; + +alter table `publication_metadata` + add constraint fk_publication_metadata_national_subject_category_id + foreign key (national_subject_category_id) references national_subject_category (id) + on delete cascade on update cascade; + +alter table `publication_metadata` + add constraint fk_publication_metadata_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +/* + * Step 16: Many-to-Many tables between project and user. + */ + +-- table: project_user_note (new changes from develop branch) + +alter table `project_user_note` drop foreign key `FK_project_user_note_user`; +alter table `project_user_note` drop foreign key `FK_project_user_note_project`; +alter table `project_user_note` drop key `FK_project_user_note_user`; + +alter table `project_user_note` + add constraint fk_project_user_note_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `project_user_note` + add constraint fk_project_user_note_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: project_cosupervisor + +alter table `project_cosupervisor` drop foreign key `FK_fj57t069dymdrnnhdxcnfvvnn`; +alter table `project_cosupervisor` drop foreign key `FK_18x2poxkt8s2bw9kpr7vbmd5j`; + +alter table `project_cosupervisor` drop key `FK_fj57t069dymdrnnhdxcnfvvnn`; +alter table `project_cosupervisor` drop key `FK_18x2poxkt8s2bw9kpr7vbmd5j`; + +alter table `project_cosupervisor` change `user_id` `user_id` bigint(20) not null after `project_id`; + +alter table `project_cosupervisor` + add constraint fk_project_cosupervisor_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `project_cosupervisor` + add constraint fk_project_cosupervisor_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: project_reviewer + +alter table `project_reviewer` drop foreign key `FK_g7yryw3e0dtmuuvgw5qjhphjm`; +alter table `project_reviewer` drop foreign key `FK_6aik0jd18kv3383fbt09xd0pi`; + +alter table `project_reviewer` drop key `FK_6aik0jd18kv3383fbt09xd0pi`; +alter table `project_reviewer` drop key `FK_g7yryw3e0dtmuuvgw5qjhphjm`; + +alter table `project_reviewer` + add constraint fk_project_reviewer_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `project_reviewer` + add constraint fk_project_reviewer_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: project_user + +alter table `project_user` drop foreign key `project_user_user_id`; +alter table `project_user` drop foreign key `project_user_project_id`; + +alter table `project_user` drop key `project_user_project_id`; + +alter table `project_user` change `user_id` `user_id` bigint(20) not null after `project_id`; +alter table `project_user` change `reflection` `reflection` text default null after `user_id`; + +alter table `project_user` + add constraint fk_project_user_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `project_user` + add constraint fk_project_user_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: grading_history_submissions + +alter table `grading_history_submissions` drop foreign key `FK_grading_history_submissions_project`; +alter table `grading_history_submissions` drop foreign key `FK_grading_history_submissions_author`; + +alter table `grading_history_submissions` drop key `FK_grading_history_submissions_project`; +alter table `grading_history_submissions` drop key `FK_grading_history_submissions_author`; + +rename table `grading_history_submissions` to `grading_history_submission`; + +alter table `grading_history_submission` change `when` `when` timestamp not null default '0000-00-00 00:00:00' after `id`; +alter table `grading_history_submission` change `corrections` `corrections` text default null after `when`; +alter table `grading_history_submission` change `author_id` `author_user_id` bigint(20) not null after `corrections`; + +alter table `grading_history_submission` + add constraint fk_grading_history_submission_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `grading_history_submission` + add constraint fk_grading_history_submission_author_user_id + foreign key (author_user_id) references user (id) + on delete cascade on update cascade; + +-- table: externallink + +alter table `externallink` drop foreign key `FK_PROJECT`; +alter table `externallink` drop foreign key `FK_USER`; + +alter table `externallink` drop key `FK_PROJECT`; +alter table `externallink` drop key `FK_USER`; + +rename table `externallink` to `external_link`; + +alter table `external_link` change `description` `description` varchar(255) default null after `url`; + +alter table `external_link` + add constraint fk_external_link_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `external_link` + add constraint fk_external_link_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: grade + +alter table `grade` drop foreign key `FK_grade_user_reportedBy`; +alter table `grade` drop foreign key `FK_grade_project`; + +alter table `grade` drop key `FK_grade_user_reportedBy`; +alter table `grade` drop key `project_id`; + +alter table `grade` change `value` `value` varchar(255) not null after `id`; +alter table `grade` change `reportedOn` `reported_when` date not null after `value`; +alter table `grade` change `project_id` `project_id` bigint(20) not null after `reported_when`; +alter table `grade` change `reportedBy` `reported_by_user_id` bigint(20) not null after `project_id`; + +alter table `grade` add constraint uk_grade_project_id unique(project_id); + +alter table `grade` + add constraint fk_grade_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `grade` + add constraint fk_grade_reported_by_user_id + foreign key (reported_by_user_id) references user (id) + on delete cascade on update cascade; + +/* + * Step 17: file_reference & file_description, FinalThesis and project_file + */ + +-- table: file_description + +alter table `file_description` drop foreign key `file_description_user`; + +alter table `file_description` drop key `file_description_user`; +alter table `file_description` drop key `file_description_identifier_index`; + +alter table `file_description` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `file_description` change `name` `name` varchar(255) default null after `version`; +alter table `file_description` change `mimeType` `mime_type` varchar(255) default null after `name`; +alter table `file_description` change `size` `size` bigint(20) default null after `mime_type`; +alter table `file_description` change `identifier` `file_identifier` varchar(255) default null after `size`; +alter table `file_description` change `type` `type` varchar(255) default null after `file_identifier`; +alter table `file_description` change `userId` `user_id` bigint(20) default null after `type`; + +alter table `file_description` + add constraint fk_file_description_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: file_reference + +alter table file_reference drop foreign key `FK_file_reference_file_description`; + +alter table file_reference drop key `FK_file_reference_file_description`; + +alter table file_reference + add constraint fk_file_reference_file_description_id + foreign key (file_description_id) references file_description (id) + on delete cascade on update cascade; + +-- table: FinalThesis + +alter table FinalThesis drop foreign key `FK_final_thesis_text_matching_document_reference`; +alter table FinalThesis drop foreign key `FK_final_thesis_project`; +alter table FinalThesis drop foreign key `FK_final_thesis_document_reference`; + +alter table FinalThesis drop key `FK_final_thesis_text_matching_document_reference`; +alter table FinalThesis drop key `FK_final_thesis_project`; + +rename table FinalThesis to `final_thesis`; + +alter table `final_thesis` change `swedishTitle` `title_sv` longtext default null after `version`; +alter table `final_thesis` change `englishTitle` `title_en` longtext default null after `title_sv`; +alter table `final_thesis` change `status` `status` varchar(32) not null after `title_en`; +alter table `final_thesis` change `dateApproved` `date_approved` date default null after `status`; +alter table `final_thesis` change `dateRejected` `date_rejected` date default null after `date_approved`; +alter table `final_thesis` change `rejection_comment` `rejection_comment` text default null after `date_rejected`; +alter table `final_thesis` change `text_matching_analysis` `text_matching_analysis` text default null after `rejection_comment`; +alter table `final_thesis` change `text_matching_document_reference_id` `text_matching_document_reference_id` bigint(20) default null after `text_matching_analysis`; +alter table `final_thesis` change `project_id` `project_id` bigint(20) not null after `document_reference_id`; + +alter table `final_thesis` + add constraint fk_final_thesis_text_matching_document_reference_id + foreign key (text_matching_document_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `final_thesis` + add constraint fk_final_thesis_document_reference_id + foreign key (document_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `final_thesis` + add constraint fk_final_thesis_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- table: project_file + +alter table `project_file` drop foreign key FK_project_file_project; +alter table `project_file` drop foreign key FK_project_file_file; + +alter table `project_file` drop key FK_project_file_file; +alter table `project_file` drop key FK_project_file_project; + +alter table `project_file` change `fileSource` `file_source` varchar(255) not null after `version`; +alter table `project_file` change `project_id` `project_id` bigint(20) not null after `file_reference_id`; + +alter table `project_file` + add constraint fk_project_file_file_reference_id + foreign key (file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `project_file` + add constraint fk_project_file_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +/* + * Step 18: Decision & ReviewerApproval + */ + +-- table: Decision + +alter table `Decision` drop foreign key `fk_Decision_ReviewerApproval`; +alter table `Decision` drop foreign key `FK_decision_reviewer`; +alter table `Decision` drop foreign key `FK_Decision_thesis`; +alter table `Decision` drop foreign key `FK_Decision_attachment`; + +alter table `Decision` drop key `FK_decision_reviewer`; +alter table `Decision` drop key `FK_Decision_attachment`; +alter table `Decision` drop key `FK_Decision_thesis`; +alter table `Decision` drop key `fk_ReviewerApproval_Decision_idx`; + +rename table `Decision` to `decision`; + +alter table `decision` change `status` `status` varchar(255) default null after `id`; +alter table `decision` change `requested` `requested_date` datetime not null; +alter table `decision` change `decisionDate` `decision_date` datetime default null; +alter table `decision` change `deadline` `deadline` datetime default null after `decision_date`; +alter table `decision` change `assigned_reviewer_date` `assigned_reviewer_date` date default null after `deadline`; +alter table `decision` change `assigned_reviewer_id` `assigned_reviewer_id` bigint(20) default null after `assigned_reviewer_date`; +alter table `decision` change `attachment_reference_id` `attachment_reference_id` bigint(20) default null after `assigned_reviewer_id`; +alter table `decision` change `reviewerApproval_id` `reviewer_approval_id` bigint(20) not null; + +alter table `decision` + add constraint fk_decision_assigned_reviewer_id + foreign key (assigned_reviewer_id) references user (id) + on delete cascade on update cascade; + +alter table `decision` + add constraint fk_decision_attachment_reference_id + foreign key (attachment_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `decision` + add constraint fk_decision_thesis_reference_id + foreign key (thesis_reference_id) references file_reference (id) + on delete cascade on update cascade; + +-- table: ReviewerApproval + +alter table `ReviewerApproval` drop foreign key `FK_9lr1dn8boyfc5a0477ld4q8rw`; + +alter table `ReviewerApproval` drop key `FK_9lr1dn8boyfc5a0477ld4q8rw`; + +rename table `ReviewerApproval` to `reviewer_approval`; + +alter table `reviewer_approval` change `type` `type` varchar(64) not null after `version`; +alter table `reviewer_approval` change `project_id` `project_id` bigint(20) not null after `type`; + +alter table `reviewer_approval` + add constraint fk_reviewer_approval_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +-- add foreign key from decision to reviewer_approval + +alter table `decision` + add constraint fk_decision_reviewer_approval_id + foreign key (reviewer_approval_id) references reviewer_approval (id) + on delete cascade on update cascade; + +/* + * Step 19: urkund_submission & plagiarium_request + */ + +-- table: urkund_submission + +alter table `urkund_submission` drop foreign key `FK_urkund_submission_receiver`; +alter table `urkund_submission` drop foreign key `FK_urkund_submission_document_reference`; + +alter table `urkund_submission` drop key `FK_urkund_submission_document_reference`; +alter table `urkund_submission` drop key `FK_urkund_submission_receiver`; + +alter table `urkund_submission` change `document_reference_id` `document_file_reference_id` bigint(20) not null; +alter table `urkund_submission` change `receiver_id` `receiver_user_id` bigint(20) not null after `document_file_reference_id`; +alter table `urkund_submission` change `submitted` `submitted_date` datetime not null; +alter table `urkund_submission` change `nextPoll` `next_poll_date` datetime not null; +alter table `urkund_submission` change `pollingDelay` `polling_delay` varchar(16) not null; +alter table `urkund_submission` change `reportUrl` `report_url` varchar(255) default null; +alter table `urkund_submission` change `analysisAddress` `analysis_address` varchar(255) default null; + +alter table `urkund_submission` + add constraint fk_urkund_submission_document_file_reference_id + foreign key (document_file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `urkund_submission` + add constraint fk_urkund_submission_receiver_user_id + foreign key (receiver_user_id) references user (id) + on delete cascade on update cascade; + +-- table: plagiarism_request + +alter table `plagiarism_request` drop foreign key `FK_plagiarism_request_receiver`; +alter table `plagiarism_request` drop foreign key `FK_plagiarism_request_document_reference`; + +alter table `plagiarism_request` drop key `FK_plagiarism_request_document_reference`; +alter table `plagiarism_request` drop key `FK_plagiarism_request_receiver`; + +alter table `plagiarism_request` change `document_reference_id` `document_file_reference_id` bigint(20) not null; +alter table `plagiarism_request` change `receiver_id` `receiver_user_id` bigint(20) not null after `document_file_reference_id`; + +alter table `plagiarism_request` + add constraint fk_plagiarism_request_document_file_reference_id + foreign key (document_file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +alter table `plagiarism_request` + add constraint fk_plagiarism_request_receiver_user_id + foreign key (receiver_user_id) references user (id) + on delete cascade on update cascade; + +/* + * Step 20: mail_event, mail_event_recipients and MailEvent_nonUserRecipients + */ + +-- table: mail_event + +alter table `mail_event` drop foreign key `FK_mail_event_attachment`; + +alter table `mail_event` drop key `FK_mail_event_attachment`; + +alter table `mail_event` change `version` `version` int(4) not null default 0 after `last_modified`; +alter table `mail_event` change `subject` `subject` varchar(255) not null after `version`; +alter table `mail_event` change `fromName` `from_name` varchar(255) default null after `subject`; +alter table `mail_event` change `fromEmail` `from_email` varchar(255) default null after `from_name`; +alter table `mail_event` change `messageBody` `message_body` longtext not null after `from_email`; +alter table `mail_event` change `sent` `sent` tinyint(1) not null default 0 after `message_body`; +alter table `mail_event` change `messageID` `message_id` varchar(255) default null after `sent`; +alter table `mail_event` change `notificationEventType` `notification_event_type` varchar(255) default null after `message_id`; +alter table `mail_event` change `attachment_reference_id` `attachment_file_reference_id` bigint(20) default null after `notification_event_type`; + +alter table `mail_event` + add constraint fk_mail_event_attachment_file_reference_id + foreign key (attachment_file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +-- table: mail_event_recipients + +alter table `mail_event_recipients` drop foreign key `FK_mail_event_recipients_user`; +alter table `mail_event_recipients` drop foreign key `FK41091C7FE7F98C6`; + +alter table `mail_event_recipients` drop key `FK41091C7B286D1B0`; +alter table `mail_event_recipients` drop key `FK41091C7FE7F98C6`; + +alter table `mail_event_recipients` drop primary key; + +rename table `mail_event_recipients` to `mail_event_recipient`; + +alter table `mail_event_recipient` change `recipients_id` `recipient_id` bigint(20) not null after `mail_event_id`; + +alter table `mail_event_recipient` add primary key (mail_event_id, recipient_id); + +alter table `mail_event_recipient` + add constraint fk_mail_event_recipient_mail_event_id + foreign key (mail_event_id) references mail_event (id) + on delete cascade on update cascade; + +alter table `mail_event_recipient` + add constraint fk_mail_event_recipient_recipient_id + foreign key (recipient_id) references user (id) + on delete cascade on update cascade; + +-- table: MailEvent_nonUserRecipients + +alter table `MailEvent_nonUserRecipients` drop foreign key `FKD7F8996D0814DF5`; +alter table `MailEvent_nonUserRecipients` drop key `FKD7F8996D0814DF5`; + +rename table `MailEvent_nonUserRecipients` to `mail_event_non_user_recipient`; + +alter table `mail_event_non_user_recipient` change `MailEvent_id` `mail_event_id` bigint(20) not null; +alter table `mail_event_non_user_recipient` change `nonUserRecipients` `non_user_recipient` varchar(255) default null; + +alter table `mail_event_non_user_recipient` + add constraint fk_mail_event_non_user_recipient_mail_event_id + foreign key (mail_event_id) references mail_event (id) + on delete cascade on update cascade; + +/* + * Step 21: project_group and project_group_project + */ + +-- table: project_group + +alter table `project_group` drop foreign key `FK_user_id`; +alter table `project_group` drop key `FK_user_id`; + +alter table `project_group` change `active` `active` bit(1) not null after `description`; + +alter table `project_group` + add constraint fk_project_group_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: project_group_project + +alter table `project_group_project` drop foreign key `FK_project_id`; +alter table `project_group_project` drop foreign key `FK_project_group_id`; + +alter table `project_group_project` drop key `FK_project_id`; +alter table `project_group_project` drop key `FK_project_group_id`; + +alter table `project_group_project` + add constraint fk_project_group_project_project_group_id + foreign key (project_group_id) references project_group (id) + on delete cascade on update cascade; + +alter table `project_group_project` + add constraint fk_project_group_project_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +/* + * Step 22: thread, forum_post and forum_post_file_description + */ + +-- table: thread + +alter table `thread` change `deleted` `deleted` tinyint(1) not null after `subject`; + +-- table: forum_post + +alter table `forum_post` drop foreign key `forum_posts_thread`; +alter table `forum_post` drop foreign key `FKEDDC4F35924F477B`; + +alter table `forum_post` drop key `deleted_index`; +alter table `forum_post` drop key `FKEDDC4F355E9380A1`; +alter table `forum_post` drop key `FKEDDC4F35924F477B`; + +alter table `forum_post` change `content` `content` longtext not null after `version`; +alter table `forum_post` change `thread` `thread_id` bigint(20) not null after `deleted`; +alter table `forum_post` change `user` `user_id` bigint(20) default null after `thread_id`; + +create index idx_forum_post_deleted on forum_post (deleted); + +alter table `forum_post` + add constraint fk_forum_post_thread_id + foreign key (thread_id) references thread (id) + on delete cascade on update cascade; + +alter table `forum_post` + add constraint fk_forum_post_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: forum_post_file_description + +alter table `forum_post_file_description` drop foreign key `FK_forum_post_file`; + +alter table `forum_post_file_description` drop key `I_forum_post_file_post`; +alter table `forum_post_file_description` drop key `FK_forum_post_file`; + +rename table `forum_post_file_description` to `forum_post_file_reference`; + +alter table `forum_post_file_reference` + add constraint fk_forum_post_file_reference_forum_post_id + foreign key (forum_post_id) references forum_post (id) + on delete cascade on update cascade; + +alter table `forum_post_file_reference` + add constraint fk_forum_post_file_reference_file_reference_id + foreign key (file_reference_id) references file_reference (id) + on delete cascade on update cascade; + +/* + * Step 23: forum_post_read, project_thread, reviewer_thread and group_thread + */ + +-- table: forum_post_read + +alter table `forum_post_read` drop foreign key `FK8A5DFC60DD74550D`; +alter table `forum_post_read` drop foreign key `FK8A5DFC60924F477B`; + +alter table `forum_post_read` drop key `FK8A5DFC60DD74550D`; +alter table `forum_post_read` drop key `FK8A5DFC60924F477B`; + +alter table `forum_post_read` drop primary key; + +rename table `forum_post_read` to `forum_post_read_state`; + +alter table `forum_post_read_state` change `read` `read` tinyint(1) not null after `post`; +alter table `forum_post_read_state` change `user` `user_id` bigint(20) not null after `post`; +alter table `forum_post_read_state` change `post` `forum_post_id` bigint(20) not null; + +alter table `forum_post_read_state` add primary key (forum_post_id, user_id); + +alter table `forum_post_read_state` + add constraint fk_forum_post_read_state_forum_post_id + foreign key (forum_post_id) references forum_post (id) + on delete cascade on update cascade; + +alter table `forum_post_read_state` + add constraint fk_forum_post_read_state_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: project_thread + +alter table `project_thread` drop foreign key `FK_project_thread_thread`; +alter table `project_thread` drop foreign key `FK_project_thread_project`; + +alter table `project_thread` drop key `FK_project_thread_thread`; +alter table `project_thread` drop key `FK_project_thread_project`; + +alter table `project_thread` change `project_id` `project_id` bigint(20) not null after `id`; + +alter table `project_thread` + add constraint fk_project_thread_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `project_thread` + add constraint fk_project_thread_thread_id + foreign key (thread_id) references thread (id) + on delete cascade on update cascade; + +-- table: reviewer_thread + +alter table `reviewer_thread` drop foreign key `FK_reviewer_thread_thread`; +alter table `reviewer_thread` drop foreign key `FK_reviewer_thread_group`; + +alter table `reviewer_thread` drop key `FK_reviewer_thread_thread`; +alter table `reviewer_thread` drop key `project_id`; + +alter table `reviewer_thread` change `thread_id` `thread_id` bigint(20) not null after `project_id`; + +alter table `reviewer_thread` add constraint uk_reviewer_thread_project_id unique(project_id, thread_id); + +alter table `reviewer_thread` + add constraint fk_reviewer_thread_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `reviewer_thread` + add constraint fk_reviewer_thread_thread_id + foreign key (thread_id) references thread (id) + on delete cascade on update cascade; + +-- table: group_thread + +alter table `group_thread` drop foreign key `FK_project_group_thread_thread`; +alter table `group_thread` drop foreign key `FK_project_group_thread_group`; + +alter table `group_thread` drop key `FK_project_group_thread_thread`; +alter table `group_thread` drop key `project_group`; + +rename table `group_thread` to `project_group_thread`; + +alter table `project_group_thread` change `group_id` `project_group_id` bigint(20) not null after `id`; + +alter table `project_group_thread` + add constraint fk_project_group_thread_project_group_id + foreign key (project_group_id) references project_group (id) + on delete cascade on update cascade; + +alter table `project_group_thread` + add constraint fk_project_group_thread_thread_id + foreign key (thread_id) references thread (id) + on delete cascade on update cascade; + +/* + * Step 24: forum_notification, Notification, NotificationData + */ + +-- table: forum_notification, + +alter table `forum_notification` drop foreign key `FK_forum_notification_notification_event`; +alter table `forum_notification` drop foreign key `FK_forum_notification_forum_post`; + +alter table `forum_notification` drop key `FK_forum_notification_notification_event`; + +alter table `forum_notification` drop primary key; + +alter table `forum_notification` change `forumPost_id` `forum_post_id` bigint(20) not null; +alter table `forum_notification` change `notificationEvent_id` `notification_data_id` bigint(20) not null; + +alter table `forum_notification` add primary key (forum_post_id, notification_data_id); + +alter table `forum_notification` + add constraint fk_forum_notification_forum_post_id + foreign key (forum_post_id) references forum_post (id) + on delete cascade on update cascade; + +-- table: Notification + +alter table `Notification` drop foreign key `FK_notification_user`; +alter table `Notification` drop foreign key `FK2D45DD0B599425F6`; + +alter table `Notification` drop key `FK2D45DD0B599425F6`; +alter table `Notification` drop key `FK2D45DD0B895349BF`; + +rename table `Notification` to `notification`; + +alter table `notification` change `mailed` `mailed` bit(1) not null after `version`; +alter table `notification` change `notificationData_id` `notification_data_id` bigint(20) default null; + +alter table `notification` + add constraint fk_notification_user_id + foreign key (user_id) references user (id) + on delete cascade on update cascade; + +-- table: NotificationData + +alter table `NotificationData` drop foreign key `FK_notification_data_user_caused_by`; +alter table `NotificationData` drop foreign key `FK_notification_data_project`; +alter table `NotificationData` drop foreign key `FK_notification_data_peer_review`; +alter table `NotificationData` drop foreign key `FK_notification_data_milestone`; +alter table `NotificationData` drop foreign key `FK_notification_data_group`; +alter table `NotificationData` drop foreign key `FK2DCAC355FCDADF61`; +alter table `NotificationData` drop foreign key `FK2DCAC3558D40D1B9`; +alter table `NotificationData` drop foreign key `FK2DCAC3554D07E0A9`; + +alter table `NotificationData` drop key `FK_notification_data_group`; +alter table `NotificationData` drop key `FK_notification_data_milestone`; +alter table `NotificationData` drop key `FK2DCAC355FCDADF61`; +alter table `NotificationData` drop key `FK2DCAC355B2E2AD78`; +alter table `NotificationData` drop key `FK2DCAC3558D40D1B9`; +alter table `NotificationData` drop key `FK2DCAC35542E9AC7B`; +alter table `NotificationData` drop key `FK2DCAC355C1813915`; +alter table `NotificationData` drop key `FK2DCAC3554D07E0A9`; + +rename table `NotificationData` to `notification_data`; + +alter table `notification_data` change `type` `type` varchar(255) default null after `event`; +alter table `notification_data` change `source` `source` longtext default null after `type`; +alter table `notification_data` change `additionalSource` `additional_source` longtext default null after `source`; +alter table `notification_data` change `DTYPE` `subclass` varchar(31) not null after `additional_source`; + +alter table `notification_data` change `seminar_id` `final_seminar_id` bigint(20) default null after `subclass`; +alter table `notification_data` change `idea_id` `idea_id` bigint(20) default null after `final_seminar_id`; +alter table `notification_data` change `mileStone_id` `milestone_id` bigint(20) default null after `idea_id`; +alter table `notification_data` change `request_id` `peer_request_id` bigint(20) default null after `milestone_id`; +alter table `notification_data` change `review_id` `peer_review_id` bigint(20) default null after `peer_request_id`; +alter table `notification_data` change `project_id` `project_id` bigint(20) default null after `peer_review_id`; +alter table `notification_data` change `group_id` `project_group_id` bigint(20) default null after `project_id`; +alter table `notification_data` change `causedBy_id` `caused_by_user_id` bigint(20) default null after `project_group_id`; + +alter table `notification_data` + add constraint fk_notification_data_final_seminar_id + foreign key (final_seminar_id) references final_seminar (id) + on delete cascade on update cascade; + +alter table `notification_data` + add constraint fk_notification_data_idea_id + foreign key (idea_id) references idea (id) + on delete cascade on update cascade; + +alter table `notification_data` + add constraint fk_notification_data_milestone_id + foreign key (milestone_id) references milestone (id) + on delete cascade on update cascade; + +alter table `notification_data` + add constraint fk_notification_data_peer_request_id + foreign key (peer_request_id) references peer_request (id) + on delete set null on update cascade; + +alter table `notification_data` + add constraint fk_notification_data_peer_review_id + foreign key (peer_review_id) references peer_review (id) + on delete cascade on update cascade; + +alter table `notification_data` + add constraint fk_notification_data_project_id + foreign key (project_id) references project (id) + on delete cascade on update cascade; + +alter table `notification_data` + add constraint fk_notification_data_project_group_id + foreign key (project_group_id) references project_group (id) + on delete cascade on update cascade; + +alter table `notification_data` + add constraint fk_notification_data_caused_by_user_id + foreign key (caused_by_user_id) references user (id) + on delete set null on update cascade; + +-- add foreign key from notification to notification_data + +alter table `notification` + add constraint fk_notification_notification_data_id + foreign key (notification_data_id) references notification_data (id) + on delete cascade on update cascade; + +-- add foreign key from forum_notification to notification_data + +alter table `forum_notification` + add constraint fk_forum_notification_notification_data_id + foreign key (notification_data_id) references notification_data (id) + on delete cascade on update cascade; diff --git a/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql b/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql new file mode 100644 index 0000000000..d80e266c9d --- /dev/null +++ b/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql @@ -0,0 +1,4 @@ +ALTER TABLE `project_user` + ADD COLUMN `reflection_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_SUBMITTED'; + +UPDATE `project_user` SET `reflection_status` = 'SUBMITTED' WHERE `reflection` IS NOT NULL; diff --git a/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql b/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql new file mode 100644 index 0000000000..f3cc5f2ce1 --- /dev/null +++ b/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql @@ -0,0 +1 @@ +ALTER TABLE `project_user` ADD COLUMN `reflection_comment_by_supervisor` TEXT NULL; diff --git a/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java b/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java index 4c0f37379d..90cc242e77 100644 --- a/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java +++ b/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java @@ -1,20 +1,15 @@ package se.su.dsv.scipro.forum; -import com.google.inject.AbstractModule; -import com.google.inject.Module; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import se.su.dsv.scipro.date.DateService; -import se.su.dsv.scipro.file.FileModule; -import se.su.dsv.scipro.file.FileStore; import se.su.dsv.scipro.notifications.NotificationController; import se.su.dsv.scipro.notifications.NotificationService; -import se.su.dsv.scipro.test.GuiceTest; -import se.su.dsv.scipro.test.InMemoryFileStore; +import se.su.dsv.scipro.test.SpringTest; @ExtendWith(MockitoExtension.class) -public abstract class ForumModuleTest extends GuiceTest { +public abstract class ForumModuleTest extends SpringTest { // TODO: Work towards removing these dependencies. @Mock private DateService dateService; @@ -23,18 +18,4 @@ public abstract class ForumModuleTest extends GuiceTest { @Mock private NotificationService notificationService; - @Override - protected Module moduleUnderTest() { - return new AbstractModule() { - @Override - protected void configure() { - install(new ForumModule()); - install(new FileModule()); - bind(FileStore.class).to(InMemoryFileStore.class); - bind(DateService.class).toInstance(dateService); - bind(NotificationController.class).toInstance(notificationController); - bind(NotificationService.class).toInstance(notificationService); - } - }; - } } diff --git a/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java index da314ab9c1..4a3e6dc33c 100644 --- a/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java +++ b/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java @@ -1,135 +1,135 @@ -package se.su.dsv.scipro.group; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import se.su.dsv.scipro.project.Project; -import se.su.dsv.scipro.system.DegreeType; -import se.su.dsv.scipro.system.ProjectType; -import se.su.dsv.scipro.system.User; -import se.su.dsv.scipro.test.IntegrationTest; - -import jakarta.inject.Inject; -import java.time.LocalDate; -import java.util.Collections; -import java.util.HashSet; - -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class GroupServiceImplTest extends IntegrationTest { - - @Inject - private GroupServiceImpl groupService; - private User author; - private User creator; - private User reviewer; - private User cosupervisor; - private Group group; - private ProjectType projectType; - - @BeforeEach - public void setUp() throws Exception { - author = saveUser("author", "name", "author@example.com"); - creator = saveUser("supervisor", "sup", "supervisor@example.com"); - reviewer = saveUser("reviewer", "test", "reviewer@example.com"); - cosupervisor = saveUser("cosupervisor", "test", "reviewer@example.com"); - projectType = save(new ProjectType(DegreeType.BACHELOR, "b", "b")); - User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build()); - Project project = save(Project.builder().title("title").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); - project.addProjectParticipant(author); - project.addReviewer(reviewer); - project.addCoSupervisor(cosupervisor); - createGroup(project); - } - - @Test - public void find_by_author() { - GroupService.Filter filter = new GroupService.Filter(); - filter.setAuthor(author); - assertGroup(filter); - } - - @Test - public void find_all() { - GroupService.Filter filter = new GroupService.Filter(); - assertGroup(filter); - } - - @Test - public void find_by_creator_fails() { - GroupService.Filter filter = new GroupService.Filter(); - filter.setCreator(author); - assertTrue(groupService.findAll(filter).isEmpty()); - } - - @Test - public void find_by_creator() { - GroupService.Filter filter = new GroupService.Filter(); - filter.setCreator(creator); - assertGroup(filter); - } - - @Test - public void find_by_reviewer_involvee() { - GroupService.Filter filter = new GroupService.Filter(); - filter.setNonAuthorInvolvee(reviewer); - assertThat(groupService.findAll(filter), not(hasItem(group))); - } - - @Test - public void find_by_cosupervisor_involvee() { - GroupService.Filter filter = new GroupService.Filter(); - filter.setNonAuthorInvolvee(cosupervisor); - assertGroup(filter); - } - - @Test - public void find_active_groups() { - GroupService.Filter filter = new GroupService.Filter(); - filter.setActive(true); - assertGroup(filter); - - filter.setActive(false); - assertTrue(groupService.findAll(filter).isEmpty()); - } - - @Test - public void count() { - GroupService.Filter filter = new GroupService.Filter(); - filter.setAuthor(author); - assertEquals(1, groupService.count(filter)); - } - - @Test - public void find_groups_by_project() { - Group another = new Group(); - another.setTitle("hi"); - another.setUser(creator); - User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build()); - Project anotherProject = save(Project.builder().title("another").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); - another.setProjects(new HashSet<>(Collections.singletonList(anotherProject))); - save(another); - GroupService.Filter filter = new GroupService.Filter(); - filter.setProject(anotherProject); - assertEquals(another, groupService.findAll(filter).get(0)); - } - - private void assertGroup(GroupService.Filter filter) { - assertThat(groupService.findAll(filter), hasItem(group)); - } - - private void createGroup(Project project) { - group = new Group(); - group.setTitle("group title"); - group.setProjects(new HashSet<>(Collections.singletonList(project))); - group.setUser(creator); - save(group); - } - - private User saveUser(String firstName, String lastName, String emailAddress) { - return save(User.builder().firstName(firstName).lastName(lastName).emailAddress(emailAddress).build()); - } -} +package se.su.dsv.scipro.group; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.system.DegreeType; +import se.su.dsv.scipro.system.ProjectType; +import se.su.dsv.scipro.system.User; +import se.su.dsv.scipro.test.IntegrationTest; + +import jakarta.inject.Inject; +import java.time.LocalDate; +import java.util.Collections; +import java.util.HashSet; + +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class GroupServiceImplTest extends IntegrationTest { + + @Inject + private GroupServiceImpl groupService; + private User author; + private User creator; + private User reviewer; + private User cosupervisor; + private Group group; + private ProjectType projectType; + + @BeforeEach + public void setUp() throws Exception { + author = saveUser("author", "name", "author@example.com"); + creator = saveUser("supervisor", "sup", "supervisor@example.com"); + reviewer = saveUser("reviewer", "test", "reviewer@example.com"); + cosupervisor = saveUser("cosupervisor", "test", "reviewer@example.com"); + projectType = save(new ProjectType(DegreeType.BACHELOR, "b", "b")); + User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build()); + Project project = save(Project.builder().title("title").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); + project.addProjectParticipant(author); + project.addReviewer(reviewer); + project.addCoSupervisor(cosupervisor); + createGroup(project); + } + + @Test + public void find_by_author() { + GroupService.Filter filter = new GroupService.Filter(); + filter.setAuthor(author); + assertGroup(filter); + } + + @Test + public void find_all() { + GroupService.Filter filter = new GroupService.Filter(); + assertGroup(filter); + } + + @Test + public void find_by_creator_fails() { + GroupService.Filter filter = new GroupService.Filter(); + filter.setCreator(author); + assertTrue(groupService.findAll(filter).isEmpty()); + } + + @Test + public void find_by_creator() { + GroupService.Filter filter = new GroupService.Filter(); + filter.setCreator(creator); + assertGroup(filter); + } + + @Test + public void find_by_reviewer_involvee() { + GroupService.Filter filter = new GroupService.Filter(); + filter.setNonAuthorInvolvee(reviewer); + assertThat(groupService.findAll(filter), not(hasItem(group))); + } + + @Test + public void find_by_cosupervisor_involvee() { + GroupService.Filter filter = new GroupService.Filter(); + filter.setNonAuthorInvolvee(cosupervisor); + assertGroup(filter); + } + + @Test + public void find_active_groups() { + GroupService.Filter filter = new GroupService.Filter(); + filter.setActive(true); + assertGroup(filter); + + filter.setActive(false); + assertTrue(groupService.findAll(filter).isEmpty()); + } + + @Test + public void count() { + GroupService.Filter filter = new GroupService.Filter(); + filter.setAuthor(author); + assertEquals(1, groupService.count(filter)); + } + + @Test + public void find_groups_by_project() { + Group another = new Group(); + another.setTitle("hi"); + another.setUser(creator); + User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build()); + Project anotherProject = save(Project.builder().title("another").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); + another.setProjects(new HashSet<>(Collections.singletonList(anotherProject))); + save(another); + GroupService.Filter filter = new GroupService.Filter(); + filter.setProject(anotherProject); + assertEquals(another, groupService.findAll(filter).get(0)); + } + + private void assertGroup(GroupService.Filter filter) { + assertThat(groupService.findAll(filter), hasItem(group)); + } + + private void createGroup(Project project) { + group = new Group(); + group.setTitle("group title"); + group.setProjects(new HashSet<>(Collections.singletonList(project))); + group.setUser(creator); + save(group); + } + + private User saveUser(String firstName, String lastName, String emailAddress) { + return save(User.builder().firstName(firstName).lastName(lastName).emailAddress(emailAddress).build()); + } +} diff --git a/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java b/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java index 63417a754b..7a189d32f4 100644 --- a/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java +++ b/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java @@ -1,9 +1,6 @@ package se.su.dsv.scipro.match; import com.google.common.eventbus.EventBus; -import com.google.inject.AbstractModule; -import com.google.inject.Module; -import com.google.inject.name.Names; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -13,10 +10,10 @@ import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; import se.su.dsv.scipro.mail.MailEventService; import se.su.dsv.scipro.notifications.NotificationController; import se.su.dsv.scipro.project.ProjectService; -import se.su.dsv.scipro.test.GuiceTest; +import se.su.dsv.scipro.test.SpringTest; @ExtendWith(MockitoExtension.class) -public abstract class MatchModuleTest extends GuiceTest { +public abstract class MatchModuleTest extends SpringTest { // ToDo:The system services should be move to a system module that other modules can depend on @Mock protected DateService dateService; @@ -34,28 +31,4 @@ public abstract class MatchModuleTest extends GuiceTest { @Mock protected ProjectService projectService; - @Override - protected Module moduleUnderTest() { - return new AbstractModule() { - @Override - protected void configure() { - install(new MatchModule()); - bind(GeneralSystemSettingsService.class).toInstance(generalSystemSettingsService); - bind(NotificationController.class).toInstance(notificationController); - bind(DateService.class).toInstance(dateService); - bind(MailEventService.class).toInstance(mailEventService); - bind(ActivityPlanFacade.class).toInstance(activityPlanFacade); - bind(EventBus.class).toInstance(eventBus); - bind(ProjectService.class).toInstance(projectService); - - // Work towards removing the dependency on NotificationSourceURL - bindConstant().annotatedWith(Names.named("source.export.fail.supervisor")).to(""); - bindConstant().annotatedWith(Names.named("source.export.fail.user")).to(""); - bindConstant().annotatedWith(Names.named("source.export.success.supervisor")).to(""); - bindConstant().annotatedWith(Names.named("source.export.success.user")).to(""); - bindConstant().annotatedWith(Names.named("source.project.supervisor")).to(""); - bindConstant().annotatedWith(Names.named("source.project.student")).to(""); - } - }; - } } diff --git a/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java b/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java index e42ccafdfc..fed52e8629 100644 --- a/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java +++ b/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java @@ -66,7 +66,7 @@ public class MilestoneActivatorTest { author.setId(123L); ProjectType bachelor = new ProjectType(DegreeType.BACHELOR, "Bachelor", "Bachelor"); - bachelor.getProjectTypeSettings().setMinimumActiveParticipationsToBeGraded(2); + bachelor.getProjectTypeSettings().setMinActiveParticipationsToBeGraded(2); project = Project.builder() .title("Project title") .projectType(bachelor) diff --git a/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java b/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java index 6453a0f537..6c770e1a9d 100755 --- a/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java +++ b/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java @@ -1,6 +1,5 @@ package se.su.dsv.scipro.notifications; -import com.google.inject.util.Providers; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; @@ -55,7 +54,7 @@ public class NotificationControllerImplTest { notificationService, mailFormatter, mailEventService, - receiverConfiguration, deliveryConfiguration, Providers.of(currentUser)); + receiverConfiguration, deliveryConfiguration, () -> currentUser); when(mailFormatter.format(isA(Notification.class))).thenReturn(new NotificationMail("Subject", "Body")); when(deliveryConfiguration.isDelivery(isA(Notification.Type.class), isA(Enum.class), isA(DeliveryMethod.class), isA(Optional.class))).thenReturn(true); diff --git a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java index a2eb62c871..8b113e1524 100644 --- a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java +++ b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java @@ -1,35 +1,16 @@ package se.su.dsv.scipro.plagiarism.urkund; -import com.google.inject.AbstractModule; -import com.google.inject.Module; import org.junit.jupiter.api.Test; -import se.su.dsv.scipro.file.FileModule; -import se.su.dsv.scipro.file.FileStore; -import se.su.dsv.scipro.sukat.SukatModule; -import se.su.dsv.scipro.test.GuiceTest; -import se.su.dsv.scipro.test.InMemoryFileStore; +import se.su.dsv.scipro.test.SpringTest; import jakarta.inject.Inject; import static org.junit.jupiter.api.Assertions.assertEquals; -public class UrkundSettingsRepositoryTest extends GuiceTest { +public class UrkundSettingsRepositoryTest extends SpringTest { @Inject private UrkundSettingsRepository urkundSettingsRepository; - @Override - protected Module moduleUnderTest() { - return new AbstractModule() { - @Override - protected void configure() { - install(new SukatModule()); - install(new UrkundModule()); - install(new FileModule()); - bind(FileStore.class).to(InMemoryFileStore.class); - } - }; - } - @Test public void change_settings() { final UrkundSettings settings = urkundSettingsRepository.getSettings(); diff --git a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java index 0d2599f5fd..6120fe3468 100644 --- a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java +++ b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java @@ -1,18 +1,12 @@ package se.su.dsv.scipro.plagiarism.urkund; -import com.google.inject.AbstractModule; -import com.google.inject.Module; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import org.junit.jupiter.api.Test; import se.su.dsv.scipro.file.FileDescription; -import se.su.dsv.scipro.file.FileModule; import se.su.dsv.scipro.file.FileReference; -import se.su.dsv.scipro.file.FileStore; -import se.su.dsv.scipro.sukat.Sukat; -import se.su.dsv.scipro.test.GuiceTest; -import se.su.dsv.scipro.test.InMemoryFileStore; +import se.su.dsv.scipro.test.SpringTest; import jakarta.inject.Inject; import java.time.Instant; @@ -22,23 +16,10 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -public class UrkundSubmissionRepositoryTest extends GuiceTest { +public class UrkundSubmissionRepositoryTest extends SpringTest { @Inject private UrkundSubmissionRepository submissionRepository; - - @Override - protected Module moduleUnderTest() { - return new AbstractModule() { - @Override - protected void configure() { - install(new UrkundModule()); - bind(Sukat.class).toInstance((username) -> Optional.empty()); - install(new FileModule()); - bind(FileStore.class).to(InMemoryFileStore.class); - } - }; - } @Test public void save() { diff --git a/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java b/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java index 8d8d462e31..745def4bcd 100644 --- a/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java +++ b/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java @@ -101,6 +101,26 @@ public class ReflectionServiceTest extends IntegrationTest { assertTrue(reflectionService.hasReachedReflectionProcess(project)); } + @Test + public void request_resubmission() { + LocalDate seminarDate = scheduleSeminar(); + clock.setDate(seminarDate.plusDays(1)); + assertTrue(reflectionService.hasToFillInReflection(project, author), + "After the final seminar the author should be required to submit a reflection"); + + String myReflection = "my reflection"; + reflectionService.submitReflection(project, author, myReflection); + assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author)); + assertFalse(reflectionService.hasToFillInReflection(project, author), + "After submitting the initial reflection it should no longer be required"); + + reflectionService.requestNewReflection(project, author, "Very bad reflection"); + assertTrue(reflectionService.hasToFillInReflection(project, author), + "After supervisor requests resubmission the author should now be required to submit a new reflection"); + assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author), + "The old reflection should be saved to make it easier for the student to update it"); + } + private LocalDate scheduleSeminar() { project.setFinalSeminarRuleExempted(true); // to bypass rough draft approval FinalSeminarDetails details = new FinalSeminarDetails("Zoom", false, 1, 1, Language.SWEDISH, Language.ENGLISH, "zoom id 123"); diff --git a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java index 8d59c17234..ba058fcce1 100644 --- a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java +++ b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java @@ -1,18 +1,6 @@ package se.su.dsv.scipro.reviewing; -import com.google.inject.AbstractModule; -import com.google.inject.Module; import se.su.dsv.scipro.test.IntegrationTest; public abstract class ReviewingModuleTest extends IntegrationTest { - @Override - protected Module moduleUnderTest() { - return new AbstractModule() { - @Override - protected void configure() { - install(ReviewingModuleTest.super.moduleUnderTest()); - bind(ReviewerAssignedDeadline.class).asEagerSingleton(); - } - }; - } } diff --git a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java index 56398d9f29..dd4ad1a076 100644 --- a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java +++ b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java @@ -1,161 +1,161 @@ -package se.su.dsv.scipro.reviewing; - -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; -import se.su.dsv.scipro.file.FileUpload; -import se.su.dsv.scipro.project.Project; -import se.su.dsv.scipro.system.DegreeType; -import se.su.dsv.scipro.system.Page; -import se.su.dsv.scipro.system.ProjectType; -import se.su.dsv.scipro.system.User; -import se.su.dsv.scipro.util.Either; - -import jakarta.inject.Inject; -import java.time.LocalDate; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; - -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.instanceOf; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class ReviewingServiceImplTest extends ReviewingModuleTest { - private static final TestPage ALL = new TestPage(0, Long.MAX_VALUE); - - @Inject - private ReviewingServiceImpl reviewingService; - @Inject - private FinalSeminarApprovalServiceImpl finalSeminarApprovalService; - @Inject - private RoughDraftApprovalServiceImpl roughDraftApprovalService; - - private Project project; - private User reviewer; - private Project project3; - - @BeforeEach - public void setUp() throws Exception { - reviewer = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build()); - User reviewer2 = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build()); - User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build()); - ProjectType bachelor = save(new ProjectType(DegreeType.BACHELOR, "Bachelor", "Bachelor")); - project = save(Project.builder().title("My project").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); - project.addReviewer(reviewer); - Project project2 = save(Project.builder().title("My project 2").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); - project2.addReviewer(reviewer2); - project3 = save(Project.builder().title("My project 3").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); - project3.addReviewer(reviewer); - } - - @Test - public void count() { - finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); - assertEquals(1, reviewingService.countDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL))); - } - - private MyReviewService.Filter getFilter(ReviewerApproval.Step step) { - MyReviewService.Filter filter = new MyReviewService.Filter(); - filter.setUser(reviewer); - filter.setStep(step); - return filter; - } - - @Test - public void find_undecided() { - finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); - assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(FinalSeminarApproval.class)))); - } - - @Test - public void find_undecided_rough_draft_approvals() { - roughDraftApprovalService.requestApproval(project, createFileUpload(), "test"); - assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(RoughDraftApproval.class)))); - } - - @Test - public void count_undecided_rough_drafts() { - roughDraftApprovalService.requestApproval(project, createFileUpload(), "test"); - assertEquals(reviewingService.countUndecidedRoughDraft(reviewer), 1); - } - - @Test - public void back_and_forth() { - assertTrue(finalSeminarApprovalService.requiresUpload(project)); - Either<AlreadyRequested, FinalSeminarApproval> first = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); - assertFalse(finalSeminarApprovalService.requiresUpload(project)); - - first.foreach(firstFinalSeminarApproval -> reviewingService.reject(firstFinalSeminarApproval, "Very bad", Optional.of(createFileUpload()))); - - assertTrue(finalSeminarApprovalService.requiresUpload(project)); - Either<AlreadyRequested, FinalSeminarApproval> second = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); - assertFalse(finalSeminarApprovalService.requiresUpload(project)); - - second.foreach(secondFinalSeminarApproval -> reviewingService.approve(secondFinalSeminarApproval, "Very good", Optional.empty())); - assertFalse(finalSeminarApprovalService.requiresUpload(project)); - } - - @Test - public void only_fetches_my_reviews() { - Either<AlreadyRequested, RoughDraftApproval> myRequest = - roughDraftApprovalService.requestApproval(project, createFileUpload(), "my request"); - assertTrue(myRequest.isRight()); - - List<Decision> requests = reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL); - assertEquals(1, requests.size()); - } - - @Test - public void sort_by_requested() { - Either<AlreadyRequested, RoughDraftApproval> request1 = - roughDraftApprovalService.requestApproval(project, createFileUpload(), "request 1"); - assertTrue(request1.isRight()); - - Either<AlreadyRequested, RoughDraftApproval> request2 = - roughDraftApprovalService.requestApproval(project3, createFileUpload(), "request 2"); - assertTrue(request2.isRight()); - - var sortByRequested = new Page.Sort<>(MyReviewService.Sort.TITLE, Page.Direction.DESCENDING); - TestPage page = new TestPage(0, Long.MAX_VALUE, sortByRequested); - List<Decision> requests = - reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), page); - - assertEquals(2, requests.size()); - assertEquals(request2.right(), requests.get(0).getReviewerApproval()); - assertEquals(request1.right(), requests.get(1).getReviewerApproval()); - } - - private FileUpload createFileUpload() { - FileUpload fileUpload = mock(FileUpload.class); - when(fileUpload.handleData(ArgumentMatchers.any())).thenReturn(null); - return fileUpload; - } - - record TestPage(long offset, long limit, Sort<MyReviewService.Sort> sort) implements Page<MyReviewService.Sort> { - TestPage(long offset, long limit) { - this(offset, limit, new Sort<>(MyReviewService.Sort.TITLE, Direction.ASCENDING)); - } - } - - private static <A, B> Matcher<A> where(Function<A, B> f, Matcher<? extends B> matcher) { - return new TypeSafeMatcher<>() { - @Override - protected boolean matchesSafely(A a) { - return matcher.matches(f.apply(a)); - } - - @Override - public void describeTo(Description description) { - description.appendText("an object where ") - .appendDescriptionOf(matcher); - } - }; - } -} +package se.su.dsv.scipro.reviewing; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import se.su.dsv.scipro.file.FileUpload; +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.system.DegreeType; +import se.su.dsv.scipro.system.Page; +import se.su.dsv.scipro.system.ProjectType; +import se.su.dsv.scipro.system.User; +import se.su.dsv.scipro.util.Either; + +import jakarta.inject.Inject; +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ReviewingServiceImplTest extends ReviewingModuleTest { + private static final TestPage ALL = new TestPage(0, Long.MAX_VALUE); + + @Inject + private ReviewingServiceImpl reviewingService; + @Inject + private FinalSeminarApprovalServiceImpl finalSeminarApprovalService; + @Inject + private RoughDraftApprovalServiceImpl roughDraftApprovalService; + + private Project project; + private User reviewer; + private Project project3; + + @BeforeEach + public void setUp() throws Exception { + reviewer = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build()); + User reviewer2 = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build()); + User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build()); + ProjectType bachelor = save(new ProjectType(DegreeType.BACHELOR, "Bachelor", "Bachelor")); + project = save(Project.builder().title("My project").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); + project.addReviewer(reviewer); + Project project2 = save(Project.builder().title("My project 2").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); + project2.addReviewer(reviewer2); + project3 = save(Project.builder().title("My project 3").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build()); + project3.addReviewer(reviewer); + } + + @Test + public void count() { + finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); + assertEquals(1, reviewingService.countDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL))); + } + + private MyReviewService.Filter getFilter(ReviewerApproval.Step step) { + MyReviewService.Filter filter = new MyReviewService.Filter(); + filter.setUser(reviewer); + filter.setStep(step); + return filter; + } + + @Test + public void find_undecided() { + finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); + assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(FinalSeminarApproval.class)))); + } + + @Test + public void find_undecided_rough_draft_approvals() { + roughDraftApprovalService.requestApproval(project, createFileUpload(), "test"); + assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(RoughDraftApproval.class)))); + } + + @Test + public void count_undecided_rough_drafts() { + roughDraftApprovalService.requestApproval(project, createFileUpload(), "test"); + assertEquals(reviewingService.countUndecidedRoughDraft(reviewer), 1); + } + + @Test + public void back_and_forth() { + assertTrue(finalSeminarApprovalService.requiresUpload(project)); + Either<AlreadyRequested, FinalSeminarApproval> first = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); + assertFalse(finalSeminarApprovalService.requiresUpload(project)); + + first.foreach(firstFinalSeminarApproval -> reviewingService.reject(firstFinalSeminarApproval, "Very bad", Optional.of(createFileUpload()))); + + assertTrue(finalSeminarApprovalService.requiresUpload(project)); + Either<AlreadyRequested, FinalSeminarApproval> second = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test"); + assertFalse(finalSeminarApprovalService.requiresUpload(project)); + + second.foreach(secondFinalSeminarApproval -> reviewingService.approve(secondFinalSeminarApproval, "Very good", Optional.empty())); + assertFalse(finalSeminarApprovalService.requiresUpload(project)); + } + + @Test + public void only_fetches_my_reviews() { + Either<AlreadyRequested, RoughDraftApproval> myRequest = + roughDraftApprovalService.requestApproval(project, createFileUpload(), "my request"); + assertTrue(myRequest.isRight()); + + List<Decision> requests = reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL); + assertEquals(1, requests.size()); + } + + @Test + public void sort_by_requested() { + Either<AlreadyRequested, RoughDraftApproval> request1 = + roughDraftApprovalService.requestApproval(project, createFileUpload(), "request 1"); + assertTrue(request1.isRight()); + + Either<AlreadyRequested, RoughDraftApproval> request2 = + roughDraftApprovalService.requestApproval(project3, createFileUpload(), "request 2"); + assertTrue(request2.isRight()); + + var sortByRequested = new Page.Sort<>(MyReviewService.Sort.TITLE, Page.Direction.DESCENDING); + TestPage page = new TestPage(0, Long.MAX_VALUE, sortByRequested); + List<Decision> requests = + reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), page); + + assertEquals(2, requests.size()); + assertEquals(request2.right(), requests.get(0).getReviewerApproval()); + assertEquals(request1.right(), requests.get(1).getReviewerApproval()); + } + + private FileUpload createFileUpload() { + FileUpload fileUpload = mock(FileUpload.class); + when(fileUpload.handleData(ArgumentMatchers.any())).thenReturn(null); + return fileUpload; + } + + record TestPage(long offset, long limit, Sort<MyReviewService.Sort> sort) implements Page<MyReviewService.Sort> { + TestPage(long offset, long limit) { + this(offset, limit, new Sort<>(MyReviewService.Sort.TITLE, Direction.ASCENDING)); + } + } + + private static <A, B> Matcher<A> where(Function<A, B> f, Matcher<? extends B> matcher) { + return new TypeSafeMatcher<>() { + @Override + protected boolean matchesSafely(A a) { + return matcher.matches(f.apply(a)); + } + + @Override + public void describeTo(Description description) { + description.appendText("an object where ") + .appendDescriptionOf(matcher); + } + }; + } +} diff --git a/core/src/test/java/se/su/dsv/scipro/test/GuiceTest.java b/core/src/test/java/se/su/dsv/scipro/test/GuiceTest.java deleted file mode 100644 index 6d2667ef5c..0000000000 --- a/core/src/test/java/se/su/dsv/scipro/test/GuiceTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package se.su.dsv.scipro.test; - -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.Module; -import com.google.inject.persist.PersistService; -import com.google.inject.persist.UnitOfWork; -import com.google.inject.persist.jpa.JpaPersistModule; -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityTransaction; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; - -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import java.time.Clock; - -public abstract class GuiceTest { - @Inject - private UnitOfWork unitOfWork; - @Inject - private PersistService persistService; - @Inject - private Provider<EntityManager> entityManager; - - @BeforeEach - public final void prepareGuice() { - Injector injector = Guice.createInjector( - new JpaPersistModule("testPersistenceUnit"), - new AbstractModule() { - @Override - protected void configure() { - final MutableFixedClock clock = new MutableFixedClock(Clock.systemDefaultZone()); - bind(Clock.class).toInstance(clock); - bind(MutableFixedClock.class).toInstance(clock); - } - }, - moduleUnderTest()); - - // Have to start the PersistService and UnitOfWork manually since they are no longer - // automatically started as an EntityManager is injected - injector.getInstance(PersistService.class).start(); - injector.getInstance(UnitOfWork.class).begin(); - - injector.injectMembers(this); - - persistService.start(); - EntityTransaction transaction = entityManager.get().getTransaction(); - transaction.begin(); - transaction.setRollbackOnly(); - } - - protected abstract Module moduleUnderTest(); - - @AfterEach - public final void shutDownPersistence() { - entityManager.get().getTransaction().rollback(); - unitOfWork.end(); - persistService.stop(); - } - - protected <T> T save(T entity) { - EntityManager em = entityManager.get(); - if (em.contains(entity)) { - return em.merge(entity); - } - else { - em.persist(entity); - return entity; - } - } -} diff --git a/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java b/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java index 4833f0e4bd..837f58dc90 100644 --- a/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java +++ b/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java @@ -1,57 +1,5 @@ package se.su.dsv.scipro.test; -import com.google.inject.AbstractModule; -import com.google.inject.Module; -import com.google.inject.name.Names; -import modules.CoreModule; -import se.su.dsv.scipro.file.FileModule; -import se.su.dsv.scipro.file.FileStore; -import se.su.dsv.scipro.grading.GradingHistory; -import se.su.dsv.scipro.grading.GradingHistoryEventRepository; -import se.su.dsv.scipro.grading.GradingHistoryEventRepositoryImpl; -import se.su.dsv.scipro.grading.GradingModule; -import se.su.dsv.scipro.grading.ThesisSubmissionHistoryService; -import se.su.dsv.scipro.plagiarism.urkund.UrkundModule; -import se.su.dsv.scipro.reviewing.ReviewingModule; -import se.su.dsv.scipro.sukat.SukatModule; -import se.su.dsv.scipro.system.CurrentUser; -import se.su.dsv.scipro.system.User; +public abstract class IntegrationTest extends SpringTest { -import jakarta.inject.Singleton; - -public abstract class IntegrationTest extends GuiceTest { - - @Override - protected Module moduleUnderTest() { - return new AbstractModule() { - @Override - protected void configure() { - bindConstant().annotatedWith(Names.named("profile")).to("TEST"); - install(new CoreModule()); - install(new FileModule()); - install(new ReviewingModule()); - install(new SukatModule()); - install(new UrkundModule()); - bind(ThesisSubmissionHistoryService.class).to(GradingHistory.class); - bind(GradingHistoryEventRepository.class).to(GradingHistoryEventRepositoryImpl.class); - bind(CurrentUser.class).to(TestUser.class); - bind(FileStore.class).to(InMemoryFileStore.class); - } - }; - } - - @Singleton - private static class TestUser implements CurrentUser { - - private User user; - - public void set(User user) { - this.user = user; - } - - @Override - public User get() { - return user; - } - } } diff --git a/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java b/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java new file mode 100644 index 0000000000..eae4492265 --- /dev/null +++ b/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java @@ -0,0 +1,92 @@ +package se.su.dsv.scipro.test; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import jakarta.persistence.Persistence; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import se.su.dsv.scipro.profiles.CurrentProfile; +import se.su.dsv.scipro.sukat.Sukat; +import se.su.dsv.scipro.system.CurrentUser; +import se.su.dsv.scipro.CoreConfig; +import se.su.dsv.scipro.RepositoryConfiguration; + +import java.time.Clock; +import java.util.Optional; + +public abstract class SpringTest { + private EntityManager entityManager; + private EntityManagerFactory entityManagerFactory; + + @BeforeEach + public final void prepareSpring() { + entityManagerFactory = Persistence.createEntityManagerFactory("testPersistenceUnit"); + this.entityManager = entityManagerFactory.createEntityManager(); + EntityTransaction transaction = entityManager.getTransaction(); + transaction.begin(); + transaction.setRollbackOnly(); + + AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); + annotationConfigApplicationContext.register(TestContext.class); + annotationConfigApplicationContext.getBeanFactory() + .registerSingleton("entityManager", this.entityManager); + annotationConfigApplicationContext.refresh(); + annotationConfigApplicationContext.getAutowireCapableBeanFactory() + .autowireBean(this); + } + + @AfterEach + public final void shutDownPersistence() { + entityManager.getTransaction().rollback(); + entityManager.close(); + entityManagerFactory.close(); + } + + protected <T> T save(T entity) { + EntityManager em = entityManager; + if (em.contains(entity)) { + return em.merge(entity); + } + else { + em.persist(entity); + return entity; + } + } + + @Configuration(proxyBeanMethods = false) + @Import({CoreConfig.class, RepositoryConfiguration.class}) + public static class TestContext { + @Bean + public InMemoryFileStore inMemoryFileStore() { + return new InMemoryFileStore(); + } + + @Bean + public MutableFixedClock clock() { + return new MutableFixedClock(Clock.systemDefaultZone()); + } + + @Bean + public Sukat sukat() { + return (username) -> Optional.empty(); + } + + @Bean + public CurrentUser currentUser() { + return () -> null; + } + + @Bean + public CurrentProfile currentProfile() { + CurrentProfile currentProfile = new CurrentProfile(); + currentProfile.setCurrentProfileString("DEV"); + return currentProfile; + } + } +} diff --git a/daisy-integration/pom.xml b/daisy-integration/pom.xml index 891a45a81e..3d94bb165c 100644 --- a/daisy-integration/pom.xml +++ b/daisy-integration/pom.xml @@ -17,8 +17,8 @@ <artifactId>core</artifactId> </dependency> <dependency> - <groupId>com.google.inject.extensions</groupId> - <artifactId>guice-servlet</artifactId> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>jakarta.servlet</groupId> diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java index 3d4acbe581..3f78ffd415 100755 --- a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java +++ b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.daisyExternal.impl; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.su.dsv.scipro.system.PageRequest; diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java index 0fe1dd6e51..9e6ea05554 100644 --- a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java +++ b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.daisyExternal.impl; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import jakarta.ws.rs.core.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyIntegrationConfiguration.java b/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyIntegrationConfiguration.java new file mode 100644 index 0000000000..1a50b0c056 --- /dev/null +++ b/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyIntegrationConfiguration.java @@ -0,0 +1,182 @@ +package se.su.dsv.scipro.integration.daisy; + +import com.google.common.eventbus.EventBus; +import jakarta.inject.Provider; +import jakarta.persistence.EntityManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import se.su.dsv.scipro.daisyExternal.ExternalImporter; +import se.su.dsv.scipro.daisyExternal.ImporterTransactions; +import se.su.dsv.scipro.daisyExternal.http.DaisyAPI; +import se.su.dsv.scipro.daisyExternal.impl.ExternalImporterDaisyImpl; +import se.su.dsv.scipro.daisyExternal.impl.ImporterTransactionsImpl; +import se.su.dsv.scipro.finalseminar.FinalSeminarService; +import se.su.dsv.scipro.finalthesis.FinalThesisService; +import se.su.dsv.scipro.forum.ProjectForumService; +import se.su.dsv.scipro.grading.NationalSubjectCategoryService; +import se.su.dsv.scipro.grading.ThesisApprovedHistoryService; +import se.su.dsv.scipro.grading.ThesisRejectionHistoryService; +import se.su.dsv.scipro.integration.daisy.workers.GradingCompletedMilestoneActivator; +import se.su.dsv.scipro.integration.daisy.workers.ImportNationalCategories; +import se.su.dsv.scipro.integration.daisy.workers.ProjectExporter; +import se.su.dsv.scipro.integration.daisy.workers.ProjectFinalizer; +import se.su.dsv.scipro.integration.daisy.workers.RejectedThesisWorker; +import se.su.dsv.scipro.integration.daisy.workers.UserImportWorker; +import se.su.dsv.scipro.io.ExternalExporter; +import se.su.dsv.scipro.io.facade.ExporterFacade; +import se.su.dsv.scipro.io.impl.ExternalExporterDaisyImpl; +import se.su.dsv.scipro.match.ProgramService; +import se.su.dsv.scipro.project.ProjectRepo; +import se.su.dsv.scipro.project.ProjectService; +import se.su.dsv.scipro.report.GradingReportService; +import se.su.dsv.scipro.springdata.services.UnitService; +import se.su.dsv.scipro.system.MergeService; +import se.su.dsv.scipro.system.MergeServiceImpl; +import se.su.dsv.scipro.system.ResearchAreaService; +import se.su.dsv.scipro.system.UserNameService; +import se.su.dsv.scipro.system.UserService; +import se.su.dsv.scipro.war.PluginConfiguration; +import se.su.dsv.scipro.workerthreads.Scheduler; + +@Configuration +public class DaisyIntegrationConfiguration implements PluginConfiguration { + @Bean + public Daisy daisy(ExporterFacade exporterFacade, ExternalExporter externalExporter) { + return new Daisy(exporterFacade, externalExporter); + } + + @Bean + public ExporterFacade exporterFacade(ExternalExporter externalExporter) { + return new ExporterFacade(externalExporter); + } + + @Bean + public ExternalExporterDaisyImpl externalExporter(DaisyAPI daisyApi) { + return new ExternalExporterDaisyImpl(daisyApi); + } + + @Bean + public DaisyWorkerInitialization daisyWorkerInitialization( + Scheduler scheduler, + Provider<ProjectExporter> projectExporter, + Provider<UserImportWorker> userImportWorker, + Provider<ProjectFinalizer> projectFinalizer, + Provider<RejectedThesisWorker> rejectedThesisWorkerProvider, + Provider<GradingCompletedMilestoneActivator> gradingFinalizer, + Provider<ImportNationalCategories> importNationalCategories) + { + return new DaisyWorkerInitialization(scheduler, projectExporter, userImportWorker, projectFinalizer, + rejectedThesisWorkerProvider, gradingFinalizer, importNationalCategories); + } + + @Bean + public ProjectExporter projectExporter( + ExporterFacade exporterFacade, + ProjectRepo projectRepo, + DaisyAPI daisyApi, + ExternalExporter externalExporter, + FinalSeminarService finalSeminarService, + FinalThesisService finalThesisService) + { + return new ProjectExporter(projectRepo, exporterFacade, daisyApi, externalExporter, finalSeminarService, + finalThesisService); + } + + @Bean + public UserImportWorker userImportWorker( + DaisyAPI daisyApi, + ImporterTransactions importerTransactions, + ExternalImporter externalImporter, + MergeService mergeService, + UserService userService, + ProgramService programService, + Provider<EntityManager> entityManager, + ResearchAreaService researchAreaService) + { + return new UserImportWorker(daisyApi, importerTransactions, externalImporter, mergeService, userService, + programService, entityManager, researchAreaService); + } + + @Bean + public ProjectFinalizer projectFinalizer( + ProjectService projectService, + DaisyAPI daisyApi, + ThesisApprovedHistoryService thesisApprovedHistoryService) + { + return new ProjectFinalizer(projectService, daisyApi, thesisApprovedHistoryService); + } + + @Bean + public RejectedThesisWorker rejectedThesisWorker( + GradingReportService gradingReportService, + ProjectService projectService, + FinalThesisService finalThesisService, + ProjectForumService projectForumService, + ThesisRejectionHistoryService thesisRejectionHistoryService, + DaisyAPI daisyApi) + { + return new RejectedThesisWorker(gradingReportService, projectService, finalThesisService, projectForumService, + thesisRejectionHistoryService, daisyApi); + } + + @Bean + public GradingCompletedMilestoneActivator gradingFinalizer( + ProjectService projectService, + DaisyAPI daisyApi, + EventBus eventBus, + UserService userService) + { + return new GradingCompletedMilestoneActivator(projectService, daisyApi, eventBus, userService); + } + + @Bean + public ImportNationalCategories importNationalCategories( + DaisyAPI daisyApi, + NationalSubjectCategoryService nationalSubjectCategoryService) + { + return new ImportNationalCategories(daisyApi, nationalSubjectCategoryService); + } + + @Bean + public ImporterTransactionsImpl importerTransactions( + UserService userService, + ResearchAreaService researchAreaService, + ProjectService projectService, + UserNameService userNameService, + DaisyAPI daisyApi, + ProgramService programService) + { + return new ImporterTransactionsImpl(userService, researchAreaService, projectService, userNameService, + daisyApi, programService); + } + + @Bean + public ExternalImporterDaisyImpl externalImporter( + DaisyAPI daisyApi, + ImporterTransactions importerTransactions, + UserService userService, + UnitService unitService) + { + return new ExternalImporterDaisyImpl(userService, unitService, daisyApi, importerTransactions); + } + + @Bean + public MergeServiceImpl mergeService(UserService userService, UserNameService userNameService) { + return new MergeServiceImpl(userNameService, userService); + } + + @Bean + SyncReviewerWithDaisy syncReviewerWithDaisy(DaisyAPI daisyApi, EventBus eventBus) { + return new SyncReviewerWithDaisy(daisyApi, eventBus); + } + + @Bean + public DaisyUserSearchService daisyUserSearchService(DaisyAPI daisyApi, UserService userService) { + return new DaisyUserSearchService(daisyApi, userService); + } + + @Bean + DaisyConsentService daisyConsentService(DaisyAPI daisyApi) { + return new DaisyConsentService(daisyApi); + } +} diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyModule.java b/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyModule.java deleted file mode 100644 index ffedb6c3c1..0000000000 --- a/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyModule.java +++ /dev/null @@ -1,44 +0,0 @@ -package se.su.dsv.scipro.integration.daisy; - -import com.google.inject.multibindings.Multibinder; -import com.google.inject.multibindings.OptionalBinder; -import com.google.inject.servlet.ServletModule; -import se.su.dsv.scipro.daisyExternal.ExternalImporter; -import se.su.dsv.scipro.daisyExternal.ImporterTransactions; -import se.su.dsv.scipro.daisyExternal.impl.ExternalImporterDaisyImpl; -import se.su.dsv.scipro.daisyExternal.impl.ImporterTransactionsImpl; -import se.su.dsv.scipro.finalthesis.PublishingConsentService; -import se.su.dsv.scipro.integration.daisy.workers.ProjectExporter; -import se.su.dsv.scipro.integration.daisy.workers.UserImportWorker; -import se.su.dsv.scipro.io.ExternalExporter; -import se.su.dsv.scipro.io.impl.ExternalExporterDaisyImpl; -import se.su.dsv.scipro.match.IdeaCreationJudge; -import se.su.dsv.scipro.system.UserImportService; -import se.su.dsv.scipro.system.UserSearchProvider; - -public class DaisyModule extends ServletModule { - @Override - protected void configureServlets() { - bind(ExternalImporter.class).to(ExternalImporterDaisyImpl.class); - bind(ImporterTransactions.class).to(ImporterTransactionsImpl.class); - - OptionalBinder.newOptionalBinder(binder(), IdeaCreationJudge.class) - .setBinding().to(Daisy.class); - - bind(ExternalExporter.class).to(ExternalExporterDaisyImpl.class); - bind(UserImportWorker.class); - bind(ProjectExporter.class); - bind(DaisyWorkerInitialization.class).asEagerSingleton(); - bind(SyncReviewerWithDaisy.class).asEagerSingleton(); - - Multibinder.newSetBinder(binder(), UserImportService.class) - .addBinding().to(ExternalImporterDaisyImpl.class); - - Multibinder.newSetBinder(binder(), UserSearchProvider.class) - .addBinding().to(DaisyUserSearchService.class); - - OptionalBinder.newOptionalBinder(binder(), PublishingConsentService.class) - .setBinding().to(DaisyConsentService.class); - } - -} diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java b/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java index 4d7c11803d..75400ab642 100755 --- a/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java +++ b/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.io.facade; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import se.su.dsv.scipro.io.ExternalExporter; import se.su.dsv.scipro.io.dto.Role; import se.su.dsv.scipro.io.exceptions.ExternalExportException; diff --git a/daisy-integration/src/main/resources/META-INF/services/com.google.inject.Module b/daisy-integration/src/main/resources/META-INF/services/com.google.inject.Module deleted file mode 100644 index f216e38b02..0000000000 --- a/daisy-integration/src/main/resources/META-INF/services/com.google.inject.Module +++ /dev/null @@ -1 +0,0 @@ -se.su.dsv.scipro.integration.daisy.DaisyModule diff --git a/daisy-integration/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration b/daisy-integration/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration new file mode 100644 index 0000000000..39148f50a9 --- /dev/null +++ b/daisy-integration/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration @@ -0,0 +1 @@ +se.su.dsv.scipro.integration.daisy.DaisyIntegrationConfiguration diff --git a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java index b583b29e21..f51c23592a 100644 --- a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java +++ b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java @@ -1,10 +1,6 @@ package se.su.dsv.scipro.integration.daisy.workers; import com.google.common.eventbus.EventBus; -import com.google.inject.persist.UnitOfWork; -import com.google.inject.util.Providers; -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityTransaction; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -23,6 +19,7 @@ import se.su.dsv.scipro.system.User; import se.su.dsv.scipro.system.UserService; import se.su.dsv.scipro.workerthreads.WorkerData; import se.su.dsv.scipro.workerthreads.WorkerDataService; +import se.su.dsv.scipro.workerthreads.WorkerTransactionManager; import java.util.*; @@ -47,22 +44,16 @@ public class GradingCompletedMilestoneActivatorTest { @Mock private EventBus eventBus; @Mock - private UnitOfWork unitOfWork; - @Mock - private EntityManager entityManager; - @Mock - private EntityTransaction entityTransaction; + private WorkerTransactionManager workerTransactionManager; @Mock private WorkerDataService workerDataService; @BeforeEach public void setup() { gradingCompletedMilestoneActivator = new GradingCompletedMilestoneActivator(projectService, daisyAPI, eventBus, userService); - gradingCompletedMilestoneActivator.setUnitOfWork(unitOfWork); - gradingCompletedMilestoneActivator.setTxManager(Providers.of(entityManager)); + gradingCompletedMilestoneActivator.setTxManager(workerTransactionManager); gradingCompletedMilestoneActivator.setWorkerDataService(workerDataService); when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData()); - when(entityManager.getTransaction()).thenReturn(entityTransaction); project.setId(3493L); project.setIdentifier(234); diff --git a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java index f4165842bb..dfd523ad4f 100644 --- a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java +++ b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java @@ -1,10 +1,6 @@ package se.su.dsv.scipro.integration.daisy.workers; -import com.google.inject.persist.UnitOfWork; -import com.google.inject.util.Providers; import com.querydsl.core.types.Predicate; -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityTransaction; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,6 +22,7 @@ import se.su.dsv.scipro.system.Unit; import se.su.dsv.scipro.system.User; import se.su.dsv.scipro.workerthreads.WorkerData; import se.su.dsv.scipro.workerthreads.WorkerDataService; +import se.su.dsv.scipro.workerthreads.WorkerTransactionManager; import java.time.LocalDate; import java.util.*; @@ -45,10 +42,8 @@ public class ProjectExporterTest { private @Mock ExporterFacade exporterFacade; private @Mock DaisyAPI daisyAPI; private @Mock ExternalExporter externalExporter; - private @Mock EntityManager entityManager; - private @Mock EntityTransaction entityTransaction; + private @Mock WorkerTransactionManager workerTransactionManager; private @Mock WorkerDataService workerDataService; - private @Mock UnitOfWork unitOfWork; private @Mock FinalSeminarService finalSeminarService; private @Mock FinalThesisService finalThesisService; @@ -61,11 +56,9 @@ public class ProjectExporterTest { @BeforeEach public void setUp() { projectExporter = new ProjectExporter(projectRepo, exporterFacade, daisyAPI, externalExporter, finalSeminarService, finalThesisService); - projectExporter.setTxManager(Providers.of(entityManager)); + projectExporter.setTxManager(workerTransactionManager); projectExporter.setWorkerDataService(workerDataService); - projectExporter.setUnitOfWork(unitOfWork); when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData()); - when(entityManager.getTransaction()).thenReturn(entityTransaction); Unit unit = new Unit(); unit.setIdentifier(239478); diff --git a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java index 576409136a..048d2165e7 100644 --- a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java +++ b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java @@ -1,7 +1,5 @@ package se.su.dsv.scipro.integration.daisy.workers; -import com.google.inject.persist.UnitOfWork; -import com.google.inject.util.Providers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,8 +16,8 @@ import se.su.dsv.scipro.project.QProject; import se.su.dsv.scipro.workerthreads.WorkerData; import se.su.dsv.scipro.workerthreads.WorkerDataService; -import jakarta.persistence.EntityManager; -import jakarta.persistence.EntityTransaction; +import se.su.dsv.scipro.workerthreads.WorkerTransactionManager; + import java.util.Collections; import java.util.List; import java.util.Optional; @@ -38,9 +36,7 @@ public class ProjectFinalizerTest { private @Mock DaisyAPI daisyAPI; private @Mock ProjectService projectService; - private @Mock UnitOfWork unitOfWork; - private @Mock EntityManager entityManager; - private @Mock EntityTransaction entityTransaction; + private @Mock WorkerTransactionManager workerTransactionManager; private @Mock WorkerDataService workerDataService; private @Mock ThesisApprovedHistoryService thesisApprovedHistoryService; @@ -48,11 +44,9 @@ public class ProjectFinalizerTest { @BeforeEach public void setup() { projectFinalizer = new ProjectFinalizer(projectService, daisyAPI, thesisApprovedHistoryService); - projectFinalizer.setUnitOfWork(unitOfWork); - projectFinalizer.setTxManager(Providers.of(entityManager)); + projectFinalizer.setTxManager(workerTransactionManager); projectFinalizer.setWorkerDataService(workerDataService); when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData()); - when(entityManager.getTransaction()).thenReturn(entityTransaction); project.setId(3493L); project.setIdentifier(234); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..637455a39e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +services: + oauth2: + container_name: scipro-dev-oauth2 + build: + context: https://github.com/dsv-su/toker.git + dockerfile: embedded.Dockerfile + restart: on-failure + ports: + - '59733:8080' + environment: + - CLIENT_ID=get-token + - CLIENT_SECRET=get-token-secret + - CLIENT_REDIRECT_URI=http://localhost:59732/ + - RESOURCE_SERVER_ID=scipro-api-client + - RESOURCE_SERVER_SECRET=scipro-api-secret diff --git a/pom.xml b/pom.xml index d222069a72..c96cb4a122 100755 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,8 @@ <module>core</module> <module>view</module> <module>daisy-integration</module> + <module>war</module> + <module>api</module> </modules> <properties> @@ -36,7 +38,6 @@ <mockito.version>5.3.1</mockito.version> <flyway.version>9.19.1</flyway.version> <jersey.version>3.1.6</jersey.version> - <guice.version>7.0.0</guice.version> <poi.version>5.2.5</poi.version> <jackson.version>2.17.0</jackson.version> @@ -88,9 +89,22 @@ </dependency> <dependency> <groupId>org.apache.wicket</groupId> - <artifactId>wicket-guice</artifactId> + <artifactId>wicket-ioc</artifactId> <version>${wicket.version}</version> </dependency> + <dependency> + <groupId>org.apache.wicket</groupId> + <artifactId>wicket-spring</artifactId> + <version>${wicket.version}</version> + </dependency> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <version>3.2.5</version> + <scope>import</scope> + <type>pom</type> + </dependency> <!-- Servlet API, needed for compilation. --> <dependency> @@ -189,13 +203,6 @@ <artifactId>guava</artifactId> <version>32.0.1-jre</version> </dependency> - <dependency> - <groupId>com.google.inject</groupId> - <artifactId>guice-bom</artifactId> - <version>${guice.version}</version> - <type>pom</type> - <scope>import</scope> - </dependency> <dependency> <groupId>jakarta.mail</groupId> @@ -260,6 +267,11 @@ <artifactId>flyway-mysql</artifactId> <version>${flyway.version}</version> </dependency> + <dependency> + <groupId>org.springdoc</groupId> + <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> + <version>2.5.0</version> + </dependency> </dependencies> </dependencyManagement> diff --git a/view/pom.xml b/view/pom.xml index c359d76206..9cdd26f28b 100644 --- a/view/pom.xml +++ b/view/pom.xml @@ -13,15 +13,6 @@ <packaging>war</packaging> <dependencies> - <dependency> - <groupId>com.google.inject.extensions</groupId> - <artifactId>guice-servlet</artifactId> - </dependency> - <dependency> - <groupId>com.google.inject.extensions</groupId> - <artifactId>guice-persist</artifactId> - </dependency> - <dependency> <groupId>se.su.dsv.scipro</groupId> <artifactId>core</artifactId> @@ -44,7 +35,7 @@ </dependency> <dependency> <groupId>org.apache.wicket</groupId> - <artifactId>wicket-guice</artifactId> + <artifactId>wicket-ioc</artifactId> </dependency> <dependency> <groupId>org.apache.wicket</groupId> @@ -55,6 +46,11 @@ <artifactId>wicket-tester</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.wicket</groupId> + <artifactId>wicket-spring</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.wicketstuff</groupId> <artifactId>wicketstuff-jasperreports</artifactId> @@ -144,6 +140,15 @@ </dependencies> <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <configuration> + <attachClasses>true</attachClasses> + </configuration> + </plugin> + </plugins> <resources> <resource> <filtering>true</filtering> diff --git a/view/src/main/java/ApplicationBootstrap.java b/view/src/main/java/ApplicationBootstrap.java deleted file mode 100644 index d5631e6f1c..0000000000 --- a/view/src/main/java/ApplicationBootstrap.java +++ /dev/null @@ -1,68 +0,0 @@ -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.Module; -import com.google.inject.name.Names; -import com.google.inject.persist.PersistFilter; -import com.google.inject.servlet.GuiceServletContextListener; -import com.google.inject.servlet.ServletModule; -import org.apache.wicket.guice.GuiceWebApplicationFactory; -import org.apache.wicket.protocol.http.WicketFilter; - -import jakarta.servlet.ServletContext; -import java.net.CookieHandler; -import java.net.CookieManager; -import java.time.Clock; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.ServiceLoader; - -public class ApplicationBootstrap extends GuiceServletContextListener { - @Override - protected Injector getInjector() { - // preserve cookies when using Jersey which will use the logged in session cookie from - // Daisy API thus drastically speeding up the batch jobs - CookieHandler.setDefault(new CookieManager()); - return Guice.createInjector( - new ServletModule() { - @Override - protected void configureServlets() { - final ServletContext servletContext = getServletContext(); - final Enumeration<String> initParameterNames = servletContext.getInitParameterNames(); - while (initParameterNames.hasMoreElements()) { - final String parameterName = initParameterNames.nextElement(); - final String value = servletContext.getInitParameter(parameterName); - bindConstant().annotatedWith(Names.named(parameterName)).to(value); - } - } - }, - new ServletModule() { - @Override - protected void configureServlets() { - filter("/*").through(PersistFilter.class); - } - }, - new AbstractModule() { - @Override - protected void configure() { - bind(Clock.class).toInstance(Clock.systemDefaultZone()); - ServiceLoader<Module> modules = ServiceLoader.load(Module.class); - for (Module module : modules) { - install(module); - } - } - }, - new ServletModule() { - @Override - protected void configureServlets() { - Map<String,String> params = new HashMap<>(); - params.put(WicketFilter.FILTER_MAPPING_PARAM, "/*"); - params.put(WicketFilter.APP_FACT_PARAM, GuiceWebApplicationFactory.class.getName()); - params.put("injectorContextAttribute", Injector.class.getName()); - filter("/*").through(new WicketFilter(), params); - } - } - ); - } -} diff --git a/view/src/main/java/DatabaseMigration.java b/view/src/main/java/DatabaseMigration.java deleted file mode 100644 index 442e3003e4..0000000000 --- a/view/src/main/java/DatabaseMigration.java +++ /dev/null @@ -1,35 +0,0 @@ -import org.flywaydb.core.Flyway; - -import javax.naming.InitialContext; -import javax.naming.NamingException; -import jakarta.servlet.ServletContextEvent; -import jakarta.servlet.ServletContextListener; -import javax.sql.DataSource; - -public class DatabaseMigration implements ServletContextListener { - @Override - public void contextInitialized(ServletContextEvent sce) { - migrateDatabase(); - } - - private void migrateDatabase() { - Flyway flyway = Flyway.configure() - .dataSource(getDataSource()) - .baselineOnMigrate(true) - .table("schema_version") - .load(); - flyway.migrate(); - } - - private DataSource getDataSource() { - try { - return InitialContext.doLookup("java:comp/env/jdbc/sciproDS"); - } catch (NamingException e) { - throw new RuntimeException(e); - } - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - } -} diff --git a/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java b/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java index 7e80019776..3d0eafc255 100644 --- a/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java +++ b/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java @@ -12,7 +12,7 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; -class FileSystemStore implements FileStore { +public class FileSystemStore implements FileStore { private static final int FILES_PER_SUBDIRECTORY = 1000; private static final String FILE_ROOT = "/scipro-files"; diff --git a/view/src/main/java/se/su/dsv/scipro/SciProApplication.java b/view/src/main/java/se/su/dsv/scipro/SciProApplication.java index ebbc21afa8..521595f7c3 100755 --- a/view/src/main/java/se/su/dsv/scipro/SciProApplication.java +++ b/view/src/main/java/se/su/dsv/scipro/SciProApplication.java @@ -53,7 +53,6 @@ import se.su.dsv.scipro.milestones.pages.SupervisorMileStonePage; import se.su.dsv.scipro.nonworkdays.NonWorkDaysPage; import se.su.dsv.scipro.notes.NotesPage; import se.su.dsv.scipro.notifications.NotificationLoader; -import se.su.dsv.scipro.notifications.NotificationModule; import se.su.dsv.scipro.notifications.pages.NotificationLandingPage; import se.su.dsv.scipro.notifications.pages.NotificationsPage; import se.su.dsv.scipro.notifications.pages.SupervisorNotificationSettingsPage; @@ -347,7 +346,7 @@ public class SciProApplication extends LifecycleManagedWebApplication { private void mountNotificationAndSettingsPages() { mountPage("notes", NotesPage.class); - mountPage(NotificationModule.NOTIFICATION_RELATIVE_PAGE_URL, NotificationLandingPage.class); + mountPage("notification", NotificationLandingPage.class); mountPage("notifications", NotificationsPage.class); mountPage("settings", BasicProfilePage.class); mountPage("settings/supervisorprofile", SupervisorProfilePage.class); diff --git a/view/src/main/java/se/su/dsv/scipro/SciProModule.java b/view/src/main/java/se/su/dsv/scipro/SciProModule.java deleted file mode 100644 index 26e7f0a6ba..0000000000 --- a/view/src/main/java/se/su/dsv/scipro/SciProModule.java +++ /dev/null @@ -1,33 +0,0 @@ -package se.su.dsv.scipro; - -import com.google.inject.Singleton; -import com.google.inject.multibindings.Multibinder; -import com.google.inject.persist.jpa.JpaPersistModule; -import com.google.inject.servlet.ServletModule; -import com.google.inject.servlet.SessionScoped; -import modules.CoreModule; -import org.apache.wicket.protocol.http.WebApplication; -import se.su.dsv.scipro.file.FileModule; -import se.su.dsv.scipro.file.FileStore; -import se.su.dsv.scipro.security.auth.AuthenticationModule; -import se.su.dsv.scipro.system.CurrentUser; -import se.su.dsv.scipro.system.Lifecycle; -import se.su.dsv.scipro.workerthreads.WorkerModule; - -public class SciProModule extends ServletModule { - @Override - protected void configureServlets() { - install(new JpaPersistModule("defaultPersistenceUnit")); - install(new CoreModule()); - install(new FileModule()); - bind(FileStore.class).to(FileSystemStore.class); - install(new WorkerModule()); - install(new AuthenticationModule()); - - bind(WebApplication.class).to(SciProApplication.class).in(Singleton.class); - - bind(CurrentUser.class).to(CurrentUserFromWicketSession.class).in(SessionScoped.class); - Multibinder<Lifecycle> lifecycles = Multibinder.newSetBinder(binder(), Lifecycle.class); - lifecycles.addBinding().to(DataInitializer.class); - } -} diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java index 5b1e8d22fe..0b3b45f8ae 100644 --- a/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.admin.pages; -import com.google.inject.Inject; +import jakarta.inject.Inject; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.link.Link; diff --git a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java index 48e268a040..eb36d66e9e 100644 --- a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.admin.panels; -import com.google.inject.persist.Transactional; +import jakarta.transaction.Transactional; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.RequiredTextField; import org.apache.wicket.markup.html.panel.Panel; diff --git a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java index ad084a3436..8284ab8966 100755 --- a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java +++ b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java @@ -54,16 +54,16 @@ public class AdminProjectTypePanel extends Panel { NumberTextField<Integer> minimumOppositionsToBeGraded = new NumberTextField<>( "minimum_oppositions_to_be_graded", LambdaModel.of(settings, - ProjectTypeSettings::getMinimumOppositionsToBeGraded, - ProjectTypeSettings::setMinimumOppositionsToBeGraded), + ProjectTypeSettings::getMinOppositionsToBeGraded, + ProjectTypeSettings::setMinOppositionsToBeGraded), Integer.class); minimumOppositionsToBeGraded.setMinimum(0); add(minimumOppositionsToBeGraded); NumberTextField<Integer> minimumActiveParticipationsToBeGraded = new NumberTextField<>( "minimum_active_participations_to_be_graded", LambdaModel.of(settings, - ProjectTypeSettings::getMinimumActiveParticipationsToBeGraded, - ProjectTypeSettings::setMinimumActiveParticipationsToBeGraded), + ProjectTypeSettings::getMinActiveParticipationsToBeGraded, + ProjectTypeSettings::setMinActiveParticipationsToBeGraded), Integer.class); minimumActiveParticipationsToBeGraded.setMinimum(0); add(minimumActiveParticipationsToBeGraded); diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java b/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java index 5e54b3e4a9..a300022d1b 100644 --- a/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java @@ -27,7 +27,7 @@ public abstract class AnswerPanel extends Panel { ANSWER_IMAGES.put(ChecklistAnswerEnum.GREEN, "images/icons/bullet_ball_glass_green.png"); ANSWER_IMAGES.put(ChecklistAnswerEnum.YELLOW, "images/icons/bullet_ball_glass_yellow.png"); ANSWER_IMAGES.put(ChecklistAnswerEnum.RED, "images/icons/bullet_ball_glass_red.png"); - ANSWER_IMAGES.put(ChecklistAnswerEnum.NOT_APLICABLE, "images/icons/bullet_ball_glass_grey.png"); + ANSWER_IMAGES.put(ChecklistAnswerEnum.NOT_APPLICABLE, "images/icons/bullet_ball_glass_grey.png"); } public static final String CLICK_ICON = "images/icons/bullet_ball_glass_click.png"; diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java index 1af096eee2..250d82e7e7 100644 --- a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java @@ -55,7 +55,7 @@ public class ChecklistOverviewPanel extends GenericPanel<Project> { ChecklistAnswerEnum.GREEN, ChecklistAnswerEnum.YELLOW, ChecklistAnswerEnum.RED, - ChecklistAnswerEnum.NOT_APLICABLE); + ChecklistAnswerEnum.NOT_APPLICABLE); add(new ListView<>("answersBreakdown", answers) { @Override protected void populateItem(ListItem<ChecklistAnswerEnum> item) { diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties index 9ad8928894..0d30f3ea89 100644 --- a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties +++ b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties @@ -1,4 +1,4 @@ ChecklistAnswerEnum.GREEN = Ok ChecklistAnswerEnum.YELLOW = Minor corrections ChecklistAnswerEnum.RED = Not done -ChecklistAnswerEnum.NOT_APLICABLE = Not applicable +ChecklistAnswerEnum.NOT_APPLICABLE = Not applicable diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java b/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java index 51e779ba99..60482c38a8 100644 --- a/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java @@ -54,7 +54,7 @@ public class TrafficLightPanel extends FormComponentPanel<ChecklistAnswerEnum> { greenLink = new TrafficLightLink("greenLink", ChecklistAnswerEnum.GREEN, selectedGreen, greenImage); redLink = new TrafficLightLink("redLink", ChecklistAnswerEnum.RED, selectedRed, redImage); yellowLink = new TrafficLightLink("yellowLink", ChecklistAnswerEnum.YELLOW, selectedYellow, yellowImage); - noAnswerLink = new TrafficLightLink("noAnswerLink", ChecklistAnswerEnum.NOT_APLICABLE, selectedNotApplicable, noAnswerImage); + noAnswerLink = new TrafficLightLink("noAnswerLink", ChecklistAnswerEnum.NOT_APPLICABLE, selectedNotApplicable, noAnswerImage); add(greenLink); add(yellowLink); add(redLink); diff --git a/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java b/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java deleted file mode 100644 index fc50e7ff37..0000000000 --- a/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java +++ /dev/null @@ -1,17 +0,0 @@ -package se.su.dsv.scipro.crosscutting; - -import com.google.common.eventbus.EventBus; -import com.google.inject.AbstractModule; -import se.su.dsv.scipro.reviewing.ReviewerAssignedDeadline; - -public class CrosscuttingModule extends AbstractModule { - @Override - protected void configure() { - requireBinding(EventBus.class); - bind(ReviewingNotifications.class).asEagerSingleton(); - bind(ReviewerSupportMailer.class).asEagerSingleton(); - bind(ReviewerAssignedNotifications.class).asEagerSingleton(); - bind(ReviewerAssignedDeadline.class).asEagerSingleton(); - bind(ForwardPhase2Feedback.class).asEagerSingleton(); - } -} diff --git a/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java b/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java new file mode 100644 index 0000000000..867703dde2 --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java @@ -0,0 +1,46 @@ +package se.su.dsv.scipro.crosscutting; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; +import jakarta.inject.Inject; +import se.su.dsv.scipro.data.dataobjects.Member; +import se.su.dsv.scipro.notifications.NotificationController; +import se.su.dsv.scipro.notifications.dataobject.NotificationSource; +import se.su.dsv.scipro.notifications.dataobject.ProjectEvent; +import se.su.dsv.scipro.reflection.ReflectionImprovementsRequestedEvent; +import se.su.dsv.scipro.reflection.ReflectionImprovementsSubmittedEvent; + +import java.util.Set; + +public class NotifyFailedReflection { + private final NotificationController notificationController; + + @Inject + public NotifyFailedReflection(NotificationController notificationController, EventBus eventBus) { + this.notificationController = notificationController; + eventBus.register(this); + } + + @Subscribe + public void reflectionImprovementsRequested(ReflectionImprovementsRequestedEvent event) { + NotificationSource source = new NotificationSource(); + source.setMessage(event.supervisorComment()); + notificationController.notifyCustomProject( + event.project(), + ProjectEvent.Event.REFLECTION_IMPROVEMENTS_REQUESTED, + source, + Set.of(new Member(event.author(), Member.Type.AUTHOR))); + } + + @Subscribe + public void reflectionImprovementsSubmittted(ReflectionImprovementsSubmittedEvent event) { + NotificationSource source = new NotificationSource(); + source.setMessage(event.reflection()); + source.setAdditionalMessage(event.author().getFullName()); + notificationController.notifyCustomProject( + event.project(), + ProjectEvent.Event.REFLECTION_IMPROVEMENTS_SUBMITTED, + source, + Set.of(new Member(event.project().getHeadSupervisor(), Member.Type.SUPERVISOR))); + } +} diff --git a/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java b/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java index 158b6ec5d9..40bb5744a8 100644 --- a/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java @@ -36,7 +36,7 @@ public class ProjectActiveParticipationListPanel extends GenericPanel<Project> { IModel<Integer> countRequired = model .map(Project::getProjectType) .map(ProjectType::getProjectTypeSettings) - .map(ProjectTypeSettings::getMinimumActiveParticipationsToBeGraded); + .map(ProjectTypeSettings::getMinActiveParticipationsToBeGraded); item.add(new Label("count_required", countRequired)); IModel<Long> countPerformed = participations.map(this::countApproved); item.add(new Label("count_approved", countPerformed)); diff --git a/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java index fbf8b36a5f..f24d065eb0 100644 --- a/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java @@ -213,8 +213,8 @@ abstract class AbstractExaminationsPanel extends GenericPanel<User> { .filter(FinalSeminarActiveParticipation::isApproved) .count(); final ProjectTypeSettings projectTypeSettings = project.getProjectType().getProjectTypeSettings(); - final int requiredOppositions = projectTypeSettings.getMinimumOppositionsToBeGraded(); - final int requiredActiveParticipations = projectTypeSettings.getMinimumActiveParticipationsToBeGraded(); + final int requiredOppositions = projectTypeSettings.getMinOppositionsToBeGraded(); + final int requiredActiveParticipations = projectTypeSettings.getMinActiveParticipationsToBeGraded(); return new SeminarParticipationGradingRequirements( new Requirement(requiredOppositions, completedOppositions), new Requirement(requiredActiveParticipations, completedParticipations)); diff --git a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html index 079fb7b067..8794749252 100644 --- a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html +++ b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html @@ -49,10 +49,16 @@ </div> </wicket:fragment> </div> - <wicket:container wicket:id="reflection"> + <div wicket:id="reflection"> + <wicket:enclosure> + <div class="alert alert-danger"> + <h4 class="alert-heading">Improvements requested</h4> + <wicket:container wicket:id="improvementsNeeded"/> + </div> + </wicket:enclosure> <a wicket:id="showReflection" href="#">View reflection</a> <div wicket:id="modal"></div> - </wicket:container> + </div> </fieldset> </wicket:panel> </body> diff --git a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java index e5475c42ed..011cb74f9f 100644 --- a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java @@ -30,10 +30,12 @@ import se.su.dsv.scipro.finalseminar.FinalSeminar; import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition; import se.su.dsv.scipro.finalseminar.FinalSeminarService; import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.reflection.Reflection; import se.su.dsv.scipro.reflection.ReflectionService; import se.su.dsv.scipro.report.AbstractGradingCriterion; import se.su.dsv.scipro.report.GradingCriterion; import se.su.dsv.scipro.report.GradingCriterionPoint; +import se.su.dsv.scipro.report.GradingReport; import se.su.dsv.scipro.report.SupervisorGradingReport; import se.su.dsv.scipro.system.Language; import se.su.dsv.scipro.system.User; @@ -264,14 +266,33 @@ public class CriteriaPanel extends GenericPanel<SupervisorGradingReport> { super(id, author); this.gradingCriterion = gradingCriterion; - IModel<String> reflection = LoadableDetachableModel.of(() -> { + IModel<Reflection> reflection = LoadableDetachableModel.of(() -> { Project project = CriteriaPanel.this.getModelObject().getProject(); - return reflectionService.getSubmittedReflection(project, author.getObject()); + return reflectionService.getReflection(project, author.getObject()); + }); + IModel<String> improvementsNeeded = reflection + .as(Reflection.ImprovementsNeeded.class) + .map(Reflection.ImprovementsNeeded::commentBySupervisor); + + add(new MultiLineLabel("improvementsNeeded", improvementsNeeded) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(!getDefaultModelObjectAsString().isBlank()); + } }); modal = new LargeModalWindow("modal"); modal.setTitle("Reflection"); - modal.setContent(id_ -> new MultiLineLabel(id_, new NullReplacementModel(reflection, "No reflection filled in."))); + modal.setContent(modalBodyId -> { + IModel<Project> projectModel = CriteriaPanel.this.getModel().map(GradingReport::getProject); + return new ReflectionModalBodyPanel(modalBodyId, projectModel, author); + }); + this.setOutputMarkupId(true); + this.setOutputMarkupPlaceholderTag(true); + modal.onClose(target -> { + target.add(ReflectionFeedbackPanel.this); + }); add(modal); WebMarkupContainer showReflection = new WebMarkupContainer("showReflection") { diff --git a/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java index d76881782b..6dff147635 100644 --- a/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java @@ -128,7 +128,7 @@ public class IndividualAuthorAssessmentPanel extends GenericPanel<User> { IModel<Integer> minimumActiveParticipationsToBeGraded = LoadableDetachableModel.of(() -> { Project project = projectModel.getObject(); - return project.getProjectType().getProjectTypeSettings().getMinimumActiveParticipationsToBeGraded(); + return project.getProjectType().getProjectTypeSettings().getMinActiveParticipationsToBeGraded(); }); IModel<Integer> completedParticipations = LoadableDetachableModel.of(() -> { Project project = projectModel.getObject(); diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html new file mode 100644 index 0000000000..7840492505 --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org"> +<body> +<wicket:panel> + <wicket:enclosure> + <div class="alert alert-info"> + <h4 class="alert-heading"> + <wicket:message key="improvements_requested"> + You've requested improvements to the submitted version. + </wicket:message> + </h4> + <wicket:container wicket:id="improvements_needed_supervisor_feedback"> + [Supervisor feedback on needed improvements] + </wicket:container> + </div> + </wicket:enclosure> + + <wicket:container wicket:id="reflection_text"> + [Authors submitted reflection] + </wicket:container> + + <button class="btn btn-outline-secondary" wicket:id="show_edit_reflection_form"> + <wicket:message key="edit_reflection"> + Edit reflection + </wicket:message> + </button> + <button class="btn btn-outline-secondary" wicket:id="show_request_improvements_form"> + <wicket:message key="request_improvements"> + Request improvements + </wicket:message> + </button> + + <form wicket:id="request_improvements_form"> + <hr> + <p> + <wicket:message key="request_improvements_text"> + Please provide feedback on what improvements are needed in the submitted version. + </wicket:message> + </p> + <div class="mb-3"> + <label class="form-label" wicket:for="comment"> + <wicket:message key="comment"> + Comment + </wicket:message> + </label> + <textarea class="form-control" wicket:id="comment" rows="5"></textarea> + </div> + <button class="btn btn-primary" wicket:id="submit"> + <wicket:message key="request_improvements"> + Request improvements + </wicket:message> + </button> + <button class="btn btn-link" wicket:id="cancel"> + <wicket:message key="cancel"> + Cancel + </wicket:message> + </button> + </form> + + <form wicket:id="edit_reflection_form"> + <div class="mb-3"> + <label class="form-label"> + <wicket:message key="reflection"> + Reflection + </wicket:message> + </label> + <textarea class="form-control" wicket:id="reflection" rows="10"></textarea> + </div> + <button class="btn btn-primary" wicket:id="submit"> + <wicket:message key="save"> + Save + </wicket:message> + </button> + <button class="btn btn-link" wicket:id="cancel"> + <wicket:message key="cancel"> + Cancel + </wicket:message> + </button> + </form> +</wicket:panel> +</body> +</html> \ No newline at end of file diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java new file mode 100644 index 0000000000..895e65018f --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java @@ -0,0 +1,191 @@ +package se.su.dsv.scipro.grading; + +import jakarta.inject.Inject; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; +import org.apache.wicket.markup.html.basic.MultiLineLabel; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.reflection.Reflection; +import se.su.dsv.scipro.reflection.ReflectionService; +import se.su.dsv.scipro.system.User; + +/** + * This is not meant to be a re-usable panel and is made specifically to be used + * as the body of the modal dialog that opens when a supervisor views the + * author's reflection as they're doing their final individual assessment. + */ +class ReflectionModalBodyPanel extends Panel { + @Inject + private ReflectionService reflectionService; + + private final IModel<Project> projectModel; + private final IModel<User> authorModel; + + private enum State { VIEWING, REQUESTING_IMPROVEMENTS, EDITING } + + private State state = State.VIEWING; + + ReflectionModalBodyPanel(String id, IModel<Project> projectModel, IModel<User> authorModel) { + super(id); + this.projectModel = projectModel; + this.authorModel = authorModel; + + setOutputMarkupPlaceholderTag(true); // enable ajax refreshing of the entire body + + IModel<Reflection> reflectionModel = projectModel.combineWith(authorModel, reflectionService::getReflection); + + add(new MultiLineLabel("reflection_text", reflectionModel.map(this::getReflectionText)) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(state != State.EDITING); + } + }); + + add(new MultiLineLabel("improvements_needed_supervisor_feedback", reflectionModel + .as(Reflection.ImprovementsNeeded.class) + .map(Reflection.ImprovementsNeeded::commentBySupervisor)) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(!getDefaultModelObjectAsString().isBlank()); + } + }); + + add(new RequestImprovementsForm("request_improvements_form", reflectionModel)); + add(new SupervisorEditReflectionForm("edit_reflection_form", reflectionModel)); + + add(new AjaxLink<>("show_request_improvements_form", reflectionModel) { + @Override + public void onClick(AjaxRequestTarget target) { + ReflectionModalBodyPanel.this.state = State.REQUESTING_IMPROVEMENTS; + target.add(ReflectionModalBodyPanel.this); + } + + @Override + protected void onConfigure() { + super.onConfigure(); + Reflection reflection = getModelObject(); + boolean canRequestImprovements = reflection instanceof Reflection.Submitted; + setVisible(state == State.VIEWING && canRequestImprovements && isEnabledInHierarchy()); + } + }); + + add(new AjaxLink<>("show_edit_reflection_form", reflectionModel) { + @Override + public void onClick(AjaxRequestTarget target) { + ReflectionModalBodyPanel.this.state = State.EDITING; + target.add(ReflectionModalBodyPanel.this); + } + + @Override + protected void onConfigure() { + super.onConfigure(); + Reflection reflection = getModelObject(); + boolean canEditReflection = reflection instanceof Reflection.Submitted || reflection instanceof Reflection.ImprovementsNeeded; + setVisible(state == State.VIEWING && canEditReflection && isEnabledInHierarchy()); + } + }); + } + + private String getReflectionText(Reflection reflection) { + if (reflection instanceof Reflection.Submitted submitted) { + return submitted.reflection(); + } else if (reflection instanceof Reflection.ImprovementsNeeded improvementsNeeded) { + return improvementsNeeded.oldReflection(); + } else { + return getString("reflection_not_submitted"); + } + } + + @Override + protected void onDetach() { + this.projectModel.detach(); + this.authorModel.detach(); + super.onDetach(); + } + + private class RequestImprovementsForm extends Form<Reflection> { + public RequestImprovementsForm(String id, IModel<Reflection> reflectionModel) { + super(id, reflectionModel); + + IModel<String> commentModel = new Model<>(); + + TextArea<String> comment = new TextArea<>("comment", commentModel); + comment.setRequired(true); + add(comment); + + add(new AjaxSubmitLink("submit") { + @Override + protected void onSubmit(AjaxRequestTarget target) { + super.onSubmit(target); + + reflectionService.requestNewReflection( + projectModel.getObject(), + authorModel.getObject(), + commentModel.getObject()); + + ReflectionModalBodyPanel.this.state = State.VIEWING; + target.add(ReflectionModalBodyPanel.this); + } + }); + add(new AjaxLink<>("cancel") { + @Override + public void onClick(AjaxRequestTarget target) { + ReflectionModalBodyPanel.this.state = State.VIEWING; + target.add(ReflectionModalBodyPanel.this); + } + }); + } + + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(state == State.REQUESTING_IMPROVEMENTS && getModelObject() instanceof Reflection.Submitted); + } + } + + private class SupervisorEditReflectionForm extends Form<Reflection> { + public SupervisorEditReflectionForm(String id, IModel<Reflection> reflectionModel) { + super(id, reflectionModel); + + IModel<String> reflectionTextModel = new Model<>(getReflectionText(reflectionModel.getObject())); + + TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionTextModel); + reflectionTextArea.setRequired(true); + add(reflectionTextArea); + + add(new AjaxSubmitLink("submit") { + @Override + protected void onSubmit(AjaxRequestTarget target) { + reflectionService.submitReflection( + projectModel.getObject(), + authorModel.getObject(), + reflectionTextModel.getObject()); + + ReflectionModalBodyPanel.this.state = State.VIEWING; + target.add(ReflectionModalBodyPanel.this); + } + }); + add(new AjaxLink<>("cancel") { + @Override + public void onClick(AjaxRequestTarget target) { + ReflectionModalBodyPanel.this.state = State.VIEWING; + target.add(ReflectionModalBodyPanel.this); + } + }); + } + + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(state == State.EDITING); + } + } +} diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties new file mode 100644 index 0000000000..cf818f1e92 --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties @@ -0,0 +1,10 @@ +improvements_requested=You've requested improvements to the submitted version. +request_improvements=Request improvements +comment=Comment +reflection_not_submitted=Reflection not submitted yet +request_improvements_text=If the submitted reflection does not meet the minimum requirements \ + you can request improvements from the student. The student will be notified and can submit a new reflection. \ + Use the comment field to provide feedback to the student. +edit_reflection=Edit reflection +reflection=Reflection +cancel=Cancel diff --git a/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java b/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java index da362486f4..51f921ae60 100644 --- a/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java +++ b/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.match; -import com.google.inject.Inject; +import jakarta.inject.Inject; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.util.string.StringValue; import se.su.dsv.scipro.components.menuhighlighting.MenuHighlightSupervisorMyIdeas; diff --git a/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java b/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java index b3b73a4bec..0fc12af49a 100644 --- a/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java +++ b/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java @@ -158,7 +158,7 @@ public class NotificationLandingPage extends WebPage { setResponsePage(RoughDraftApprovalDecisionPage.class, reviewerParameters); } break; - case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED: + case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED, REFLECTION_IMPROVEMENTS_SUBMITTED: if (project.isSupervisor(currentUser)) { setResponsePage(SupervisorGradingReportPage.class, pp); } diff --git a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java index 2c6818bb3e..7679a75eba 100644 --- a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java @@ -38,7 +38,7 @@ public class DisplayQuestionPanel extends GenericPanel<Answer> { return "images/icons/bullet_ball_glass_red.png"; case GREEN: return "images/icons/bullet_ball_glass_green.png"; - case NOT_APLICABLE: + case NOT_APPLICABLE: return "images/icons/bullet_ball_glass_grey.png"; default: throw new IllegalStateException("unknown answer"); diff --git a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties index 83808b9c7e..a2d4ad4158 100644 --- a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties +++ b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties @@ -2,4 +2,4 @@ no.motivation= No motivation written YELLOW= Minor corrections RED= Not done GREEN= Ok -NOT_APLICABLE= Not applicable \ No newline at end of file +NOT_APPLICABLE= Not applicable \ No newline at end of file diff --git a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java index 5cca6a2310..144dd24f30 100644 --- a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.peer; -import com.google.inject.Inject; +import jakarta.inject.Inject; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; diff --git a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java index 18381874c6..2193555a56 100644 --- a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.peer; -import com.google.inject.Inject; +import jakarta.inject.Inject; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html index a50d6d7828..6cc7d5661d 100644 --- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html +++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html @@ -38,6 +38,30 @@ <div wicket:id="current_thesis_file"></div> </div> </wicket:enclosure> + <wicket:enclosure child="old_reflection"> + <div class="alert alert-info"> + <h4 class="alert-heading"> + <wicket:message key="reflection_improvements_needed_heading"> + Reflection improvements needed + </wicket:message> + </h4> + <p> + <wicket:message key="reflection_improvements_needed"> + Your supervisor has requested that you improve and resubmit your reflection. + See their comments below about what changes are necessary. + </wicket:message> + </p> + <p wicket:id="supervisor_comment"> + [You need to reflect more on the methods you used.] + </p> + </div> + <h4> + <wicket:message key="old_reflection"> + Your previous reflection + </wicket:message> + </h4> + <p wicket:id="old_reflection"></p> + </wicket:enclosure> <div class="mb-3"> <label class="form-label" wicket:for="reflection"> <wicket:message key="reflection">[Reflection]</wicket:message> diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java index 0283f15c13..95d9fb319a 100644 --- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java @@ -24,6 +24,7 @@ import se.su.dsv.scipro.grading.PublicationMetadata; import se.su.dsv.scipro.grading.PublicationMetadataFormComponentPanel; import se.su.dsv.scipro.grading.PublicationMetadataService; import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.reflection.Reflection; import se.su.dsv.scipro.reflection.ReflectionService; import se.su.dsv.scipro.session.SciProSession; @@ -45,17 +46,20 @@ public class FinalStepsPanel extends GenericPanel<Project> { add(new FencedFeedbackPanel("feedback", this)); - IModel<String> reflection = LoadableDetachableModel.of(() -> - reflectionService.getSubmittedReflection(projectModel.getObject(), SciProSession.get().getUser())); - add(new MultiLineLabel("reflection", reflection) { + IModel<Reflection> currentReflection = LoadableDetachableModel.of(() -> + reflectionService.getReflection(projectModel.getObject(), SciProSession.get().getUser())); + IModel<String> reflectionText = currentReflection + .as(Reflection.Submitted.class) + .map(Reflection.Submitted::reflection); + add(new MultiLineLabel("reflection", reflectionText) { @Override protected void onConfigure() { super.onConfigure(); - setVisible(getDefaultModelObject() != null); + setVisible(!getDefaultModelObjectAsString().isBlank()); } }); - add(new FinalStepsForm("submit_reflection", projectModel)); + add(new FinalStepsForm("submit_reflection", projectModel, currentReflection)); } @Override @@ -67,22 +71,49 @@ public class FinalStepsPanel extends GenericPanel<Project> { private class FinalStepsForm extends Form<Project> { private final FinalThesisUploadComponent thesisFileUpload; private final IModel<PublicationMetadata> publicationMetadataModel; + private final IModel<Reflection> currentReflection; private IModel<String> reflectionModel; private IModel<PublishingConsentService.Level> levelModel; - public FinalStepsForm(String id, IModel<Project> projectModel) { + public FinalStepsForm(String id, IModel<Project> projectModel, IModel<Reflection> currentReflection) { super(id, projectModel); + this.currentReflection = currentReflection; + + IModel<Reflection.ImprovementsNeeded> improvementsNeeded = this.currentReflection.as(Reflection.ImprovementsNeeded.class); + + IModel<String> oldReflection = improvementsNeeded.map(Reflection.ImprovementsNeeded::oldReflection); + add(new MultiLineLabel("old_reflection", oldReflection) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank()); + } + }); + + add(new MultiLineLabel("supervisor_comment", improvementsNeeded.map(Reflection.ImprovementsNeeded::commentBySupervisor)) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank()); + } + }); reflectionModel = new Model<>(); - TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel); + TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(FinalStepsForm.this.currentReflection.getObject().isSubmittable()); + } + }; reflectionTextArea.setRequired(true); add(reflectionTextArea); IModel<PublishingConsentService.PublishingConsent> publishingConsent = LoadableDetachableModel.of(() -> publishingConsentService.getPublishingConsent(getModelObject(), SciProSession.get().getUser())); - levelModel = new Model<>(); + levelModel = new Model<>(publishingConsent.getObject().selected()); FormComponent<PublishingConsentService.Level> publishingConsentLevel = new BootstrapRadioChoice<>( "publishingConsentLevel", levelModel, @@ -111,7 +142,13 @@ public class FinalStepsPanel extends GenericPanel<Project> { currentThesisFile.add(new OppositeVisibility(thesisFileUpload)); add(currentThesisFile); publicationMetadataModel = LoadableDetachableModel.of(() -> publicationMetadataService.getByProject(getModelObject())); - WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata"); + WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata") { + @Override + protected void onConfigure() { + super.onConfigure(); + setEnabled(finalThesisService.isUploadAllowed(FinalStepsPanel.FinalStepsForm.this.getModelObject())); + } + }; add(publicationMetadata); publicationMetadata.add(new PublicationMetadataFormComponentPanel("publication_metadata_components", publicationMetadataModel)); } @@ -119,7 +156,7 @@ public class FinalStepsPanel extends GenericPanel<Project> { @Override protected void onConfigure() { super.onConfigure(); - setVisibilityAllowed(reflectionService.hasToFillInReflection(getModelObject(), SciProSession.get().getUser())); + setVisibilityAllowed(currentReflection.getObject().isSubmittable()); } @Override @@ -131,6 +168,7 @@ public class FinalStepsPanel extends GenericPanel<Project> { new WicketProjectFileUpload(finalThesisUpload.fileUpload(), FinalStepsPanel.this.getModelObject()), finalThesisUpload.englishTitle(), finalThesisUpload.swedishTitle()); + success(getString("final_thesis_uploaded")); } reflectionService.submitReflection(getModelObject(), SciProSession.get().getUser(), reflectionModel.getObject()); if (levelModel.getObject() != null) { diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties index a0f79eb71a..f21ad3bd37 100644 --- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties +++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties @@ -9,3 +9,8 @@ current_final_thesis=Final thesis publication_metadata_why=Please provide the following metadata. englishTitle=English title swedishTitle=Swedish title +reflection_improvements_needed_heading=Reflection improvements needed +reflection_improvements_needed=Your supervisor has requested that you improve and resubmit your reflection. \ +See their comments below about what changes are necessary. +old_reflection=Your previous reflection +final_thesis_uploaded=Final thesis uploaded diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html index bf546f6a76..13c72afcac 100644 --- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html @@ -6,7 +6,7 @@ <div wicket:id="feedback"></div> <div class="mb-3"> <label wicket:for="note" class="sr-only">Note</label> - <textarea wicket:id="note" rows="20" class="form-control"></textarea> + <textarea wicket:id="note" rows="7" class="form-control"></textarea> </div> <button wicket:id="save" type="submit" class="btn btn-primary">Save</button> </form> diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java index b35962f891..77424cf02a 100644 --- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java @@ -51,11 +51,8 @@ public class ProjectNoteColumn extends AbstractExportableColumn<Project, String> } @Override - public void populateItem( - Item<ICellPopulator<Project>> cellItem, - String componentId, - IModel<Project> rowModel) - { + public void populateItem(Item<ICellPopulator<Project>> cellItem, String componentId, + IModel<Project> rowModel) { cellItem.add(new ViewAndEditNoteCellPanel(componentId, rowModel)); } diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java index 3a39a1088c..32920d25d7 100644 --- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java +++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java @@ -1,6 +1,6 @@ package se.su.dsv.scipro.supervisor.panels; -import com.google.inject.Inject; +import jakarta.inject.Inject; import org.apache.wicket.feedback.FencedFeedbackPanel; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.OnEventHeaderItem; diff --git a/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties b/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties index 74aa56c867..97ea5d57c3 100644 --- a/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties +++ b/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties @@ -65,6 +65,8 @@ ProjectEvent.FIRST_MEETING = First meeting created. (with date, time, place/room ProjectEvent.OPPOSITION_FAILED = An author fails their opposition. ProjectEvent.PARTICIPATION_APPROVED = An author's active participation is approved. ProjectEvent.PARTICIPATION_FAILED = An author fails their active participation. +ProjectEvent.REFLECTION_IMPROVEMENTS_REQUESTED = Reflection improvements requested. +ProjectEvent.REFLECTION_IMPROVEMENTS_SUBMITTED = Reflection improvements submitted. ProjectForumEvent.NEW_FORUM_POST = Forum thread created. ProjectForumEvent.NEW_FORUM_POST_COMMENT = Comment posted in forum thread. diff --git a/view/src/main/resources/META-INF/services/com.google.inject.Module b/view/src/main/resources/META-INF/services/com.google.inject.Module deleted file mode 100644 index c0c493be41..0000000000 --- a/view/src/main/resources/META-INF/services/com.google.inject.Module +++ /dev/null @@ -1,15 +0,0 @@ -se.su.dsv.scipro.SciProModule -se.su.dsv.scipro.reviewing.ReviewingModule -se.su.dsv.scipro.crosscutting.CrosscuttingModule -se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarModule -se.su.dsv.scipro.integration.activityforum.ActivityForumModule -se.su.dsv.scipro.peer.PeerModule -se.su.dsv.scipro.firstmeeting.FirstMeetingModule -se.su.dsv.scipro.forum.notifications.ForumNotificationsModule -se.su.dsv.scipro.daisyExternal.DaisyExternalModule -se.su.dsv.scipro.plagiarism.urkund.UrkundModule -se.su.dsv.scipro.sukat.SukatModule -se.su.dsv.scipro.oauth.OAuthModule -se.su.dsv.scipro.grading.GradingModule -se.su.dsv.scipro.gdpr.GDPRModule -se.su.dsv.scipro.survey.SurveyModule diff --git a/view/src/main/webapp/WEB-INF/web.xml b/view/src/main/webapp/WEB-INF/web.xml deleted file mode 100755 index bf2a938984..0000000000 --- a/view/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> -<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" - version="4.0" metadata-complete="true"> - - <display-name>SciPro</display-name> - - <filter> - <filter-name>guiceFilter</filter-name> - <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> - </filter> - <filter-mapping> - <filter-name>guiceFilter</filter-name> - <url-pattern>/*</url-pattern> - </filter-mapping> - - <listener> - <listener-class>ApplicationBootstrap</listener-class> - </listener> - - <listener> - <listener-class>DatabaseMigration</listener-class> - </listener> - - <session-config> - <session-timeout>480</session-timeout> - </session-config> -</web-app> diff --git a/view/src/test/java/se/su/dsv/scipro/SciProTest.java b/view/src/test/java/se/su/dsv/scipro/SciProTest.java index ee39fc8b41..2b469c39ec 100755 --- a/view/src/test/java/se/su/dsv/scipro/SciProTest.java +++ b/view/src/test/java/se/su/dsv/scipro/SciProTest.java @@ -1,17 +1,13 @@ package se.su.dsv.scipro; import com.google.common.eventbus.EventBus; -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.multibindings.Multibinder; -import com.google.inject.name.Names; import org.apache.wicket.Component; import org.apache.wicket.Page; import org.apache.wicket.Session; -import org.apache.wicket.guice.GuiceComponentInjector; import org.apache.wicket.request.Request; import org.apache.wicket.request.Response; +import org.apache.wicket.spring.injection.annot.SpringComponentInjector; +import org.apache.wicket.spring.test.ApplicationContextMock; import org.apache.wicket.util.tester.WicketTester; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; @@ -143,6 +139,7 @@ import java.util.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public abstract class SciProTest { @@ -364,9 +361,12 @@ public abstract class SciProTest { @BeforeEach public void setUpApplication() { final Class<? extends SciProTest> clazz = getClass(); - final Injector injector = Guice.createInjector(new MockModule(clazz)); + ApplicationContextMock applicationContext = new MockModule(clazz); - SciProApplication application = new SciProApplication(injector.getInstance(CurrentProfile.class)) { + CurrentProfile currentProfile = new CurrentProfile(); + currentProfile.setCurrentProfileString("TEST"); + + SciProApplication application = new SciProApplication(currentProfile) { @Override public Session newSession(Request request, Response response) { @@ -374,7 +374,7 @@ public abstract class SciProTest { } }; application.getComponentInstantiationListeners().add( - new GuiceComponentInjector(application, injector)); + new SpringComponentInjector(application, applicationContext)); tester = new WicketTester(application, System.getProperty("user.dir") + "/src/main/webapp"); setLoggedIn(true); @@ -391,6 +391,8 @@ public abstract class SciProTest { publicationMetadata.setProject(answer.getArgument(0)); return publicationMetadata; }); + lenient().when(publishingConsentService.getPublishingConsent(any(), any())) + .thenReturn(new PublishingConsentService.PublishingConsent(null, List.of())); } @BeforeEach @@ -467,27 +469,23 @@ public abstract class SciProTest { return sb.toString(); } - private class MockModule extends AbstractModule { + private class MockModule extends ApplicationContextMock { private final Class<? extends SciProTest> clazz; public MockModule(Class<? extends SciProTest> clazz) { this.clazz = clazz; + configure(); } @SuppressWarnings("unchecked") - @Override - protected void configure() { - Multibinder.newSetBinder(binder(), Lifecycle.class); - Multibinder.newSetBinder(binder(), UserImportService.class) - .addBinding().toInstance(userImportService); - bindConstant().annotatedWith(Names.named("profile")).to("TEST"); - bind(Clock.class).toInstance(Clock.systemDefaultZone()); + private void configure() { + putBean(Clock.systemDefaultZone()); for (Class<?> c = clazz; c != null; c = c.getSuperclass()) { for (Field f : c.getDeclaredFields()) { if (f.getAnnotation(Mock.class) != null && f.trySetAccessible()) { try { Class<Object> type = (Class<Object>) f.getType(); - bind(type).toInstance(f.get(SciProTest.this)); + putBean(f.getName(), f.get(SciProTest.this)); } catch (IllegalAccessException e) { throw new RuntimeException(e); } diff --git a/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java b/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java index d8785aca19..b6c0e57856 100644 --- a/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java +++ b/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java @@ -25,7 +25,7 @@ public class TrafficLightPanelTest extends SciProTest { @Test public void renders_not_applicable() { - startPanel(Model.of(ChecklistAnswerEnum.NOT_APLICABLE)); + startPanel(Model.of(ChecklistAnswerEnum.NOT_APPLICABLE)); } @Test diff --git a/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java b/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java index 56212cd5d9..fbb66e7b45 100644 --- a/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java +++ b/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java @@ -28,7 +28,7 @@ public class DisplayQuestionPanelTest extends SciProTest { @Test public void renders_with_not_applicable_answer() { - startPanel(ChecklistAnswerEnum.NOT_APLICABLE, "motivation"); + startPanel(ChecklistAnswerEnum.NOT_APPLICABLE, "motivation"); } @Test diff --git a/war/pom.xml b/war/pom.xml new file mode 100644 index 0000000000..2c4ad17242 --- /dev/null +++ b/war/pom.xml @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>se.su.dsv.scipro</groupId> + <artifactId>SciPro</artifactId> + <version>0.1-SNAPSHOT</version> + </parent> + + <artifactId>war</artifactId> + <packaging>war</packaging> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <exclusions> + <!-- exclude default logging implementation (logback) since we want log4j2 --> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-log4j2</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-tomcat</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-orm</artifactId> + </dependency> + <dependency> + <groupId>org.hibernate.orm</groupId> + <artifactId>hibernate-core</artifactId> + <scope>runtime</scope> + </dependency> + + <dependency> + <groupId>org.apache.wicket</groupId> + <artifactId>wicket-spring</artifactId> + </dependency> + + <dependency> + <groupId>org.springdoc</groupId> + <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> + </dependency> + + <dependency> + <groupId>se.su.dsv.scipro</groupId> + <artifactId>view</artifactId> + <version>${project.version}</version> + <type>war</type> + </dependency> + <dependency> + <!-- needed only at compile time --> + <!-- the classes will be moved as part of the overlay by the war plugin --> + <groupId>se.su.dsv.scipro</groupId> + <artifactId>view</artifactId> + <version>${project.version}</version> + <classifier>classes</classifier> + <optional>true</optional> + </dependency> + <dependency> + <groupId>se.su.dsv.scipro</groupId> + <artifactId>api</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <version>3.4.0</version> + <configuration> + <overlays> + <overlay> + <groupId>se.su.dsv.scipro</groupId> + <artifactId>view</artifactId> + <type>war</type> + </overlay> + </overlays> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/war/src/main/java/se/su/dsv/scipro/war/ApiConfig.java b/war/src/main/java/se/su/dsv/scipro/war/ApiConfig.java new file mode 100644 index 0000000000..f8b410b8aa --- /dev/null +++ b/war/src/main/java/se/su/dsv/scipro/war/ApiConfig.java @@ -0,0 +1,72 @@ +package se.su.dsv.scipro.war; + +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; + +import java.util.List; + +@Configuration(proxyBeanMethods = false) +@ComponentScan("se.su.dsv.scipro.api") +public class ApiConfig { + @Bean + @Order(1) + public SecurityFilterChain documentationSecurity( + HttpSecurity http, + HandlerMappingIntrospector introspector, + WebMvcProperties webMvcProperties) + throws Exception + { + MvcRequestMatcher.Builder mvc = new MvcRequestMatcher.Builder(introspector) + .servletPath(webMvcProperties.getServlet().getPath()); + return http + .securityMatchers(matchers -> matchers + .requestMatchers( + mvc.pattern("/v3/api-docs/**"), + mvc.pattern("/swagger"), + mvc.pattern("/swagger-ui/**"))) + .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll()) + .build(); + } + + @Bean + @Order(2) + public SecurityFilterChain apiSecurity( + HttpSecurity http, + HandlerMappingIntrospector introspector, + WebMvcProperties webMvcProperties) + throws Exception + { + MvcRequestMatcher.Builder mvc = new MvcRequestMatcher.Builder(introspector) + .servletPath(webMvcProperties.getServlet().getPath()); + return http + .securityMatcher(mvc.pattern("/**")) + .authorizeHttpRequests(authorize -> authorize + .anyRequest().authenticated()) + .oauth2ResourceServer(oauth2 -> oauth2.opaqueToken(Customizer.withDefaults())) + .build(); + } + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .security(List.of(new SecurityRequirement().addList("access-token"))) + .components(new Components() + .addSecuritySchemes("access-token", new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .in(SecurityScheme.In.HEADER) + .scheme("bearer") + .bearerFormat("opaque"))); + } +} diff --git a/core/src/main/java/se/su/dsv/scipro/mail/MailModule.java b/war/src/main/java/se/su/dsv/scipro/war/MailConfig.java similarity index 52% rename from core/src/main/java/se/su/dsv/scipro/mail/MailModule.java rename to war/src/main/java/se/su/dsv/scipro/war/MailConfig.java index c23bc66811..a96c89f56c 100644 --- a/core/src/main/java/se/su/dsv/scipro/mail/MailModule.java +++ b/war/src/main/java/se/su/dsv/scipro/war/MailConfig.java @@ -1,38 +1,40 @@ -package se.su.dsv.scipro.mail; - -import com.google.inject.Exposed; -import com.google.inject.PrivateModule; -import com.google.inject.Provides; -import se.su.dsv.scipro.file.FileService; -import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; -import se.su.dsv.scipro.profiles.CurrentProfile; +package se.su.dsv.scipro.war; import jakarta.mail.Session; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import se.su.dsv.scipro.data.facade.MailFacade; +import se.su.dsv.scipro.file.FileService; +import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; +import se.su.dsv.scipro.mail.Mail; +import se.su.dsv.scipro.mail.Mailer; +import se.su.dsv.scipro.mail.PrintingMailer; +import se.su.dsv.scipro.mail.RedirectingMailer; +import se.su.dsv.scipro.profiles.CurrentProfile; + import java.util.Properties; -public class MailModule extends PrivateModule { - - private static final String TEST_MAIL_SINK = "scipro-mailtest@dsv.su.se"; - - @Override - protected void configure() { - requireBinding(CurrentProfile.class); - requireBinding(GeneralSystemSettingsService.class); - bind(MailEventService.class).to(MailEventServiceImpl.class); - expose(MailEventService.class); +@Configuration(proxyBeanMethods = false) +public class MailConfig { + @Bean + public MailFacade mailFacade() { + return new MailFacade(); } - @Provides - @Exposed - public Mailer mailer(CurrentProfile currentProfile, Session session, FileService fileDescriptionService) { + @Bean + public Mailer mailer( + CurrentProfile currentProfile, + Session session, + FileService fileDescriptionService) + { return switch (currentProfile.getCurrentProfile()) { case DEV -> new PrintingMailer(); case PROD -> new Mail(session, fileDescriptionService); - case TEST -> new RedirectingMailer(session, TEST_MAIL_SINK, fileDescriptionService); + case TEST -> new RedirectingMailer(session, "scipro-mailtest@dsv.su.se", fileDescriptionService); }; } - @Provides + @Bean public Session session(GeneralSystemSettingsService generalSystemSettings) { String smtpHost = generalSystemSettings.getGeneralSystemSettingsInstance().getSmtpServer(); Properties properties = new Properties(); diff --git a/war/src/main/java/se/su/dsv/scipro/war/Main.java b/war/src/main/java/se/su/dsv/scipro/war/Main.java new file mode 100644 index 0000000000..026130dd7d --- /dev/null +++ b/war/src/main/java/se/su/dsv/scipro/war/Main.java @@ -0,0 +1,168 @@ +package se.su.dsv.scipro.war; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.servlet.ServletContainerInitializer; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilderCustomizer; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.orm.jpa.SharedEntityManagerCreator; +import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; +import se.su.dsv.scipro.CoreConfig; +import se.su.dsv.scipro.CurrentUserFromWicketSession; +import se.su.dsv.scipro.FileSystemStore; +import se.su.dsv.scipro.RepositoryConfiguration; +import se.su.dsv.scipro.file.FileStore; +import se.su.dsv.scipro.finalthesis.PublishingConsentService; +import se.su.dsv.scipro.finalthesis.PublishingConsentUnavailable; +import se.su.dsv.scipro.profiles.CurrentProfile; +import se.su.dsv.scipro.system.AggregateUserSearch; +import se.su.dsv.scipro.system.Lifecycle; +import se.su.dsv.scipro.system.ResearchArea; +import se.su.dsv.scipro.system.User; +import se.su.dsv.scipro.system.UserImportService; +import se.su.dsv.scipro.system.UserSearchProvider; +import se.su.dsv.scipro.system.UserSearchService; +import se.su.dsv.scipro.system.UserService; + +import java.time.Clock; +import java.util.List; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.Set; + +@SpringBootApplication(proxyBeanMethods = false) +@EntityScan("se.su.dsv.scipro") +@Import({ + CoreConfig.class, + ApiConfig.class, + WorkerConfig.class, + MailConfig.class, + RepositoryConfiguration.class, + WicketConfiguration.class +}) +public class Main extends SpringBootServletInitializer implements ServletContainerInitializer { + @Override + public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException { + onStartup(ctx); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + for (PluginConfiguration pluginConfiguration : ServiceLoader.load(PluginConfiguration.class)) { + builder.sources(pluginConfiguration.getClass()); + } + return builder.sources(Main.class); + } + + @Bean + public EntityManagerFactoryBuilderCustomizer entityManagerFactoryCustomizer() { + return factoryBuilder -> { + factoryBuilder.setBootstrapExecutor(new SimpleAsyncTaskExecutor()); + }; + } + + @Bean + public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() { + return new OpenEntityManagerInViewFilter(); + } + + @Bean + public CurrentProfile currentProfile(@Value("${profile}" ) String profile) { + CurrentProfile currentProfile = new CurrentProfile(); + currentProfile.setCurrentProfileString(profile); + return currentProfile; + } + + @Bean + public CurrentUserFromWicketSession currentUserFromWicketSession() { + return new CurrentUserFromWicketSession(); + } + + @Bean + public FileStore fileStore() { + return new FileSystemStore(); + } + + @Bean + public Clock clock() { + return Clock.systemDefaultZone(); + } + + /** + * Allow injecting of {@link EntityManager} directly instead of {@link EntityManagerFactory} + */ + @Bean + public EntityManager entityManager(EntityManagerFactory emf) { + return SharedEntityManagerCreator.createSharedEntityManager(emf); + } + + /** + * Exists because Spring refuses to inject a collection of beans if there are no beans of that type. + */ + @Bean + public UserImportService dummyUserImportService() { + return new UserImportService() { + @Override + public Optional<User> importUser(String userName) { + return Optional.empty(); + } + + @Override + public List<ImportableUser> search(String searchTerm) { + return List.of(); + } + + @Override + public void importUser(ImportableUser importableUser) { + // do nothing + } + + @Override + public Set<ResearchArea> importResearchAreasForSupervisor(User supervisor) { + return Set.of(); + } + }; + } + + /** + * Exists because Spring refuses to inject a collection of beans if there are no beans of that type. + */ + @Bean + public Lifecycle dummyLifecycle() { + return new Lifecycle() { + @Override + public void start() { + // do nothing + } + + @Override + public void stop() { + // do nothing + } + }; + } + + @Bean + public UserSearchService aggregateSearchService( + Set<UserSearchProvider> userSearchProviders, + UserService userService) + { + return new AggregateUserSearch(userSearchProviders, userService); + } + + @Bean + @ConditionalOnMissingBean(PublishingConsentService.class) + public PublishingConsentUnavailable publishingConsentService() { + return new PublishingConsentUnavailable(); + } +} diff --git a/war/src/main/java/se/su/dsv/scipro/war/SpringManagedWorkerTransactions.java b/war/src/main/java/se/su/dsv/scipro/war/SpringManagedWorkerTransactions.java new file mode 100644 index 0000000000..ae66a50e36 --- /dev/null +++ b/war/src/main/java/se/su/dsv/scipro/war/SpringManagedWorkerTransactions.java @@ -0,0 +1,50 @@ +package se.su.dsv.scipro.war; + +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import se.su.dsv.scipro.workerthreads.WorkerTransactionManager; + +public class SpringManagedWorkerTransactions implements WorkerTransactionManager { + private final PlatformTransactionManager platformTransactionManager; + + private TransactionStatus activeTransaction; + + public SpringManagedWorkerTransactions(PlatformTransactionManager platformTransactionManager) { + this.platformTransactionManager = platformTransactionManager; + } + + @Override + public void rollbackIfActive() { + if (this.activeTransaction != null) { + platformTransactionManager.rollback(this.activeTransaction); + this.activeTransaction = null; + } + } + + @Override + public void begin() { + if (this.activeTransaction != null) { + throw new IllegalStateException("A transaction is already active"); + } + this.activeTransaction = platformTransactionManager.getTransaction(TransactionDefinition.withDefaults()); + } + + @Override + public void commit() { + if (this.activeTransaction == null) { + throw new IllegalStateException("A transaction is not active"); + } + platformTransactionManager.commit(this.activeTransaction); + this.activeTransaction = null; + } + + @Override + public void rollback() { + if (this.activeTransaction == null) { + throw new IllegalStateException("A transaction is not active"); + } + platformTransactionManager.rollback(this.activeTransaction); + this.activeTransaction = null; + } +} diff --git a/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java new file mode 100644 index 0000000000..bb255d4915 --- /dev/null +++ b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java @@ -0,0 +1,100 @@ +package se.su.dsv.scipro.war; + +import com.google.common.eventbus.EventBus; +import org.apache.wicket.protocol.http.WebApplication; +import org.apache.wicket.protocol.http.WicketFilter; +import org.apache.wicket.spring.injection.annot.SpringComponentInjector; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import se.su.dsv.scipro.SciProApplication; +import se.su.dsv.scipro.crosscutting.ForwardPhase2Feedback; +import se.su.dsv.scipro.crosscutting.NotifyFailedReflection; +import se.su.dsv.scipro.crosscutting.ReviewerAssignedNotifications; +import se.su.dsv.scipro.crosscutting.ReviewerSupportMailer; +import se.su.dsv.scipro.crosscutting.ReviewingNotifications; +import se.su.dsv.scipro.forum.ProjectForumService; +import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; +import se.su.dsv.scipro.mail.MailEventService; +import se.su.dsv.scipro.notifications.NotificationController; +import se.su.dsv.scipro.profiles.CurrentProfile; +import se.su.dsv.scipro.reviewing.FinalSeminarApprovalService; +import se.su.dsv.scipro.reviewing.RoughDraftApprovalService; + +@Configuration +public class WicketConfiguration { + @Bean + public FilterRegistrationBean<WicketFilter> wicket( + WebApplication webApplication, + ApplicationContext applicationContext) + { + webApplication.getComponentInstantiationListeners() + .add(new SpringComponentInjector(webApplication, applicationContext)); + + WicketFilter filter = new WicketFilter(webApplication); + filter.setFilterPath(""); + + FilterRegistrationBean<WicketFilter> registration = new FilterRegistrationBean<>(); + registration.setFilter(filter); + registration.addUrlPatterns("/*"); + registration.setMatchAfter(true); + return registration; + } + + @Bean + public WebApplication webApplication(CurrentProfile currentProfile) { + return new SciProApplication(currentProfile); + } + + @Bean + public ReviewingNotifications reviewingNotifications( + EventBus eventBus, + NotificationController notificationController, + GeneralSystemSettingsService generalSystemSettingsService, + WebApplication webApplication) + { + return new ReviewingNotifications(eventBus, notificationController, generalSystemSettingsService, + webApplication); + } + + @Bean + public ForwardPhase2Feedback forwardPhase2Feedback( + EventBus eventBus, + WebApplication webApplication, + ProjectForumService projectForumService) + { + return new ForwardPhase2Feedback(webApplication, projectForumService, eventBus); + } + + // Not sure why this dependency lives in the view module + @Bean + public ReviewerSupportMailer reviewerSupportMailer( + EventBus eventBus, + GeneralSystemSettingsService generalSystemSettingsService, + MailEventService mailEventService) + { + return new ReviewerSupportMailer(eventBus, mailEventService, generalSystemSettingsService); + } + + // Not sure why this dependency lives in the view module + @Bean + public ReviewerAssignedNotifications reviewerAssignedNotifications( + EventBus eventBus, + NotificationController notificationController, + RoughDraftApprovalService roughDraftApprovalService, + FinalSeminarApprovalService finalSeminarApprovalService) + { + return new ReviewerAssignedNotifications(roughDraftApprovalService, + finalSeminarApprovalService, notificationController, eventBus); + } + + // Not sure why this dependency lives in the view module + @Bean + public NotifyFailedReflection notifyFailedReflection( + EventBus eventBus, + NotificationController notificationController) + { + return new NotifyFailedReflection(notificationController, eventBus); + } +} diff --git a/war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java b/war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java new file mode 100644 index 0000000000..076bc219fc --- /dev/null +++ b/war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java @@ -0,0 +1,245 @@ +package se.su.dsv.scipro.war; + +import com.google.common.eventbus.EventBus; +import jakarta.inject.Provider; +import jakarta.persistence.EntityManagerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Scope; +import org.springframework.transaction.PlatformTransactionManager; +import se.su.dsv.scipro.file.FileService; +import se.su.dsv.scipro.finalseminar.FinalSeminarService; +import se.su.dsv.scipro.firstmeeting.FirstMeetingReminderWorker; +import se.su.dsv.scipro.firstmeeting.FirstMeetingService; +import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService; +import se.su.dsv.scipro.mail.MailEventService; +import se.su.dsv.scipro.mail.MailEventWorker; +import se.su.dsv.scipro.mail.Mailer; +import se.su.dsv.scipro.match.AllowAllIdeaCreationJudge; +import se.su.dsv.scipro.match.ApplicationPeriodService; +import se.su.dsv.scipro.match.IdeaCreationJudge; +import se.su.dsv.scipro.match.IdeaService; +import se.su.dsv.scipro.misc.DaysService; +import se.su.dsv.scipro.peer.ExpiredRequestWorker; +import se.su.dsv.scipro.peer.ExpiredReviewResetWorker; +import se.su.dsv.scipro.peer.PeerWorkerSchedules; +import se.su.dsv.scipro.plagiarism.PlagiarismRequestRepository; +import se.su.dsv.scipro.plagiarism.PlagiarismSubmitter; +import se.su.dsv.scipro.plagiarism.urkund.StatusPollingWorker; +import se.su.dsv.scipro.plagiarism.urkund.UrkundApi; +import se.su.dsv.scipro.plagiarism.urkund.UrkundService; +import se.su.dsv.scipro.plagiarism.urkund.UrkundSettings; +import se.su.dsv.scipro.plagiarism.urkund.UrkundSettingsRepository; +import se.su.dsv.scipro.plagiarism.urkund.UrkundSubmissionRepository; +import se.su.dsv.scipro.project.ProjectService; +import se.su.dsv.scipro.projectpartner.ProjectPartnerRepository; +import se.su.dsv.scipro.projectpartner.RemoveFulfilledPartnerAdsWorker; +import se.su.dsv.scipro.reviewing.MyReviewService; +import se.su.dsv.scipro.reviewing.ReviewerDecisionReminderWorker; +import se.su.dsv.scipro.sukat.Sukat; +import se.su.dsv.scipro.workerthreads.GradeFinalSeminarParticipantReminderWorker; +import se.su.dsv.scipro.workerthreads.IdeaExportWorker; +import se.su.dsv.scipro.workerthreads.ManualMatchRemindWorker; +import se.su.dsv.scipro.workerthreads.NotificationCompilationWorker; +import se.su.dsv.scipro.workerthreads.Scheduler; +import se.su.dsv.scipro.workerthreads.SchedulerImpl; +import se.su.dsv.scipro.workerthreads.TemporaryWorkerScheduler; +import se.su.dsv.scipro.workerthreads.ThesisUploadDeadlineWorker; +import se.su.dsv.scipro.workerthreads.ThesisUploadReminderWorker; +import se.su.dsv.scipro.workerthreads.WorkerTransactionManager; + +import java.time.Clock; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +@Configuration(proxyBeanMethods = false) +@Import(WorkerConfig.Workers.class) +public class WorkerConfig { + private static final int NUMBER_OF_WORKER_THREADS = 4; + + @Bean + public ScheduledExecutorService scheduledExecutorService() { + return Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS); + } + + @Bean + public SchedulerImpl scheduler( + ScheduledExecutorService scheduledExecutorService, + EntityManagerFactory entityManagerFactory) + { + return new SchedulerImpl(scheduledExecutorService, entityManagerFactory); + } + + @Bean + public TemporaryWorkerScheduler temporaryWorkerScheduler( + Scheduler scheduler, + Provider<MailEventWorker> mailEventWorker, + Provider<NotificationCompilationWorker> notificationCompilationWorker, + Provider<IdeaExportWorker> ideaExportWorker, + Provider<ThesisUploadReminderWorker> thesisUploadReminderWorker, + Provider<ThesisUploadDeadlineWorker> thesisUploadDeadlineWorker, + Provider<ManualMatchRemindWorker> manualMatchRemindWorkerProvider, + Provider<ReviewerDecisionReminderWorker> reviewerDecisionReminderWorker, + Provider<PlagiarismSubmitter> plagiarismSubmitter, + Provider<StatusPollingWorker> urkundPoller, + Provider<RemoveFulfilledPartnerAdsWorker> removeFulfilledPartnerAds, + Provider<GradeFinalSeminarParticipantReminderWorker> gradeFinalSeminarParticipantReminderWorkerProvider) + { + return new TemporaryWorkerScheduler(scheduler, mailEventWorker, notificationCompilationWorker, ideaExportWorker, thesisUploadReminderWorker, thesisUploadDeadlineWorker, manualMatchRemindWorkerProvider, reviewerDecisionReminderWorker, plagiarismSubmitter, urkundPoller, removeFulfilledPartnerAds, gradeFinalSeminarParticipantReminderWorkerProvider); + } + + @Bean + public FirstMeetingReminderWorker.FirstMeetingReminderWorkerSchedule firstMeetingReminderWorkerScheduler( + Scheduler scheduler, + Provider<FirstMeetingReminderWorker> firstMeetingReminderWorkerProvider) + { + return new FirstMeetingReminderWorker.FirstMeetingReminderWorkerSchedule(scheduler, firstMeetingReminderWorkerProvider); + } + + @Bean + public PeerWorkerSchedules peerWorkerSchedules( + Scheduler scheduler, + Provider<ExpiredRequestWorker> expiredRequestWorker, + Provider<ExpiredReviewResetWorker> expiredReviewResetWorker) + { + return new PeerWorkerSchedules(scheduler, expiredRequestWorker, expiredReviewResetWorker); + } + + @Bean + @ConditionalOnMissingBean(IdeaCreationJudge.class) + public IdeaCreationJudge ideaCreationJudge() { + return new AllowAllIdeaCreationJudge(); + } + + @Bean + public PlagiarismSubmitter plagiarismSubmitter( + Provider<UrkundSettings> urkundSettings, + PlagiarismRequestRepository plagiarismRequestRepository, + UrkundService urkundService, + FileService fileService) + { + return new PlagiarismSubmitter(urkundSettings, plagiarismRequestRepository, urkundService, fileService); + } + + @Bean + public UrkundSettings urkundSettings(UrkundSettingsRepository urkundSettingsRepository) { + return urkundSettingsRepository.getSettings(); + } + + @Bean + @Scope("prototype") + public WorkerTransactionManager workerTransactionManager(PlatformTransactionManager platformTransactionManager) { + return new SpringManagedWorkerTransactions(platformTransactionManager); + } + + @Configuration + public static class Workers { + @Bean + public MailEventWorker mailEventWorker( + MailEventService mailEventService, + GeneralSystemSettingsService generalSystemSettingsService, + Mailer mailer) + { + return new MailEventWorker(mailEventService, generalSystemSettingsService, mailer); + } + + @Bean + public NotificationCompilationWorker notificationCompilationWorker() { + return new NotificationCompilationWorker(); + } + + @Bean + public IdeaExportWorker ideaExportWorker( + IdeaService ideaService, + MailEventService mailEventService, + ProjectService projectService, + IdeaCreationJudge ideaCreationJudge, + EventBus eventBus, + FirstMeetingService firstMeetingService) + { + return new IdeaExportWorker(ideaService, mailEventService, projectService, ideaCreationJudge, eventBus, + firstMeetingService); + } + + @Bean + public ThesisUploadReminderWorker thesisUploadReminderWorker() { + return new ThesisUploadReminderWorker(); + } + + @Bean + public ThesisUploadDeadlineWorker thesisUploadDeadlineWorker() { + return new ThesisUploadDeadlineWorker(); + } + + @Bean + public ManualMatchRemindWorker manualMatchRemindWorker( + ApplicationPeriodService applicationPeriodService, + MailEventService mailEventService, + GeneralSystemSettingsService generalSystemSettingsService, + IdeaService ideaService, + Clock clock) + { + return new ManualMatchRemindWorker(applicationPeriodService, mailEventService, generalSystemSettingsService, + ideaService, clock); + } + + @Bean + public ReviewerDecisionReminderWorker reviewerDecisionReminderWorker( + MyReviewService myReviewService, + DaysService daysService, + MailEventService mailEventService) + { + return new ReviewerDecisionReminderWorker(myReviewService, daysService, mailEventService); + } + + @Bean + public StatusPollingWorker statusPollingWorker( + UrkundSubmissionRepository urkundSubmissionRepository, + UrkundApi urkundApi, + Provider<UrkundSettings> urkundSettingsProvider, + Sukat sukat) + { + return new StatusPollingWorker(urkundSubmissionRepository, urkundApi, urkundSettingsProvider, sukat); + } + + @Bean + public RemoveFulfilledPartnerAdsWorker removeFulfilledPartnerAdsWorker( + IdeaService ideaService, + ProjectPartnerRepository projectPartnerRepository) + { + return new RemoveFulfilledPartnerAdsWorker(ideaService, projectPartnerRepository); + } + + @Bean + public GradeFinalSeminarParticipantReminderWorker gradeFinalSeminarParticipantReminderWorker( + MailEventService mailEventService, + GeneralSystemSettingsService generalSystemSettingsService, + FinalSeminarService finalSeminarService) + { + return new GradeFinalSeminarParticipantReminderWorker(finalSeminarService, mailEventService, generalSystemSettingsService); + } + + @Bean + public FirstMeetingReminderWorker firstMeetingReminderWorker( + IdeaService ideaService, + DaysService daysService, + MailEventService mailEventService, + GeneralSystemSettingsService generalSystemSettingsService, + Clock clock) + { + return new FirstMeetingReminderWorker(ideaService, daysService, mailEventService, generalSystemSettingsService, clock); + } + + @Bean + public ExpiredReviewResetWorker expiredReviewResetWorker() { + return new ExpiredReviewResetWorker(); + } + + @Bean + public ExpiredRequestWorker expiredRequestWorker() { + return new ExpiredRequestWorker(); + } + } +} diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java b/war/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java similarity index 63% rename from core/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java rename to war/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java index d8ecf35252..0acb56920c 100755 --- a/core/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java +++ b/war/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java @@ -1,12 +1,18 @@ package se.su.dsv.scipro.workerthreads; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.orm.jpa.EntityManagerFactoryUtils; +import org.springframework.orm.jpa.EntityManagerHolder; +import org.springframework.transaction.support.TransactionSynchronizationManager; import se.su.dsv.scipro.system.Lifecycle; import jakarta.inject.Inject; import jakarta.inject.Provider; import jakarta.inject.Singleton; + import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -19,13 +25,15 @@ public class SchedulerImpl implements Lifecycle, Scheduler { private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerImpl.class); private final ScheduledExecutorService scheduledExecutorService; + private final EntityManagerFactory emf; private final Set<Task> tasks = new TreeSet<>(new Task.ByDescriptionComparator()); private final Set<Task> runningWorkers = Collections.synchronizedSet(new HashSet<>()); @Inject - public SchedulerImpl(ScheduledExecutorService scheduledExecutorService) { + public SchedulerImpl(ScheduledExecutorService scheduledExecutorService, EntityManagerFactory emf) { this.scheduledExecutorService = scheduledExecutorService; + this.emf = emf; } @Override @@ -43,6 +51,14 @@ public class SchedulerImpl implements Lifecycle, Scheduler { private Runnable tracked(final Task task) { return () -> { try { + // Since we're not in a web request when running a scheduled job, Spring's OpenEntityManagerInView + // filter is not active. Therefore, we need to manually bind a new EntityManager to the current thread + // to be shared by all DAOs. If we do not, we will get problems with detached entity passed to persist + // since every read and write from the database will be in a new EntityManager. + EntityManager em = emf.createEntityManager(); + EntityManagerHolder emHolder = new EntityManagerHolder(em); + TransactionSynchronizationManager.bindResource(emf, emHolder); + runningWorkers.add(task); task.execute(); } @@ -51,6 +67,11 @@ public class SchedulerImpl implements Lifecycle, Scheduler { } finally { runningWorkers.remove(task); + + // Clean up the shared EntityManager + EntityManagerHolder emHolder = (EntityManagerHolder) + TransactionSynchronizationManager.unbindResource(emf); + EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager()); } }; } diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java b/war/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java similarity index 100% rename from core/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java rename to war/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java diff --git a/war/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer b/war/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer new file mode 100644 index 0000000000..ad4ffa3bbd --- /dev/null +++ b/war/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer @@ -0,0 +1 @@ +se.su.dsv.scipro.war.Main diff --git a/war/src/main/resources/application.properties b/war/src/main/resources/application.properties new file mode 100644 index 0000000000..753d0e323c --- /dev/null +++ b/war/src/main/resources/application.properties @@ -0,0 +1,20 @@ +spring.datasource.jndi-name=java:/comp/env/jdbc/sciproDS +spring.flyway.table=schema_version + +# Spring Boot changes Hibernates default naming strategy to convert camelCase to snake_case +# We currently rely on the names to be treated as they are in Java, so we need to set it back to the default +spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl + +# We also need to set the implicit strategy to be JPA compliant, as we rely on this naming strategy for certain +# join tables (idea_Keyword vs idea_keyword) +spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl + +spring.mvc.servlet.path=/api + +springdoc.swagger-ui.path=/swagger +springdoc.swagger-ui.persist-authorization=true + +# These will be overwritten by configuration in the environment of servers it is deployed to +spring.security.oauth2.resourceserver.opaquetoken.client-id=scipro-api-client +spring.security.oauth2.resourceserver.opaquetoken.client-secret=scipro-api-secret +spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=http://localhost:59733/introspect diff --git a/war/src/main/webapp/WEB-INF/web.xml b/war/src/main/webapp/WEB-INF/web.xml new file mode 100755 index 0000000000..9741e82487 --- /dev/null +++ b/war/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" + version="4.0" metadata-complete="true"> + + <display-name>SciPro</display-name> + + <!-- disables Spring's built in ServletContainerInitializer which causes a slow class path scanning --> + <absolute-ordering/> + + <session-config> + <session-timeout>480</session-timeout> + + <!-- + By default, Tomcat will use a cookie to track the session. + However, if there is no cookie sent by the browser it will append + the session id to the URL. The way it does this is by adding a + ";jsessionid=..." to the end. This is not a problem in itself, but + it can enable session hijacking if the URL is shared and ";" is + a blocked character by the default Spring Security configuration. + (see StrictHttpFirewall). + + So what happens is a user navigates to SciPro. No session cookie is + sent since this is the first request. SciPro sees that the user is + not authenticated and redirects the user to the login page. + When SciPro checks for authentication it checks the session which + will instruct Tomcat to create a session. Since Tomcat sees no + cookie it will append the session id to the redirect URL to try and + track the session. After the user has logged in it is redirected + back to SciPro with the session id in the URL which is then blocked + by Spring's StrictHttpFirewall. + + To avoid this, we can set the tracking mode to *only* COOKIE. + --> + <tracking-mode>COOKIE</tracking-mode> + </session-config> +</web-app> diff --git a/core/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java b/war/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java similarity index 83% rename from core/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java rename to war/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java index 45e9ec4f67..f79a05cd26 100644 --- a/core/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java +++ b/war/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java @@ -1,8 +1,10 @@ package se.su.dsv.scipro.workerthreads; -import com.google.inject.util.Providers; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -24,6 +26,8 @@ public class SchedulerImplTest { private Worker abstractWorker; @Mock private Task task; + @Mock(answer = Answers.RETURNS_MOCKS) + private EntityManagerFactory emf; @InjectMocks private SchedulerImpl scheduler; @@ -31,7 +35,7 @@ public class SchedulerImplTest { public void schedules_correctly() { long period = 1; TimeUnit timeUnit = TimeUnit.SECONDS; - scheduler.schedule("My worker").runBy(Providers.of(abstractWorker)).every(period, timeUnit); + scheduler.schedule("My worker").runBy(() -> abstractWorker).every(period, timeUnit); verify(scheduledExecutorService).scheduleAtFixedRate(any(Runnable.class), eq(period), eq(period), eq(timeUnit)); }