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

Fri, 09 Oct 2020 11:46:10 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 09 Oct 2020 11:46:10 +0200
changeset 117
874ff787949b
parent 110
9d0be0b1580f
child 118
d3583959c875
permissions
-rw-r--r--

fixes New Project button not resetting the session cached project ID

universe@41 1 /*
universe@41 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@41 3 *
universe@41 4 * Copyright 2018 Mike Becker. All rights reserved.
universe@41 5 *
universe@41 6 * Redistribution and use in source and binary forms, with or without
universe@41 7 * modification, are permitted provided that the following conditions are met:
universe@41 8 *
universe@41 9 * 1. Redistributions of source code must retain the above copyright
universe@41 10 * notice, this list of conditions and the following disclaimer.
universe@41 11 *
universe@41 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@41 13 * notice, this list of conditions and the following disclaimer in the
universe@41 14 * documentation and/or other materials provided with the distribution.
universe@41 15 *
universe@41 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@41 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@41 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@41 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@41 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@41 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@41 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@41 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@41 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@41 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@41 26 * POSSIBILITY OF SUCH DAMAGE.
universe@41 27 *
universe@41 28 */
universe@41 29 package de.uapcore.lightpit.modules;
universe@41 30
universe@41 31
universe@41 32 import de.uapcore.lightpit.*;
universe@41 33 import de.uapcore.lightpit.dao.DataAccessObjects;
universe@64 34 import de.uapcore.lightpit.entities.*;
universe@86 35 import de.uapcore.lightpit.viewmodel.*;
universe@59 36 import org.slf4j.Logger;
universe@59 37 import org.slf4j.LoggerFactory;
universe@41 38
universe@41 39 import javax.servlet.annotation.WebServlet;
universe@41 40 import javax.servlet.http.HttpServletRequest;
universe@59 41 import javax.servlet.http.HttpServletResponse;
universe@59 42 import java.io.IOException;
universe@75 43 import java.sql.Date;
universe@47 44 import java.sql.SQLException;
universe@86 45 import java.util.NoSuchElementException;
universe@99 46 import java.util.Optional;
universe@83 47 import java.util.stream.Collectors;
universe@83 48 import java.util.stream.Stream;
universe@41 49
universe@52 50 import static de.uapcore.lightpit.Functions.fqn;
universe@52 51
universe@41 52 @WebServlet(
universe@41 53 name = "ProjectsModule",
universe@41 54 urlPatterns = "/projects/*"
universe@41 55 )
universe@41 56 public final class ProjectsModule extends AbstractLightPITServlet {
universe@41 57
universe@59 58 private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class);
universe@59 59
universe@99 60 private static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected_project");
universe@99 61 private static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version");
universe@99 62 private static final String PARAMETER_SELECTED_PROJECT = "pid";
universe@99 63 private static final String PARAMETER_SELECTED_VERSION = "vid";
universe@71 64
universe@78 65 @Override
universe@78 66 protected String getResourceBundleName() {
universe@78 67 return "localization.projects";
universe@78 68 }
universe@71 69
universe@99 70 private int syncParamWithSession(HttpServletRequest req, String param, String attr) {
universe@99 71 final var session = req.getSession();
universe@99 72 final var idParam = getParameter(req, Integer.class, param);
universe@99 73 final int id;
universe@99 74 if (idParam.isPresent()) {
universe@99 75 id = idParam.get();
universe@99 76 session.setAttribute(attr, id);
universe@99 77 } else {
universe@99 78 id = Optional.ofNullable(session.getAttribute(attr)).map(x->(Integer)x).orElse(-1);
universe@99 79 }
universe@99 80 return id;
universe@99 81 }
universe@99 82
universe@99 83 private void populate(ProjectView viewModel, HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@99 84 final var projectDao = dao.getProjectDao();
universe@99 85 final var versionDao = dao.getVersionDao();
universe@99 86
universe@99 87 projectDao.list().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add);
universe@99 88
universe@99 89 // Select Project
universe@99 90 final int pid = syncParamWithSession(req, PARAMETER_SELECTED_PROJECT, SESSION_ATTR_SELECTED_PROJECT);
universe@99 91 if (pid >= 0) {
universe@99 92 final var project = projectDao.find(pid);
universe@107 93 if (project == null) {
universe@107 94 req.setAttribute(SESSION_ATTR_SELECTED_PROJECT, -1);
universe@107 95 } else {
universe@107 96 final var info = new ProjectInfo(project);
universe@107 97 info.setVersions(versionDao.list(project));
universe@107 98 info.setIssueSummary(projectDao.getIssueSummary(project));
universe@107 99 viewModel.setProjectInfo(info);
universe@107 100 }
universe@99 101 }
universe@99 102
universe@99 103 // Select Version
universe@99 104 final int vid = syncParamWithSession(req, PARAMETER_SELECTED_VERSION, SESSION_ATTR_SELECTED_VERSION);
universe@99 105 if (vid >= 0) {
universe@99 106 viewModel.setVersionFilter(versionDao.find(vid));
universe@99 107 }
universe@99 108 }
universe@99 109
universe@99 110 private ResponseType forwardView(HttpServletRequest req, ProjectView viewModel, String name) {
universe@99 111 setViewModel(req, viewModel);
universe@99 112 setContentPage(req, name);
universe@99 113 setStylesheet(req, "projects");
universe@109 114 setNavigationMenu(req, "project-navmenu");
universe@99 115 return ResponseType.HTML;
universe@64 116 }
universe@64 117
universe@61 118 @RequestMapping(method = HttpMethod.GET)
universe@47 119 public ResponseType index(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@99 120 final var viewModel = new ProjectView();
universe@99 121 populate(viewModel, req, dao);
universe@86 122
universe@86 123 final var projectDao = dao.getProjectDao();
universe@86 124 final var versionDao = dao.getVersionDao();
universe@86 125
universe@99 126 for (var info : viewModel.getProjectList()) {
universe@99 127 info.setVersions(versionDao.list(info.getProject()));
universe@99 128 info.setIssueSummary(projectDao.getIssueSummary(info.getProject()));
universe@86 129 }
universe@86 130
universe@99 131 return forwardView(req, viewModel, "projects");
universe@45 132 }
universe@45 133
universe@99 134 private void configure(ProjectEditView viewModel, Project project, DataAccessObjects dao) throws SQLException {
universe@99 135 viewModel.setProject(project);
universe@86 136 viewModel.setUsers(dao.getUserDao().list());
universe@71 137 }
universe@71 138
universe@47 139 @RequestMapping(requestPath = "edit", method = HttpMethod.GET)
universe@51 140 public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@99 141 final var viewModel = new ProjectEditView();
universe@99 142 populate(viewModel, req, dao);
universe@47 143
universe@99 144 final var project = Optional.ofNullable(viewModel.getProjectInfo())
universe@99 145 .map(ProjectInfo::getProject)
universe@99 146 .orElse(new Project(-1));
universe@99 147 configure(viewModel, project, dao);
universe@47 148
universe@99 149 return forwardView(req, viewModel, "project-form");
universe@47 150 }
universe@47 151
universe@47 152 @RequestMapping(requestPath = "commit", method = HttpMethod.POST)
universe@68 153 public ResponseType commit(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@47 154
universe@75 155 Project project = new Project(-1);
universe@47 156 try {
universe@99 157 project = new Project(getParameter(req, Integer.class, "pid").orElseThrow());
universe@47 158 project.setName(getParameter(req, String.class, "name").orElseThrow());
universe@47 159 getParameter(req, String.class, "description").ifPresent(project::setDescription);
universe@47 160 getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl);
universe@47 161 getParameter(req, Integer.class, "owner").map(
universe@47 162 ownerId -> ownerId >= 0 ? new User(ownerId) : null
universe@47 163 ).ifPresent(project::setOwner);
universe@47 164
universe@47 165 dao.getProjectDao().saveOrUpdate(project);
universe@47 166
universe@109 167 setRedirectLocation(req, "./projects/versions?pid="+project.getId());
universe@74 168 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@59 169 LOG.debug("Successfully updated project {}", project.getName());
universe@99 170
universe@99 171 return ResponseType.HTML;
universe@75 172 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
universe@59 173 LOG.warn("Form validation failure: {}", ex.getMessage());
universe@59 174 LOG.debug("Details:", ex);
universe@99 175 final var viewModel = new ProjectEditView();
universe@99 176 populate(viewModel, req, dao);
universe@99 177 configure(viewModel, project, dao);
universe@99 178 // TODO: error text
universe@99 179 return forwardView(req, viewModel, "project-form");
universe@47 180 }
universe@47 181 }
universe@47 182
universe@70 183 @RequestMapping(requestPath = "view", method = HttpMethod.GET)
universe@80 184 public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException {
universe@99 185 final var viewModel = new ProjectDetailsView();
universe@99 186 populate(viewModel, req, dao);
universe@86 187
universe@99 188 if (viewModel.getProjectInfo() == null) {
universe@80 189 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected.");
universe@80 190 return ResponseType.NONE;
universe@80 191 }
universe@47 192
universe@86 193 final var issueDao = dao.getIssueDao();
universe@70 194
universe@105 195 final var version = viewModel.getVersionFilter();
universe@99 196
universe@99 197 final var detailView = viewModel.getProjectDetails();
universe@105 198 final var issues = issueDao.list(version);
universe@100 199 for (var issue : issues) issueDao.joinVersionInformation(issue);
universe@105 200 detailView.updateDetails(issues, version);
universe@80 201
universe@99 202 return forwardView(req, viewModel, "project-details");
universe@71 203 }
universe@71 204
universe@109 205 @RequestMapping(requestPath = "versions", method = HttpMethod.GET)
universe@109 206 public ResponseType versions(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException {
universe@109 207 final var viewModel = new VersionsView();
universe@109 208 populate(viewModel, req, dao);
universe@109 209 viewModel.setVersionFilter(null);
universe@109 210
universe@109 211 final var projectInfo = viewModel.getProjectInfo();
universe@109 212 if (projectInfo == null) {
universe@109 213 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected.");
universe@109 214 return ResponseType.NONE;
universe@109 215 }
universe@109 216
universe@109 217 final var issueDao = dao.getIssueDao();
universe@109 218 final var issues = issueDao.list(projectInfo.getProject());
universe@109 219 for (var issue : issues) issueDao.joinVersionInformation(issue);
universe@109 220 viewModel.update(projectInfo.getVersions(), issues);
universe@109 221
universe@109 222 return forwardView(req, viewModel, "versions");
universe@109 223 }
universe@109 224
universe@59 225 @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET)
universe@110 226 public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException {
universe@99 227 final var viewModel = new VersionEditView();
universe@99 228 populate(viewModel, req, dao);
universe@99 229
universe@110 230 if (viewModel.getProjectInfo() == null) {
universe@110 231 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected.");
universe@110 232 return ResponseType.NONE;
universe@110 233 }
universe@110 234
universe@99 235 if (viewModel.getVersionFilter() == null) {
universe@110 236 final var version = new Version(-1);
universe@110 237 version.setProject(viewModel.getProjectInfo().getProject());
universe@110 238 viewModel.setVersion(version);
universe@86 239 } else {
universe@99 240 viewModel.setVersion(viewModel.getVersionFilter());
universe@86 241 }
universe@59 242
universe@99 243 return forwardView(req, viewModel, "version-form");
universe@59 244 }
universe@59 245
universe@59 246 @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST)
universe@80 247 public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
universe@59 248
universe@86 249 var version = new Version(-1);
universe@59 250 try {
universe@86 251 version = new Version(getParameter(req, Integer.class, "id").orElseThrow());
universe@86 252 version.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow()));
universe@59 253 version.setName(getParameter(req, String.class, "name").orElseThrow());
universe@59 254 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
universe@59 255 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
universe@59 256 dao.getVersionDao().saveOrUpdate(version);
universe@59 257
universe@75 258 // specifying the pid parameter will purposely reset the session selected version!
universe@109 259 setRedirectLocation(req, "./projects/versions?pid=" + version.getProject().getId());
universe@74 260 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@75 261 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
universe@59 262 LOG.warn("Form validation failure: {}", ex.getMessage());
universe@59 263 LOG.debug("Details:", ex);
universe@99 264 final var viewModel = new VersionEditView();
universe@99 265 populate(viewModel, req, dao);
universe@99 266 viewModel.setVersion(version);
universe@86 267 // TODO: set Error Text
universe@99 268 return forwardView(req, viewModel, "version-form");
universe@59 269 }
universe@41 270
universe@43 271 return ResponseType.HTML;
universe@41 272 }
universe@64 273
universe@99 274 private void configure(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException {
universe@99 275 issue.setProject(viewModel.getProjectInfo().getProject());
universe@99 276 viewModel.setIssue(issue);
universe@99 277 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
universe@86 278 viewModel.setUsers(dao.getUserDao().list());
universe@71 279 }
universe@71 280
universe@64 281 @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET)
universe@80 282 public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
universe@99 283 final var viewModel = new IssueEditView();
universe@99 284
universe@99 285 final var issueParam = getParameter(req, Integer.class, "issue");
universe@99 286 if (issueParam.isPresent()) {
universe@104 287 final var issueDao = dao.getIssueDao();
universe@104 288 final var issue = issueDao.find(issueParam.get());
universe@104 289 issueDao.joinVersionInformation(issue);
universe@99 290 req.getSession().setAttribute(SESSION_ATTR_SELECTED_PROJECT, issue.getProject().getId());
universe@99 291 populate(viewModel, req, dao);
universe@99 292 configure(viewModel, issue, dao);
universe@86 293 } else {
universe@99 294 populate(viewModel, req, dao);
universe@99 295 configure(viewModel, new Issue(-1), dao);
universe@86 296 }
universe@64 297
universe@99 298 return forwardView(req, viewModel, "issue-form");
universe@64 299 }
universe@64 300
universe@64 301 @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST)
universe@80 302 public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
universe@86 303 Issue issue = new Issue(-1);
universe@64 304 try {
universe@86 305 issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow());
universe@86 306 issue.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow()));
universe@75 307 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
universe@75 308 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
universe@75 309 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
universe@75 310 getParameter(req, Integer.class, "assignee").map(
universe@75 311 userid -> userid >= 0 ? new User(userid) : null
universe@75 312 ).ifPresent(issue::setAssignee);
universe@75 313 getParameter(req, String.class, "description").ifPresent(issue::setDescription);
universe@75 314 getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
universe@83 315
universe@83 316 getParameter(req, Integer[].class, "affected")
universe@83 317 .map(Stream::of)
universe@83 318 .map(stream ->
universe@96 319 stream.map(Version::new).collect(Collectors.toList())
universe@83 320 ).ifPresent(issue::setAffectedVersions);
universe@83 321 getParameter(req, Integer[].class, "resolved")
universe@83 322 .map(Stream::of)
universe@83 323 .map(stream ->
universe@86 324 stream.map(Version::new).collect(Collectors.toList())
universe@83 325 ).ifPresent(issue::setResolvedVersions);
universe@83 326
universe@64 327 dao.getIssueDao().saveOrUpdate(issue);
universe@64 328
universe@96 329 // specifying the issue parameter keeps the edited issue as menu item
universe@102 330 setRedirectLocation(req, "./projects/view?pid=" + issue.getProject().getId());
universe@74 331 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@75 332 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
universe@64 333 // TODO: set request attribute with error text
universe@64 334 LOG.warn("Form validation failure: {}", ex.getMessage());
universe@64 335 LOG.debug("Details:", ex);
universe@99 336 final var viewModel = new IssueEditView();
universe@99 337 configure(viewModel, issue, dao);
universe@86 338 // TODO: set Error Text
universe@99 339 return forwardView(req, viewModel, "issue-form");
universe@64 340 }
universe@64 341
universe@64 342 return ResponseType.HTML;
universe@64 343 }
universe@41 344 }

mercurial