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

Sat, 29 Aug 2020 16:48:15 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 29 Aug 2020 16:48:15 +0200
changeset 104
8be80ea4f52b
parent 102
7eee7cad093d
child 105
250c5cbb8276
permissions
-rw-r--r--

fixes issue not containing version information in issue form

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.ArrayList;
universe@86 46 import java.util.List;
universe@86 47 import java.util.NoSuchElementException;
universe@99 48 import java.util.Optional;
universe@83 49 import java.util.stream.Collectors;
universe@83 50 import java.util.stream.Stream;
universe@41 51
universe@52 52 import static de.uapcore.lightpit.Functions.fqn;
universe@52 53
universe@41 54 @WebServlet(
universe@41 55 name = "ProjectsModule",
universe@41 56 urlPatterns = "/projects/*"
universe@41 57 )
universe@41 58 public final class ProjectsModule extends AbstractLightPITServlet {
universe@41 59
universe@59 60 private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class);
universe@59 61
universe@99 62 private static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected_project");
universe@99 63 private static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version");
universe@99 64 private static final String PARAMETER_SELECTED_PROJECT = "pid";
universe@99 65 private static final String PARAMETER_SELECTED_VERSION = "vid";
universe@71 66
universe@78 67 @Override
universe@78 68 protected String getResourceBundleName() {
universe@78 69 return "localization.projects";
universe@78 70 }
universe@71 71
universe@99 72 private String queryParams(Project p, Version v) {
universe@99 73 return String.format("pid=%d&vid=%d",
universe@97 74 p == null ? -1 : p.getId(),
universe@99 75 v == null ? -1 : v.getId()
universe@97 76 );
universe@97 77 }
universe@80 78
universe@71 79 /**
universe@96 80 * Creates the navigation menu.
universe@71 81 *
universe@99 82 * @param req the servlet request
universe@99 83 * @param viewModel the current view model
universe@71 84 */
universe@99 85 private void setNavigationMenu(HttpServletRequest req, ProjectView viewModel) {
universe@99 86 final Project selectedProject = Optional.ofNullable(viewModel.getProjectInfo()).map(ProjectInfo::getProject).orElse(null);
universe@99 87
universe@97 88 final var navigation = new ArrayList<MenuEntry>();
universe@71 89
universe@99 90 for (ProjectInfo plistInfo : viewModel.getProjectList()) {
universe@99 91 final var proj = plistInfo.getProject();
universe@97 92 final var projEntry = new MenuEntry(
universe@97 93 proj.getName(),
universe@99 94 "projects/view?" + queryParams(proj, null)
universe@97 95 );
universe@97 96 navigation.add(projEntry);
universe@99 97 if (proj.equals(selectedProject)) {
universe@99 98 final var projInfo = viewModel.getProjectInfo();
universe@97 99 projEntry.setActive(true);
universe@71 100
universe@97 101 // ****************
universe@97 102 // Versions Section
universe@97 103 // ****************
universe@97 104 {
universe@97 105 final var entry = new MenuEntry(1,
universe@99 106 new ResourceKey(getResourceBundleName(), "menu.versions"),
universe@99 107 "projects/view?" + queryParams(proj, null)
universe@97 108 );
universe@97 109 navigation.add(entry);
universe@97 110 }
universe@97 111
universe@97 112 final var level2 = new ArrayList<MenuEntry>();
universe@97 113 {
universe@97 114 final var entry = new MenuEntry(
universe@99 115 new ResourceKey(getResourceBundleName(), "filter.all"),
universe@99 116 "projects/view?" + queryParams(proj, null)
universe@97 117 );
universe@99 118 if (viewModel.getVersionFilter() == null) entry.setActive(true);
universe@97 119 level2.add(entry);
universe@97 120 }
universe@97 121
universe@97 122 for (Version version : projInfo.getVersions()) {
universe@97 123 final var entry = new MenuEntry(
universe@97 124 version.getName(),
universe@99 125 "projects/view?" + queryParams(proj, version)
universe@97 126 );
universe@99 127 if (version.equals(viewModel.getVersionFilter())) entry.setActive(true);
universe@97 128 level2.add(entry);
universe@97 129 }
universe@97 130
universe@97 131 level2.forEach(e -> e.setLevel(2));
universe@97 132 navigation.addAll(level2);
universe@75 133 }
universe@75 134 }
universe@75 135
universe@99 136 setNavigationMenu(req, navigation);
universe@99 137 }
universe@99 138
universe@99 139 private int syncParamWithSession(HttpServletRequest req, String param, String attr) {
universe@99 140 final var session = req.getSession();
universe@99 141 final var idParam = getParameter(req, Integer.class, param);
universe@99 142 final int id;
universe@99 143 if (idParam.isPresent()) {
universe@99 144 id = idParam.get();
universe@99 145 session.setAttribute(attr, id);
universe@99 146 } else {
universe@99 147 id = Optional.ofNullable(session.getAttribute(attr)).map(x->(Integer)x).orElse(-1);
universe@99 148 }
universe@99 149 return id;
universe@99 150 }
universe@99 151
universe@99 152 private void populate(ProjectView viewModel, HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@99 153 final var projectDao = dao.getProjectDao();
universe@99 154 final var versionDao = dao.getVersionDao();
universe@99 155
universe@99 156 projectDao.list().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add);
universe@99 157
universe@99 158 // Select Project
universe@99 159 final int pid = syncParamWithSession(req, PARAMETER_SELECTED_PROJECT, SESSION_ATTR_SELECTED_PROJECT);
universe@99 160 if (pid >= 0) {
universe@99 161 final var project = projectDao.find(pid);
universe@99 162 final var info = new ProjectInfo(project);
universe@99 163 info.setVersions(versionDao.list(project));
universe@99 164 info.setIssueSummary(projectDao.getIssueSummary(project));
universe@99 165 viewModel.setProjectInfo(info);
universe@99 166 }
universe@99 167
universe@99 168 // Select Version
universe@99 169 final int vid = syncParamWithSession(req, PARAMETER_SELECTED_VERSION, SESSION_ATTR_SELECTED_VERSION);
universe@99 170 if (vid >= 0) {
universe@99 171 viewModel.setVersionFilter(versionDao.find(vid));
universe@99 172 }
universe@99 173 }
universe@99 174
universe@99 175 private ResponseType forwardView(HttpServletRequest req, ProjectView viewModel, String name) {
universe@99 176 setViewModel(req, viewModel);
universe@99 177 setContentPage(req, name);
universe@99 178 setStylesheet(req, "projects");
universe@99 179 setNavigationMenu(req, viewModel);
universe@99 180 return ResponseType.HTML;
universe@64 181 }
universe@64 182
universe@61 183 @RequestMapping(method = HttpMethod.GET)
universe@47 184 public ResponseType index(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@99 185 final var viewModel = new ProjectView();
universe@99 186 populate(viewModel, req, dao);
universe@86 187
universe@86 188 final var projectDao = dao.getProjectDao();
universe@86 189 final var versionDao = dao.getVersionDao();
universe@86 190
universe@99 191 for (var info : viewModel.getProjectList()) {
universe@99 192 info.setVersions(versionDao.list(info.getProject()));
universe@99 193 info.setIssueSummary(projectDao.getIssueSummary(info.getProject()));
universe@86 194 }
universe@86 195
universe@99 196 return forwardView(req, viewModel, "projects");
universe@45 197 }
universe@45 198
universe@99 199 private void configure(ProjectEditView viewModel, Project project, DataAccessObjects dao) throws SQLException {
universe@99 200 viewModel.setProject(project);
universe@86 201 viewModel.setUsers(dao.getUserDao().list());
universe@71 202 }
universe@71 203
universe@47 204 @RequestMapping(requestPath = "edit", method = HttpMethod.GET)
universe@51 205 public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@99 206 final var viewModel = new ProjectEditView();
universe@99 207 populate(viewModel, req, dao);
universe@47 208
universe@99 209 final var project = Optional.ofNullable(viewModel.getProjectInfo())
universe@99 210 .map(ProjectInfo::getProject)
universe@99 211 .orElse(new Project(-1));
universe@99 212 configure(viewModel, project, dao);
universe@47 213
universe@99 214 return forwardView(req, viewModel, "project-form");
universe@47 215 }
universe@47 216
universe@47 217 @RequestMapping(requestPath = "commit", method = HttpMethod.POST)
universe@68 218 public ResponseType commit(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@47 219
universe@75 220 Project project = new Project(-1);
universe@47 221 try {
universe@99 222 project = new Project(getParameter(req, Integer.class, "pid").orElseThrow());
universe@47 223 project.setName(getParameter(req, String.class, "name").orElseThrow());
universe@47 224 getParameter(req, String.class, "description").ifPresent(project::setDescription);
universe@47 225 getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl);
universe@47 226 getParameter(req, Integer.class, "owner").map(
universe@47 227 ownerId -> ownerId >= 0 ? new User(ownerId) : null
universe@47 228 ).ifPresent(project::setOwner);
universe@47 229
universe@47 230 dao.getProjectDao().saveOrUpdate(project);
universe@47 231
universe@99 232 setRedirectLocation(req, "./projects/view?pid="+project.getId());
universe@74 233 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@59 234 LOG.debug("Successfully updated project {}", project.getName());
universe@99 235
universe@99 236 return ResponseType.HTML;
universe@75 237 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
universe@59 238 LOG.warn("Form validation failure: {}", ex.getMessage());
universe@59 239 LOG.debug("Details:", ex);
universe@99 240 final var viewModel = new ProjectEditView();
universe@99 241 populate(viewModel, req, dao);
universe@99 242 configure(viewModel, project, dao);
universe@99 243 // TODO: error text
universe@99 244 return forwardView(req, viewModel, "project-form");
universe@47 245 }
universe@47 246 }
universe@47 247
universe@70 248 @RequestMapping(requestPath = "view", method = HttpMethod.GET)
universe@80 249 public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException {
universe@99 250 final var viewModel = new ProjectDetailsView();
universe@99 251 populate(viewModel, req, dao);
universe@86 252
universe@99 253 if (viewModel.getProjectInfo() == null) {
universe@80 254 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected.");
universe@80 255 return ResponseType.NONE;
universe@80 256 }
universe@47 257
universe@86 258 final var issueDao = dao.getIssueDao();
universe@70 259
universe@99 260 final var project = viewModel.getProjectInfo().getProject();
universe@99 261
universe@99 262 final var detailView = viewModel.getProjectDetails();
universe@100 263 final var issues = issueDao.list(project);
universe@100 264 for (var issue : issues) issueDao.joinVersionInformation(issue);
universe@100 265 detailView.setIssues(issues);
universe@99 266 if (viewModel.getVersionFilter() != null) {
universe@99 267 detailView.updateVersionInfo(List.of(viewModel.getVersionFilter()));
universe@99 268 } else {
universe@99 269 detailView.updateVersionInfo(viewModel.getProjectInfo().getVersions());
universe@99 270 }
universe@80 271
universe@99 272 return forwardView(req, viewModel, "project-details");
universe@71 273 }
universe@71 274
universe@59 275 @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET)
universe@86 276 public ResponseType editVersion(HttpServletRequest req, DataAccessObjects dao) throws SQLException {
universe@99 277 final var viewModel = new VersionEditView();
universe@99 278 populate(viewModel, req, dao);
universe@99 279
universe@99 280 if (viewModel.getVersionFilter() == null) {
universe@99 281 viewModel.setVersion(new Version(-1));
universe@86 282 } else {
universe@99 283 viewModel.setVersion(viewModel.getVersionFilter());
universe@86 284 }
universe@59 285
universe@99 286 return forwardView(req, viewModel, "version-form");
universe@59 287 }
universe@59 288
universe@59 289 @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST)
universe@80 290 public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
universe@59 291
universe@86 292 var version = new Version(-1);
universe@59 293 try {
universe@86 294 version = new Version(getParameter(req, Integer.class, "id").orElseThrow());
universe@86 295 version.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow()));
universe@59 296 version.setName(getParameter(req, String.class, "name").orElseThrow());
universe@59 297 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
universe@59 298 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
universe@59 299 dao.getVersionDao().saveOrUpdate(version);
universe@59 300
universe@75 301 // specifying the pid parameter will purposely reset the session selected version!
universe@96 302 setRedirectLocation(req, "./projects/view?pid=" + version.getProject().getId());
universe@74 303 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@75 304 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
universe@59 305 LOG.warn("Form validation failure: {}", ex.getMessage());
universe@59 306 LOG.debug("Details:", ex);
universe@99 307 final var viewModel = new VersionEditView();
universe@99 308 populate(viewModel, req, dao);
universe@99 309 viewModel.setVersion(version);
universe@86 310 // TODO: set Error Text
universe@99 311 return forwardView(req, viewModel, "version-form");
universe@59 312 }
universe@41 313
universe@43 314 return ResponseType.HTML;
universe@41 315 }
universe@64 316
universe@99 317 private void configure(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException {
universe@99 318 issue.setProject(viewModel.getProjectInfo().getProject());
universe@99 319 viewModel.setIssue(issue);
universe@99 320 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
universe@86 321 viewModel.setUsers(dao.getUserDao().list());
universe@71 322 }
universe@71 323
universe@64 324 @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET)
universe@80 325 public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
universe@99 326 final var viewModel = new IssueEditView();
universe@99 327
universe@99 328 final var issueParam = getParameter(req, Integer.class, "issue");
universe@99 329 if (issueParam.isPresent()) {
universe@104 330 final var issueDao = dao.getIssueDao();
universe@104 331 final var issue = issueDao.find(issueParam.get());
universe@104 332 issueDao.joinVersionInformation(issue);
universe@99 333 req.getSession().setAttribute(SESSION_ATTR_SELECTED_PROJECT, issue.getProject().getId());
universe@99 334 populate(viewModel, req, dao);
universe@99 335 configure(viewModel, issue, dao);
universe@86 336 } else {
universe@99 337 populate(viewModel, req, dao);
universe@99 338 configure(viewModel, new Issue(-1), dao);
universe@86 339 }
universe@64 340
universe@99 341 return forwardView(req, viewModel, "issue-form");
universe@64 342 }
universe@64 343
universe@64 344 @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST)
universe@80 345 public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException {
universe@86 346 Issue issue = new Issue(-1);
universe@64 347 try {
universe@86 348 issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow());
universe@86 349 issue.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow()));
universe@75 350 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
universe@75 351 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
universe@75 352 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
universe@75 353 getParameter(req, Integer.class, "assignee").map(
universe@75 354 userid -> userid >= 0 ? new User(userid) : null
universe@75 355 ).ifPresent(issue::setAssignee);
universe@75 356 getParameter(req, String.class, "description").ifPresent(issue::setDescription);
universe@75 357 getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
universe@83 358
universe@83 359 getParameter(req, Integer[].class, "affected")
universe@83 360 .map(Stream::of)
universe@83 361 .map(stream ->
universe@96 362 stream.map(Version::new).collect(Collectors.toList())
universe@83 363 ).ifPresent(issue::setAffectedVersions);
universe@83 364 getParameter(req, Integer[].class, "resolved")
universe@83 365 .map(Stream::of)
universe@83 366 .map(stream ->
universe@86 367 stream.map(Version::new).collect(Collectors.toList())
universe@83 368 ).ifPresent(issue::setResolvedVersions);
universe@83 369
universe@64 370 dao.getIssueDao().saveOrUpdate(issue);
universe@64 371
universe@96 372 // specifying the issue parameter keeps the edited issue as menu item
universe@102 373 setRedirectLocation(req, "./projects/view?pid=" + issue.getProject().getId());
universe@74 374 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@75 375 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
universe@64 376 // TODO: set request attribute with error text
universe@64 377 LOG.warn("Form validation failure: {}", ex.getMessage());
universe@64 378 LOG.debug("Details:", ex);
universe@99 379 final var viewModel = new IssueEditView();
universe@99 380 configure(viewModel, issue, dao);
universe@86 381 // TODO: set Error Text
universe@99 382 return forwardView(req, viewModel, "issue-form");
universe@64 383 }
universe@64 384
universe@64 385 return ResponseType.HTML;
universe@64 386 }
universe@41 387 }

mercurial