src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java

Tue, 05 Jan 2021 19:19:31 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 05 Jan 2021 19:19:31 +0100
changeset 179
623c340058f3
parent 178
88207b860cba
child 180
009700915269
permissions
-rw-r--r--

migrates the utility classes for the AbstractServlet

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2018 Mike Becker. All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  *
    28  */
    29 package de.uapcore.lightpit.modules;
    32 import de.uapcore.lightpit.*;
    33 import de.uapcore.lightpit.dao.DataAccessObject;
    34 import de.uapcore.lightpit.entities.*;
    35 import de.uapcore.lightpit.filter.AllFilter;
    36 import de.uapcore.lightpit.filter.IssueFilter;
    37 import de.uapcore.lightpit.filter.NoneFilter;
    38 import de.uapcore.lightpit.filter.SpecificFilter;
    39 import de.uapcore.lightpit.types.IssueCategory;
    40 import de.uapcore.lightpit.types.IssueStatus;
    41 import de.uapcore.lightpit.types.VersionStatus;
    42 import de.uapcore.lightpit.types.WebColor;
    43 import de.uapcore.lightpit.viewmodel.*;
    44 import de.uapcore.lightpit.viewmodel.util.IssueSorter;
    45 import org.slf4j.Logger;
    46 import org.slf4j.LoggerFactory;
    48 import javax.servlet.ServletException;
    49 import javax.servlet.annotation.WebServlet;
    50 import javax.servlet.http.HttpServletRequest;
    51 import javax.servlet.http.HttpServletResponse;
    52 import java.io.IOException;
    53 import java.sql.Date;
    54 import java.sql.SQLException;
    55 import java.util.NoSuchElementException;
    56 import java.util.Optional;
    57 import java.util.stream.Collectors;
    58 import java.util.stream.Stream;
    60 @WebServlet(
    61         name = "ProjectsModule",
    62         urlPatterns = "/projects/*"
    63 )
    64 public final class ProjectsModule extends AbstractServlet {
    66     private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class);
    68     @Override
    69     protected String getResourceBundleName() {
    70         return "localization.projects";
    71     }
    73     private static int parseIntOrZero(String str) {
    74         try {
    75             return Integer.parseInt(str);
    76         } catch (NumberFormatException ex) {
    77             return 0;
    78         }
    79     }
    81     private void populate(ProjectView viewModel, PathParameters pathParameters, DataAccessObject dao) {
    82         dao.listProjects().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add);
    84         if (pathParameters == null)
    85             return;
    87         // Select Project
    88         final var project = dao.findProjectByNode(pathParameters.get("project"));
    89         if (project == null)
    90             return;
    92         final var info = new ProjectInfo(project);
    93         info.setVersions(dao.listVersions(project));
    94         info.setComponents(dao.listComponents(project));
    95         info.setIssueSummary(dao.collectIssueSummary(project));
    96         viewModel.setProjectInfo(info);
    98         // Select Version
    99         final var versionNode = pathParameters.get("version");
   100         if (versionNode != null) {
   101             if ("no-version".equals(versionNode)) {
   102                 viewModel.setVersionFilter(ProjectView.NO_VERSION);
   103             } else if ("all-versions".equals(versionNode)) {
   104                 viewModel.setVersionFilter(ProjectView.ALL_VERSIONS);
   105             } else {
   106                 viewModel.setVersionFilter(dao.findVersionByNode(project, versionNode));
   107             }
   108         }
   110         // Select Component
   111         final var componentNode = pathParameters.get("component");
   112         if (componentNode != null) {
   113             if ("no-component".equals(componentNode)) {
   114                 viewModel.setComponentFilter(ProjectView.NO_COMPONENT);
   115             } else if ("all-components".equals(componentNode)) {
   116                 viewModel.setComponentFilter(ProjectView.ALL_COMPONENTS);
   117             } else {
   118                 viewModel.setComponentFilter(dao.findComponentByNode(project, componentNode));
   119             }
   120         }
   121     }
   123     private static String sanitizeNode(String node, String defaultValue) {
   124         String result = node == null || node.isBlank() ? defaultValue : node;
   125         result = result.replace('/', '-');
   126         if (result.equals(".") || result.equals("..")) {
   127             return "_"+result;
   128         } else {
   129             return result;
   130         }
   131     }
   133     private void forwardView(HttpServletRequest req, HttpServletResponse resp, ProjectView viewModel, String name) throws ServletException, IOException {
   134         setViewModel(req, viewModel);
   135         setContentPage(req, name);
   136         setStylesheet(req, "projects");
   137         setNavigationMenu(req, "project-navmenu");
   138         renderSite(req, resp);
   139     }
   141     @RequestMapping(method = HttpMethod.GET)
   142     public void index(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws ServletException, IOException {
   143         final var viewModel = new ProjectView();
   144         populate(viewModel, null, dao);
   146         for (var info : viewModel.getProjectList()) {
   147             info.setVersions(dao.listVersions(info.getProject()));
   148             info.setIssueSummary(dao.collectIssueSummary(info.getProject()));
   149         }
   151         forwardView(req, resp, viewModel, "projects");
   152     }
   154     private void configureProjectEditor(ProjectEditView viewModel, Project project, DataAccessObject dao) {
   155         viewModel.setProject(project);
   156         viewModel.setUsers(dao.listUsers());
   157     }
   159     @RequestMapping(requestPath = "$project/edit", method = HttpMethod.GET)
   160     public void edit(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObject dao) throws IOException, SQLException, ServletException {
   161         final var viewModel = new ProjectEditView();
   162         populate(viewModel, pathParams, dao);
   164         if (!viewModel.isProjectInfoPresent()) {
   165             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   166             return;
   167         }
   169         configureProjectEditor(viewModel, viewModel.getProjectInfo().getProject(), dao);
   170         forwardView(req, resp, viewModel, "project-form");
   171     }
   173     @RequestMapping(requestPath = "create", method = HttpMethod.GET)
   174     public void create(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws SQLException, ServletException, IOException {
   175         final var viewModel = new ProjectEditView();
   176         populate(viewModel, null, dao);
   177         configureProjectEditor(viewModel, new Project(-1), dao);
   178         forwardView(req, resp, viewModel, "project-form");
   179     }
   181     @RequestMapping(requestPath = "commit", method = HttpMethod.POST)
   182     public void commit(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
   184         try {
   185             final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow());
   186             project.setName(getParameter(req, String.class, "name").orElseThrow());
   188             final var node = getParameter(req, String.class, "node").orElse(null);
   189             project.setNode(sanitizeNode(node, project.getName()));
   190             getParameter(req, Integer.class, "ordinal").ifPresent(project::setOrdinal);
   192             getParameter(req, String.class, "description").ifPresent(project::setDescription);
   193             getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl);
   194             getParameter(req, Integer.class, "owner").map(
   195                     ownerId -> ownerId >= 0 ? new User(ownerId) : null
   196             ).ifPresent(project::setOwner);
   198             if (project.getId() > 0) {
   199                 dao.updateProject(project);
   200             } else {
   201                 dao.insertProject(project);
   202             }
   204             setRedirectLocation(req, "./projects/");
   205             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   206             LOG.debug("Successfully updated project {}", project.getName());
   208             renderSite(req, resp);
   209         } catch (NoSuchElementException | IllegalArgumentException ex) {
   210             resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
   211             // TODO: implement - fix issue #21
   212         }
   213     }
   215     @RequestMapping(requestPath = "$project/$component/$version/issues/", method = HttpMethod.GET)
   216     public void issues(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObject dao) throws SQLException, IOException, ServletException {
   217         final var viewModel = new ProjectDetailsView();
   218         populate(viewModel, pathParams, dao);
   220         if (!viewModel.isEveryFilterValid()) {
   221             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   222             return;
   223         }
   225         final var project = viewModel.getProjectInfo().getProject();
   226         final var version = viewModel.getVersionFilter();
   227         final var component = viewModel.getComponentFilter();
   229         // TODO: use new IssueFilter class for the ViewModel
   231         final var projectFilter = new SpecificFilter<>(project);
   232         final IssueFilter filter;
   233         if (version.equals(ProjectView.NO_VERSION)) {
   234             if (component.equals(ProjectView.ALL_COMPONENTS)) {
   235                 filter = new IssueFilter(projectFilter,
   236                         new NoneFilter<>(),
   237                         new AllFilter<>()
   238                 );
   239             } else if (component.equals(ProjectView.NO_COMPONENT)) {
   240                 filter = new IssueFilter(projectFilter,
   241                         new NoneFilter<>(),
   242                         new NoneFilter<>()
   243                 );
   244             } else {
   245                 filter = new IssueFilter(projectFilter,
   246                         new NoneFilter<>(),
   247                         new SpecificFilter<>(component)
   248                 );
   249             }
   250         } else if (version.equals(ProjectView.ALL_VERSIONS)) {
   251             if (component.equals(ProjectView.ALL_COMPONENTS)) {
   252                 filter = new IssueFilter(projectFilter,
   253                         new AllFilter<>(),
   254                         new AllFilter<>()
   255                 );
   256             } else if (component.equals(ProjectView.NO_COMPONENT)) {
   257                 filter = new IssueFilter(projectFilter,
   258                         new AllFilter<>(),
   259                         new NoneFilter<>()
   260                 );
   261             } else {
   262                 filter = new IssueFilter(projectFilter,
   263                         new AllFilter<>(),
   264                         new SpecificFilter<>(component)
   265                 );
   266             }
   267         } else {
   268             if (component.equals(ProjectView.ALL_COMPONENTS)) {
   269                 filter = new IssueFilter(projectFilter,
   270                         new SpecificFilter<>(version),
   271                         new AllFilter<>()
   272                 );
   273             } else if (component.equals(ProjectView.NO_COMPONENT)) {
   274                 filter = new IssueFilter(projectFilter,
   275                         new SpecificFilter<>(version),
   276                         new NoneFilter<>()
   277                 );
   278             } else {
   279                 filter = new IssueFilter(projectFilter,
   280                         new SpecificFilter<>(version),
   281                         new SpecificFilter<>(component)
   282                 );
   283             }
   284         }
   286         final var issues = dao.listIssues(filter);
   287         issues.sort(new IssueSorter(
   288                 new IssueSorter.Criteria(IssueSorter.Field.DONE, true),
   289                 new IssueSorter.Criteria(IssueSorter.Field.ETA, true),
   290                 new IssueSorter.Criteria(IssueSorter.Field.UPDATED, false)
   291         ));
   294         viewModel.getProjectDetails().updateDetails(issues);
   295         if (version.getId() > 0)
   296             viewModel.getProjectDetails().updateVersionInfo(version);
   298         forwardView(req, resp, viewModel, "project-details");
   299     }
   301     @RequestMapping(requestPath = "$project/versions/", method = HttpMethod.GET)
   302     public void versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException {
   303         final var viewModel = new VersionsView();
   304         populate(viewModel, pathParameters, dao);
   306         final var projectInfo = viewModel.getProjectInfo();
   307         if (projectInfo == null) {
   308             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   309             return;
   310         }
   312         final var issues = dao.listIssues(
   313                 new IssueFilter(
   314                         new SpecificFilter<>(projectInfo.getProject()),
   315                         new AllFilter<>(),
   316                         new AllFilter<>()
   317                 )
   318         );
   319         viewModel.update(projectInfo.getVersions(), issues);
   321         forwardView(req, resp, viewModel, "versions");
   322     }
   324     @RequestMapping(requestPath = "$project/versions/$version/edit", method = HttpMethod.GET)
   325     public void editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
   326         final var viewModel = new VersionEditView();
   327         populate(viewModel, pathParameters, dao);
   329         if (viewModel.getProjectInfo() == null || viewModel.getVersionFilter() == null) {
   330             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   331             return;
   332         }
   334         viewModel.setVersion(viewModel.getVersionFilter());
   336         forwardView(req, resp, viewModel, "version-form");
   337     }
   339     @RequestMapping(requestPath = "$project/create-version", method = HttpMethod.GET)
   340     public void createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
   341         final var viewModel = new VersionEditView();
   342         populate(viewModel, pathParameters, dao);
   344         if (viewModel.getProjectInfo() == null) {
   345             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   346             return;
   347         }
   349         viewModel.setVersion(new Version(-1, viewModel.getProjectInfo().getProject().getId()));
   351         forwardView(req, resp, viewModel, "version-form");
   352     }
   354     @RequestMapping(requestPath = "commit-version", method = HttpMethod.POST)
   355     public void commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
   357         try {
   358             final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow());
   359             if (project == null) {
   360                 // TODO: improve error handling, because not found is not correct for this POST request
   361                 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   362                 return;
   363             }
   364             final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow(), project.getId());
   365             version.setName(getParameter(req, String.class, "name").orElseThrow());
   367             final var node = getParameter(req, String.class, "node").orElse(null);
   368             version.setNode(sanitizeNode(node, version.getName()));
   370             getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
   371             version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
   373             if (version.getId() > 0) {
   374                 dao.updateVersion(version);
   375             } else {
   376                 dao.insertVersion(version);
   377             }
   379             setRedirectLocation(req, "./projects/" + project.getNode() + "/versions/");
   380             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   382             renderSite(req, resp);
   383         } catch (NoSuchElementException | IllegalArgumentException ex) {
   384             resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
   385             // TODO: implement - fix issue #21
   386         }
   387     }
   389     @RequestMapping(requestPath = "$project/components/", method = HttpMethod.GET)
   390     public void components(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException {
   391         final var viewModel = new ComponentsView();
   392         populate(viewModel, pathParameters, dao);
   394         final var projectInfo = viewModel.getProjectInfo();
   395         if (projectInfo == null) {
   396             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   397             return;
   398         }
   400         final var issues = dao.listIssues(
   401                 new IssueFilter(
   402                         new SpecificFilter<>(projectInfo.getProject()),
   403                         new AllFilter<>(),
   404                         new AllFilter<>()
   405                 )
   406         );
   407         viewModel.update(projectInfo.getComponents(), issues);
   409         forwardView(req, resp, viewModel, "components");
   410     }
   412     @RequestMapping(requestPath = "$project/components/$component/edit", method = HttpMethod.GET)
   413     public void editComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
   414         final var viewModel = new ComponentEditView();
   415         populate(viewModel, pathParameters, dao);
   417         if (viewModel.getProjectInfo() == null || viewModel.getComponentFilter() == null) {
   418             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   419             return;
   420         }
   422         viewModel.setComponent(viewModel.getComponentFilter());
   423         viewModel.setUsers(dao.listUsers());
   425         forwardView(req, resp, viewModel, "component-form");
   426     }
   428     @RequestMapping(requestPath = "$project/create-component", method = HttpMethod.GET)
   429     public void createComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
   430         final var viewModel = new ComponentEditView();
   431         populate(viewModel, pathParameters, dao);
   433         if (viewModel.getProjectInfo() == null) {
   434             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   435             return;
   436         }
   438         viewModel.setComponent(new Component(-1, viewModel.getProjectInfo().getProject().getId()));
   439         viewModel.setUsers(dao.listUsers());
   441         forwardView(req, resp, viewModel, "component-form");
   442     }
   444     @RequestMapping(requestPath = "commit-component", method = HttpMethod.POST)
   445     public void commitComponent(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
   447         try {
   448             final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow());
   449             if (project == null) {
   450                 // TODO: improve error handling, because not found is not correct for this POST request
   451                 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   452                 return;
   453             }
   454             final var component = new Component(getParameter(req, Integer.class, "id").orElseThrow(), project.getId());
   455             component.setName(getParameter(req, String.class, "name").orElseThrow());
   457             final var node = getParameter(req, String.class, "node").orElse(null);
   458             component.setNode(sanitizeNode(node, component.getName()));
   460             component.setColor(getParameter(req, WebColor.class, "color").orElseThrow());
   461             getParameter(req, Integer.class, "ordinal").ifPresent(component::setOrdinal);
   462             getParameter(req, Integer.class, "lead").map(
   463                     userid -> userid >= 0 ? new User(userid) : null
   464             ).ifPresent(component::setLead);
   465             getParameter(req, String.class, "description").ifPresent(component::setDescription);
   467             if (component.getId() > 0) {
   468                 dao.updateComponent(component);
   469             } else {
   470                 dao.insertComponent(component);
   471             }
   473             setRedirectLocation(req, "./projects/" + project.getNode() + "/components/");
   474             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   476             renderSite(req, resp);
   477         } catch (NoSuchElementException | IllegalArgumentException ex) {
   478             resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
   479             // TODO: implement - fix issue #21
   480         }
   481     }
   483     private void configureIssueEditor(IssueEditView viewModel, Issue issue, DataAccessObject dao) {
   484         final var project = viewModel.getProjectInfo().getProject();
   485         issue.setProject(project); // automatically set current project for new issues
   486         viewModel.setIssue(issue);
   487         viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
   488         viewModel.setUsers(dao.listUsers());
   489         viewModel.setComponents(dao.listComponents(project));
   490     }
   492     @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET)
   493     public void viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
   494         final var viewModel = new IssueDetailView();
   495         populate(viewModel, pathParameters, dao);
   497         final var projectInfo = viewModel.getProjectInfo();
   498         if (projectInfo == null) {
   499             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   500             return;
   501         }
   503         final var issue = dao.findIssue(parseIntOrZero(pathParameters.get("issue")));
   504         if (issue == null) {
   505             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   506             return;
   507         }
   509         viewModel.setIssue(issue);
   510         viewModel.setComments(dao.listComments(issue));
   512         viewModel.processMarkdown();
   514         forwardView(req, resp, viewModel, "issue-view");
   515     }
   517     // TODO: why should the issue editor be child of $project?
   518     @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET)
   519     public void editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException {
   520         final var viewModel = new IssueEditView();
   521         populate(viewModel, pathParameters, dao);
   523         final var projectInfo = viewModel.getProjectInfo();
   524         if (projectInfo == null) {
   525             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   526             return;
   527         }
   529         final var issue = dao.findIssue(parseIntOrZero(pathParameters.get("issue")));
   530         if (issue == null) {
   531             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   532             return;
   533         }
   535         configureIssueEditor(viewModel, issue, dao);
   537         forwardView(req, resp, viewModel, "issue-form");
   538     }
   540     @RequestMapping(requestPath = "$project/create-issue", method = HttpMethod.GET)
   541     public void createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
   542         final var viewModel = new IssueEditView();
   543         populate(viewModel, pathParameters, dao);
   545         final var projectInfo = viewModel.getProjectInfo();
   546         if (projectInfo == null) {
   547             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   548             return;
   549         }
   551         setAttributeFromParameter(req, "more");
   552         setAttributeFromParameter(req, "cid");
   553         setAttributeFromParameter(req, "vid");
   555         final var issue = new Issue(-1, projectInfo.getProject(), null);
   556         issue.setProject(projectInfo.getProject());
   557         configureIssueEditor(viewModel, issue, dao);
   559         forwardView(req, resp, viewModel, "issue-form");
   560     }
   562     @RequestMapping(requestPath = "commit-issue", method = HttpMethod.POST)
   563     public void commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
   564         try {
   565             final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow());
   566             if (project == null) {
   567                 // TODO: improve error handling, because not found is not correct for this POST request
   568                 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   569                 return;
   570             }
   571             final var componentId = getParameter(req, Integer.class, "component");
   572             final Component component;
   573             if (componentId.isPresent()) {
   574                 component = dao.findComponent(componentId.get());
   575             } else {
   576                 component = null;
   577             }
   578             final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow(), project, component);
   579             getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
   580             getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
   581             issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
   582             getParameter(req, Integer.class, "assignee").map(userid -> {
   583                 if (userid >= 0) {
   584                     return new User(userid);
   585                 } else if (userid == -2) {
   586                     return Optional.ofNullable(component).map(Component::getLead).orElse(null);
   587                 } else {
   588                     return null;
   589                 }
   590             }
   591             ).ifPresent(issue::setAssignee);
   592             getParameter(req, String.class, "description").ifPresent(issue::setDescription);
   593             getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
   595             getParameter(req, Integer[].class, "affected")
   596                     .map(Stream::of)
   597                     .map(stream ->
   598                             stream.map(id -> new Version(id, project.getId()))
   599                                     .collect(Collectors.toList())
   600                     ).ifPresent(issue::setAffectedVersions);
   601             getParameter(req, Integer[].class, "resolved")
   602                     .map(Stream::of)
   603                     .map(stream ->
   604                             stream.map(id -> new Version(id, project.getId()))
   605                                     .collect(Collectors.toList())
   606                     ).ifPresent(issue::setResolvedVersions);
   608             if (issue.getId() > 0) {
   609                 dao.updateIssue(issue);
   610             } else {
   611                 dao.insertIssue(issue);
   612             }
   614             if (getParameter(req, Boolean.class, "create-another").orElse(false)) {
   615                 // TODO: fix #38 - automatically select component (and version)
   616                 setRedirectLocation(req, "./projects/" + issue.getProject().getNode() + "/create-issue?more=true");
   617             } else{
   618                 setRedirectLocation(req, "./projects/" + issue.getProject().getNode() + "/issues/" + issue.getId() + "/view");
   619             }
   620             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   622             renderSite(req, resp);
   623         } catch (NoSuchElementException | IllegalArgumentException ex) {
   624             resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
   625             // TODO: implement - fix issue #21
   626         }
   627     }
   629     @RequestMapping(requestPath = "commit-issue-comment", method = HttpMethod.POST)
   630     public void commentIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
   631         final var issueIdParam = getParameter(req, Integer.class, "issueid");
   632         if (issueIdParam.isEmpty()) {
   633             resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Detected manipulated form.");
   634             return;
   635         }
   636         final var issue = dao.findIssue(issueIdParam.get());
   637         if (issue == null) {
   638             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
   639             return;
   640         }
   641         try {
   642             final var issueComment = new IssueComment(getParameter(req, Integer.class, "commentid").orElse(-1), issue.getId());
   643             issueComment.setComment(getParameter(req, String.class, "comment").orElse(""));
   645             if (issueComment.getComment().isBlank()) {
   646                 throw new IllegalArgumentException("comment.null");
   647             }
   649             LOG.debug("User {} is commenting on issue #{}", req.getRemoteUser(), issue.getId());
   650             if (req.getRemoteUser() != null) {
   651                 Optional.ofNullable(dao.findUserByName(req.getRemoteUser())).ifPresent(issueComment::setAuthor);
   652             }
   654             dao.insertComment(issueComment);
   656             setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
   657             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   659             renderSite(req, resp);
   660         } catch (NoSuchElementException | IllegalArgumentException ex) {
   661             resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
   662             // TODO: implement - fix issue #21
   663         }
   664     }
   665 }

mercurial