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

Wed, 06 Jan 2021 15:39:56 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 06 Jan 2021 15:39:56 +0100
changeset 180
009700915269
parent 179
623c340058f3
permissions
-rw-r--r--

merge resource bundles

universe@41 1 /*
universe@41 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@41 3 *
universe@180 4 * Copyright 2021 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@167 33 import de.uapcore.lightpit.dao.DataAccessObject;
universe@64 34 import de.uapcore.lightpit.entities.*;
universe@167 35 import de.uapcore.lightpit.filter.AllFilter;
universe@167 36 import de.uapcore.lightpit.filter.IssueFilter;
universe@167 37 import de.uapcore.lightpit.filter.NoneFilter;
universe@167 38 import de.uapcore.lightpit.filter.SpecificFilter;
universe@167 39 import de.uapcore.lightpit.types.IssueCategory;
universe@167 40 import de.uapcore.lightpit.types.IssueStatus;
universe@167 41 import de.uapcore.lightpit.types.VersionStatus;
universe@134 42 import de.uapcore.lightpit.types.WebColor;
universe@86 43 import de.uapcore.lightpit.viewmodel.*;
universe@121 44 import de.uapcore.lightpit.viewmodel.util.IssueSorter;
universe@59 45 import org.slf4j.Logger;
universe@59 46 import org.slf4j.LoggerFactory;
universe@41 47
universe@157 48 import javax.servlet.ServletException;
universe@41 49 import javax.servlet.annotation.WebServlet;
universe@41 50 import javax.servlet.http.HttpServletRequest;
universe@59 51 import javax.servlet.http.HttpServletResponse;
universe@59 52 import java.io.IOException;
universe@75 53 import java.sql.Date;
universe@47 54 import java.sql.SQLException;
universe@86 55 import java.util.NoSuchElementException;
universe@136 56 import java.util.Optional;
universe@83 57 import java.util.stream.Collectors;
universe@83 58 import java.util.stream.Stream;
universe@41 59
universe@41 60 @WebServlet(
universe@41 61 name = "ProjectsModule",
universe@41 62 urlPatterns = "/projects/*"
universe@41 63 )
universe@179 64 public final class ProjectsModule extends AbstractServlet {
universe@41 65
universe@59 66 private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class);
universe@59 67
universe@158 68 private static int parseIntOrZero(String str) {
universe@158 69 try {
universe@158 70 return Integer.parseInt(str);
universe@158 71 } catch (NumberFormatException ex) {
universe@158 72 return 0;
universe@158 73 }
universe@158 74 }
universe@158 75
universe@167 76 private void populate(ProjectView viewModel, PathParameters pathParameters, DataAccessObject dao) {
universe@167 77 dao.listProjects().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add);
universe@99 78
universe@131 79 if (pathParameters == null)
universe@131 80 return;
universe@131 81
universe@99 82 // Select Project
universe@167 83 final var project = dao.findProjectByNode(pathParameters.get("project"));
universe@138 84 if (project == null)
universe@138 85 return;
universe@138 86
universe@138 87 final var info = new ProjectInfo(project);
universe@167 88 info.setVersions(dao.listVersions(project));
universe@167 89 info.setComponents(dao.listComponents(project));
universe@167 90 info.setIssueSummary(dao.collectIssueSummary(project));
universe@138 91 viewModel.setProjectInfo(info);
universe@99 92
universe@99 93 // Select Version
universe@138 94 final var versionNode = pathParameters.get("version");
universe@161 95 if (versionNode != null) {
universe@161 96 if ("no-version".equals(versionNode)) {
universe@161 97 viewModel.setVersionFilter(ProjectView.NO_VERSION);
universe@161 98 } else if ("all-versions".equals(versionNode)) {
universe@161 99 viewModel.setVersionFilter(ProjectView.ALL_VERSIONS);
universe@161 100 } else {
universe@167 101 viewModel.setVersionFilter(dao.findVersionByNode(project, versionNode));
universe@161 102 }
universe@131 103 }
universe@131 104
universe@131 105 // Select Component
universe@138 106 final var componentNode = pathParameters.get("component");
universe@161 107 if (componentNode != null) {
universe@161 108 if ("no-component".equals(componentNode)) {
universe@161 109 viewModel.setComponentFilter(ProjectView.NO_COMPONENT);
universe@161 110 } else if ("all-components".equals(componentNode)) {
universe@161 111 viewModel.setComponentFilter(ProjectView.ALL_COMPONENTS);
universe@161 112 } else {
universe@167 113 viewModel.setComponentFilter(dao.findComponentByNode(project, componentNode));
universe@161 114 }
universe@138 115 }
universe@138 116 }
universe@138 117
universe@138 118 private static String sanitizeNode(String node, String defaultValue) {
universe@138 119 String result = node == null || node.isBlank() ? defaultValue : node;
universe@138 120 result = result.replace('/', '-');
universe@138 121 if (result.equals(".") || result.equals("..")) {
universe@138 122 return "_"+result;
universe@138 123 } else {
universe@138 124 return result;
universe@129 125 }
universe@99 126 }
universe@99 127
universe@157 128 private void forwardView(HttpServletRequest req, HttpServletResponse resp, ProjectView viewModel, String name) throws ServletException, IOException {
universe@99 129 setViewModel(req, viewModel);
universe@99 130 setContentPage(req, name);
universe@99 131 setStylesheet(req, "projects");
universe@109 132 setNavigationMenu(req, "project-navmenu");
universe@157 133 renderSite(req, resp);
universe@64 134 }
universe@64 135
universe@61 136 @RequestMapping(method = HttpMethod.GET)
universe@167 137 public void index(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws ServletException, IOException {
universe@99 138 final var viewModel = new ProjectView();
universe@131 139 populate(viewModel, null, dao);
universe@86 140
universe@99 141 for (var info : viewModel.getProjectList()) {
universe@167 142 info.setVersions(dao.listVersions(info.getProject()));
universe@167 143 info.setIssueSummary(dao.collectIssueSummary(info.getProject()));
universe@86 144 }
universe@86 145
universe@157 146 forwardView(req, resp, viewModel, "projects");
universe@45 147 }
universe@45 148
universe@167 149 private void configureProjectEditor(ProjectEditView viewModel, Project project, DataAccessObject dao) {
universe@99 150 viewModel.setProject(project);
universe@167 151 viewModel.setUsers(dao.listUsers());
universe@71 152 }
universe@71 153
universe@131 154 @RequestMapping(requestPath = "$project/edit", method = HttpMethod.GET)
universe@167 155 public void edit(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObject dao) throws IOException, SQLException, ServletException {
universe@99 156 final var viewModel = new ProjectEditView();
universe@131 157 populate(viewModel, pathParams, dao);
universe@47 158
universe@134 159 if (!viewModel.isProjectInfoPresent()) {
universe@131 160 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 161 return;
universe@131 162 }
universe@47 163
universe@131 164 configureProjectEditor(viewModel, viewModel.getProjectInfo().getProject(), dao);
universe@157 165 forwardView(req, resp, viewModel, "project-form");
universe@131 166 }
universe@131 167
universe@131 168 @RequestMapping(requestPath = "create", method = HttpMethod.GET)
universe@167 169 public void create(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws SQLException, ServletException, IOException {
universe@131 170 final var viewModel = new ProjectEditView();
universe@131 171 populate(viewModel, null, dao);
universe@131 172 configureProjectEditor(viewModel, new Project(-1), dao);
universe@157 173 forwardView(req, resp, viewModel, "project-form");
universe@47 174 }
universe@47 175
universe@47 176 @RequestMapping(requestPath = "commit", method = HttpMethod.POST)
universe@167 177 public void commit(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
universe@47 178
universe@47 179 try {
universe@131 180 final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow());
universe@47 181 project.setName(getParameter(req, String.class, "name").orElseThrow());
universe@138 182
universe@138 183 final var node = getParameter(req, String.class, "node").orElse(null);
universe@138 184 project.setNode(sanitizeNode(node, project.getName()));
universe@175 185 getParameter(req, Integer.class, "ordinal").ifPresent(project::setOrdinal);
universe@138 186
universe@47 187 getParameter(req, String.class, "description").ifPresent(project::setDescription);
universe@47 188 getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl);
universe@47 189 getParameter(req, Integer.class, "owner").map(
universe@47 190 ownerId -> ownerId >= 0 ? new User(ownerId) : null
universe@47 191 ).ifPresent(project::setOwner);
universe@47 192
mike@159 193 if (project.getId() > 0) {
universe@167 194 dao.updateProject(project);
mike@159 195 } else {
universe@167 196 dao.insertProject(project);
mike@159 197 }
universe@47 198
universe@118 199 setRedirectLocation(req, "./projects/");
universe@74 200 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@59 201 LOG.debug("Successfully updated project {}", project.getName());
universe@99 202
universe@157 203 renderSite(req, resp);
mike@159 204 } catch (NoSuchElementException | IllegalArgumentException ex) {
universe@131 205 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
universe@131 206 // TODO: implement - fix issue #21
universe@47 207 }
universe@47 208 }
universe@47 209
universe@134 210 @RequestMapping(requestPath = "$project/$component/$version/issues/", method = HttpMethod.GET)
universe@167 211 public void issues(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObject dao) throws SQLException, IOException, ServletException {
universe@99 212 final var viewModel = new ProjectDetailsView();
universe@131 213 populate(viewModel, pathParams, dao);
universe@86 214
universe@134 215 if (!viewModel.isEveryFilterValid()) {
universe@131 216 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 217 return;
universe@80 218 }
universe@47 219
universe@134 220 final var project = viewModel.getProjectInfo().getProject();
universe@134 221 final var version = viewModel.getVersionFilter();
universe@134 222 final var component = viewModel.getComponentFilter();
universe@134 223
universe@167 224 // TODO: use new IssueFilter class for the ViewModel
universe@70 225
universe@167 226 final var projectFilter = new SpecificFilter<>(project);
universe@167 227 final IssueFilter filter;
universe@134 228 if (version.equals(ProjectView.NO_VERSION)) {
universe@134 229 if (component.equals(ProjectView.ALL_COMPONENTS)) {
universe@167 230 filter = new IssueFilter(projectFilter,
universe@167 231 new NoneFilter<>(),
universe@167 232 new AllFilter<>()
universe@167 233 );
universe@134 234 } else if (component.equals(ProjectView.NO_COMPONENT)) {
universe@167 235 filter = new IssueFilter(projectFilter,
universe@167 236 new NoneFilter<>(),
universe@167 237 new NoneFilter<>()
universe@167 238 );
universe@134 239 } else {
universe@167 240 filter = new IssueFilter(projectFilter,
universe@167 241 new NoneFilter<>(),
universe@167 242 new SpecificFilter<>(component)
universe@167 243 );
universe@134 244 }
universe@134 245 } else if (version.equals(ProjectView.ALL_VERSIONS)) {
universe@134 246 if (component.equals(ProjectView.ALL_COMPONENTS)) {
universe@167 247 filter = new IssueFilter(projectFilter,
universe@167 248 new AllFilter<>(),
universe@167 249 new AllFilter<>()
universe@167 250 );
universe@134 251 } else if (component.equals(ProjectView.NO_COMPONENT)) {
universe@167 252 filter = new IssueFilter(projectFilter,
universe@167 253 new AllFilter<>(),
universe@167 254 new NoneFilter<>()
universe@167 255 );
universe@134 256 } else {
universe@167 257 filter = new IssueFilter(projectFilter,
universe@167 258 new AllFilter<>(),
universe@167 259 new SpecificFilter<>(component)
universe@167 260 );
universe@134 261 }
universe@134 262 } else {
universe@134 263 if (component.equals(ProjectView.ALL_COMPONENTS)) {
universe@167 264 filter = new IssueFilter(projectFilter,
universe@167 265 new SpecificFilter<>(version),
universe@167 266 new AllFilter<>()
universe@167 267 );
universe@134 268 } else if (component.equals(ProjectView.NO_COMPONENT)) {
universe@167 269 filter = new IssueFilter(projectFilter,
universe@167 270 new SpecificFilter<>(version),
universe@167 271 new NoneFilter<>()
universe@167 272 );
universe@134 273 } else {
universe@167 274 filter = new IssueFilter(projectFilter,
universe@167 275 new SpecificFilter<>(version),
universe@167 276 new SpecificFilter<>(component)
universe@167 277 );
universe@134 278 }
universe@134 279 }
universe@134 280
universe@167 281 final var issues = dao.listIssues(filter);
universe@121 282 issues.sort(new IssueSorter(
universe@141 283 new IssueSorter.Criteria(IssueSorter.Field.DONE, true),
universe@121 284 new IssueSorter.Criteria(IssueSorter.Field.ETA, true),
universe@121 285 new IssueSorter.Criteria(IssueSorter.Field.UPDATED, false)
universe@121 286 ));
universe@134 287
universe@134 288
universe@134 289 viewModel.getProjectDetails().updateDetails(issues);
universe@134 290 if (version.getId() > 0)
universe@134 291 viewModel.getProjectDetails().updateVersionInfo(version);
universe@80 292
universe@157 293 forwardView(req, resp, viewModel, "project-details");
universe@71 294 }
universe@71 295
universe@131 296 @RequestMapping(requestPath = "$project/versions/", method = HttpMethod.GET)
universe@167 297 public void versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException {
universe@109 298 final var viewModel = new VersionsView();
universe@131 299 populate(viewModel, pathParameters, dao);
universe@109 300
universe@109 301 final var projectInfo = viewModel.getProjectInfo();
universe@109 302 if (projectInfo == null) {
universe@131 303 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 304 return;
universe@109 305 }
universe@109 306
universe@167 307 final var issues = dao.listIssues(
universe@167 308 new IssueFilter(
universe@167 309 new SpecificFilter<>(projectInfo.getProject()),
universe@167 310 new AllFilter<>(),
universe@167 311 new AllFilter<>()
universe@167 312 )
universe@167 313 );
universe@109 314 viewModel.update(projectInfo.getVersions(), issues);
universe@109 315
universe@157 316 forwardView(req, resp, viewModel, "versions");
universe@109 317 }
universe@109 318
universe@131 319 @RequestMapping(requestPath = "$project/versions/$version/edit", method = HttpMethod.GET)
universe@167 320 public void editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
universe@99 321 final var viewModel = new VersionEditView();
universe@131 322 populate(viewModel, pathParameters, dao);
universe@99 323
universe@131 324 if (viewModel.getProjectInfo() == null || viewModel.getVersionFilter() == null) {
universe@131 325 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 326 return;
universe@110 327 }
universe@110 328
universe@131 329 viewModel.setVersion(viewModel.getVersionFilter());
universe@59 330
universe@157 331 forwardView(req, resp, viewModel, "version-form");
universe@59 332 }
universe@59 333
universe@131 334 @RequestMapping(requestPath = "$project/create-version", method = HttpMethod.GET)
universe@167 335 public void createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
universe@131 336 final var viewModel = new VersionEditView();
universe@131 337 populate(viewModel, pathParameters, dao);
universe@59 338
universe@131 339 if (viewModel.getProjectInfo() == null) {
universe@131 340 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 341 return;
universe@131 342 }
universe@131 343
universe@167 344 viewModel.setVersion(new Version(-1, viewModel.getProjectInfo().getProject().getId()));
universe@131 345
universe@157 346 forwardView(req, resp, viewModel, "version-form");
universe@131 347 }
universe@131 348
universe@131 349 @RequestMapping(requestPath = "commit-version", method = HttpMethod.POST)
universe@167 350 public void commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
universe@131 351
universe@59 352 try {
universe@167 353 final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow());
universe@138 354 if (project == null) {
universe@138 355 // TODO: improve error handling, because not found is not correct for this POST request
universe@138 356 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 357 return;
universe@138 358 }
universe@167 359 final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow(), project.getId());
universe@59 360 version.setName(getParameter(req, String.class, "name").orElseThrow());
universe@138 361
universe@138 362 final var node = getParameter(req, String.class, "node").orElse(null);
universe@138 363 version.setNode(sanitizeNode(node, version.getName()));
universe@138 364
universe@59 365 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
universe@59 366 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
mike@159 367
mike@159 368 if (version.getId() > 0) {
universe@167 369 dao.updateVersion(version);
mike@159 370 } else {
universe@167 371 dao.insertVersion(version);
mike@159 372 }
universe@59 373
universe@138 374 setRedirectLocation(req, "./projects/" + project.getNode() + "/versions/");
universe@74 375 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@157 376
universe@157 377 renderSite(req, resp);
mike@159 378 } catch (NoSuchElementException | IllegalArgumentException ex) {
universe@131 379 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
universe@131 380 // TODO: implement - fix issue #21
universe@59 381 }
universe@41 382 }
universe@64 383
universe@134 384 @RequestMapping(requestPath = "$project/components/", method = HttpMethod.GET)
universe@167 385 public void components(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException {
universe@134 386 final var viewModel = new ComponentsView();
universe@134 387 populate(viewModel, pathParameters, dao);
universe@134 388
universe@134 389 final var projectInfo = viewModel.getProjectInfo();
universe@134 390 if (projectInfo == null) {
universe@134 391 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 392 return;
universe@134 393 }
universe@134 394
universe@167 395 final var issues = dao.listIssues(
universe@167 396 new IssueFilter(
universe@167 397 new SpecificFilter<>(projectInfo.getProject()),
universe@167 398 new AllFilter<>(),
universe@167 399 new AllFilter<>()
universe@167 400 )
universe@167 401 );
universe@134 402 viewModel.update(projectInfo.getComponents(), issues);
universe@134 403
universe@157 404 forwardView(req, resp, viewModel, "components");
universe@134 405 }
universe@134 406
universe@134 407 @RequestMapping(requestPath = "$project/components/$component/edit", method = HttpMethod.GET)
universe@167 408 public void editComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
universe@134 409 final var viewModel = new ComponentEditView();
universe@134 410 populate(viewModel, pathParameters, dao);
universe@134 411
universe@134 412 if (viewModel.getProjectInfo() == null || viewModel.getComponentFilter() == null) {
universe@134 413 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 414 return;
universe@134 415 }
universe@134 416
universe@134 417 viewModel.setComponent(viewModel.getComponentFilter());
universe@167 418 viewModel.setUsers(dao.listUsers());
universe@134 419
universe@157 420 forwardView(req, resp, viewModel, "component-form");
universe@134 421 }
universe@134 422
universe@134 423 @RequestMapping(requestPath = "$project/create-component", method = HttpMethod.GET)
universe@167 424 public void createComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
universe@134 425 final var viewModel = new ComponentEditView();
universe@134 426 populate(viewModel, pathParameters, dao);
universe@134 427
universe@134 428 if (viewModel.getProjectInfo() == null) {
universe@134 429 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 430 return;
universe@134 431 }
universe@134 432
universe@167 433 viewModel.setComponent(new Component(-1, viewModel.getProjectInfo().getProject().getId()));
universe@167 434 viewModel.setUsers(dao.listUsers());
universe@134 435
universe@157 436 forwardView(req, resp, viewModel, "component-form");
universe@134 437 }
universe@134 438
universe@134 439 @RequestMapping(requestPath = "commit-component", method = HttpMethod.POST)
universe@167 440 public void commitComponent(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
universe@134 441
universe@134 442 try {
universe@167 443 final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow());
universe@138 444 if (project == null) {
universe@138 445 // TODO: improve error handling, because not found is not correct for this POST request
universe@138 446 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 447 return;
universe@138 448 }
universe@167 449 final var component = new Component(getParameter(req, Integer.class, "id").orElseThrow(), project.getId());
universe@134 450 component.setName(getParameter(req, String.class, "name").orElseThrow());
universe@138 451
universe@138 452 final var node = getParameter(req, String.class, "node").orElse(null);
universe@138 453 component.setNode(sanitizeNode(node, component.getName()));
universe@138 454
universe@134 455 component.setColor(getParameter(req, WebColor.class, "color").orElseThrow());
universe@134 456 getParameter(req, Integer.class, "ordinal").ifPresent(component::setOrdinal);
universe@134 457 getParameter(req, Integer.class, "lead").map(
universe@134 458 userid -> userid >= 0 ? new User(userid) : null
universe@134 459 ).ifPresent(component::setLead);
universe@134 460 getParameter(req, String.class, "description").ifPresent(component::setDescription);
universe@134 461
mike@159 462 if (component.getId() > 0) {
universe@167 463 dao.updateComponent(component);
mike@159 464 } else {
universe@167 465 dao.insertComponent(component);
mike@159 466 }
universe@134 467
universe@138 468 setRedirectLocation(req, "./projects/" + project.getNode() + "/components/");
universe@134 469 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@157 470
universe@157 471 renderSite(req, resp);
mike@159 472 } catch (NoSuchElementException | IllegalArgumentException ex) {
universe@134 473 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
universe@134 474 // TODO: implement - fix issue #21
universe@134 475 }
universe@134 476 }
universe@134 477
universe@167 478 private void configureIssueEditor(IssueEditView viewModel, Issue issue, DataAccessObject dao) {
universe@134 479 final var project = viewModel.getProjectInfo().getProject();
universe@146 480 issue.setProject(project); // automatically set current project for new issues
universe@99 481 viewModel.setIssue(issue);
universe@99 482 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
universe@167 483 viewModel.setUsers(dao.listUsers());
universe@167 484 viewModel.setComponents(dao.listComponents(project));
universe@71 485 }
universe@71 486
universe@146 487 @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET)
universe@167 488 public void viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
universe@146 489 final var viewModel = new IssueDetailView();
universe@146 490 populate(viewModel, pathParameters, dao);
universe@146 491
universe@146 492 final var projectInfo = viewModel.getProjectInfo();
universe@146 493 if (projectInfo == null) {
universe@146 494 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 495 return;
universe@146 496 }
universe@146 497
universe@167 498 final var issue = dao.findIssue(parseIntOrZero(pathParameters.get("issue")));
universe@146 499 if (issue == null) {
universe@146 500 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 501 return;
universe@146 502 }
universe@146 503
universe@146 504 viewModel.setIssue(issue);
universe@167 505 viewModel.setComments(dao.listComments(issue));
universe@146 506
universe@162 507 viewModel.processMarkdown();
universe@162 508
universe@157 509 forwardView(req, resp, viewModel, "issue-view");
universe@146 510 }
universe@146 511
universe@146 512 // TODO: why should the issue editor be child of $project?
universe@131 513 @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET)
universe@167 514 public void editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException {
universe@99 515 final var viewModel = new IssueEditView();
universe@131 516 populate(viewModel, pathParameters, dao);
universe@99 517
universe@131 518 final var projectInfo = viewModel.getProjectInfo();
universe@131 519 if (projectInfo == null) {
universe@131 520 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 521 return;
universe@86 522 }
universe@64 523
universe@167 524 final var issue = dao.findIssue(parseIntOrZero(pathParameters.get("issue")));
universe@131 525 if (issue == null) {
universe@131 526 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 527 return;
universe@131 528 }
universe@131 529
universe@133 530 configureIssueEditor(viewModel, issue, dao);
universe@131 531
universe@157 532 forwardView(req, resp, viewModel, "issue-form");
universe@64 533 }
universe@64 534
universe@131 535 @RequestMapping(requestPath = "$project/create-issue", method = HttpMethod.GET)
universe@168 536 public void createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException {
universe@131 537 final var viewModel = new IssueEditView();
universe@131 538 populate(viewModel, pathParameters, dao);
universe@131 539
universe@131 540 final var projectInfo = viewModel.getProjectInfo();
universe@131 541 if (projectInfo == null) {
universe@131 542 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 543 return;
universe@131 544 }
universe@131 545
universe@168 546 setAttributeFromParameter(req, "more");
universe@178 547 setAttributeFromParameter(req, "cid");
universe@178 548 setAttributeFromParameter(req, "vid");
universe@168 549
universe@167 550 final var issue = new Issue(-1, projectInfo.getProject(), null);
universe@131 551 issue.setProject(projectInfo.getProject());
universe@133 552 configureIssueEditor(viewModel, issue, dao);
universe@131 553
universe@157 554 forwardView(req, resp, viewModel, "issue-form");
universe@131 555 }
universe@131 556
universe@131 557 @RequestMapping(requestPath = "commit-issue", method = HttpMethod.POST)
universe@167 558 public void commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
universe@64 559 try {
universe@167 560 final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow());
universe@138 561 if (project == null) {
universe@138 562 // TODO: improve error handling, because not found is not correct for this POST request
universe@138 563 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 564 return;
universe@138 565 }
universe@167 566 final var componentId = getParameter(req, Integer.class, "component");
universe@167 567 final Component component;
universe@167 568 if (componentId.isPresent()) {
universe@167 569 component = dao.findComponent(componentId.get());
universe@167 570 } else {
universe@167 571 component = null;
universe@167 572 }
universe@167 573 final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow(), project, component);
universe@75 574 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
universe@75 575 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
universe@75 576 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
universe@136 577 getParameter(req, Integer.class, "assignee").map(userid -> {
universe@136 578 if (userid >= 0) {
universe@136 579 return new User(userid);
universe@136 580 } else if (userid == -2) {
universe@136 581 return Optional.ofNullable(component).map(Component::getLead).orElse(null);
universe@136 582 } else {
universe@136 583 return null;
universe@136 584 }
universe@136 585 }
universe@75 586 ).ifPresent(issue::setAssignee);
universe@75 587 getParameter(req, String.class, "description").ifPresent(issue::setDescription);
universe@75 588 getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
universe@83 589
universe@83 590 getParameter(req, Integer[].class, "affected")
universe@83 591 .map(Stream::of)
universe@83 592 .map(stream ->
universe@167 593 stream.map(id -> new Version(id, project.getId()))
universe@167 594 .collect(Collectors.toList())
universe@83 595 ).ifPresent(issue::setAffectedVersions);
universe@83 596 getParameter(req, Integer[].class, "resolved")
universe@83 597 .map(Stream::of)
universe@83 598 .map(stream ->
universe@167 599 stream.map(id -> new Version(id, project.getId()))
universe@167 600 .collect(Collectors.toList())
universe@83 601 ).ifPresent(issue::setResolvedVersions);
universe@83 602
mike@159 603 if (issue.getId() > 0) {
universe@167 604 dao.updateIssue(issue);
mike@159 605 } else {
universe@167 606 dao.insertIssue(issue);
mike@159 607 }
universe@64 608
universe@168 609 if (getParameter(req, Boolean.class, "create-another").orElse(false)) {
universe@168 610 // TODO: fix #38 - automatically select component (and version)
universe@168 611 setRedirectLocation(req, "./projects/" + issue.getProject().getNode() + "/create-issue?more=true");
universe@168 612 } else{
universe@168 613 setRedirectLocation(req, "./projects/" + issue.getProject().getNode() + "/issues/" + issue.getId() + "/view");
universe@168 614 }
universe@74 615 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@124 616
universe@157 617 renderSite(req, resp);
mike@159 618 } catch (NoSuchElementException | IllegalArgumentException ex) {
universe@131 619 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
universe@131 620 // TODO: implement - fix issue #21
universe@64 621 }
universe@124 622 }
universe@64 623
universe@131 624 @RequestMapping(requestPath = "commit-issue-comment", method = HttpMethod.POST)
universe@167 625 public void commentIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException {
universe@124 626 final var issueIdParam = getParameter(req, Integer.class, "issueid");
universe@124 627 if (issueIdParam.isEmpty()) {
universe@124 628 resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Detected manipulated form.");
universe@157 629 return;
universe@124 630 }
universe@167 631 final var issue = dao.findIssue(issueIdParam.get());
universe@137 632 if (issue == null) {
universe@137 633 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
universe@157 634 return;
universe@137 635 }
universe@124 636 try {
universe@167 637 final var issueComment = new IssueComment(getParameter(req, Integer.class, "commentid").orElse(-1), issue.getId());
universe@124 638 issueComment.setComment(getParameter(req, String.class, "comment").orElse(""));
universe@124 639
universe@124 640 if (issueComment.getComment().isBlank()) {
universe@124 641 throw new IllegalArgumentException("comment.null");
universe@124 642 }
universe@124 643
universe@124 644 LOG.debug("User {} is commenting on issue #{}", req.getRemoteUser(), issue.getId());
universe@124 645 if (req.getRemoteUser() != null) {
universe@167 646 Optional.ofNullable(dao.findUserByName(req.getRemoteUser())).ifPresent(issueComment::setAuthor);
universe@124 647 }
universe@124 648
universe@167 649 dao.insertComment(issueComment);
universe@124 650
universe@146 651 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
universe@124 652 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
universe@124 653
universe@157 654 renderSite(req, resp);
mike@159 655 } catch (NoSuchElementException | IllegalArgumentException ex) {
universe@131 656 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
universe@131 657 // TODO: implement - fix issue #21
universe@124 658 }
universe@64 659 }
universe@41 660 }

mercurial