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

Thu, 08 Oct 2020 20:16:47 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 08 Oct 2020 20:16:47 +0200
changeset 109
2e0669e814ff
parent 107
b5f740a87af4
child 110
9d0be0b1580f
permissions
-rw-r--r--

adds versions overview

includes major refactoring of side menu generation

     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.DataAccessObjects;
    34 import de.uapcore.lightpit.entities.*;
    35 import de.uapcore.lightpit.viewmodel.*;
    36 import org.slf4j.Logger;
    37 import org.slf4j.LoggerFactory;
    39 import javax.servlet.annotation.WebServlet;
    40 import javax.servlet.http.HttpServletRequest;
    41 import javax.servlet.http.HttpServletResponse;
    42 import java.io.IOException;
    43 import java.sql.Date;
    44 import java.sql.SQLException;
    45 import java.util.NoSuchElementException;
    46 import java.util.Optional;
    47 import java.util.stream.Collectors;
    48 import java.util.stream.Stream;
    50 import static de.uapcore.lightpit.Functions.fqn;
    52 @WebServlet(
    53         name = "ProjectsModule",
    54         urlPatterns = "/projects/*"
    55 )
    56 public final class ProjectsModule extends AbstractLightPITServlet {
    58     private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class);
    60     private static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected_project");
    61     private static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version");
    62     private static final String PARAMETER_SELECTED_PROJECT = "pid";
    63     private static final String PARAMETER_SELECTED_VERSION = "vid";
    65     @Override
    66     protected String getResourceBundleName() {
    67         return "localization.projects";
    68     }
    70     private int syncParamWithSession(HttpServletRequest req, String param, String attr) {
    71         final var session = req.getSession();
    72         final var idParam = getParameter(req, Integer.class, param);
    73         final int id;
    74         if (idParam.isPresent()) {
    75             id = idParam.get();
    76             session.setAttribute(attr, id);
    77         } else {
    78             id = Optional.ofNullable(session.getAttribute(attr)).map(x->(Integer)x).orElse(-1);
    79         }
    80         return id;
    81     }
    83     private void populate(ProjectView viewModel, HttpServletRequest req, DataAccessObjects dao) throws SQLException {
    84         final var projectDao = dao.getProjectDao();
    85         final var versionDao = dao.getVersionDao();
    87         projectDao.list().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add);
    89         // Select Project
    90         final int pid = syncParamWithSession(req, PARAMETER_SELECTED_PROJECT, SESSION_ATTR_SELECTED_PROJECT);
    91         if (pid >= 0) {
    92             final var project = projectDao.find(pid);
    93             if (project == null) {
    94                 req.setAttribute(SESSION_ATTR_SELECTED_PROJECT, -1);
    95             } else {
    96                 final var info = new ProjectInfo(project);
    97                 info.setVersions(versionDao.list(project));
    98                 info.setIssueSummary(projectDao.getIssueSummary(project));
    99                 viewModel.setProjectInfo(info);
   100             }
   101         }
   103         // Select Version
   104         final int vid = syncParamWithSession(req, PARAMETER_SELECTED_VERSION, SESSION_ATTR_SELECTED_VERSION);
   105         if (vid >= 0) {
   106             viewModel.setVersionFilter(versionDao.find(vid));
   107         }
   108     }
   110     private ResponseType forwardView(HttpServletRequest req, ProjectView viewModel, String name) {
   111         setViewModel(req, viewModel);
   112         setContentPage(req, name);
   113         setStylesheet(req, "projects");
   114         setNavigationMenu(req, "project-navmenu");
   115         return ResponseType.HTML;
   116     }
   118     @RequestMapping(method = HttpMethod.GET)
   119     public ResponseType index(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
   120         final var viewModel = new ProjectView();
   121         populate(viewModel, req, dao);
   123         final var projectDao = dao.getProjectDao();
   124         final var versionDao = dao.getVersionDao();
   126         for (var info : viewModel.getProjectList()) {
   127             info.setVersions(versionDao.list(info.getProject()));
   128             info.setIssueSummary(projectDao.getIssueSummary(info.getProject()));
   129         }
   131         return forwardView(req, viewModel, "projects");
   132     }
   134     private void configure(ProjectEditView viewModel, Project project, DataAccessObjects dao) throws SQLException {
   135         viewModel.setProject(project);
   136         viewModel.setUsers(dao.getUserDao().list());
   137     }
   139     @RequestMapping(requestPath = "edit", method = HttpMethod.GET)
   140     public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
   141         final var viewModel = new ProjectEditView();
   142         populate(viewModel, req, dao);
   144         final var project = Optional.ofNullable(viewModel.getProjectInfo())
   145                 .map(ProjectInfo::getProject)
   146                 .orElse(new Project(-1));
   147         configure(viewModel, project, dao);
   149         return forwardView(req, viewModel, "project-form");
   150     }
   152     @RequestMapping(requestPath = "commit", method = HttpMethod.POST)
   153     public ResponseType commit(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
   155         Project project = new Project(-1);
   156         try {
   157             project = new Project(getParameter(req, Integer.class, "pid").orElseThrow());
   158             project.setName(getParameter(req, String.class, "name").orElseThrow());
   159             getParameter(req, String.class, "description").ifPresent(project::setDescription);
   160             getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl);
   161             getParameter(req, Integer.class, "owner").map(
   162                     ownerId -> ownerId >= 0 ? new User(ownerId) : null
   163             ).ifPresent(project::setOwner);
   165             dao.getProjectDao().saveOrUpdate(project);
   167             setRedirectLocation(req, "./projects/versions?pid="+project.getId());
   168             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   169             LOG.debug("Successfully updated project {}", project.getName());
   171             return ResponseType.HTML;
   172         } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
   173             LOG.warn("Form validation failure: {}", ex.getMessage());
   174             LOG.debug("Details:", ex);
   175             final var viewModel = new ProjectEditView();
   176             populate(viewModel, req, dao);
   177             configure(viewModel, project, dao);
   178             // TODO: error text
   179             return forwardView(req, viewModel, "project-form");
   180         }
   181     }
   183     @RequestMapping(requestPath = "view", method = HttpMethod.GET)
   184     public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException {
   185         final var viewModel = new ProjectDetailsView();
   186         populate(viewModel, req, dao);
   188         if (viewModel.getProjectInfo() == null) {
   189             resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected.");
   190             return ResponseType.NONE;
   191         }
   193         final var issueDao = dao.getIssueDao();
   195         final var version = viewModel.getVersionFilter();
   197         final var detailView = viewModel.getProjectDetails();
   198         final var issues = issueDao.list(version);
   199         for (var issue : issues) issueDao.joinVersionInformation(issue);
   200         detailView.updateDetails(issues, version);
   202         return forwardView(req, viewModel, "project-details");
   203     }
   205     @RequestMapping(requestPath = "versions", method = HttpMethod.GET)
   206     public ResponseType versions(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException {
   207         final var viewModel = new VersionsView();
   208         populate(viewModel, req, dao);
   209         viewModel.setVersionFilter(null);
   211         final var projectInfo = viewModel.getProjectInfo();
   212         if (projectInfo == null) {
   213             resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected.");
   214             return ResponseType.NONE;
   215         }
   217         final var issueDao = dao.getIssueDao();
   218         final var issues = issueDao.list(projectInfo.getProject());
   219         for (var issue : issues) issueDao.joinVersionInformation(issue);
   220         viewModel.update(projectInfo.getVersions(), issues);
   222         return forwardView(req, viewModel, "versions");
   223     }
   225     @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET)
   226     public ResponseType editVersion(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
   227         final var viewModel = new VersionEditView();
   228         populate(viewModel, req, dao);
   230         if (viewModel.getVersionFilter() == null) {
   231             viewModel.setVersion(new Version(-1));
   232         } else {
   233             viewModel.setVersion(viewModel.getVersionFilter());
   234         }
   236         return forwardView(req, viewModel, "version-form");
   237     }
   239     @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST)
   240     public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
   242         var version = new Version(-1);
   243         try {
   244             version = new Version(getParameter(req, Integer.class, "id").orElseThrow());
   245             version.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow()));
   246             version.setName(getParameter(req, String.class, "name").orElseThrow());
   247             getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
   248             version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
   249             dao.getVersionDao().saveOrUpdate(version);
   251             // specifying the pid parameter will purposely reset the session selected version!
   252             setRedirectLocation(req, "./projects/versions?pid=" + version.getProject().getId());
   253             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   254         } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
   255             LOG.warn("Form validation failure: {}", ex.getMessage());
   256             LOG.debug("Details:", ex);
   257             final var viewModel = new VersionEditView();
   258             populate(viewModel, req, dao);
   259             viewModel.setVersion(version);
   260             // TODO: set Error Text
   261             return forwardView(req, viewModel, "version-form");
   262         }
   264         return ResponseType.HTML;
   265     }
   267     private void configure(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException {
   268         issue.setProject(viewModel.getProjectInfo().getProject());
   269         viewModel.setIssue(issue);
   270         viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
   271         viewModel.setUsers(dao.getUserDao().list());
   272     }
   274     @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET)
   275     public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
   276         final var viewModel = new IssueEditView();
   278         final var issueParam = getParameter(req, Integer.class, "issue");
   279         if (issueParam.isPresent()) {
   280             final var issueDao = dao.getIssueDao();
   281             final var issue = issueDao.find(issueParam.get());
   282             issueDao.joinVersionInformation(issue);
   283             req.getSession().setAttribute(SESSION_ATTR_SELECTED_PROJECT, issue.getProject().getId());
   284             populate(viewModel, req, dao);
   285             configure(viewModel, issue, dao);
   286         } else {
   287             populate(viewModel, req, dao);
   288             configure(viewModel, new Issue(-1), dao);
   289         }
   291         return forwardView(req, viewModel, "issue-form");
   292     }
   294     @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST)
   295     public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
   296         Issue issue = new Issue(-1);
   297         try {
   298             issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow());
   299             issue.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow()));
   300             getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
   301             getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
   302             issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
   303             getParameter(req, Integer.class, "assignee").map(
   304                     userid -> userid >= 0 ? new User(userid) : null
   305             ).ifPresent(issue::setAssignee);
   306             getParameter(req, String.class, "description").ifPresent(issue::setDescription);
   307             getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
   309             getParameter(req, Integer[].class, "affected")
   310                     .map(Stream::of)
   311                     .map(stream ->
   312                             stream.map(Version::new).collect(Collectors.toList())
   313                     ).ifPresent(issue::setAffectedVersions);
   314             getParameter(req, Integer[].class, "resolved")
   315                     .map(Stream::of)
   316                     .map(stream ->
   317                             stream.map(Version::new).collect(Collectors.toList())
   318                     ).ifPresent(issue::setResolvedVersions);
   320             dao.getIssueDao().saveOrUpdate(issue);
   322             // specifying the issue parameter keeps the edited issue as menu item
   323             setRedirectLocation(req, "./projects/view?pid=" + issue.getProject().getId());
   324             setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
   325         } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
   326             // TODO: set request attribute with error text
   327             LOG.warn("Form validation failure: {}", ex.getMessage());
   328             LOG.debug("Details:", ex);
   329             final var viewModel = new IssueEditView();
   330             configure(viewModel, issue, dao);
   331             // TODO: set Error Text
   332             return forwardView(req, viewModel, "issue-form");
   333         }
   335         return ResponseType.HTML;
   336     }
   337 }

mercurial