Allow changes to the reflection to be made after it's been submitted #13
16
.gitea/workflows/test-on-push.yaml
Normal file
16
.gitea/workflows/test-on-push.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
name: Build and test
|
||||
on:
|
||||
- push
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
- name: Build with Maven
|
||||
run: ./mvnw --batch-mode --update-snapshots verify
|
19
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
19
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
wrapperVersion=3.3.2
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip
|
@ -25,6 +25,8 @@ 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;
|
||||
@ -59,5 +61,6 @@ public class RepositoryModule extends AbstractModule {
|
||||
bind(FinalSeminarRepository.class).to(FinalSeminarRepositoryImpl.class);
|
||||
bind(ReviewerTargetRepository.class).to(ReviewerTargetRepositoryImpl.class);
|
||||
bind(DecisionRepository.class).to(DecisionRepositoryImpl.class);
|
||||
bind(SupervisorGradingReportRepository.class).to(SupervisorGradingReportRepositoryImpl.class);
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import se.su.dsv.scipro.milestones.service.MilestoneActivityTemplateService;
|
||||
import se.su.dsv.scipro.profiles.CurrentProfile;
|
||||
import se.su.dsv.scipro.profiles.Profiles;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.report.AbstractGradingCriterion;
|
||||
import se.su.dsv.scipro.report.GradingCriterionPointTemplate;
|
||||
import se.su.dsv.scipro.report.GradingReportTemplate;
|
||||
import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||
@ -20,6 +21,7 @@ import jakarta.inject.Provider;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Month;
|
||||
import java.util.*;
|
||||
|
||||
public class DataInitializer implements Lifecycle {
|
||||
@ -232,19 +234,20 @@ public class DataInitializer implements Lifecycle {
|
||||
}
|
||||
|
||||
private void createGradingCriterionTemplateIfNotDone() {
|
||||
save(getBachelorTemplate(0));
|
||||
save(getBachelorTemplate(ProjectType.HP_15));
|
||||
save(getBachelorTemplate(ProjectType.HP_30));
|
||||
save(getMasterTemplate(0));
|
||||
save(getMasterTemplate(ProjectType.HP_15));
|
||||
save(getMasterTemplate(ProjectType.HP_30));
|
||||
save(getMagisterTemplate(0));
|
||||
save(getMagisterTemplate(ProjectType.HP_15));
|
||||
save(getMagisterTemplate(ProjectType.HP_30));
|
||||
save(getBachelorTemplate());
|
||||
save(getBachelorTemplate());
|
||||
save(getBachelorTemplate());
|
||||
save(getMasterTemplate());
|
||||
save(getMasterTemplate());
|
||||
save(getMasterTemplate());
|
||||
save(getMagisterTemplate());
|
||||
save(getMagisterTemplate());
|
||||
save(getMagisterTemplate());
|
||||
}
|
||||
|
||||
private GradingReportTemplate getBachelorTemplate(int credits) {
|
||||
GradingReportTemplate gradingReportTemplate = new GradingReportTemplate(bachelorClass, credits);
|
||||
private GradingReportTemplate getBachelorTemplate() {
|
||||
GradingReportTemplate gradingReportTemplate = new GradingReportTemplate(bachelorClass,
|
||||
LocalDate.of(2024, Month.JANUARY, 1));
|
||||
|
||||
List<GradingCriterionPointTemplate> gradingCriterionPointTemplates = initPointTemplates();
|
||||
gradingCriterionPointTemplates.add(new GradingCriterionPointTemplate.Builder()
|
||||
@ -401,7 +404,7 @@ public class DataInitializer implements Lifecycle {
|
||||
.description("För 2 poäng krävs dessutom: att oppositionsrapporten ingående och välbalanserat beskriver styrkor och svagheter hos det utvärderade arbetet ur flera aspekter samt att den innehåller tydliga och välmotiverade förslag till förbättringar.")
|
||||
.descriptionEn("For 2 points the following is also required: that the opposition report thoroughly and in a well-balanced way describes from numerous aspects the strengths and weaknesses of the evaluated thesis and that it offers clear and well-motivated suggestions for improvements.")
|
||||
.build());
|
||||
gradingReportTemplate.addIndividualCriterion("Ö1 Oppositionsrapport", "Ö1 Opposition report", 1, gradingCriterionPointTemplates);
|
||||
gradingReportTemplate.addIndividualCriterion("Ö1 Oppositionsrapport", "Ö1 Opposition report", 1, gradingCriterionPointTemplates, AbstractGradingCriterion.Flag.OPPOSITION);
|
||||
|
||||
gradingCriterionPointTemplates = initPointTemplates();
|
||||
gradingCriterionPointTemplates.add(new GradingCriterionPointTemplate.Builder()
|
||||
@ -441,13 +444,14 @@ public class DataInitializer implements Lifecycle {
|
||||
.description("För 1 poäng krävs: att förmåga har uppvisats att reflektera över det genomförda examensarbetet genom individuellt författande av ett reflektionsdokument.")
|
||||
.descriptionEn("Requirement for 1 point: that the ability to reflect about the thesis work has been demonstrated through the individual writing of a reflection document.")
|
||||
.build());
|
||||
gradingReportTemplate.addIndividualCriterion("Ö6 Reflektion", "Ö6 Reflection", 0, gradingCriterionPointTemplates).setFx(false);
|
||||
gradingReportTemplate.addIndividualCriterion("Ö6 Reflektion", "Ö6 Reflection", 0, gradingCriterionPointTemplates, AbstractGradingCriterion.Flag.REFLECTION).setFx(false);
|
||||
|
||||
return gradingReportTemplate;
|
||||
}
|
||||
|
||||
private GradingReportTemplate getMasterTemplate(int credits) {
|
||||
GradingReportTemplate gradingReportTemplateMaster = new GradingReportTemplate(masterClass, credits);
|
||||
private GradingReportTemplate getMasterTemplate() {
|
||||
GradingReportTemplate gradingReportTemplateMaster = new GradingReportTemplate(masterClass,
|
||||
LocalDate.of(2024, Month.JANUARY, 1));
|
||||
|
||||
List<GradingCriterionPointTemplate> gradingCriterionPointTemplates = initPointTemplates();
|
||||
gradingCriterionPointTemplates.add(new GradingCriterionPointTemplate.Builder()
|
||||
@ -629,7 +633,8 @@ public class DataInitializer implements Lifecycle {
|
||||
.description("För 2 poäng krävs dessutom: att oppositionsrapporten ingående och välbalanserat beskriver styrkor och svagheter hos det utvärderade arbetet ur flera aspekter samt att den innehåller tydliga och välmotiverade förslag till förbättringar.")
|
||||
.descriptionEn("For 2 points the following is also required: that the opposition report thoroughly and in a well-balanced way describes from numerous aspects the strengths and weaknesses of the evaluated thesis and that it offers clear and well-motivated suggestions for improvements.")
|
||||
.build());
|
||||
gradingReportTemplateMaster.addIndividualCriterion("Ö1 Oppositionsrapport", "Ö1 Opposition report", 1, gradingCriterionPointTemplates);
|
||||
gradingReportTemplateMaster.addIndividualCriterion("Ö1 Oppositionsrapport", "Ö1 Opposition report", 1, gradingCriterionPointTemplates,
|
||||
AbstractGradingCriterion.Flag.OPPOSITION);
|
||||
|
||||
gradingCriterionPointTemplates = initPointTemplates();
|
||||
gradingCriterionPointTemplates.add(new GradingCriterionPointTemplate.Builder()
|
||||
@ -669,13 +674,14 @@ public class DataInitializer implements Lifecycle {
|
||||
.description("För 1 poäng krävs: att förmåga har uppvisats att reflektera över det genomförda examensarbetet genom individuellt författande av ett reflektionsdokument.")
|
||||
.descriptionEn("Requirement for 1 point: that the ability to reflect about the thesis work has been demonstrated through the individual writing of a reflection document.")
|
||||
.build());
|
||||
gradingReportTemplateMaster.addIndividualCriterion("Ö6 Reflektion", "Ö6 Reflection", 1, gradingCriterionPointTemplates).setFx(false);
|
||||
gradingReportTemplateMaster.addIndividualCriterion("Ö6 Reflektion", "Ö6 Reflection", 1, gradingCriterionPointTemplates, AbstractGradingCriterion.Flag.REFLECTION).setFx(false);
|
||||
|
||||
return gradingReportTemplateMaster;
|
||||
}
|
||||
|
||||
private GradingReportTemplate getMagisterTemplate(int credits) {
|
||||
GradingReportTemplate gradingReportTemplateMagister = new GradingReportTemplate(magisterClass, credits);
|
||||
private GradingReportTemplate getMagisterTemplate() {
|
||||
GradingReportTemplate gradingReportTemplateMagister = new GradingReportTemplate(magisterClass,
|
||||
LocalDate.of(2024, Month.JANUARY, 1));
|
||||
|
||||
List<GradingCriterionPointTemplate> gradingCriterionPointTemplates = initPointTemplates();
|
||||
gradingCriterionPointTemplates.add(new GradingCriterionPointTemplate.Builder()
|
||||
@ -837,7 +843,8 @@ public class DataInitializer implements Lifecycle {
|
||||
.description("För 2 poäng krävs dessutom: att oppositionsrapporten ingående och välbalanserat beskriver styrkor och svagheter hos det utvärderade arbetet ur flera aspekter samt att den innehåller tydliga och välmotiverade förslag till förbättringar.")
|
||||
.descriptionEn("For 2 points the following is also required: that the opposition report thoroughly and in a well-balanced way describes from numerous aspects the strengths and weaknesses of the evaluated thesis and that it offers clear and well-motivated suggestions for improvements.")
|
||||
.build());
|
||||
gradingReportTemplateMagister.addIndividualCriterion("Ö1 Oppositionsrapport", "Ö1 Opposition report", 1, gradingCriterionPointTemplates);
|
||||
gradingReportTemplateMagister.addIndividualCriterion("Ö1 Oppositionsrapport", "Ö1 Opposition report", 1, gradingCriterionPointTemplates,
|
||||
AbstractGradingCriterion.Flag.OPPOSITION);
|
||||
|
||||
gradingCriterionPointTemplates = initPointTemplates();
|
||||
gradingCriterionPointTemplates.add(new GradingCriterionPointTemplate.Builder()
|
||||
@ -877,7 +884,7 @@ public class DataInitializer implements Lifecycle {
|
||||
.description("För 1 poäng krävs: att förmåga har uppvisats att reflektera över det genomförda examensarbetet genom individuellt författande av ett reflektionsdokument.")
|
||||
.descriptionEn("Requirement for 1 point: that the ability to reflect about the thesis work has been demonstrated through the individual writing of a reflection document.")
|
||||
.build());
|
||||
gradingReportTemplateMagister.addIndividualCriterion("Ö6 Reflektion", "Ö6 Reflection", 1, gradingCriterionPointTemplates).setFx(false);
|
||||
gradingReportTemplateMagister.addIndividualCriterion("Ö6 Reflektion", "Ö6 Reflection", 1, gradingCriterionPointTemplates, AbstractGradingCriterion.Flag.REFLECTION).setFx(false);
|
||||
|
||||
return gradingReportTemplateMagister;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.activityplan;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.checklist.Checklist;
|
||||
import se.su.dsv.scipro.checklist.ChecklistTemplate;
|
||||
import se.su.dsv.scipro.file.ProjectFileUpload;
|
||||
|
@ -4,7 +4,7 @@ import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.checklist.Checklist;
|
||||
import se.su.dsv.scipro.checklist.ChecklistAnswerEnum;
|
||||
import se.su.dsv.scipro.checklist.ChecklistCategory;
|
||||
|
@ -2,7 +2,7 @@ package se.su.dsv.scipro.activityplan;
|
||||
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.checklist;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
|
||||
|
||||
@Transactional
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.checklist;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
|
||||
|
||||
@Transactional
|
||||
|
@ -2,7 +2,7 @@ package se.su.dsv.scipro.checklist;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.file;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
|
||||
|
||||
@Transactional
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.file;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -2,7 +2,7 @@ package se.su.dsv.scipro.file;
|
||||
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.file;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
||||
import java.util.*;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package se.su.dsv.scipro.file;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.finalseminar;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
package se.su.dsv.scipro.finalseminar;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.*;
|
||||
import se.su.dsv.scipro.util.Either;
|
||||
|
@ -5,7 +5,7 @@ import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.file.FileReference;
|
||||
import se.su.dsv.scipro.file.FileService;
|
||||
import se.su.dsv.scipro.misc.DaysService;
|
||||
|
@ -5,7 +5,7 @@ import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.file.FileDescription;
|
||||
import se.su.dsv.scipro.file.FileReference;
|
||||
import se.su.dsv.scipro.file.FileService;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package se.su.dsv.scipro.forum;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
|
||||
|
||||
public interface AbstractThreadRepository extends JpaRepository<ForumThread, Long>, QueryDslPredicateExecutor<ForumThread> {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.forum;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ForumPostReadState;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ForumPostReadStateId;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.forum;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ForumPost;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ForumThread;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.forum;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.forum.dataobjects.GroupThread;
|
||||
import se.su.dsv.scipro.group.Group;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.forum;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
||||
|
@ -3,6 +3,7 @@ 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
|
||||
@ -29,5 +30,8 @@ public class GradingModule extends PrivateModule {
|
||||
bind(NationalSubjectCategoryRepository.class).to(NationalSubjectCategoryRepositoryImpl.class);
|
||||
bind(NationalSubjectCategoryService.class).to(NationalSubjectCategoryServiceImpl.class);
|
||||
expose(NationalSubjectCategoryService.class);
|
||||
|
||||
bind(GradingReportTemplateService.class).to(GradingReportServiceImpl.class);
|
||||
expose(GradingReportTemplateService.class);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
package se.su.dsv.scipro.grading;
|
||||
|
||||
import se.su.dsv.scipro.report.DuplicateDateException;
|
||||
import se.su.dsv.scipro.report.GradingReportTemplate;
|
||||
import se.su.dsv.scipro.report.ValidDateMustBeInTheFutureException;
|
||||
import se.su.dsv.scipro.report.NoSuchTemplateException;
|
||||
import se.su.dsv.scipro.report.TemplateLockedException;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface GradingReportTemplateService {
|
||||
List<ProjectType> getProjectTypes();
|
||||
|
||||
GradingReportTemplate getCurrentTemplate(ProjectType projectType);
|
||||
|
||||
GradingReportTemplate getTemplate(long templateId);
|
||||
|
||||
/**
|
||||
* Returns the end date of this grading report template.
|
||||
* End date is specified as the date before another template takes over.
|
||||
*
|
||||
* @return the end date of this grading report template, possibly {@code null}
|
||||
*/
|
||||
LocalDate getEndDate(GradingReportTemplate gradingReportTemplate);
|
||||
|
||||
List<GradingReportTemplate> getUpcomingTemplates(ProjectType projectType);
|
||||
|
||||
GradingReportTemplate update(long templateId, GradingReportTemplateUpdate update)
|
||||
throws
|
||||
ValidDateMustBeInTheFutureException,
|
||||
NoSuchTemplateException,
|
||||
DuplicateDateException,
|
||||
TemplateLockedException;
|
||||
|
||||
GradingReportTemplate create(ProjectType projectType, GradingReportTemplateUpdate update)
|
||||
throws
|
||||
ValidDateMustBeInTheFutureException,
|
||||
DuplicateDateException;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package se.su.dsv.scipro.grading;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record GradingReportTemplateUpdate(
|
||||
LocalDate validFrom,
|
||||
@Nullable String note,
|
||||
String failingGrade,
|
||||
List<GradeLimit> gradeLimits,
|
||||
List<Criteria> criteria)
|
||||
{
|
||||
public GradingReportTemplateUpdate {
|
||||
Objects.requireNonNull(validFrom, "Valid from must not be null");
|
||||
Objects.requireNonNull(failingGrade, "Failing grade must not be null");
|
||||
Objects.requireNonNull(gradeLimits, "Grades must not be null");
|
||||
Objects.requireNonNull(criteria, "Criteria must not be null");
|
||||
|
||||
for (GradeLimit gradeLimit1 : gradeLimits) {
|
||||
for (GradeLimit gradeLimit2 : gradeLimits) {
|
||||
if (gradeLimit1 != gradeLimit2 && gradeLimit1.minimumPoints() == gradeLimit2.minimumPoints()) {
|
||||
throw new IllegalArgumentException("Duplicate minimum points on grades: %s and %s".formatted(
|
||||
gradeLimit1.grade(),
|
||||
gradeLimit2.grade()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record GradeLimit(String grade, int minimumPoints) {
|
||||
public GradeLimit {
|
||||
Objects.requireNonNull(grade, "Grade must not be null");
|
||||
}
|
||||
}
|
||||
|
||||
public record Criteria(
|
||||
LocalizedString title,
|
||||
Type type,
|
||||
int minimumPointsRequiredToPass,
|
||||
@Nullable Flag flag,
|
||||
List<Requirement> requirements)
|
||||
{
|
||||
public enum Type {THESIS, INDIVIDUAL}
|
||||
public enum Flag {OPPOSITION, REFLECTION}
|
||||
|
||||
public Criteria {
|
||||
Objects.requireNonNull(title, "Title must not be null");
|
||||
Objects.requireNonNull(type, "Type must not be null");
|
||||
Objects.requireNonNull(requirements, "Requirements must not be null");
|
||||
}
|
||||
|
||||
public record Requirement(int points, LocalizedString description) {
|
||||
public Requirement {
|
||||
Objects.requireNonNull(description, "Description must not be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package se.su.dsv.scipro.grading;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record LocalizedString(String english, String swedish) {
|
||||
public LocalizedString {
|
||||
Objects.requireNonNull(english, "English must not be null");
|
||||
Objects.requireNonNull(swedish, "Swedish must not be null");
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package se.su.dsv.scipro.group;
|
||||
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
import se.su.dsv.scipro.system.FilteredService;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.integration.activityfinalseminar;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.finalseminar.FinalSeminar;
|
||||
|
||||
import java.util.Optional;
|
||||
|
@ -2,7 +2,7 @@ package se.su.dsv.scipro.mail;
|
||||
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
@ -3,8 +3,8 @@ package se.su.dsv.scipro.match;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import se.su.dsv.scipro.system.PageRequest;
|
||||
import se.su.dsv.scipro.system.Sort;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
import se.su.dsv.scipro.system.DegreeType;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.match;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
|
||||
|
||||
@Transactional
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.match;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.match;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.match.Idea.Status;
|
||||
import se.su.dsv.scipro.match.Idea.Type;
|
||||
import se.su.dsv.scipro.system.*;
|
||||
|
@ -9,7 +9,7 @@ import com.querydsl.core.types.dsl.DateTimeExpression;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.data.dataobjects.Member;
|
||||
import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettings;
|
||||
import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.match;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.GenericService;
|
||||
import se.su.dsv.scipro.system.ResearchArea;
|
||||
|
||||
|
@ -4,9 +4,9 @@ import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import se.su.dsv.scipro.system.PageRequest;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.Sort;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
import se.su.dsv.scipro.system.ResearchArea;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.match;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
import java.util.Set;
|
||||
|
@ -8,7 +8,7 @@ import com.querydsl.core.types.dsl.StringPath;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.match;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.GenericService;
|
||||
|
||||
public interface MatchService extends GenericService<Match, Long> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.match;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
@ -2,8 +2,8 @@ package se.su.dsv.scipro.match;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import se.su.dsv.scipro.system.PageRequest;
|
||||
import se.su.dsv.scipro.system.Sort;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
import se.su.dsv.scipro.system.Program;
|
||||
import se.su.dsv.scipro.system.QProgram;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.milestones;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestonePhaseTemplate;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.milestones.service;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.Milestone;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.milestones.service;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import se.su.dsv.scipro.system.Sort;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestonePhaseTemplate;
|
||||
import se.su.dsv.scipro.springdata.SortOrderService;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.milestones.service;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.project.ProjectStatus;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package se.su.dsv.scipro.milestones.service.impl;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import se.su.dsv.scipro.system.Sort;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestonePhaseTemplate;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.QMilestonePhaseTemplate;
|
||||
import se.su.dsv.scipro.milestones.service.MilestonePhaseTemplateService;
|
||||
|
@ -4,7 +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 org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.Milestone;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.QMilestone;
|
||||
|
@ -8,8 +8,8 @@ import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.core.types.dsl.StringPath;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.system.Sort;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.Milestone;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
|
||||
import se.su.dsv.scipro.milestones.dataobjects.QMilestone;
|
||||
|
@ -3,7 +3,7 @@ package se.su.dsv.scipro.notifications;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.notifications.dataobject.Notification;
|
||||
import se.su.dsv.scipro.notifications.dataobject.NotificationEvent;
|
||||
import se.su.dsv.scipro.notifications.dataobject.QNotification;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.peer;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
|
||||
|
||||
@Transactional
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.peer;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
|
||||
@Transactional
|
||||
public interface PeerRequestRepository extends JpaRepository<PeerRequest, Long>, QueryDslPredicateExecutor<PeerRequest> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.peer;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.*;
|
||||
|
||||
|
@ -4,7 +4,7 @@ import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.file.FileReference;
|
||||
import se.su.dsv.scipro.file.FileService;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package se.su.dsv.scipro.peer;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.peer;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.*;
|
||||
|
||||
|
@ -3,7 +3,7 @@ package se.su.dsv.scipro.peer;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
import se.su.dsv.scipro.system.Language;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.plagiarism;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.file.FileDescription;
|
||||
|
||||
import java.util.Optional;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package se.su.dsv.scipro.project;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -5,7 +5,7 @@ import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.data.dataobjects.Member;
|
||||
import se.su.dsv.scipro.reusable.SciProUtilities;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.projectpartner;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.match.ApplicationPeriod;
|
||||
import se.su.dsv.scipro.system.GenericService;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
@ -3,7 +3,7 @@ package se.su.dsv.scipro.projectpartner;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.match.ApplicationPeriod;
|
||||
import se.su.dsv.scipro.match.QIdea;
|
||||
import se.su.dsv.scipro.match.QIdeaParticipation;
|
||||
|
@ -1,17 +1,42 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
|
||||
@MappedSuperclass
|
||||
public abstract class AbstractGradingCriterion extends AbstractCriterion {
|
||||
|
||||
public enum Flag {
|
||||
/**
|
||||
* Criterion marked with this flag will add extra functionality related
|
||||
* to the authors submitted reflection. It should only be used on
|
||||
* individual criteria.
|
||||
*/
|
||||
REFLECTION,
|
||||
/**
|
||||
* Criterion marked with this flag will add extra functionality related
|
||||
* to the authors performed opposition. For example, it will have its
|
||||
* points and feedback filled in when the seminar supervisor assesses
|
||||
* their opposition and submitted report. It should only be used on
|
||||
* individual criteria.
|
||||
*/
|
||||
OPPOSITION
|
||||
}
|
||||
|
||||
@Basic(optional = false)
|
||||
protected int pointsRequiredToPass;
|
||||
|
||||
@Basic
|
||||
private boolean fx = true;
|
||||
|
||||
@Basic
|
||||
@Column(name = "flag")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Flag flag;
|
||||
|
||||
protected AbstractGradingCriterion() {
|
||||
|
||||
}
|
||||
@ -21,6 +46,17 @@ public abstract class AbstractGradingCriterion extends AbstractCriterion {
|
||||
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();
|
||||
@ -35,6 +71,14 @@ public abstract class AbstractGradingCriterion extends AbstractCriterion {
|
||||
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;
|
||||
|
@ -0,0 +1,23 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class DuplicateDateException extends Exception {
|
||||
private final LocalDate validFrom;
|
||||
private final ProjectType projectType;
|
||||
|
||||
public DuplicateDateException(LocalDate validFrom, ProjectType projectType) {
|
||||
this.validFrom = validFrom;
|
||||
this.projectType = projectType;
|
||||
}
|
||||
|
||||
public LocalDate validFrom() {
|
||||
return validFrom;
|
||||
}
|
||||
|
||||
public ProjectType projectType() {
|
||||
return projectType;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.report.calculators.original.SupervisorBachelorGradeCalculator;
|
||||
import se.su.dsv.scipro.report.calculators.original.SupervisorMaster15GradeCalculator;
|
||||
@ -8,8 +9,21 @@ import se.su.dsv.scipro.system.DegreeType;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
||||
public class GradeCalculatorServiceImpl implements GradeCalculatorService {
|
||||
|
||||
private final GradingReportService gradingReportTemplateService;
|
||||
|
||||
@Inject
|
||||
public GradeCalculatorServiceImpl(GradingReportService gradingReportService) {
|
||||
this.gradingReportTemplateService = gradingReportService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradeCalculator getSupervisorCalculator(final Project project) {
|
||||
GradingReportTemplate template = gradingReportTemplateService.getTemplate(project);
|
||||
if (!template.getGradeLimits().isEmpty()) {
|
||||
return new GradingReportTemplateGradeCalculator(template);
|
||||
}
|
||||
|
||||
DegreeType degreeType = project.getProjectType().getDegreeType();
|
||||
if (degreeType == DegreeType.BACHELOR) {
|
||||
if (getYear(project) >= 2017) {
|
||||
|
46
core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java
Normal file
46
core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java
Normal file
@ -0,0 +1,46 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
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 = "grading_report_template_grade_limits")
|
||||
public class GradeLimit {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "grade")
|
||||
private String grade;
|
||||
|
||||
@Column(name = "lower_limit")
|
||||
private int lowerLimit;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getGrade() {
|
||||
return grade;
|
||||
}
|
||||
|
||||
public void setGrade(String grade) {
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
public int getLowerLimit() {
|
||||
return lowerLimit;
|
||||
}
|
||||
|
||||
public void setLowerLimit(int lowerLimit) {
|
||||
this.lowerLimit = lowerLimit;
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ public abstract class GradingCriterion extends AbstractGradingCriterion {
|
||||
}
|
||||
|
||||
GradingCriterion(GradingReport gradingReport, GradingCriterionTemplate gradingCriterionTemplate) {
|
||||
super(gradingCriterionTemplate.getTitle(), gradingCriterionTemplate.getTitleEn(), gradingCriterionTemplate.getSortOrder(), gradingCriterionTemplate.getPointsRequiredToPass());
|
||||
super(gradingCriterionTemplate.getTitle(), gradingCriterionTemplate.getTitleEn(), gradingCriterionTemplate.getSortOrder(), gradingCriterionTemplate.getPointsRequiredToPass(), gradingCriterionTemplate.getFlag());
|
||||
this.gradingReport = gradingReport;
|
||||
for (GradingCriterionPointTemplate pointTemplate : gradingCriterionTemplate.getGradingCriterionPointTemplates()) {
|
||||
gradingCriterionPoints.add(new GradingCriterionPoint(
|
||||
|
@ -15,8 +15,14 @@ import java.util.stream.Collectors;
|
||||
@Entity
|
||||
public abstract class GradingReport extends Report {
|
||||
|
||||
public enum Grade {
|
||||
A, B, C, D, E, F, FX
|
||||
public record Grade(String name) {
|
||||
public static final Grade A = new Grade("A");
|
||||
public static final Grade B = new Grade("B");
|
||||
public static final Grade C = new Grade("C");
|
||||
public static final Grade D = new Grade("D");
|
||||
public static final Grade E = new Grade("E");
|
||||
public static final Grade F = new Grade("F");
|
||||
public static final Grade FX = new Grade("FX");
|
||||
}
|
||||
|
||||
public enum State { INITIAL, REVIEWING, FINALIZED }
|
||||
|
@ -3,14 +3,13 @@ package se.su.dsv.scipro.report;
|
||||
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
||||
import se.su.dsv.scipro.grading.GradingBasis;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.GenericService;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
import se.su.dsv.scipro.util.Either;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
public interface GradingReportService extends GenericService<GradingReport, Long> {
|
||||
public interface GradingReportService {
|
||||
|
||||
SupervisorGradingReport getSupervisorGradingReport(Project project, User student);
|
||||
|
||||
|
@ -2,54 +2,60 @@ package se.su.dsv.scipro.report;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
||||
import se.su.dsv.scipro.grading.GradingBasis;
|
||||
import se.su.dsv.scipro.grading.GradingReportTemplateService;
|
||||
import se.su.dsv.scipro.grading.GradingReportTemplateUpdate;
|
||||
import se.su.dsv.scipro.grading.ThesisSubmissionHistoryService;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.AbstractServiceImpl;
|
||||
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.ProjectTypeService;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
import se.su.dsv.scipro.util.Either;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Provider;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
|
||||
@Named
|
||||
public class GradingReportServiceImpl extends AbstractServiceImpl<GradingReport, Long> implements GradingReportService {
|
||||
public class GradingReportServiceImpl implements GradingReportTemplateService, GradingReportService {
|
||||
|
||||
public static final String OPPOSITION_SWEDISH = "Ö1 Oppositionsrapport";
|
||||
public static final String OPPOSITION_ENGLISH = "Ö1 Opposition report";
|
||||
private final EventBus eventBus;
|
||||
private final ThesisSubmissionHistoryService thesisSubmissionHistoryService;
|
||||
private final Clock clock;
|
||||
private final SupervisorGradingReportRepository supervisorGradingReportRepository;
|
||||
private final GradingReportTemplateRepo gradingReportTemplateRepo;
|
||||
private final ProjectTypeService projectTypeService;
|
||||
|
||||
@Inject
|
||||
public GradingReportServiceImpl(
|
||||
Provider<EntityManager> em,
|
||||
EventBus eventBus,
|
||||
ThesisSubmissionHistoryService thesisSubmissionHistoryService,
|
||||
Clock clock)
|
||||
Clock clock,
|
||||
SupervisorGradingReportRepository supervisorGradingReportRepository,
|
||||
GradingReportTemplateRepo gradingReportTemplateRepo,
|
||||
ProjectTypeService projectTypeService)
|
||||
{
|
||||
super(em, GradingReport.class, QGradingReport.gradingReport);
|
||||
this.eventBus = eventBus;
|
||||
this.thesisSubmissionHistoryService = thesisSubmissionHistoryService;
|
||||
this.clock = clock;
|
||||
this.supervisorGradingReportRepository = supervisorGradingReportRepository;
|
||||
this.gradingReportTemplateRepo = gradingReportTemplateRepo;
|
||||
this.projectTypeService = projectTypeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateOppositionCriteria(SupervisorGradingReport report, FinalSeminarOpposition opposition) {
|
||||
for (GradingCriterion gradingCriterion : report.getIndividualCriteria()) {
|
||||
boolean isOppositionCriterion = gradingCriterion.getTitle().equals(OPPOSITION_SWEDISH) || gradingCriterion.getTitle().equals(OPPOSITION_ENGLISH);
|
||||
boolean isOppositionCriterion = gradingCriterion.getFlag() == GradingCriterion.Flag.OPPOSITION;
|
||||
boolean betterGrade = gradingCriterion.getPoints() == null || opposition.getPoints() > gradingCriterion.getPoints();
|
||||
if (isOppositionCriterion && betterGrade) {
|
||||
gradingCriterion.setFeedback(opposition.getFeedback());
|
||||
gradingCriterion.setPoints(opposition.getPoints());
|
||||
save(report);
|
||||
supervisorGradingReportRepository.save(report);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -88,7 +94,7 @@ public class GradingReportServiceImpl extends AbstractServiceImpl<GradingReport,
|
||||
}
|
||||
supervisorGradingReport.setMotivation(gradingBasis.getOverallMotivation());
|
||||
supervisorGradingReport.setRejectionCommentFeedback(gradingBasis.getRejectionCommentFeedback());
|
||||
save(supervisorGradingReport);
|
||||
supervisorGradingReportRepository.save(supervisorGradingReport);
|
||||
}
|
||||
return getGradingBasis(project);
|
||||
}
|
||||
@ -138,22 +144,18 @@ public class GradingReportServiceImpl extends AbstractServiceImpl<GradingReport,
|
||||
@Override
|
||||
@Transactional
|
||||
public SupervisorGradingReport getSupervisorGradingReport(Project project, User user) {
|
||||
SupervisorGradingReport supervisorGradingReport = from(QSupervisorGradingReport.supervisorGradingReport)
|
||||
.where(QSupervisorGradingReport.supervisorGradingReport.user.eq(user).and(
|
||||
QSupervisorGradingReport.supervisorGradingReport.project.eq(project)))
|
||||
.fetchOne();
|
||||
SupervisorGradingReport supervisorGradingReport = supervisorGradingReportRepository.getReport(project, user);
|
||||
if (supervisorGradingReport == null) {
|
||||
supervisorGradingReport = save(getTemplate(project).createSupervisorReport(project, user));
|
||||
GradingReportTemplate template = getTemplate(project);
|
||||
SupervisorGradingReport supervisorReport = template.createSupervisorReport(project, user);
|
||||
supervisorGradingReport = supervisorGradingReportRepository.save(supervisorReport);
|
||||
}
|
||||
return supervisorGradingReport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate getTemplate(Project project) {
|
||||
QGradingReportTemplate template = QGradingReportTemplate.gradingReportTemplate;
|
||||
return from(template)
|
||||
.where(template.projectType.eq(project.getProjectType()).and(template.credits.eq(project.getCredits())))
|
||||
.fetchOne();
|
||||
return gradingReportTemplateRepo.getTemplate(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -192,11 +194,100 @@ public class GradingReportServiceImpl extends AbstractServiceImpl<GradingReport,
|
||||
rejectionCommentFeedback);
|
||||
}
|
||||
|
||||
save(supervisorGradingReport);
|
||||
supervisorGradingReportRepository.save(supervisorGradingReport);
|
||||
return Either.right(supervisorGradingReport);
|
||||
}
|
||||
|
||||
private static boolean isBlank(final String str) {
|
||||
return str == null || str.isBlank();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProjectType> getProjectTypes() {
|
||||
return projectTypeService.findWithModule(ProjectModule.GRADING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate getCurrentTemplate(ProjectType projectType) {
|
||||
return gradingReportTemplateRepo.getCurrentTemplate(projectType, LocalDate.now(clock));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate getTemplate(long templateId) {
|
||||
return gradingReportTemplateRepo.findOne(templateId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate getEndDate(GradingReportTemplate gradingReportTemplate) {
|
||||
GradingReportTemplate next = gradingReportTemplateRepo.getNextTemplate(gradingReportTemplate);
|
||||
if (next == null) {
|
||||
return null;
|
||||
} else {
|
||||
return next.getValidFrom().minusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GradingReportTemplate> getUpcomingTemplates(ProjectType projectType) {
|
||||
GradingReportTemplate current = getCurrentTemplate(projectType);
|
||||
if (current == null) {
|
||||
return gradingReportTemplateRepo.getTemplatesValidAfter(projectType, LocalDate.now(clock));
|
||||
} else {
|
||||
return gradingReportTemplateRepo.getTemplatesValidAfter(projectType, current.getValidFrom());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate update(long templateId, GradingReportTemplateUpdate update)
|
||||
throws ValidDateMustBeInTheFutureException,
|
||||
NoSuchTemplateException,
|
||||
DuplicateDateException,
|
||||
TemplateLockedException
|
||||
{
|
||||
LocalDate today = LocalDate.now(clock);
|
||||
if (!update.validFrom().isAfter(today)) {
|
||||
throw new ValidDateMustBeInTheFutureException(update.validFrom(), today.plusDays(1));
|
||||
}
|
||||
|
||||
GradingReportTemplate template = gradingReportTemplateRepo.getTemplateById(templateId);
|
||||
if (template == null) {
|
||||
throw new NoSuchTemplateException();
|
||||
}
|
||||
|
||||
GradingReportTemplate currentTemplate = gradingReportTemplateRepo.getCurrentTemplate(
|
||||
template.getProjectType(),
|
||||
update.validFrom());
|
||||
if (currentTemplate.getId() != templateId &&
|
||||
Objects.equals(currentTemplate.getValidFrom(), update.validFrom()))
|
||||
{
|
||||
throw new DuplicateDateException(update.validFrom(), template.getProjectType());
|
||||
}
|
||||
|
||||
if (!template.getValidFrom().isAfter(today)) {
|
||||
throw new TemplateLockedException(template.getValidFrom());
|
||||
}
|
||||
|
||||
return gradingReportTemplateRepo.updateTemplate(templateId, update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate create(ProjectType projectType, GradingReportTemplateUpdate update)
|
||||
throws ValidDateMustBeInTheFutureException, DuplicateDateException
|
||||
{
|
||||
LocalDate today = LocalDate.now(clock);
|
||||
if (!update.validFrom().isAfter(today)) {
|
||||
throw new ValidDateMustBeInTheFutureException(update.validFrom(), today.plusDays(1));
|
||||
}
|
||||
|
||||
GradingReportTemplate currentTemplate = gradingReportTemplateRepo.getCurrentTemplate(
|
||||
projectType,
|
||||
update.validFrom());
|
||||
if (currentTemplate != null &&
|
||||
Objects.equals(currentTemplate.getValidFrom(), update.validFrom()))
|
||||
{
|
||||
throw new DuplicateDateException(update.validFrom(), projectType);
|
||||
}
|
||||
|
||||
return gradingReportTemplateRepo.createTemplate(projectType, update);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ 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;
|
||||
@ -23,22 +26,35 @@ public class GradingReportTemplate extends DomainObject {
|
||||
@OneToOne(optional = false)
|
||||
private ProjectType projectType;
|
||||
|
||||
@OneToMany(mappedBy = "gradingReportTemplate", cascade = {CascadeType.ALL})
|
||||
@OneToMany(mappedBy = "gradingReportTemplate", cascade = {CascadeType.ALL}, orphanRemoval = true)
|
||||
private Collection<GradingCriterionTemplate> criteria = new HashSet<>();
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "valid_from")
|
||||
private LocalDate validFrom;
|
||||
|
||||
@Basic
|
||||
private int credits;
|
||||
@Column(name = "note")
|
||||
private String note;
|
||||
|
||||
@Basic
|
||||
@Column(name = "failing_grade")
|
||||
private String failingGrade;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "grading_report_template_id")
|
||||
private Collection<GradeLimit> gradeLimits = new ArrayList<>();
|
||||
|
||||
protected GradingReportTemplate() {
|
||||
|
||||
}
|
||||
|
||||
public GradingReportTemplate(ProjectType projectType, int credits) {
|
||||
public GradingReportTemplate(ProjectType projectType, LocalDate validFrom) {
|
||||
if (projectType == null) {
|
||||
throw new IllegalArgumentException("ProjectType may not be null");
|
||||
}
|
||||
this.projectType = projectType;
|
||||
this.credits = credits;
|
||||
this.validFrom = validFrom;
|
||||
}
|
||||
|
||||
public SupervisorGradingReport createSupervisorReport(Project project, User student) {
|
||||
@ -53,18 +69,28 @@ public class GradingReportTemplate extends DomainObject {
|
||||
}
|
||||
|
||||
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 Iterable<GradingCriterionTemplate> getCriteria() {
|
||||
public Collection<GradingCriterionTemplate> getCriteria() {
|
||||
return criteria;
|
||||
}
|
||||
|
||||
@ -73,6 +99,46 @@ public class GradingReportTemplate extends DomainObject {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public LocalDate getValidFrom() {
|
||||
return validFrom;
|
||||
}
|
||||
|
||||
public void setValidFrom(LocalDate validFrom) {
|
||||
this.validFrom = validFrom;
|
||||
}
|
||||
|
||||
public ProjectType getProjectType() {
|
||||
return projectType;
|
||||
}
|
||||
|
||||
public void setProjectType(ProjectType projectType) {
|
||||
this.projectType = projectType;
|
||||
}
|
||||
|
||||
public String getNote() {
|
||||
return note;
|
||||
}
|
||||
|
||||
public void setNote(String note) {
|
||||
this.note = note;
|
||||
}
|
||||
|
||||
public String getFailingGrade() {
|
||||
return failingGrade;
|
||||
}
|
||||
|
||||
public void setFailingGrade(String failingGrade) {
|
||||
this.failingGrade = failingGrade;
|
||||
}
|
||||
|
||||
public Collection<GradeLimit> getGradeLimits() {
|
||||
return gradeLimits;
|
||||
}
|
||||
|
||||
public void setGradeLimits(Collection<GradeLimit> gradeLimits) {
|
||||
this.gradeLimits = gradeLimits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (o == this) return true;
|
||||
@ -93,6 +159,6 @@ public class GradingReportTemplate extends DomainObject {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GradingReportTemplate(id=" + this.id + ", projectType=" + this.projectType + ", credits=" + this.credits + ")";
|
||||
return "GradingReportTemplate(id=" + this.id + ", projectType=" + this.projectType + ", validFrom=" + this.validFrom + ")";
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
class GradingReportTemplateGradeCalculator implements GradeCalculator {
|
||||
private final GradingReportTemplate template;
|
||||
|
||||
GradingReportTemplateGradeCalculator(GradingReportTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReport.Grade getGrade(GradingReport gradingReport) {
|
||||
for (GradingCriterion gradingCriterion : gradingReport.getGradingCriteria()) {
|
||||
if (!gradingCriterion.meetsMinimumPointRequirement()) {
|
||||
return new GradingReport.Grade(template.getFailingGrade());
|
||||
}
|
||||
}
|
||||
long points = getPoints(gradingReport);
|
||||
String textualGrade = template.getGradeLimits()
|
||||
.stream()
|
||||
.filter(gradeLimit -> points >= gradeLimit.getLowerLimit())
|
||||
.max(Comparator.comparing(GradeLimit::getLowerLimit))
|
||||
.map(GradeLimit::getGrade)
|
||||
.orElseGet(template::getFailingGrade);
|
||||
return new GradingReport.Grade(textualGrade);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPoints(GradingReport gradingReport) {
|
||||
return gradingReport.getGradingCriteria()
|
||||
.stream()
|
||||
.map(GradingCriterion::getPoints)
|
||||
.filter(Objects::nonNull)
|
||||
.mapToInt(Integer::intValue)
|
||||
.sum();
|
||||
}
|
||||
}
|
@ -1,8 +1,25 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.grading.GradingReportTemplateUpdate;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface GradingReportTemplateRepo extends JpaRepository<GradingReportTemplate, Long> {
|
||||
GradingReportTemplate findByProjectTypeAndCredits(ProjectType projectType, int credits);
|
||||
GradingReportTemplate getTemplate(Project project);
|
||||
|
||||
GradingReportTemplate getCurrentTemplate(ProjectType projectType, LocalDate now);
|
||||
|
||||
GradingReportTemplate getNextTemplate(GradingReportTemplate gradingReportTemplate);
|
||||
|
||||
List<GradingReportTemplate> getTemplatesValidAfter(ProjectType projectType, LocalDate date);
|
||||
|
||||
GradingReportTemplate getTemplateById(long templateId);
|
||||
|
||||
GradingReportTemplate updateTemplate(long templateId, GradingReportTemplateUpdate update);
|
||||
|
||||
GradingReportTemplate createTemplate(ProjectType projectType, GradingReportTemplateUpdate update);
|
||||
}
|
||||
|
@ -1,12 +1,19 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
import se.su.dsv.scipro.grading.GradingReportTemplateUpdate;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.GenericRepo;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Provider;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public class GradingReportTemplateRepoImpl extends GenericRepo<GradingReportTemplate, Long> implements GradingReportTemplateRepo {
|
||||
@Inject
|
||||
@ -15,10 +22,114 @@ public class GradingReportTemplateRepoImpl extends GenericRepo<GradingReportTemp
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate findByProjectTypeAndCredits(ProjectType projectType, int credits) {
|
||||
TypedQuery<GradingReportTemplate> query = em().createQuery("select distinct template from GradingReportTemplate template where template.projectType = :projectType and template.credits = :credits", GradingReportTemplate.class);
|
||||
query.setParameter("projectType", projectType);
|
||||
query.setParameter("credits", credits);
|
||||
return query.getSingleResult();
|
||||
public GradingReportTemplate getTemplate(Project project) {
|
||||
return getCurrentTemplate(project.getProjectType(), project.getStartDate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate getCurrentTemplate(ProjectType projectType, LocalDate now) {
|
||||
QGradingReportTemplate template = QGradingReportTemplate.gradingReportTemplate;
|
||||
// find the latest template that is valid for the project
|
||||
JPQLQuery<LocalDate> validFrom = JPAExpressions
|
||||
.select(template.validFrom.max())
|
||||
.from(template)
|
||||
.where(template.projectType.eq(projectType)
|
||||
.and(template.validFrom.loe(now)));
|
||||
return findOne(template.projectType.eq(projectType).and(template.validFrom.eq(validFrom)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate getNextTemplate(GradingReportTemplate gradingReportTemplate) {
|
||||
QGradingReportTemplate template = QGradingReportTemplate.gradingReportTemplate;
|
||||
// find the latest template that is valid for the project
|
||||
JPQLQuery<LocalDate> validFrom = JPAExpressions
|
||||
.select(template.validFrom.min())
|
||||
.from(template)
|
||||
.where(template.projectType.eq(gradingReportTemplate.getProjectType())
|
||||
.and(template.validFrom.gt(gradingReportTemplate.getValidFrom())));
|
||||
return findOne(template.projectType.eq(gradingReportTemplate.getProjectType()).and(template.validFrom.eq(validFrom)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GradingReportTemplate> getTemplatesValidAfter(ProjectType projectType, LocalDate date) {
|
||||
return findAll(QGradingReportTemplate.gradingReportTemplate.projectType.eq(projectType)
|
||||
.and(QGradingReportTemplate.gradingReportTemplate.validFrom.gt(date)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradingReportTemplate getTemplateById(long templateId) {
|
||||
return findOne(templateId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public GradingReportTemplate updateTemplate(long templateId, GradingReportTemplateUpdate update) {
|
||||
GradingReportTemplate gradingReportTemplate = findOne(templateId);
|
||||
return updateTemplate(gradingReportTemplate, update);
|
||||
}
|
||||
|
||||
private GradingReportTemplate updateTemplate(
|
||||
GradingReportTemplate gradingReportTemplate,
|
||||
GradingReportTemplateUpdate update)
|
||||
{
|
||||
gradingReportTemplate.setValidFrom(update.validFrom());
|
||||
gradingReportTemplate.setNote(update.note());
|
||||
gradingReportTemplate.setFailingGrade(update.failingGrade());
|
||||
|
||||
gradingReportTemplate.getCriteria().clear();
|
||||
for (var criteria : update.criteria()) {
|
||||
final List<GradingCriterionPointTemplate> pointTemplates = criteria.requirements()
|
||||
.stream()
|
||||
.map(this::toPointTemplate)
|
||||
.toList();
|
||||
AbstractGradingCriterion.Flag flag = criteria.flag() == null ? null : switch (criteria.flag()) {
|
||||
case OPPOSITION -> AbstractGradingCriterion.Flag.OPPOSITION;
|
||||
case REFLECTION -> AbstractGradingCriterion.Flag.REFLECTION;
|
||||
//case null -> null; sigh java 17
|
||||
};
|
||||
switch (criteria.type()) {
|
||||
case THESIS -> {
|
||||
gradingReportTemplate.addProjectCriterion(
|
||||
criteria.title().swedish(),
|
||||
criteria.title().english(),
|
||||
criteria.minimumPointsRequiredToPass(),
|
||||
pointTemplates,
|
||||
flag);
|
||||
}
|
||||
case INDIVIDUAL -> {
|
||||
gradingReportTemplate.addIndividualCriterion(
|
||||
criteria.title().swedish(),
|
||||
criteria.title().english(),
|
||||
criteria.minimumPointsRequiredToPass(),
|
||||
pointTemplates,
|
||||
flag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gradingReportTemplate.getGradeLimits().clear();
|
||||
for (var grade : update.gradeLimits()) {
|
||||
GradeLimit gradeLimit = new GradeLimit();
|
||||
gradeLimit.setGrade(grade.grade());
|
||||
gradeLimit.setLowerLimit(grade.minimumPoints());
|
||||
gradingReportTemplate.getGradeLimits().add(gradeLimit);
|
||||
}
|
||||
|
||||
return save(gradingReportTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public GradingReportTemplate createTemplate(ProjectType projectType, GradingReportTemplateUpdate update) {
|
||||
GradingReportTemplate gradingReportTemplate = new GradingReportTemplate(projectType, update.validFrom());
|
||||
return updateTemplate(gradingReportTemplate, update);
|
||||
}
|
||||
|
||||
private GradingCriterionPointTemplate toPointTemplate(GradingReportTemplateUpdate.Criteria.Requirement requirement) {
|
||||
return new GradingCriterionPointTemplate.Builder()
|
||||
.point(requirement.points())
|
||||
.description(requirement.description().swedish())
|
||||
.descriptionEn(requirement.description().english())
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
public class NoSuchTemplateException extends Exception {
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
|
||||
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
||||
|
||||
public interface OppositionReportRepo extends JpaRepository<OppositionReport, Long>, QueryDslPredicateExecutor<OppositionReport> {
|
||||
|
@ -33,7 +33,7 @@ public class OppositionReportServiceImpl implements OppositionReportService {
|
||||
if (oppositionReport != null) {
|
||||
return oppositionReport;
|
||||
} else {
|
||||
OppositionReport newReport = gradingReportTemplateRepo.findByProjectTypeAndCredits(finalSeminarOpposition.getProjectType(), finalSeminarOpposition.getProject().getCredits())
|
||||
OppositionReport newReport = gradingReportTemplateRepo.getTemplate(finalSeminarOpposition.getProject())
|
||||
.createOppositionReport(finalSeminarOpposition);
|
||||
return oppositionReportRepo.save(newReport);
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
public interface SupervisorGradingReportRepository {
|
||||
SupervisorGradingReport save(SupervisorGradingReport report);
|
||||
|
||||
SupervisorGradingReport getReport(Project project, User author);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Provider;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.AbstractRepository;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
public class SupervisorGradingReportRepositoryImpl extends AbstractRepository
|
||||
implements SupervisorGradingReportRepository
|
||||
{
|
||||
@Inject
|
||||
public SupervisorGradingReportRepositoryImpl(Provider<EntityManager> em) {
|
||||
super(em);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SupervisorGradingReport save(SupervisorGradingReport report) {
|
||||
EntityManager entityManager = em();
|
||||
if (entityManager.contains(report)) {
|
||||
return entityManager.merge(report);
|
||||
}
|
||||
else {
|
||||
entityManager.persist(report);
|
||||
return report;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SupervisorGradingReport getReport(Project project, User author) {
|
||||
return from(QSupervisorGradingReport.supervisorGradingReport)
|
||||
.where(QSupervisorGradingReport.supervisorGradingReport.user.eq(author).and(
|
||||
QSupervisorGradingReport.supervisorGradingReport.project.eq(project)))
|
||||
.fetchOne();
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class TemplateLockedException extends Exception {
|
||||
private final LocalDate becameValidAt;
|
||||
|
||||
public TemplateLockedException(LocalDate becameValidAt) {
|
||||
this.becameValidAt = becameValidAt;
|
||||
}
|
||||
|
||||
public LocalDate becameValidAt() {
|
||||
return becameValidAt;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package se.su.dsv.scipro.report;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class ValidDateMustBeInTheFutureException extends Exception {
|
||||
private final LocalDate validFrom;
|
||||
private final LocalDate earliestAllowedValidFrom;
|
||||
|
||||
public ValidDateMustBeInTheFutureException(LocalDate validFrom, LocalDate earliestAllowedValidFrom) {
|
||||
this.validFrom = validFrom;
|
||||
this.earliestAllowedValidFrom = earliestAllowedValidFrom;
|
||||
}
|
||||
|
||||
public LocalDate validFrom() {
|
||||
return validFrom;
|
||||
}
|
||||
|
||||
public LocalDate earliestAllowedValidFrom() {
|
||||
return earliestAllowedValidFrom;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.reviewing;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.project.ProjectStatus;
|
||||
import se.su.dsv.scipro.system.GenericService;
|
||||
|
@ -7,7 +7,7 @@ import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.core.types.dsl.StringPath;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.finalseminar.QFinalSeminar;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.project.ProjectStatus;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.reviewing;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.forum.dataobjects.ReviewerThread;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
|
||||
|
@ -3,7 +3,7 @@ package se.su.dsv.scipro.springdata.serviceimpls;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.match.ApplicationPeriod;
|
||||
import se.su.dsv.scipro.match.QTarget;
|
||||
import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.springdata.services;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import se.su.dsv.scipro.system.Pageable;
|
||||
import se.su.dsv.scipro.match.ApplicationPeriod;
|
||||
import se.su.dsv.scipro.system.*;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.survey;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
|
||||
public interface QuestionRepository extends JpaRepository<Question, Long> {
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package se.su.dsv.scipro.survey;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import se.su.dsv.scipro.system.JpaRepository;
|
||||
import se.su.dsv.scipro.project.Project;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
|
@ -6,8 +6,6 @@ import com.querydsl.core.types.dsl.EntityPathBase;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.core.types.dsl.StringPath;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
import jakarta.inject.Provider;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
@ -1,7 +1,5 @@
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
|
||||
@Transactional
|
||||
public interface FooterAddressRepo extends JpaRepository<FooterAddress, Long>, QueryDslPredicateExecutor<FooterAddress> {
|
||||
|
@ -1,8 +1,6 @@
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -6,10 +6,6 @@ import com.querydsl.core.types.dsl.EntityPathBase;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.core.types.dsl.StringPath;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
|
||||
import jakarta.inject.Provider;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
@ -1,7 +1,6 @@
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.springframework.data.jpa.repository;
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
@ -1,6 +1,5 @@
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.springframework.data.domain;
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import java.util.Objects;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.springframework.data.domain;
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
public interface Pageable {
|
||||
long getOffset();
|
@ -1,8 +1,6 @@
|
||||
package se.su.dsv.scipro.system;
|
||||
|
||||
import com.google.inject.persist.Transactional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
|
||||
|
||||
@Transactional
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user