2934 PO remove toggle for the approval step

This commit is contained in:
Andreas Svanberg 2023-10-13 11:24:05 +02:00
parent fd73aec166
commit 5f676b2eda
3 changed files with 147 additions and 196 deletions
view/src
main
java/se/su/dsv/scipro/reviewer
resources/se/su/dsv/scipro/reviewer
test/java/se/su/dsv/scipro/reviewer

@ -1,8 +1,6 @@
package se.su.dsv.scipro.reviewer;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.feedback.FencedFeedbackPanel;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.OnEventHeaderItem;
@ -123,8 +121,6 @@ public class RoughDraftApprovalDecisionPage extends ReviewerPage {
private final TextArea<String> feedback;
private final FileUploadField attachment;
private final WebMarkupContainer decisionButtons;
private final WebMarkupContainer gradeAndApprove;
public DecisionForm(String id, IModel<ReviewerApproval> reviewerApproval) {
super(id, reviewerApproval);
@ -135,11 +131,7 @@ public class RoughDraftApprovalDecisionPage extends ReviewerPage {
attachment = new FileUploadField("attachment");
add(attachment);
decisionButtons = new WebMarkupContainer("decision_buttons");
decisionButtons.setOutputMarkupPlaceholderTag(true);
add(decisionButtons);
decisionButtons.add(new Button("reject") {
add(new Button("reject") {
@Override
public void onSubmit() {
reviewerDecisionService.reject(
@ -149,20 +141,20 @@ public class RoughDraftApprovalDecisionPage extends ReviewerPage {
}
});
gradeAndApprove = new ApproveAndGrade("approve_and_grade");
gradeAndApprove.setVisible(false);
gradeAndApprove.setOutputMarkupPlaceholderTag(true);
add(gradeAndApprove);
addExaminationInfo();
decisionButtons.add(new AjaxLink<>("approve") {
add(new Button("approve") {
@Override
public void onClick(AjaxRequestTarget target) {
checkGradeServiceAuthentication();
gradeAndApprove.setVisible(true);
target.add(gradeAndApprove);
target.appendJavaScript("$('#%s').hide().slideDown()".formatted(gradeAndApprove.getMarkupId()));
decisionButtons.setVisible(false);
target.add(decisionButtons);
public void onSubmit() {
super.onSubmit();
Project project = approval.getObject().getProject();
for (User author : project.getProjectParticipants()) {
reportGrade(author, project);
}
reviewerDecisionService.approve(
approval.getObject(),
feedback.getModelObject(),
WicketFileUpload.ofOptional(attachment.getFileUpload()));
}
});
}
@ -173,151 +165,117 @@ public class RoughDraftApprovalDecisionPage extends ReviewerPage {
setVisible(!getModelObject().isDecided());
}
private class ApproveAndGrade extends WebMarkupContainer {
public ApproveAndGrade(String id) {
super(id);
IModel<List<User>> authors = approval.map(ReviewerApproval::getProject)
.map(Project::getProjectParticipants)
.map(ArrayList::new);
add(new Label("examination_date", this::getExaminationDate));
ListView<User> listView = new ListView<>("authors", authors) {
@Override
protected void populateItem(ListItem<User> item) {
item.add(new UserLabel("name", item.getModel()));
IModel<List<Examination>> examinations = LoadableDetachableModel.of(() ->
getExaminationsToReport(item.getModelObject()));
item.add(new AutoHidingListView<>("examinations", examinations) {
@Override
protected void populateItem(ListItem<Examination> item) {
item.add(new Label("name", item.getModel().map(Examination::name).map(Name::english)));
item.add(new Label("points", item.getModel().map(Examination::points)));
}
});
item.add(new WebMarkupContainer("nothing_to_report") {
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(examinations.getObject().isEmpty());
}
});
}
};
listView.setReuseItems(true);
add(listView);
add(new Button("approve") {
@Override
public void onSubmit() {
super.onSubmit();
Project project = approval.getObject().getProject();
for (User author : project.getProjectParticipants()) {
reportGrade(author, project);
private void addExaminationInfo() {
IModel<List<User>> authors = approval.map(ReviewerApproval::getProject)
.map(Project::getProjectParticipants)
.map(ArrayList::new);
add(new Label("examination_date", this::getExaminationDate));
ListView<User> listView = new ListView<>("authors", authors) {
@Override
protected void populateItem(ListItem<User> item) {
item.add(new UserLabel("name", item.getModel()));
IModel<List<Examination>> examinations = LoadableDetachableModel.of(() ->
getExaminationsToReport(item.getModelObject()));
item.add(new AutoHidingListView<>("examinations", examinations) {
@Override
protected void populateItem(ListItem<Examination> item) {
item.add(new Label("name", item.getModel().map(Examination::name).map(Name::english)));
item.add(new Label("points", item.getModel().map(Examination::points)));
}
reviewerDecisionService.approve(
approval.getObject(),
feedback.getModelObject(),
WicketFileUpload.ofOptional(attachment.getFileUpload()));
}
});
add(new AjaxLink<>("cancel") {
@Override
public void onClick(AjaxRequestTarget target) {
gradeAndApprove.setVisible(false);
target.add(gradeAndApprove);
decisionButtons.setVisible(true);
target.add(decisionButtons);
}
});
}
});
item.add(new WebMarkupContainer("nothing_to_report") {
@Override
protected void onConfigure() {
super.onConfigure();
setVisible(examinations.getObject().isEmpty());
}
});
}
};
listView.setReuseItems(true);
add(listView);
}
private List<Examination> getExaminationsToReport(User author) {
return getPassFailExaminations(author)
.stream()
.filter(examination -> hasNoGrade(author, examination))
.toList();
}
private List<Examination> getExaminationsToReport(User author) {
return getPassFailExaminations(author)
.stream()
.filter(examination -> hasNoGrade(author, examination))
.toList();
}
private boolean hasNoGrade(User author, Examination examination) {
Either<GetGradeError, Optional<Result>> currentResult = gradingService.getResult(
getSession().getMetaData(OAuth.TOKEN),
approval.getObject().getProject().getIdentifier(),
author.getIdentifier(),
examination.id());
return currentResult.isRight() && currentResult.right().isEmpty();
}
private boolean hasNoGrade(User author, Examination examination) {
Either<GetGradeError, Optional<Result>> currentResult = gradingService.getResult(
getSession().getMetaData(OAuth.TOKEN),
approval.getObject().getProject().getIdentifier(),
author.getIdentifier(),
examination.id());
return currentResult.isRight() && currentResult.right().isEmpty();
}
private List<Examination> getPassFailExaminations(User author) {
return gradingService.getExaminations(
getSession().getMetaData(OAuth.TOKEN),
approval.getObject().getProject().getIdentifier(),
author.getIdentifier())
.stream()
.filter(Predicate.not(Examination::hasManyPassingGrades))
.toList();
}
private List<Examination> getPassFailExaminations(User author) {
return gradingService.getExaminations(
getSession().getMetaData(OAuth.TOKEN),
approval.getObject().getProject().getIdentifier(),
author.getIdentifier())
.stream()
.filter(Predicate.not(Examination::hasManyPassingGrades))
.toList();
}
private void reportGrade(User author, Project project) {
List<Examination> examinations = getExaminationsToReport(author);
for (Examination examination : examinations) {
reportGrade(author, project, examination);
private void reportGrade(User author, Project project) {
List<Examination> examinations = getExaminationsToReport(author);
for (Examination examination : examinations) {
reportGrade(author, project, examination);
}
}
private void reportGrade(User author, Project project, Examination examination) {
Grade passingGrade = getPassingGrade(examination);
Either<ReportGradeError, Void> reported = gradingService.reportGrade(
getSession().getMetaData(OAuth.TOKEN),
project.getIdentifier(),
author.getIdentifier(),
examination.id(),
passingGrade.letter(),
getExaminationDate());
if (!reported.isRight()) {
if (reported.left() == ReportGradeError.NO_GRADING_ROLE) {
RoughDraftApprovalDecisionPage.this.error(getString("failed_to_report_phase_two_grade"));
}
else {
LOGGER.log(
System.Logger.Level.WARNING,
"""
Failed to report phase two grade to Daisy: %s, \
author: %s (%d), project: %s (%d), examination: %s (%d)
""".formatted(
reported.left(),
author.getFullName(),
author.getId(),
project.getTitle(),
project.getId(),
examination.name().swedish(),
examination.id()));
}
}
}
private void reportGrade(User author, Project project, Examination examination) {
Grade passingGrade = getPassingGrade(examination);
Either<ReportGradeError, Void> reported = gradingService.reportGrade(
getSession().getMetaData(OAuth.TOKEN),
project.getIdentifier(),
author.getIdentifier(),
examination.id(),
passingGrade.letter(),
getExaminationDate());
if (!reported.isRight()) {
if (reported.left() == ReportGradeError.NO_GRADING_ROLE) {
RoughDraftApprovalDecisionPage.this.error(getString("failed_to_report_phase_two_grade"));
}
else {
LOGGER.log(
System.Logger.Level.WARNING,
"""
Failed to report phase two grade to Daisy: %s, \
author: %s (%d), project: %s (%d), examination: %s (%d)
""".formatted(
reported.left(),
author.getFullName(),
author.getId(),
project.getTitle(),
project.getId(),
examination.name().swedish(),
examination.id()));
}
}
}
private LocalDate getExaminationDate() {
return approval.getObject()
.getCurrentDecision()
.getRequested()
.toInstant()
.atZone(ZoneId.of("Europe/Stockholm"))
.toLocalDate();
}
private LocalDate getExaminationDate() {
return approval.getObject()
.getCurrentDecision()
.getRequested()
.toInstant()
.atZone(ZoneId.of("Europe/Stockholm"))
.toLocalDate();
}
private Grade getPassingGrade(Examination examination) {
Optional<Grade> passingGrade = examination.grades()
.stream()
.filter(g -> g.type() == Grade.Type.PASSING)
.findFirst();
assert passingGrade.isPresent();
return passingGrade.get();
}
@Override
protected void onDetach() {
super.onDetach();
}
private Grade getPassingGrade(Examination examination) {
Optional<Grade> passingGrade = examination.grades()
.stream()
.filter(g -> g.type() == Grade.Type.PASSING)
.findFirst();
assert passingGrade.isPresent();
return passingGrade.get();
}
}

@ -28,48 +28,39 @@
<label for="attachment" class="form-label" wicket:for="attachment">Attachment</label>
<input type="file" id="attachment" class="form-control" wicket:id="attachment">
</div>
<div class="mb-3" wicket:id="decision_buttons">
<button type="submit" class="btn btn-outline-success btn-sm" wicket:id="approve">
<p class="mb-3 alert alert-info"><wicket:message key="report_halfway_explanation">
[When approving a project for phase two review you should also report the halfway examination.
Please select the appropriate examination below for each author before approving.]
</wicket:message></p>
<dl>
<dt>Examination date</dt>
<dd wicket:id="examination_date"></dd>
<wicket:container wicket:id="authors">
<dt wicket:id="name"></dt>
<wicket:enclosure child="examinations">
<dd>
<ul>
<li wicket:id="examinations">
<span wicket:id="name"></span>
(<span wicket:id="points"></span> hec)
</li>
</ul>
</dd>
</wicket:enclosure>
<dd wicket:id="nothing_to_report">
Nothing to report (already passed)
</dd>
</wicket:container>
</dl>
<div class="mb-3">
<button type="submit" class="btn btn-success btn-sm" wicket:id="approve">
<wicket:message key="approve">Approve</wicket:message>
</button>
<button type="submit" class="btn btn-danger btn-sm" wicket:id="reject">
<wicket:message key="reject">Improvements are needed</wicket:message>
</button>
</div>
<div wicket:id="approve_and_grade">
<p class="mb-3 alert alert-info"><wicket:message key="report_halfway_explanation">
[When approving a project for phase two review you should also report the halfway examination.
Please select the appropriate examination below for each author before approving.]
</wicket:message></p>
<dl>
<dt>Examination date</dt>
<dd wicket:id="examination_date"></dd>
<wicket:container wicket:id="authors">
<dt wicket:id="name"></dt>
<wicket:enclosure child="examinations">
<dd>
<ul>
<li wicket:id="examinations">
<span wicket:id="name"></span>
(<span wicket:id="points"></span> hec)
</li>
</ul>
</dd>
</wicket:enclosure>
<dd wicket:id="nothing_to_report">
Nothing to report (already passed)
</dd>
</wicket:container>
</dl>
<button type="submit" class="btn btn-success btn-sm" wicket:id="approve">
Approve
</button>
<a wicket:id="cancel" class="btn btn-link btn-sm">
Cancel
</a>
</div>
</form>
</div>
<div class="col-12 col-xl-6">

@ -60,6 +60,8 @@ public class RoughDraftApprovalDecisionPageTest extends SciProTest {
.thenReturn(List.of(problemAndMethod));
lenient().when(gradingService.reportGrade(any(), anyLong(), anyLong(), anyInt(), any(), any()))
.thenReturn(Either.right(null));
when(gradingService.getResult(any(), anyLong(), anyLong(), anyLong()))
.thenReturn(Either.right(Optional.empty()));
startPage();
}
@ -81,7 +83,7 @@ public class RoughDraftApprovalDecisionPageTest extends SciProTest {
FormTester formTester = tester.newFormTester("decision");
formTester.setValue("feedback", feedback);
formTester.submit(path("decision_buttons", "reject"));
formTester.submit("reject");
verify(reviewerDecisionService).reject(roughDraftApproval, feedback, Optional.empty());
}
@ -95,11 +97,11 @@ public class RoughDraftApprovalDecisionPageTest extends SciProTest {
when(gradingService.getResult(anyString(), anyLong(), anyLong(), anyLong()))
.thenReturn(Either.right(Optional.empty()));
tester.executeAjaxEvent(path("decision", "decision_buttons", "approve"), "click");
tester.executeAjaxEvent(path("decision", "approve"), "click");
FormTester formTester = tester.newFormTester("decision");
formTester.setValue("feedback", feedback);
formTester.setFile("attachment", attachment, "application/pdf");
formTester.submit(path("approve_and_grade", "approve"));
formTester.submit("approve");
tester.assertNoErrorMessage();
ArgumentCaptor<Optional> captor = ArgumentCaptor.forClass(Optional.class);