Allow supervisors to request improvements from final seminar opponents #78
@ -28,6 +28,7 @@ import se.su.dsv.scipro.file.ProjectFileRepository;
|
|||||||
import se.su.dsv.scipro.file.ProjectFileService;
|
import se.su.dsv.scipro.file.ProjectFileService;
|
||||||
import se.su.dsv.scipro.file.ProjectFileServiceImpl;
|
import se.su.dsv.scipro.file.ProjectFileServiceImpl;
|
||||||
import se.su.dsv.scipro.finalseminar.AuthorRepository;
|
import se.su.dsv.scipro.finalseminar.AuthorRepository;
|
||||||
|
import se.su.dsv.scipro.finalseminar.ExpireUnfulfilledOppositionImprovementsWorker;
|
||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepository;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepository;
|
||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationServiceImpl;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationServiceImpl;
|
||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarCreationSubscribers;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarCreationSubscribers;
|
||||||
@ -204,6 +205,7 @@ import se.su.dsv.scipro.system.UserRepo;
|
|||||||
import se.su.dsv.scipro.system.UserService;
|
import se.su.dsv.scipro.system.UserService;
|
||||||
import se.su.dsv.scipro.system.UserServiceImpl;
|
import se.su.dsv.scipro.system.UserServiceImpl;
|
||||||
import se.su.dsv.scipro.thesislink.ExternalLinkServiceImpl;
|
import se.su.dsv.scipro.thesislink.ExternalLinkServiceImpl;
|
||||||
|
import se.su.dsv.scipro.workerthreads.Scheduler;
|
||||||
import se.su.dsv.scipro.workerthreads.WorkerDataServiceImpl;
|
import se.su.dsv.scipro.workerthreads.WorkerDataServiceImpl;
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ -1167,4 +1169,19 @@ public class CoreConfig {
|
|||||||
notificationController
|
notificationController
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ExpireUnfulfilledOppositionImprovementsWorker expireUnfulfilledOppositionImprovementsWorker(
|
||||||
|
FinalSeminarOppositionServiceImpl finalSeminarOppositionService
|
||||||
|
) {
|
||||||
|
return new ExpireUnfulfilledOppositionImprovementsWorker(finalSeminarOppositionService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ExpireUnfulfilledOppositionImprovementsWorker.Schedule expireUnfulfilledOppositionImprovementsWorkerSchedule(
|
||||||
|
Scheduler scheduler,
|
||||||
|
Provider<ExpireUnfulfilledOppositionImprovementsWorker> worker
|
||||||
|
) {
|
||||||
|
return new ExpireUnfulfilledOppositionImprovementsWorker.Schedule(scheduler, worker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package se.su.dsv.scipro.finalseminar;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.inject.Provider;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import se.su.dsv.scipro.workerthreads.AbstractWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.Scheduler;
|
||||||
|
|
||||||
|
public class ExpireUnfulfilledOppositionImprovementsWorker extends AbstractWorker {
|
||||||
|
|
||||||
|
private final FinalSeminarOppositionServiceImpl oppositionService;
|
||||||
|
|
||||||
|
public ExpireUnfulfilledOppositionImprovementsWorker(FinalSeminarOppositionServiceImpl oppositionService) {
|
||||||
|
this.oppositionService = oppositionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWork() {
|
||||||
|
oppositionService.expireUnfulfilledOppositionImprovements();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Schedule {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Schedule(Scheduler scheduler, Provider<ExpireUnfulfilledOppositionImprovementsWorker> worker) {
|
||||||
|
scheduler
|
||||||
|
.schedule("Fail opponents that have not submitted improvements")
|
||||||
|
.runBy(worker)
|
||||||
|
.every(1, TimeUnit.HOURS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,4 +11,6 @@ import se.su.dsv.scipro.system.User;
|
|||||||
public interface FinalSeminarOppositionRepo
|
public interface FinalSeminarOppositionRepo
|
||||||
extends JpaRepository<FinalSeminarOpposition, Long>, QueryDslPredicateExecutor<FinalSeminarOpposition> {
|
extends JpaRepository<FinalSeminarOpposition, Long>, QueryDslPredicateExecutor<FinalSeminarOpposition> {
|
||||||
List<FinalSeminarOpposition> findByOpposingUserAndType(User user, ProjectType projectType);
|
List<FinalSeminarOpposition> findByOpposingUserAndType(User user, ProjectType projectType);
|
||||||
|
|
||||||
|
Collection<FinalSeminarOpposition> findUnfulfilledOppositionImprovements();
|
||||||
}
|
}
|
||||||
|
@ -24,4 +24,13 @@ public class FinalSeminarOppositionRepoImpl
|
|||||||
.where(QFinalSeminarOpposition.finalSeminarOpposition.project.projectType.eq(projectType))
|
.where(QFinalSeminarOpposition.finalSeminarOpposition.project.projectType.eq(projectType))
|
||||||
.fetch();
|
.fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<FinalSeminarOpposition> findUnfulfilledOppositionImprovements() {
|
||||||
|
return createQuery()
|
||||||
|
.innerJoin(QFinalSeminarOpposition.finalSeminarOpposition.oppositionReport)
|
||||||
|
.where(QFinalSeminarOpposition.finalSeminarOpposition.improvementsRequestedAt.isNotNull())
|
||||||
|
.where(QFinalSeminarOpposition.finalSeminarOpposition.oppositionReport.submitted.isFalse())
|
||||||
|
.fetch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import jakarta.persistence.EntityManager;
|
|||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import se.su.dsv.scipro.misc.DaysService;
|
import se.su.dsv.scipro.misc.DaysService;
|
||||||
@ -65,11 +66,24 @@ public class FinalSeminarOppositionServiceImpl
|
|||||||
throw new PointNotValidException(points, List.of(0, 1));
|
throw new PointNotValidException(points, List.of(0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FinalSeminarGrade notApproved = criteriaForOpposition.pointsToPass() > points
|
||||||
|
? FinalSeminarGrade.NOT_APPROVED
|
||||||
|
: FinalSeminarGrade.APPROVED;
|
||||||
|
return internalGradeOpponent(opposition, points, feedback, notApproved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FinalSeminarOpposition internalGradeOpponent(
|
||||||
|
FinalSeminarOpposition opposition,
|
||||||
|
int points,
|
||||||
|
String feedback,
|
||||||
|
FinalSeminarGrade grade
|
||||||
|
) {
|
||||||
|
opposition.setGrade(grade);
|
||||||
opposition.setPoints(points);
|
opposition.setPoints(points);
|
||||||
opposition.setFeedback(feedback);
|
opposition.setFeedback(feedback);
|
||||||
FinalSeminarOpposition assessedOpposition = finalSeminarOppositionRepository.save(opposition);
|
FinalSeminarOpposition assessedOpposition = finalSeminarOppositionRepository.save(opposition);
|
||||||
|
|
||||||
if (criteriaForOpposition.pointsToPass() > points) {
|
if (grade == FinalSeminarGrade.NOT_APPROVED) {
|
||||||
eventBus.post(new OppositionFailedEvent(assessedOpposition));
|
eventBus.post(new OppositionFailedEvent(assessedOpposition));
|
||||||
} else {
|
} else {
|
||||||
eventBus.post(new OppositionApprovedEvent(assessedOpposition));
|
eventBus.post(new OppositionApprovedEvent(assessedOpposition));
|
||||||
@ -128,4 +142,36 @@ public class FinalSeminarOppositionServiceImpl
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void expireUnfulfilledOppositionImprovements() {
|
||||||
|
Collection<FinalSeminarOpposition> unfulfilledOppositions =
|
||||||
|
finalSeminarOppositionRepository.findUnfulfilledOppositionImprovements();
|
||||||
|
|
||||||
|
Instant now = clock.instant();
|
||||||
|
int workDaysToFixRequestedImprovementsToOppositionReport = finalSeminarSettingsService
|
||||||
|
.getInstance()
|
||||||
|
.getWorkDaysToFixRequestedImprovementsToOppositionReport();
|
||||||
|
for (FinalSeminarOpposition unfulfilledOpposition : unfulfilledOppositions) {
|
||||||
|
Instant deadline = daysService.workDaysAfter(
|
||||||
|
unfulfilledOpposition.getImprovementsRequestedAt(),
|
||||||
|
workDaysToFixRequestedImprovementsToOppositionReport
|
||||||
|
);
|
||||||
|
if (now.isAfter(deadline)) {
|
||||||
|
internalGradeOpponent(
|
||||||
|
unfulfilledOpposition,
|
||||||
|
0,
|
||||||
|
unfulfilledOpposition.getSupervisorCommentForImprovements(),
|
||||||
|
FinalSeminarGrade.NOT_APPROVED
|
||||||
|
);
|
||||||
|
|
||||||
|
OppositionReport oppositionReport = unfulfilledOpposition.getOppositionReport();
|
||||||
|
if (oppositionReport != null) {
|
||||||
|
// Lock the report so it's not possible to submit it again
|
||||||
|
oppositionReport.setSubmitted(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalSeminarOppositionRepository.save(unfulfilledOpposition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user