Allow changes to the reflection to be made after it's been submitted #13
@ -744,9 +744,10 @@ public class CoreConfig {
|
|||||||
@Bean
|
@Bean
|
||||||
public ReflectionServiceImpl reflectionService(
|
public ReflectionServiceImpl reflectionService(
|
||||||
AuthorRepository authorRepository,
|
AuthorRepository authorRepository,
|
||||||
FinalSeminarServiceImpl finalSeminarService)
|
FinalSeminarServiceImpl finalSeminarService,
|
||||||
|
EventBus eventBus)
|
||||||
{
|
{
|
||||||
return new ReflectionServiceImpl(authorRepository, finalSeminarService);
|
return new ReflectionServiceImpl(authorRepository, finalSeminarService, eventBus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -23,7 +23,8 @@ public class ProjectEvent extends NotificationEvent {
|
|||||||
ROUGH_DRAFT_APPROVAL_APPROVED, ROUGH_DRAFT_APPROVAL_REJECTED, REVIEWER_GRADING_REPORT_SUBMITTED,
|
ROUGH_DRAFT_APPROVAL_APPROVED, ROUGH_DRAFT_APPROVAL_REJECTED, REVIEWER_GRADING_REPORT_SUBMITTED,
|
||||||
ONE_YEAR_PASSED_FROM_LATEST_ANNUAL_REVIEW, SUPERVISOR_GRADING_INITIAL_ASSESSMENT_DONE,
|
ONE_YEAR_PASSED_FROM_LATEST_ANNUAL_REVIEW, SUPERVISOR_GRADING_INITIAL_ASSESSMENT_DONE,
|
||||||
EXPORTED_SUCCESS, REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, FIRST_MEETING, OPPOSITION_FAILED,
|
EXPORTED_SUCCESS, REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, FIRST_MEETING, OPPOSITION_FAILED,
|
||||||
PARTICIPATION_APPROVED, COMPLETED, PARTICIPATION_FAILED
|
PARTICIPATION_APPROVED, COMPLETED, PARTICIPATION_FAILED, REFLECTION_IMPROVEMENTS_REQUESTED,
|
||||||
|
REFLECTION_IMPROVEMENTS_SUBMITTED
|
||||||
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
|
@ -85,6 +85,13 @@ PROJECT.PARTICIPATION_APPROVED.body = Your active participation on {0} has been
|
|||||||
PROJECT.PARTICIPATION_FAILED.title = Your active participation on {1} did not meet the minimum requirements.
|
PROJECT.PARTICIPATION_FAILED.title = Your active participation on {1} did not meet the minimum requirements.
|
||||||
PROJECT.PARTICIPATION_FAILED.body = Your active participation did not meet the minimum requirements set, and you will \
|
PROJECT.PARTICIPATION_FAILED.body = Your active participation did not meet the minimum requirements set, and you will \
|
||||||
have to be an active participant on a different final seminar to pass this step.
|
have to be an active participant on a different final seminar to pass this step.
|
||||||
|
PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.title = Reflection improvements requested
|
||||||
|
PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.body = The supervisor has deemed that the reflection submitted does not meet \
|
||||||
|
the minimum requirements and has requested improvements. Please log into SciPro and submit a new reflection. \
|
||||||
|
Their comments can be seen below:\n\n{0}
|
||||||
|
PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.title = Reflection improvements submitted
|
||||||
|
PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.body = The reflection improvements have been submitted. \
|
||||||
|
\n\n{0}
|
||||||
|
|
||||||
FORUM.NEW_FORUM_POST.title = Forum post: {2}
|
FORUM.NEW_FORUM_POST.title = Forum post: {2}
|
||||||
FORUM.NEW_FORUM_POST.body = New forum post submitted:<br /><br />{0}
|
FORUM.NEW_FORUM_POST.body = New forum post submitted:<br /><br />{0}
|
||||||
|
@ -5,6 +5,8 @@ import jakarta.persistence.Column;
|
|||||||
import jakarta.persistence.Embeddable;
|
import jakarta.persistence.Embeddable;
|
||||||
import jakarta.persistence.EmbeddedId;
|
import jakarta.persistence.EmbeddedId;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.EnumType;
|
||||||
|
import jakarta.persistence.Enumerated;
|
||||||
import jakarta.persistence.JoinColumn;
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.MapsId;
|
import jakarta.persistence.MapsId;
|
||||||
@ -30,6 +32,15 @@ public class Author {
|
|||||||
@Column(name = "reflection")
|
@Column(name = "reflection")
|
||||||
private String reflection;
|
private String reflection;
|
||||||
|
|
||||||
|
@Basic
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@Column(name = "reflection_status")
|
||||||
|
private ReflectionStatus reflectionStatus = ReflectionStatus.NOT_SUBMITTED;
|
||||||
|
|
||||||
|
@Basic
|
||||||
|
@Column(name = "reflection_comment_by_supervisor")
|
||||||
|
private String reflectionSupervisorComment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this author wants to be notified when a final seminar created
|
* If this author wants to be notified when a final seminar created
|
||||||
* as long as they have not yet completed both an opposition and
|
* as long as they have not yet completed both an opposition and
|
||||||
@ -85,6 +96,22 @@ public class Author {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReflectionStatus getReflectionStatus() {
|
||||||
|
return reflectionStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReflectionStatus(ReflectionStatus reflectionStatus) {
|
||||||
|
this.reflectionStatus = reflectionStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReflectionSupervisorComment(String reflectionSupervisorComment) {
|
||||||
|
this.reflectionSupervisorComment = reflectionSupervisorComment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReflectionSupervisorComment() {
|
||||||
|
return reflectionSupervisorComment;
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
// Nested class
|
// Nested class
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package se.su.dsv.scipro.project;
|
||||||
|
|
||||||
|
public enum ReflectionStatus {
|
||||||
|
NOT_SUBMITTED,
|
||||||
|
SUBMITTED,
|
||||||
|
IMPROVEMENTS_NEEDED
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package se.su.dsv.scipro.reflection;
|
||||||
|
|
||||||
|
public sealed interface Reflection {
|
||||||
|
boolean isSubmittable();
|
||||||
|
|
||||||
|
record NotSubmitted() implements Reflection {
|
||||||
|
@Override
|
||||||
|
public boolean isSubmittable() { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
record Submitted(String reflection) implements Reflection {
|
||||||
|
@Override
|
||||||
|
public boolean isSubmittable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record ImprovementsNeeded(String oldReflection, String commentBySupervisor) implements Reflection {
|
||||||
|
@Override
|
||||||
|
public boolean isSubmittable() { return true; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package se.su.dsv.scipro.reflection;
|
||||||
|
|
||||||
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
|
public record ReflectionImprovementsRequestedEvent(Project project, User author, String supervisorComment) {
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package se.su.dsv.scipro.reflection;
|
||||||
|
|
||||||
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event may be triggered by the supervisor if they edit the reflection after requesting improvements.
|
||||||
|
*/
|
||||||
|
public record ReflectionImprovementsSubmittedEvent(Project project, User author, String reflection) {
|
||||||
|
}
|
@ -14,4 +14,15 @@ public interface ReflectionService {
|
|||||||
* @return the reflection, or {@code null} if none has been submitted
|
* @return the reflection, or {@code null} if none has been submitted
|
||||||
*/
|
*/
|
||||||
String getSubmittedReflection(Project project, User author);
|
String getSubmittedReflection(Project project, User author);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the supervisor when the currently submitted reflection does not meet the minimum requirements.
|
||||||
|
* This is done individually by author.
|
||||||
|
*
|
||||||
|
* @param author the author whose reflection does not meet the minimum requirements.
|
||||||
|
* @param supervisorComment feedback provided by the supervisor so the author knows what to improve.
|
||||||
|
*/
|
||||||
|
void requestNewReflection(Project project, User author, String supervisorComment);
|
||||||
|
|
||||||
|
Reflection getReflection(Project project, User author);
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
package se.su.dsv.scipro.reflection;
|
package se.su.dsv.scipro.reflection;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
import se.su.dsv.scipro.finalseminar.AuthorRepository;
|
import se.su.dsv.scipro.finalseminar.AuthorRepository;
|
||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarService;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarService;
|
||||||
import se.su.dsv.scipro.project.Author;
|
import se.su.dsv.scipro.project.Author;
|
||||||
import se.su.dsv.scipro.project.Project;
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.project.ReflectionStatus;
|
||||||
import se.su.dsv.scipro.system.User;
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class ReflectionServiceImpl implements ReflectionService {
|
public class ReflectionServiceImpl implements ReflectionService {
|
||||||
private final AuthorRepository authorRepository;
|
private final AuthorRepository authorRepository;
|
||||||
private final FinalSeminarService finalSeminarService;
|
private final FinalSeminarService finalSeminarService;
|
||||||
|
private final EventBus eventBus;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ReflectionServiceImpl(AuthorRepository authorRepository, FinalSeminarService finalSeminarService) {
|
public ReflectionServiceImpl(
|
||||||
|
AuthorRepository authorRepository,
|
||||||
|
FinalSeminarService finalSeminarService,
|
||||||
|
EventBus eventBus)
|
||||||
|
{
|
||||||
this.authorRepository = authorRepository;
|
this.authorRepository = authorRepository;
|
||||||
this.finalSeminarService = finalSeminarService;
|
this.finalSeminarService = finalSeminarService;
|
||||||
|
this.eventBus = eventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -25,10 +35,13 @@ public class ReflectionServiceImpl implements ReflectionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasToFillInReflection(Project project, User author) {
|
public boolean hasToFillInReflection(Project project, User user) {
|
||||||
boolean noReflectionSubmitted = authorRepository.findByProjectAndUser(project, author)
|
Optional<Author> optionalAuthor = authorRepository.findByProjectAndUser(project, user);
|
||||||
.map(Author::getReflection)
|
if (optionalAuthor.isEmpty()) {
|
||||||
.isEmpty();
|
return false;
|
||||||
|
}
|
||||||
|
Author author = optionalAuthor.get();
|
||||||
|
boolean noReflectionSubmitted = author.getReflectionStatus() != ReflectionStatus.SUBMITTED;
|
||||||
return hasReachedReflectionProcess(project) && noReflectionSubmitted;
|
return hasReachedReflectionProcess(project) && noReflectionSubmitted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +49,13 @@ public class ReflectionServiceImpl implements ReflectionService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void submitReflection(Project project, User user, String reflection) {
|
public void submitReflection(Project project, User user, String reflection) {
|
||||||
authorRepository.findByProjectAndUser(project, user)
|
authorRepository.findByProjectAndUser(project, user)
|
||||||
.ifPresent(author -> author.setReflection(reflection));
|
.ifPresent(author -> {
|
||||||
|
if (author.getReflectionStatus() == ReflectionStatus.IMPROVEMENTS_NEEDED) {
|
||||||
|
eventBus.post(new ReflectionImprovementsSubmittedEvent(project, user, reflection));
|
||||||
|
}
|
||||||
|
author.setReflection(reflection);
|
||||||
|
author.setReflectionStatus(ReflectionStatus.SUBMITTED);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -45,4 +64,32 @@ public class ReflectionServiceImpl implements ReflectionService {
|
|||||||
.map(Author::getReflection)
|
.map(Author::getReflection)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void requestNewReflection(Project project, User user, String supervisorComment) {
|
||||||
|
authorRepository.findByProjectAndUser(project, user)
|
||||||
|
.ifPresent(author -> {
|
||||||
|
author.setReflectionStatus(ReflectionStatus.IMPROVEMENTS_NEEDED);
|
||||||
|
author.setReflectionSupervisorComment(supervisorComment);
|
||||||
|
});
|
||||||
|
eventBus.post(new ReflectionImprovementsRequestedEvent(project, user, supervisorComment));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Reflection getReflection(Project project, User author) {
|
||||||
|
return authorRepository.findByProjectAndUser(project, author)
|
||||||
|
.map(this::toReflection)
|
||||||
|
.orElseGet(Reflection.NotSubmitted::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Reflection toReflection(Author author) {
|
||||||
|
return switch (author.getReflectionStatus()) {
|
||||||
|
case SUBMITTED -> new Reflection.Submitted(author.getReflection());
|
||||||
|
case IMPROVEMENTS_NEEDED -> new Reflection.ImprovementsNeeded(
|
||||||
|
author.getReflection(),
|
||||||
|
author.getReflectionSupervisorComment());
|
||||||
|
default -> new Reflection.NotSubmitted();
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE `project_user`
|
||||||
|
ADD COLUMN `reflection_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_SUBMITTED';
|
||||||
|
|
||||||
|
UPDATE `project_user` SET `reflection_status` = 'SUBMITTED' WHERE `reflection` IS NOT NULL;
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `project_user` ADD COLUMN `reflection_comment_by_supervisor` TEXT NULL;
|
@ -101,6 +101,26 @@ public class ReflectionServiceTest extends IntegrationTest {
|
|||||||
assertTrue(reflectionService.hasReachedReflectionProcess(project));
|
assertTrue(reflectionService.hasReachedReflectionProcess(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void request_resubmission() {
|
||||||
|
LocalDate seminarDate = scheduleSeminar();
|
||||||
|
clock.setDate(seminarDate.plusDays(1));
|
||||||
|
assertTrue(reflectionService.hasToFillInReflection(project, author),
|
||||||
|
"After the final seminar the author should be required to submit a reflection");
|
||||||
|
|
||||||
|
String myReflection = "my reflection";
|
||||||
|
reflectionService.submitReflection(project, author, myReflection);
|
||||||
|
assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author));
|
||||||
|
assertFalse(reflectionService.hasToFillInReflection(project, author),
|
||||||
|
"After submitting the initial reflection it should no longer be required");
|
||||||
|
|
||||||
|
reflectionService.requestNewReflection(project, author, "Very bad reflection");
|
||||||
|
assertTrue(reflectionService.hasToFillInReflection(project, author),
|
||||||
|
"After supervisor requests resubmission the author should now be required to submit a new reflection");
|
||||||
|
assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author),
|
||||||
|
"The old reflection should be saved to make it easier for the student to update it");
|
||||||
|
}
|
||||||
|
|
||||||
private LocalDate scheduleSeminar() {
|
private LocalDate scheduleSeminar() {
|
||||||
project.setFinalSeminarRuleExempted(true); // to bypass rough draft approval
|
project.setFinalSeminarRuleExempted(true); // to bypass rough draft approval
|
||||||
FinalSeminarDetails details = new FinalSeminarDetails("Zoom", false, 1, 1, Language.SWEDISH, Language.ENGLISH, "zoom id 123");
|
FinalSeminarDetails details = new FinalSeminarDetails("Zoom", false, 1, 1, Language.SWEDISH, Language.ENGLISH, "zoom id 123");
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package se.su.dsv.scipro.crosscutting;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import se.su.dsv.scipro.data.dataobjects.Member;
|
||||||
|
import se.su.dsv.scipro.notifications.NotificationController;
|
||||||
|
import se.su.dsv.scipro.notifications.dataobject.NotificationSource;
|
||||||
|
import se.su.dsv.scipro.notifications.dataobject.ProjectEvent;
|
||||||
|
import se.su.dsv.scipro.reflection.ReflectionImprovementsRequestedEvent;
|
||||||
|
import se.su.dsv.scipro.reflection.ReflectionImprovementsSubmittedEvent;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class NotifyFailedReflection {
|
||||||
|
private final NotificationController notificationController;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public NotifyFailedReflection(NotificationController notificationController, EventBus eventBus) {
|
||||||
|
this.notificationController = notificationController;
|
||||||
|
eventBus.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void reflectionImprovementsRequested(ReflectionImprovementsRequestedEvent event) {
|
||||||
|
NotificationSource source = new NotificationSource();
|
||||||
|
source.setMessage(event.supervisorComment());
|
||||||
|
notificationController.notifyCustomProject(
|
||||||
|
event.project(),
|
||||||
|
ProjectEvent.Event.REFLECTION_IMPROVEMENTS_REQUESTED,
|
||||||
|
source,
|
||||||
|
Set.of(new Member(event.author(), Member.Type.AUTHOR)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void reflectionImprovementsSubmittted(ReflectionImprovementsSubmittedEvent event) {
|
||||||
|
NotificationSource source = new NotificationSource();
|
||||||
|
source.setMessage(event.reflection());
|
||||||
|
source.setAdditionalMessage(event.author().getFullName());
|
||||||
|
notificationController.notifyCustomProject(
|
||||||
|
event.project(),
|
||||||
|
ProjectEvent.Event.REFLECTION_IMPROVEMENTS_SUBMITTED,
|
||||||
|
source,
|
||||||
|
Set.of(new Member(event.project().getHeadSupervisor(), Member.Type.SUPERVISOR)));
|
||||||
|
}
|
||||||
|
}
|
@ -49,10 +49,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</wicket:fragment>
|
</wicket:fragment>
|
||||||
</div>
|
</div>
|
||||||
<wicket:container wicket:id="reflection">
|
<div wicket:id="reflection">
|
||||||
|
<wicket:enclosure>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h4 class="alert-heading">Improvements requested</h4>
|
||||||
|
<wicket:container wicket:id="improvementsNeeded"/>
|
||||||
|
</div>
|
||||||
|
</wicket:enclosure>
|
||||||
<a wicket:id="showReflection" href="#">View reflection</a>
|
<a wicket:id="showReflection" href="#">View reflection</a>
|
||||||
<div wicket:id="modal"></div>
|
<div wicket:id="modal"></div>
|
||||||
</wicket:container>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</wicket:panel>
|
</wicket:panel>
|
||||||
</body>
|
</body>
|
||||||
|
@ -30,10 +30,12 @@ import se.su.dsv.scipro.finalseminar.FinalSeminar;
|
|||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
|
||||||
import se.su.dsv.scipro.finalseminar.FinalSeminarService;
|
import se.su.dsv.scipro.finalseminar.FinalSeminarService;
|
||||||
import se.su.dsv.scipro.project.Project;
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.reflection.Reflection;
|
||||||
import se.su.dsv.scipro.reflection.ReflectionService;
|
import se.su.dsv.scipro.reflection.ReflectionService;
|
||||||
import se.su.dsv.scipro.report.AbstractGradingCriterion;
|
import se.su.dsv.scipro.report.AbstractGradingCriterion;
|
||||||
import se.su.dsv.scipro.report.GradingCriterion;
|
import se.su.dsv.scipro.report.GradingCriterion;
|
||||||
import se.su.dsv.scipro.report.GradingCriterionPoint;
|
import se.su.dsv.scipro.report.GradingCriterionPoint;
|
||||||
|
import se.su.dsv.scipro.report.GradingReport;
|
||||||
import se.su.dsv.scipro.report.SupervisorGradingReport;
|
import se.su.dsv.scipro.report.SupervisorGradingReport;
|
||||||
import se.su.dsv.scipro.system.Language;
|
import se.su.dsv.scipro.system.Language;
|
||||||
import se.su.dsv.scipro.system.User;
|
import se.su.dsv.scipro.system.User;
|
||||||
@ -264,14 +266,33 @@ public class CriteriaPanel extends GenericPanel<SupervisorGradingReport> {
|
|||||||
super(id, author);
|
super(id, author);
|
||||||
this.gradingCriterion = gradingCriterion;
|
this.gradingCriterion = gradingCriterion;
|
||||||
|
|
||||||
IModel<String> reflection = LoadableDetachableModel.of(() -> {
|
IModel<Reflection> reflection = LoadableDetachableModel.of(() -> {
|
||||||
Project project = CriteriaPanel.this.getModelObject().getProject();
|
Project project = CriteriaPanel.this.getModelObject().getProject();
|
||||||
return reflectionService.getSubmittedReflection(project, author.getObject());
|
return reflectionService.getReflection(project, author.getObject());
|
||||||
|
});
|
||||||
|
IModel<String> improvementsNeeded = reflection
|
||||||
|
.as(Reflection.ImprovementsNeeded.class)
|
||||||
|
.map(Reflection.ImprovementsNeeded::commentBySupervisor);
|
||||||
|
|
||||||
|
add(new MultiLineLabel("improvementsNeeded", improvementsNeeded) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(!getDefaultModelObjectAsString().isBlank());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
modal = new LargeModalWindow("modal");
|
modal = new LargeModalWindow("modal");
|
||||||
modal.setTitle("Reflection");
|
modal.setTitle("Reflection");
|
||||||
modal.setContent(id_ -> new MultiLineLabel(id_, new NullReplacementModel(reflection, "No reflection filled in.")));
|
modal.setContent(modalBodyId -> {
|
||||||
|
IModel<Project> projectModel = CriteriaPanel.this.getModel().map(GradingReport::getProject);
|
||||||
|
return new ReflectionModalBodyPanel(modalBodyId, projectModel, author);
|
||||||
|
});
|
||||||
|
this.setOutputMarkupId(true);
|
||||||
|
this.setOutputMarkupPlaceholderTag(true);
|
||||||
|
modal.onClose(target -> {
|
||||||
|
target.add(ReflectionFeedbackPanel.this);
|
||||||
|
});
|
||||||
add(modal);
|
add(modal);
|
||||||
|
|
||||||
WebMarkupContainer showReflection = new WebMarkupContainer("showReflection") {
|
WebMarkupContainer showReflection = new WebMarkupContainer("showReflection") {
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
|
||||||
|
<body>
|
||||||
|
<wicket:panel>
|
||||||
|
<wicket:enclosure>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<h4 class="alert-heading">
|
||||||
|
<wicket:message key="improvements_requested">
|
||||||
|
You've requested improvements to the submitted version.
|
||||||
|
</wicket:message>
|
||||||
|
</h4>
|
||||||
|
<wicket:container wicket:id="improvements_needed_supervisor_feedback">
|
||||||
|
[Supervisor feedback on needed improvements]
|
||||||
|
</wicket:container>
|
||||||
|
</div>
|
||||||
|
</wicket:enclosure>
|
||||||
|
|
||||||
|
<wicket:container wicket:id="reflection_text">
|
||||||
|
[Authors submitted reflection]
|
||||||
|
</wicket:container>
|
||||||
|
|
||||||
|
<button class="btn btn-outline-secondary" wicket:id="show_edit_reflection_form">
|
||||||
|
<wicket:message key="edit_reflection">
|
||||||
|
Edit reflection
|
||||||
|
</wicket:message>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-outline-secondary" wicket:id="show_request_improvements_form">
|
||||||
|
<wicket:message key="request_improvements">
|
||||||
|
Request improvements
|
||||||
|
</wicket:message>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<form wicket:id="request_improvements_form">
|
||||||
|
<hr>
|
||||||
|
<p>
|
||||||
|
<wicket:message key="request_improvements_text">
|
||||||
|
Please provide feedback on what improvements are needed in the submitted version.
|
||||||
|
</wicket:message>
|
||||||
|
</p>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label" wicket:for="comment">
|
||||||
|
<wicket:message key="comment">
|
||||||
|
Comment
|
||||||
|
</wicket:message>
|
||||||
|
</label>
|
||||||
|
<textarea class="form-control" wicket:id="comment" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary" wicket:id="submit">
|
||||||
|
<wicket:message key="request_improvements">
|
||||||
|
Request improvements
|
||||||
|
</wicket:message>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-link" wicket:id="cancel">
|
||||||
|
<wicket:message key="cancel">
|
||||||
|
Cancel
|
||||||
|
</wicket:message>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form wicket:id="edit_reflection_form">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">
|
||||||
|
<wicket:message key="reflection">
|
||||||
|
Reflection
|
||||||
|
</wicket:message>
|
||||||
|
</label>
|
||||||
|
<textarea class="form-control" wicket:id="reflection" rows="10"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary" wicket:id="submit">
|
||||||
|
<wicket:message key="save">
|
||||||
|
Save
|
||||||
|
</wicket:message>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-link" wicket:id="cancel">
|
||||||
|
<wicket:message key="cancel">
|
||||||
|
Cancel
|
||||||
|
</wicket:message>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</wicket:panel>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,191 @@
|
|||||||
|
package se.su.dsv.scipro.grading;
|
||||||
|
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||||
|
import org.apache.wicket.ajax.markup.html.AjaxLink;
|
||||||
|
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
|
||||||
|
import org.apache.wicket.markup.html.basic.MultiLineLabel;
|
||||||
|
import org.apache.wicket.markup.html.form.Form;
|
||||||
|
import org.apache.wicket.markup.html.form.TextArea;
|
||||||
|
import org.apache.wicket.markup.html.panel.Panel;
|
||||||
|
import org.apache.wicket.model.IModel;
|
||||||
|
import org.apache.wicket.model.Model;
|
||||||
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.reflection.Reflection;
|
||||||
|
import se.su.dsv.scipro.reflection.ReflectionService;
|
||||||
|
import se.su.dsv.scipro.system.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not meant to be a re-usable panel and is made specifically to be used
|
||||||
|
* as the body of the modal dialog that opens when a supervisor views the
|
||||||
|
* author's reflection as they're doing their final individual assessment.
|
||||||
|
*/
|
||||||
|
class ReflectionModalBodyPanel extends Panel {
|
||||||
|
@Inject
|
||||||
|
private ReflectionService reflectionService;
|
||||||
|
|
||||||
|
private final IModel<Project> projectModel;
|
||||||
|
private final IModel<User> authorModel;
|
||||||
|
|
||||||
|
private enum State { VIEWING, REQUESTING_IMPROVEMENTS, EDITING }
|
||||||
|
|
||||||
|
private State state = State.VIEWING;
|
||||||
|
|
||||||
|
ReflectionModalBodyPanel(String id, IModel<Project> projectModel, IModel<User> authorModel) {
|
||||||
|
super(id);
|
||||||
|
this.projectModel = projectModel;
|
||||||
|
this.authorModel = authorModel;
|
||||||
|
|
||||||
|
setOutputMarkupPlaceholderTag(true); // enable ajax refreshing of the entire body
|
||||||
|
|
||||||
|
IModel<Reflection> reflectionModel = projectModel.combineWith(authorModel, reflectionService::getReflection);
|
||||||
|
|
||||||
|
add(new MultiLineLabel("reflection_text", reflectionModel.map(this::getReflectionText)) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(state != State.EDITING);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add(new MultiLineLabel("improvements_needed_supervisor_feedback", reflectionModel
|
||||||
|
.as(Reflection.ImprovementsNeeded.class)
|
||||||
|
.map(Reflection.ImprovementsNeeded::commentBySupervisor)) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(!getDefaultModelObjectAsString().isBlank());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add(new RequestImprovementsForm("request_improvements_form", reflectionModel));
|
||||||
|
add(new SupervisorEditReflectionForm("edit_reflection_form", reflectionModel));
|
||||||
|
|
||||||
|
add(new AjaxLink<>("show_request_improvements_form", reflectionModel) {
|
||||||
|
@Override
|
||||||
|
public void onClick(AjaxRequestTarget target) {
|
||||||
|
ReflectionModalBodyPanel.this.state = State.REQUESTING_IMPROVEMENTS;
|
||||||
|
target.add(ReflectionModalBodyPanel.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
Reflection reflection = getModelObject();
|
||||||
|
boolean canRequestImprovements = reflection instanceof Reflection.Submitted;
|
||||||
|
setVisible(state == State.VIEWING && canRequestImprovements && isEnabledInHierarchy());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add(new AjaxLink<>("show_edit_reflection_form", reflectionModel) {
|
||||||
|
@Override
|
||||||
|
public void onClick(AjaxRequestTarget target) {
|
||||||
|
ReflectionModalBodyPanel.this.state = State.EDITING;
|
||||||
|
target.add(ReflectionModalBodyPanel.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
Reflection reflection = getModelObject();
|
||||||
|
boolean canEditReflection = reflection instanceof Reflection.Submitted || reflection instanceof Reflection.ImprovementsNeeded;
|
||||||
|
setVisible(state == State.VIEWING && canEditReflection && isEnabledInHierarchy());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getReflectionText(Reflection reflection) {
|
||||||
|
if (reflection instanceof Reflection.Submitted submitted) {
|
||||||
|
return submitted.reflection();
|
||||||
|
} else if (reflection instanceof Reflection.ImprovementsNeeded improvementsNeeded) {
|
||||||
|
return improvementsNeeded.oldReflection();
|
||||||
|
} else {
|
||||||
|
return getString("reflection_not_submitted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDetach() {
|
||||||
|
this.projectModel.detach();
|
||||||
|
this.authorModel.detach();
|
||||||
|
super.onDetach();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RequestImprovementsForm extends Form<Reflection> {
|
||||||
|
public RequestImprovementsForm(String id, IModel<Reflection> reflectionModel) {
|
||||||
|
super(id, reflectionModel);
|
||||||
|
|
||||||
|
IModel<String> commentModel = new Model<>();
|
||||||
|
|
||||||
|
TextArea<String> comment = new TextArea<>("comment", commentModel);
|
||||||
|
comment.setRequired(true);
|
||||||
|
add(comment);
|
||||||
|
|
||||||
|
add(new AjaxSubmitLink("submit") {
|
||||||
|
@Override
|
||||||
|
protected void onSubmit(AjaxRequestTarget target) {
|
||||||
|
super.onSubmit(target);
|
||||||
|
|
||||||
|
reflectionService.requestNewReflection(
|
||||||
|
projectModel.getObject(),
|
||||||
|
authorModel.getObject(),
|
||||||
|
commentModel.getObject());
|
||||||
|
|
||||||
|
ReflectionModalBodyPanel.this.state = State.VIEWING;
|
||||||
|
target.add(ReflectionModalBodyPanel.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(new AjaxLink<>("cancel") {
|
||||||
|
@Override
|
||||||
|
public void onClick(AjaxRequestTarget target) {
|
||||||
|
ReflectionModalBodyPanel.this.state = State.VIEWING;
|
||||||
|
target.add(ReflectionModalBodyPanel.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(state == State.REQUESTING_IMPROVEMENTS && getModelObject() instanceof Reflection.Submitted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SupervisorEditReflectionForm extends Form<Reflection> {
|
||||||
|
public SupervisorEditReflectionForm(String id, IModel<Reflection> reflectionModel) {
|
||||||
|
super(id, reflectionModel);
|
||||||
|
|
||||||
|
IModel<String> reflectionTextModel = new Model<>(getReflectionText(reflectionModel.getObject()));
|
||||||
|
|
||||||
|
TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionTextModel);
|
||||||
|
reflectionTextArea.setRequired(true);
|
||||||
|
add(reflectionTextArea);
|
||||||
|
|
||||||
|
add(new AjaxSubmitLink("submit") {
|
||||||
|
@Override
|
||||||
|
protected void onSubmit(AjaxRequestTarget target) {
|
||||||
|
reflectionService.submitReflection(
|
||||||
|
projectModel.getObject(),
|
||||||
|
authorModel.getObject(),
|
||||||
|
reflectionTextModel.getObject());
|
||||||
|
|
||||||
|
ReflectionModalBodyPanel.this.state = State.VIEWING;
|
||||||
|
target.add(ReflectionModalBodyPanel.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(new AjaxLink<>("cancel") {
|
||||||
|
@Override
|
||||||
|
public void onClick(AjaxRequestTarget target) {
|
||||||
|
ReflectionModalBodyPanel.this.state = State.VIEWING;
|
||||||
|
target.add(ReflectionModalBodyPanel.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(state == State.EDITING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
improvements_requested=You've requested improvements to the submitted version.
|
||||||
|
request_improvements=Request improvements
|
||||||
|
comment=Comment
|
||||||
|
reflection_not_submitted=Reflection not submitted yet
|
||||||
|
request_improvements_text=If the submitted reflection does not meet the minimum requirements \
|
||||||
|
you can request improvements from the student. The student will be notified and can submit a new reflection. \
|
||||||
|
Use the comment field to provide feedback to the student.
|
||||||
|
edit_reflection=Edit reflection
|
||||||
|
reflection=Reflection
|
||||||
|
cancel=Cancel
|
@ -158,7 +158,7 @@ public class NotificationLandingPage extends WebPage {
|
|||||||
setResponsePage(RoughDraftApprovalDecisionPage.class, reviewerParameters);
|
setResponsePage(RoughDraftApprovalDecisionPage.class, reviewerParameters);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED:
|
case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED, REFLECTION_IMPROVEMENTS_SUBMITTED:
|
||||||
if (project.isSupervisor(currentUser)) {
|
if (project.isSupervisor(currentUser)) {
|
||||||
setResponsePage(SupervisorGradingReportPage.class, pp);
|
setResponsePage(SupervisorGradingReportPage.class, pp);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,30 @@
|
|||||||
<div wicket:id="current_thesis_file"></div>
|
<div wicket:id="current_thesis_file"></div>
|
||||||
</div>
|
</div>
|
||||||
</wicket:enclosure>
|
</wicket:enclosure>
|
||||||
|
<wicket:enclosure child="old_reflection">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<h4 class="alert-heading">
|
||||||
|
<wicket:message key="reflection_improvements_needed_heading">
|
||||||
|
Reflection improvements needed
|
||||||
|
</wicket:message>
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
<wicket:message key="reflection_improvements_needed">
|
||||||
|
Your supervisor has requested that you improve and resubmit your reflection.
|
||||||
|
See their comments below about what changes are necessary.
|
||||||
|
</wicket:message>
|
||||||
|
</p>
|
||||||
|
<p wicket:id="supervisor_comment">
|
||||||
|
[You need to reflect more on the methods you used.]
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<h4>
|
||||||
|
<wicket:message key="old_reflection">
|
||||||
|
Your previous reflection
|
||||||
|
</wicket:message>
|
||||||
|
</h4>
|
||||||
|
<p wicket:id="old_reflection"></p>
|
||||||
|
</wicket:enclosure>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" wicket:for="reflection">
|
<label class="form-label" wicket:for="reflection">
|
||||||
<wicket:message key="reflection">[Reflection]</wicket:message>
|
<wicket:message key="reflection">[Reflection]</wicket:message>
|
||||||
|
@ -24,6 +24,7 @@ import se.su.dsv.scipro.grading.PublicationMetadata;
|
|||||||
import se.su.dsv.scipro.grading.PublicationMetadataFormComponentPanel;
|
import se.su.dsv.scipro.grading.PublicationMetadataFormComponentPanel;
|
||||||
import se.su.dsv.scipro.grading.PublicationMetadataService;
|
import se.su.dsv.scipro.grading.PublicationMetadataService;
|
||||||
import se.su.dsv.scipro.project.Project;
|
import se.su.dsv.scipro.project.Project;
|
||||||
|
import se.su.dsv.scipro.reflection.Reflection;
|
||||||
import se.su.dsv.scipro.reflection.ReflectionService;
|
import se.su.dsv.scipro.reflection.ReflectionService;
|
||||||
import se.su.dsv.scipro.session.SciProSession;
|
import se.su.dsv.scipro.session.SciProSession;
|
||||||
|
|
||||||
@ -45,17 +46,20 @@ public class FinalStepsPanel extends GenericPanel<Project> {
|
|||||||
|
|
||||||
add(new FencedFeedbackPanel("feedback", this));
|
add(new FencedFeedbackPanel("feedback", this));
|
||||||
|
|
||||||
IModel<String> reflection = LoadableDetachableModel.of(() ->
|
IModel<Reflection> currentReflection = LoadableDetachableModel.of(() ->
|
||||||
reflectionService.getSubmittedReflection(projectModel.getObject(), SciProSession.get().getUser()));
|
reflectionService.getReflection(projectModel.getObject(), SciProSession.get().getUser()));
|
||||||
add(new MultiLineLabel("reflection", reflection) {
|
IModel<String> reflectionText = currentReflection
|
||||||
|
.as(Reflection.Submitted.class)
|
||||||
|
.map(Reflection.Submitted::reflection);
|
||||||
|
add(new MultiLineLabel("reflection", reflectionText) {
|
||||||
@Override
|
@Override
|
||||||
protected void onConfigure() {
|
protected void onConfigure() {
|
||||||
super.onConfigure();
|
super.onConfigure();
|
||||||
setVisible(getDefaultModelObject() != null);
|
setVisible(!getDefaultModelObjectAsString().isBlank());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
add(new FinalStepsForm("submit_reflection", projectModel));
|
add(new FinalStepsForm("submit_reflection", projectModel, currentReflection));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -67,22 +71,49 @@ public class FinalStepsPanel extends GenericPanel<Project> {
|
|||||||
private class FinalStepsForm extends Form<Project> {
|
private class FinalStepsForm extends Form<Project> {
|
||||||
private final FinalThesisUploadComponent thesisFileUpload;
|
private final FinalThesisUploadComponent thesisFileUpload;
|
||||||
private final IModel<PublicationMetadata> publicationMetadataModel;
|
private final IModel<PublicationMetadata> publicationMetadataModel;
|
||||||
|
private final IModel<Reflection> currentReflection;
|
||||||
private IModel<String> reflectionModel;
|
private IModel<String> reflectionModel;
|
||||||
private IModel<PublishingConsentService.Level> levelModel;
|
private IModel<PublishingConsentService.Level> levelModel;
|
||||||
|
|
||||||
public FinalStepsForm(String id, IModel<Project> projectModel) {
|
public FinalStepsForm(String id, IModel<Project> projectModel, IModel<Reflection> currentReflection) {
|
||||||
super(id, projectModel);
|
super(id, projectModel);
|
||||||
|
|
||||||
|
this.currentReflection = currentReflection;
|
||||||
|
|
||||||
|
IModel<Reflection.ImprovementsNeeded> improvementsNeeded = this.currentReflection.as(Reflection.ImprovementsNeeded.class);
|
||||||
|
|
||||||
|
IModel<String> oldReflection = improvementsNeeded.map(Reflection.ImprovementsNeeded::oldReflection);
|
||||||
|
add(new MultiLineLabel("old_reflection", oldReflection) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add(new MultiLineLabel("supervisor_comment", improvementsNeeded.map(Reflection.ImprovementsNeeded::commentBySupervisor)) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
reflectionModel = new Model<>();
|
reflectionModel = new Model<>();
|
||||||
TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel);
|
TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel) {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setVisible(FinalStepsForm.this.currentReflection.getObject().isSubmittable());
|
||||||
|
}
|
||||||
|
};
|
||||||
reflectionTextArea.setRequired(true);
|
reflectionTextArea.setRequired(true);
|
||||||
add(reflectionTextArea);
|
add(reflectionTextArea);
|
||||||
|
|
||||||
IModel<PublishingConsentService.PublishingConsent> publishingConsent = LoadableDetachableModel.of(() ->
|
IModel<PublishingConsentService.PublishingConsent> publishingConsent = LoadableDetachableModel.of(() ->
|
||||||
publishingConsentService.getPublishingConsent(getModelObject(), SciProSession.get().getUser()));
|
publishingConsentService.getPublishingConsent(getModelObject(), SciProSession.get().getUser()));
|
||||||
|
|
||||||
levelModel = new Model<>();
|
levelModel = new Model<>(publishingConsent.getObject().selected());
|
||||||
FormComponent<PublishingConsentService.Level> publishingConsentLevel = new BootstrapRadioChoice<>(
|
FormComponent<PublishingConsentService.Level> publishingConsentLevel = new BootstrapRadioChoice<>(
|
||||||
"publishingConsentLevel",
|
"publishingConsentLevel",
|
||||||
levelModel,
|
levelModel,
|
||||||
@ -111,7 +142,13 @@ public class FinalStepsPanel extends GenericPanel<Project> {
|
|||||||
currentThesisFile.add(new OppositeVisibility(thesisFileUpload));
|
currentThesisFile.add(new OppositeVisibility(thesisFileUpload));
|
||||||
add(currentThesisFile);
|
add(currentThesisFile);
|
||||||
publicationMetadataModel = LoadableDetachableModel.of(() -> publicationMetadataService.getByProject(getModelObject()));
|
publicationMetadataModel = LoadableDetachableModel.of(() -> publicationMetadataService.getByProject(getModelObject()));
|
||||||
WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata");
|
WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata") {
|
||||||
|
@Override
|
||||||
|
protected void onConfigure() {
|
||||||
|
super.onConfigure();
|
||||||
|
setEnabled(finalThesisService.isUploadAllowed(FinalStepsPanel.FinalStepsForm.this.getModelObject()));
|
||||||
|
}
|
||||||
|
};
|
||||||
add(publicationMetadata);
|
add(publicationMetadata);
|
||||||
publicationMetadata.add(new PublicationMetadataFormComponentPanel("publication_metadata_components", publicationMetadataModel));
|
publicationMetadata.add(new PublicationMetadataFormComponentPanel("publication_metadata_components", publicationMetadataModel));
|
||||||
}
|
}
|
||||||
@ -119,7 +156,7 @@ public class FinalStepsPanel extends GenericPanel<Project> {
|
|||||||
@Override
|
@Override
|
||||||
protected void onConfigure() {
|
protected void onConfigure() {
|
||||||
super.onConfigure();
|
super.onConfigure();
|
||||||
setVisibilityAllowed(reflectionService.hasToFillInReflection(getModelObject(), SciProSession.get().getUser()));
|
setVisibilityAllowed(currentReflection.getObject().isSubmittable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -131,6 +168,7 @@ public class FinalStepsPanel extends GenericPanel<Project> {
|
|||||||
new WicketProjectFileUpload(finalThesisUpload.fileUpload(), FinalStepsPanel.this.getModelObject()),
|
new WicketProjectFileUpload(finalThesisUpload.fileUpload(), FinalStepsPanel.this.getModelObject()),
|
||||||
finalThesisUpload.englishTitle(),
|
finalThesisUpload.englishTitle(),
|
||||||
finalThesisUpload.swedishTitle());
|
finalThesisUpload.swedishTitle());
|
||||||
|
success(getString("final_thesis_uploaded"));
|
||||||
}
|
}
|
||||||
reflectionService.submitReflection(getModelObject(), SciProSession.get().getUser(), reflectionModel.getObject());
|
reflectionService.submitReflection(getModelObject(), SciProSession.get().getUser(), reflectionModel.getObject());
|
||||||
if (levelModel.getObject() != null) {
|
if (levelModel.getObject() != null) {
|
||||||
|
@ -9,3 +9,8 @@ current_final_thesis=Final thesis
|
|||||||
publication_metadata_why=Please provide the following metadata.
|
publication_metadata_why=Please provide the following metadata.
|
||||||
englishTitle=English title
|
englishTitle=English title
|
||||||
swedishTitle=Swedish title
|
swedishTitle=Swedish title
|
||||||
|
reflection_improvements_needed_heading=Reflection improvements needed
|
||||||
|
reflection_improvements_needed=Your supervisor has requested that you improve and resubmit your reflection. \
|
||||||
|
See their comments below about what changes are necessary.
|
||||||
|
old_reflection=Your previous reflection
|
||||||
|
final_thesis_uploaded=Final thesis uploaded
|
||||||
|
@ -65,6 +65,8 @@ ProjectEvent.FIRST_MEETING = First meeting created. (with date, time, place/room
|
|||||||
ProjectEvent.OPPOSITION_FAILED = An author fails their opposition.
|
ProjectEvent.OPPOSITION_FAILED = An author fails their opposition.
|
||||||
ProjectEvent.PARTICIPATION_APPROVED = An author's active participation is approved.
|
ProjectEvent.PARTICIPATION_APPROVED = An author's active participation is approved.
|
||||||
ProjectEvent.PARTICIPATION_FAILED = An author fails their active participation.
|
ProjectEvent.PARTICIPATION_FAILED = An author fails their active participation.
|
||||||
|
ProjectEvent.REFLECTION_IMPROVEMENTS_REQUESTED = Reflection improvements requested.
|
||||||
|
ProjectEvent.REFLECTION_IMPROVEMENTS_SUBMITTED = Reflection improvements submitted.
|
||||||
|
|
||||||
ProjectForumEvent.NEW_FORUM_POST = Forum thread created.
|
ProjectForumEvent.NEW_FORUM_POST = Forum thread created.
|
||||||
ProjectForumEvent.NEW_FORUM_POST_COMMENT = Comment posted in forum thread.
|
ProjectForumEvent.NEW_FORUM_POST_COMMENT = Comment posted in forum thread.
|
||||||
|
@ -139,6 +139,7 @@ import java.util.*;
|
|||||||
import static org.mockito.ArgumentMatchers.*;
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
public abstract class SciProTest {
|
public abstract class SciProTest {
|
||||||
@ -390,6 +391,8 @@ public abstract class SciProTest {
|
|||||||
publicationMetadata.setProject(answer.getArgument(0));
|
publicationMetadata.setProject(answer.getArgument(0));
|
||||||
return publicationMetadata;
|
return publicationMetadata;
|
||||||
});
|
});
|
||||||
|
lenient().when(publishingConsentService.getPublishingConsent(any(), any()))
|
||||||
|
.thenReturn(new PublishingConsentService.PublishingConsent(null, List.of()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
@ -10,6 +10,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import se.su.dsv.scipro.SciProApplication;
|
import se.su.dsv.scipro.SciProApplication;
|
||||||
import se.su.dsv.scipro.crosscutting.ForwardPhase2Feedback;
|
import se.su.dsv.scipro.crosscutting.ForwardPhase2Feedback;
|
||||||
|
import se.su.dsv.scipro.crosscutting.NotifyFailedReflection;
|
||||||
import se.su.dsv.scipro.crosscutting.ReviewerAssignedNotifications;
|
import se.su.dsv.scipro.crosscutting.ReviewerAssignedNotifications;
|
||||||
import se.su.dsv.scipro.crosscutting.ReviewerSupportMailer;
|
import se.su.dsv.scipro.crosscutting.ReviewerSupportMailer;
|
||||||
import se.su.dsv.scipro.crosscutting.ReviewingNotifications;
|
import se.su.dsv.scipro.crosscutting.ReviewingNotifications;
|
||||||
@ -87,4 +88,13 @@ public class WicketConfiguration {
|
|||||||
return new ReviewerAssignedNotifications(roughDraftApprovalService,
|
return new ReviewerAssignedNotifications(roughDraftApprovalService,
|
||||||
finalSeminarApprovalService, notificationController, eventBus);
|
finalSeminarApprovalService, notificationController, eventBus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not sure why this dependency lives in the view module
|
||||||
|
@Bean
|
||||||
|
public NotifyFailedReflection notifyFailedReflection(
|
||||||
|
EventBus eventBus,
|
||||||
|
NotificationController notificationController)
|
||||||
|
{
|
||||||
|
return new NotifyFailedReflection(notificationController, eventBus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user
Move the Event enum to its own file, it has grown to be very big.
That way we can separate the enums and also add comments as explanation for the different events.
Suggesting this to be done in a separate issue marked as technical debt.