diff --git a/core/src/main/java/se/su/dsv/scipro/grading/GradingReportTemplateService.java b/core/src/main/java/se/su/dsv/scipro/grading/GradingReportTemplateService.java index 42c03c8a55..1c23b7c0a5 100644 --- a/core/src/main/java/se/su/dsv/scipro/grading/GradingReportTemplateService.java +++ b/core/src/main/java/se/su/dsv/scipro/grading/GradingReportTemplateService.java @@ -33,4 +33,9 @@ public interface GradingReportTemplateService { NoSuchTemplateException, DuplicateDateException, TemplateLockedException; + + GradingReportTemplate create(ProjectType projectType, GradingReportTemplateUpdate update) + throws + ValidDateMustBeInTheFutureException, + DuplicateDateException; } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java index e538f8cf14..6f9b1a9824 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java @@ -269,4 +269,25 @@ public class GradingReportServiceImpl implements GradingReportTemplateService, G 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); + } } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepo.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepo.java index 320f8150e4..0ea11f562d 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepo.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepo.java @@ -20,4 +20,6 @@ public interface GradingReportTemplateRepo extends JpaRepository<GradingReportTe GradingReportTemplate getTemplateById(long templateId); GradingReportTemplate updateTemplate(long templateId, GradingReportTemplateUpdate update); + + GradingReportTemplate createTemplate(ProjectType projectType, GradingReportTemplateUpdate update); } diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java index 4886571bc3..8cf96941a1 100644 --- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java +++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java @@ -65,6 +65,13 @@ public class GradingReportTemplateRepoImpl extends GenericRepo<GradingReportTemp @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()); @@ -111,6 +118,13 @@ public class GradingReportTemplateRepoImpl extends GenericRepo<GradingReportTemp 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()) diff --git a/view/src/main/java/se/su/dsv/scipro/SciProApplication.java b/view/src/main/java/se/su/dsv/scipro/SciProApplication.java index 0ea39d14e7..ebbc21afa8 100755 --- a/view/src/main/java/se/su/dsv/scipro/SciProApplication.java +++ b/view/src/main/java/se/su/dsv/scipro/SciProApplication.java @@ -14,6 +14,7 @@ import org.apache.wicket.util.convert.converter.LocalDateConverter; import org.apache.wicket.util.convert.converter.LocalDateTimeConverter; import se.su.dsv.scipro.activityplan.*; import se.su.dsv.scipro.admin.pages.*; +import se.su.dsv.scipro.admin.pages.grading.AdminGradingTemplateCreationPage; import se.su.dsv.scipro.admin.pages.grading.AdminGradingTemplateEditPage; import se.su.dsv.scipro.admin.pages.grading.AdminGradingTemplatePage; import se.su.dsv.scipro.admin.pages.grading.AdminGradingTemplatesOverviewPage; @@ -288,6 +289,7 @@ public class SciProApplication extends LifecycleManagedWebApplication { mountPage("admin/project/grading/template", AdminGradingTemplatesOverviewPage.class); mountPage("admin/project/grading/template/view", AdminGradingTemplatePage.class); mountPage("admin/project/grading/template/edit", AdminGradingTemplateEditPage.class); + mountPage("admin/project/grading/template/create", AdminGradingTemplateCreationPage.class); mountPage("admin/edit", AdminEditProjectPage.class); mountPage("admin/finalseminars", AdminFinalSeminarPage.class); mountPage("admin/finalseminars/exemptions", AdminFinalSeminarExemptionPage.class); diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html new file mode 100644 index 0000000000..8fd44e66ab --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.html @@ -0,0 +1,26 @@ +<?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:extend> + <h1>Create a new grading report template</h1> + + <div wicket:id="feedback"></div> + + <form wicket:id="form" class="line-length-limit"> + <div class="mb-3"> + <label class="form-label" wicket:for="project_type">Project type</label> + <select wicket:id="project_type" class="form-select"> + <option value="bachelor">Bachelor</option> + <option value="master">Master</option> + </select> + </div> + + <div wicket:id="grading_template_component_panel"></div> + + <div class="position-sticky bottom-0 bg-white p-3 border line-length-limit"> + <button type="submit" class="btn btn-primary">Create</button> + </div> + </form> +</wicket:extend> +</body> +</html> \ No newline at end of file diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java new file mode 100644 index 0000000000..c14d4925db --- /dev/null +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateCreationPage.java @@ -0,0 +1,80 @@ +package se.su.dsv.scipro.admin.pages.grading; + +import jakarta.inject.Inject; +import org.apache.wicket.RestartResponseException; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.LambdaChoiceRenderer; +import org.apache.wicket.markup.html.panel.FeedbackPanel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import se.su.dsv.scipro.admin.pages.AbstractAdminProjectPage; +import se.su.dsv.scipro.components.AjaxDropDownChoice; +import se.su.dsv.scipro.data.DetachableServiceModel; +import se.su.dsv.scipro.grading.GradingReportTemplateService; +import se.su.dsv.scipro.grading.GradingReportTemplateUpdate; +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.system.ProjectType; +import se.su.dsv.scipro.system.ProjectTypeService; + +public class AdminGradingTemplateCreationPage extends AbstractAdminProjectPage implements MenuHighlightGradingTemplates { + + @Inject + GradingReportTemplateService gradingReportTemplateService; + @Inject + ProjectTypeService projectTypeService; + + private final IModel<ProjectType> projectTypeModel; + private EditingGradingTemplate editingGradingTemplateModel; + + public AdminGradingTemplateCreationPage() { + projectTypeModel = new DetachableServiceModel<>(projectTypeService); + + add(new FeedbackPanel("feedback")); + + Form<?> form = new Form<>("form") { + @Override + protected void onSubmit() { + super.onSubmit(); + GradingReportTemplateUpdate update = AdminGradingTemplateEditPage.toUpdate(editingGradingTemplateModel); + try { + GradingReportTemplate gradingReportTemplate = gradingReportTemplateService.create( + projectTypeModel.getObject(), + update); + getSession().success(getString("template_created", projectTypeModel)); + PageParameters pageParameters = AdminGradingTemplateEditPage.getPageParameters(gradingReportTemplate); + throw new RestartResponseException(AdminGradingTemplateEditPage.class, pageParameters); + } catch (ValidDateMustBeInTheFutureException e) { + error(getString("valid_from_must_be_in_the_future", () -> e)); + } catch (DuplicateDateException e) { + error(getString("another_template_exists_for_the_given_date_date", () -> e)); + } + } + }; + form.setOutputMarkupId(true); + add(form); + + form.add(new AjaxDropDownChoice<>( + "project_type", + projectTypeModel, + gradingReportTemplateService.getProjectTypes(), + new LambdaChoiceRenderer<>(ProjectType::getName, ProjectType::getId)) { + @Override + public void onNewSelection(AjaxRequestTarget target, ProjectType objectSelected) { + target.add(form); + } + }); + + editingGradingTemplateModel = new EditingGradingTemplate(); + form.add(new EditingGradingTemplateComponentPanel("grading_template_component_panel", Model.of(editingGradingTemplateModel)) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(projectTypeModel.getObject() != null); + } + }); + } +} diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java index 3b75b4ce2a..7a5d2d27e7 100644 --- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.java @@ -66,17 +66,17 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple add(form); } - private GradingReportTemplateUpdate toUpdate(EditingGradingTemplate editingGradingTemplate) { + public static GradingReportTemplateUpdate toUpdate(EditingGradingTemplate editingGradingTemplate) { List<GradingReportTemplateUpdate.GradeLimit> gradeLimits = editingGradingTemplate .getGradeLimits() .getGradeLimits() .stream() - .map(this::toGrade) + .map(AdminGradingTemplateEditPage::toGrade) .toList(); List<GradingReportTemplateUpdate.Criteria> criteria = editingGradingTemplate .getCriteria() .stream() - .map(this::toCriteria) + .map(AdminGradingTemplateEditPage::toCriteria) .toList(); return new GradingReportTemplateUpdate( editingGradingTemplate.getValidFrom(), @@ -86,7 +86,7 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple criteria); } - private GradingReportTemplateUpdate.Criteria toCriteria(EditingGradingTemplate.Criteria criteria) { + private static GradingReportTemplateUpdate.Criteria toCriteria(EditingGradingTemplate.Criteria criteria) { ArrayList<GradingReportTemplateUpdate.Criteria.Requirement> requirements = new ArrayList<>(); requirements.add(ZERO_REQUIREMENT); for (int i = 0; i < criteria.getPoints().size(); i++) { @@ -117,7 +117,7 @@ public class AdminGradingTemplateEditPage extends AbstractAdminProjectPage imple }; } - private GradingReportTemplateUpdate.GradeLimit toGrade(GradeLimits.GradeLimit gradeLimit) { + private static GradingReportTemplateUpdate.GradeLimit toGrade(GradeLimits.GradeLimit gradeLimit) { return new GradingReportTemplateUpdate.GradeLimit( gradeLimit.getGrade(), gradeLimit.getLowerLimit()); diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplatesOverviewPage.html b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplatesOverviewPage.html index ec048d4f7a..cff625cde3 100644 --- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplatesOverviewPage.html +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplatesOverviewPage.html @@ -32,15 +32,9 @@ </p> <div class="btn-group mb-3" role="group"> - <button type="button" class="btn btn-outline-primary">Create new template</button> - - <div class="btn-group" role="group"> - <button type="button" class="btn btn-outline-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"> - </button> - <ul class="dropdown-menu"> - <li><button class="dropdown-item" href="#">Create new based on another template</button></li> - </ul> - </div> + <wicket:link> + <a href="AdminGradingTemplateCreationPage.html" class="btn btn-outline-primary">Create new template</a> + </wicket:link> </div> <div class="mb-3" wicket:id="project_types"> diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java index bbb6ce3149..c6d490e392 100644 --- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/EditingGradingTemplate.java @@ -15,6 +15,11 @@ class EditingGradingTemplate implements Serializable { private List<Criteria> criteria; private GradeLimits gradeLimits; + public EditingGradingTemplate() { + this.gradeLimits = new GradeLimits(); + this.criteria = new ArrayList<>(); + } + EditingGradingTemplate(GradingReportTemplate template) { this.note = template.getNote(); this.validFrom = template.getValidFrom(); diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java index cb728abd76..29bd5877d2 100644 --- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/GradeLimits.java @@ -10,6 +10,10 @@ class GradeLimits implements Serializable { private List<GradeLimit> gradeLimits; private String failingGrade; + public GradeLimits() { + this.gradeLimits = new ArrayList<>(); + } + GradeLimits(GradingReportTemplate template) { this.gradeLimits = new ArrayList<>(); for (var gradeLimit : template.getGradeLimits()) { diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.utf8.properties b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties similarity index 90% rename from view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.utf8.properties rename to view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties index a9420cf6bd..f761f20e4e 100644 --- a/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/AdminGradingTemplateEditPage.utf8.properties +++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/grading/wicket-package.utf8.properties @@ -2,3 +2,4 @@ template_updated=Template updated valid_from_must_be_in_the_future=The templates valid date must be in the future. The given date was ${validFrom} but it must be at least ${earliestAllowedValidFrom}. another_template_exists_for_the_given_date_date=There is already another ${projectType.name} template that becomes valid at ${validFrom}, please pick another date. template_is_locked=You can not edit templates that have become current. The template you are trying to edit became current at ${validFrom}. +template_created=New template for ${name} created.