Allow supervisors to request improvements from final seminar opponents #78

Merged
niat8586 merged 41 commits from opponent-completion into develop 2025-03-05 10:05:38 +01:00
9 changed files with 85 additions and 17 deletions
Showing only changes of commit 7bb37407d6 - Show all commits

View File

@ -436,14 +436,18 @@ public class CoreConfig {
FinalSeminarOppositionGrading finalSeminarOppositionGrading,
EventBus eventBus,
FinalSeminarOppositionRepo finalSeminarOppositionRepository,
Clock clock
Clock clock,
FinalSeminarSettingsService finalSeminarSettingsService,
DaysService daysService
) {
return new FinalSeminarOppositionServiceImpl(
em,
finalSeminarOppositionGrading,
eventBus,
finalSeminarOppositionRepository,
clock
clock,
finalSeminarSettingsService,
daysService
);
}

View File

@ -1,5 +1,6 @@
package se.su.dsv.scipro.finalseminar;
import java.time.Instant;
import se.su.dsv.scipro.system.GenericService;
public interface FinalSeminarOppositionService extends GenericService<FinalSeminarOpposition, Long> {
@ -11,5 +12,8 @@ public interface FinalSeminarOppositionService extends GenericService<FinalSemin
FinalSeminarOpposition gradeOpponent(FinalSeminarOpposition opposition, int points, String feedback)
throws PointNotValidException;
void requestImprovements(FinalSeminarOpposition opposition, String supervisorComment);
/**
* @return the deadline by which the improvements must have been submitted
*/
Instant requestImprovements(FinalSeminarOpposition opposition, String supervisorComment);
}

View File

@ -6,7 +6,9 @@ import jakarta.inject.Provider;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import java.time.Clock;
import java.time.Instant;
import java.util.List;
import se.su.dsv.scipro.misc.DaysService;
import se.su.dsv.scipro.report.OppositionReport;
import se.su.dsv.scipro.system.AbstractServiceImpl;
@ -18,6 +20,8 @@ public class FinalSeminarOppositionServiceImpl
private final EventBus eventBus;
private final FinalSeminarOppositionRepo finalSeminarOppositionRepository;
private final Clock clock;
private final FinalSeminarSettingsService finalSeminarSettingsService;
private final DaysService daysService;
@Inject
public FinalSeminarOppositionServiceImpl(
@ -25,13 +29,17 @@ public class FinalSeminarOppositionServiceImpl
FinalSeminarOppositionGrading finalSeminarOppositionGrading,
EventBus eventBus,
FinalSeminarOppositionRepo finalSeminarOppositionRepository,
Clock clock
Clock clock,
FinalSeminarSettingsService finalSeminarSettingsService,
DaysService daysService
) {
super(em, FinalSeminarOpposition.class, QFinalSeminarOpposition.finalSeminarOpposition);
this.finalSeminarOppositionGrading = finalSeminarOppositionGrading;
this.eventBus = eventBus;
this.finalSeminarOppositionRepository = finalSeminarOppositionRepository;
this.clock = clock;
this.finalSeminarSettingsService = finalSeminarSettingsService;
this.daysService = daysService;
}
@Override
@ -67,13 +75,24 @@ public class FinalSeminarOppositionServiceImpl
@Override
@Transactional
public void requestImprovements(FinalSeminarOpposition opposition, String supervisorComment) {
public Instant requestImprovements(FinalSeminarOpposition opposition, String supervisorComment) {
OppositionReport oppositionReport = opposition.getOppositionReport();
if (oppositionReport == null) {
return;
throw new IllegalStateException("There is no opposition report submitted");
}
FinalSeminarSettings finalSeminarSettings = finalSeminarSettingsService.getInstance();
Instant now = clock.instant();
Instant deadline = daysService.workDaysAfter(
now,
finalSeminarSettings.getWorkDaysToFixRequestedImprovementsToOppositionReport()
);
oppositionReport.setSubmitted(false);
opposition.setImprovementsRequestedAt(clock.instant());
opposition.setImprovementsRequestedAt(now);
opposition.setSupervisorCommentForImprovements(supervisorComment);
return deadline;
}
}

View File

@ -34,6 +34,9 @@ public class FinalSeminarSettings extends DomainObject {
@Column(name = "days_ahead_to_upload_thesis", nullable = false)
private int daysAheadToUploadThesis = DEFAULT_DAYS_AHEAD_TO_UPLOAD_THESIS;
@Column(name = "work_days_to_fix_requested_improvements_to_opposition_report", nullable = false)
private int workDaysToFixRequestedImprovementsToOppositionReport = 10;
@Column(name = "thesis_must_be_pdf", nullable = false)
private boolean thesisMustBePDF = false;
@ -113,6 +116,17 @@ public class FinalSeminarSettings extends DomainObject {
this.oppositionPriorityDays = oppositionPriorityDays;
}
public int getWorkDaysToFixRequestedImprovementsToOppositionReport() {
return workDaysToFixRequestedImprovementsToOppositionReport;
}
public void setWorkDaysToFixRequestedImprovementsToOppositionReport(
int workDaysToFixRequestedImprovementsToOppositionReport
) {
this.workDaysToFixRequestedImprovementsToOppositionReport =
workDaysToFixRequestedImprovementsToOppositionReport;
}
@Override
public String toString() {
return (

View File

@ -1,6 +1,9 @@
package se.su.dsv.scipro.misc;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
public interface DaysService {
@ -9,4 +12,11 @@ public interface DaysService {
int workDaysBetween(Date startDate, Date endDate);
LocalDate workDaysAhead(LocalDate date, int days);
LocalDate workDaysAfter(LocalDate date, int days);
default Instant workDaysAfter(Instant instant, int days) {
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
LocalDate localDate = zonedDateTime.toLocalDate();
LocalDate newDate = workDaysAfter(localDate, days);
return newDate.atTime(zonedDateTime.toLocalTime()).atZone(ZoneId.systemDefault()).toInstant();
}
}

View File

@ -0,0 +1,2 @@
ALTER TABLE `final_seminar_settings`
ADD COLUMN `work_days_to_fix_requested_improvements_to_opposition_report` INT(11) NOT NULL DEFAULT 10;

View File

@ -42,6 +42,13 @@
</div>
</div>
<div class="mb-3">
<label class="col-lg-4">How many work days opponents have to resubmit their report</label>
<div class="col-lg-1">
<input class="form-control" type="text" wicket:id="work_days_to_fix_requested_improvements_to_opposition_report" />
</div>
</div>
<div class="mb-3">
<div class="col-lg-offset-4 col-lg-4">
<div class="form-check">

View File

@ -131,6 +131,17 @@ public class AdminFinalSeminarSettingsPage extends AbstractAdminSystemPage {
Integer.class
)
);
add(
new RequiredTextField<>(
"work_days_to_fix_requested_improvements_to_opposition_report",
LambdaModel.of(
model,
FinalSeminarSettings::getWorkDaysToFixRequestedImprovementsToOppositionReport,
FinalSeminarSettings::setWorkDaysToFixRequestedImprovementsToOppositionReport
),
Integer.class
)
);
add(
new CheckBox(
SEMINAR_PDF,

View File

@ -2,7 +2,7 @@ package se.su.dsv.scipro.finalseminar;
import com.google.common.eventbus.EventBus;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
@ -360,19 +360,16 @@ public class SeminarOppositionPanel extends Panel {
@Override
protected void onSubmit() {
// TODO: return deadline
finalSeminarOppositionService.requestImprovements(getModelObject(), feedbackToOpponentModel.getObject());
Instant deadline = finalSeminarOppositionService.requestImprovements(
getModelObject(),
feedbackToOpponentModel.getObject()
);
record ImprovementFeedback(String fullName, ZonedDateTime deadline) {}
ZonedDateTime deadline = getModelObject()
.getFinalSeminar()
.getStartDate()
.toInstant()
.plus(Duration.ofDays(10))
.atZone(ZoneId.of("Europe/Stockholm"));
ZonedDateTime localDeadline = deadline.atZone(ZoneId.systemDefault());
success(
getString("feedback.opponent.requested.improvements", () ->
new ImprovementFeedback(getModelObject().getUser().getFullName(), deadline)
new ImprovementFeedback(getModelObject().getUser().getFullName(), localDeadline)
)
);
}