Fri, 18 Dec 2020 16:16:54 +0100
Add mailto link to the display name above comments - fixes #112
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.DaoProvider;
34 import de.uapcore.lightpit.entities.*;
35 import de.uapcore.lightpit.types.WebColor;
36 import de.uapcore.lightpit.viewmodel.*;
37 import de.uapcore.lightpit.viewmodel.util.IssueSorter;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 import javax.servlet.ServletException;
42 import javax.servlet.annotation.WebServlet;
43 import javax.servlet.http.HttpServletRequest;
44 import javax.servlet.http.HttpServletResponse;
45 import java.io.IOException;
46 import java.sql.Date;
47 import java.sql.SQLException;
48 import java.util.List;
49 import java.util.NoSuchElementException;
50 import java.util.Optional;
51 import java.util.stream.Collectors;
52 import java.util.stream.Stream;
54 @WebServlet(
55 name = "ProjectsModule",
56 urlPatterns = "/projects/*"
57 )
58 public final class ProjectsModule extends AbstractLightPITServlet {
60 private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class);
62 @Override
63 protected String getResourceBundleName() {
64 return "localization.projects";
65 }
67 private static int parseIntOrZero(String str) {
68 try {
69 return Integer.parseInt(str);
70 } catch (NumberFormatException ex) {
71 return 0;
72 }
73 }
75 private void populate(ProjectView viewModel, PathParameters pathParameters, DaoProvider dao) {
76 final var projectDao = dao.getProjectDao();
77 final var versionDao = dao.getVersionDao();
78 final var componentDao = dao.getComponentDao();
80 projectDao.list().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add);
82 if (pathParameters == null)
83 return;
85 // Select Project
86 final var project = projectDao.findByNode(pathParameters.get("project"));
87 if (project == null)
88 return;
90 final var info = new ProjectInfo(project);
91 info.setVersions(versionDao.list(project));
92 info.setComponents(componentDao.list(project));
93 info.setIssueSummary(projectDao.getIssueSummary(project));
94 viewModel.setProjectInfo(info);
96 // Select Version
97 final var versionNode = pathParameters.get("version");
98 if (versionNode != null) {
99 if ("no-version".equals(versionNode)) {
100 viewModel.setVersionFilter(ProjectView.NO_VERSION);
101 } else if ("all-versions".equals(versionNode)) {
102 viewModel.setVersionFilter(ProjectView.ALL_VERSIONS);
103 } else {
104 viewModel.setVersionFilter(versionDao.findByNode(project, versionNode));
105 }
106 }
108 // Select Component
109 final var componentNode = pathParameters.get("component");
110 if (componentNode != null) {
111 if ("no-component".equals(componentNode)) {
112 viewModel.setComponentFilter(ProjectView.NO_COMPONENT);
113 } else if ("all-components".equals(componentNode)) {
114 viewModel.setComponentFilter(ProjectView.ALL_COMPONENTS);
115 } else {
116 viewModel.setComponentFilter(componentDao.findByNode(project, componentNode));
117 }
118 }
119 }
121 private static String sanitizeNode(String node, String defaultValue) {
122 String result = node == null || node.isBlank() ? defaultValue : node;
123 result = result.replace('/', '-');
124 if (result.equals(".") || result.equals("..")) {
125 return "_"+result;
126 } else {
127 return result;
128 }
129 }
131 private void forwardView(HttpServletRequest req, HttpServletResponse resp, ProjectView viewModel, String name) throws ServletException, IOException {
132 setViewModel(req, viewModel);
133 setContentPage(req, name);
134 setStylesheet(req, "projects");
135 setNavigationMenu(req, "project-navmenu");
136 renderSite(req, resp);
137 }
139 @RequestMapping(method = HttpMethod.GET)
140 public void index(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws SQLException, ServletException, IOException {
141 final var viewModel = new ProjectView();
142 populate(viewModel, null, dao);
144 final var projectDao = dao.getProjectDao();
145 final var versionDao = dao.getVersionDao();
147 for (var info : viewModel.getProjectList()) {
148 info.setVersions(versionDao.list(info.getProject()));
149 info.setIssueSummary(projectDao.getIssueSummary(info.getProject()));
150 }
152 forwardView(req, resp, viewModel, "projects");
153 }
155 private void configureProjectEditor(ProjectEditView viewModel, Project project, DaoProvider dao) throws SQLException {
156 viewModel.setProject(project);
157 viewModel.setUsers(dao.getUserDao().list());
158 }
160 @RequestMapping(requestPath = "$project/edit", method = HttpMethod.GET)
161 public void edit(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DaoProvider dao) throws IOException, SQLException, ServletException {
162 final var viewModel = new ProjectEditView();
163 populate(viewModel, pathParams, dao);
165 if (!viewModel.isProjectInfoPresent()) {
166 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
167 return;
168 }
170 configureProjectEditor(viewModel, viewModel.getProjectInfo().getProject(), dao);
171 forwardView(req, resp, viewModel, "project-form");
172 }
174 @RequestMapping(requestPath = "create", method = HttpMethod.GET)
175 public void create(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws SQLException, ServletException, IOException {
176 final var viewModel = new ProjectEditView();
177 populate(viewModel, null, dao);
178 configureProjectEditor(viewModel, new Project(-1), dao);
179 forwardView(req, resp, viewModel, "project-form");
180 }
182 @RequestMapping(requestPath = "commit", method = HttpMethod.POST)
183 public void commit(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
185 try {
186 final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow());
187 project.setName(getParameter(req, String.class, "name").orElseThrow());
189 final var node = getParameter(req, String.class, "node").orElse(null);
190 project.setNode(sanitizeNode(node, project.getName()));
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 final var projectDao = dao.getProjectDao();
199 if (project.getId() > 0) {
200 // TODO: unused return value
201 projectDao.update(project);
202 } else {
203 projectDao.save(project);
204 }
206 setRedirectLocation(req, "./projects/");
207 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
208 LOG.debug("Successfully updated project {}", project.getName());
210 renderSite(req, resp);
211 } catch (NoSuchElementException | IllegalArgumentException ex) {
212 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
213 // TODO: implement - fix issue #21
214 }
215 }
217 @RequestMapping(requestPath = "$project/$component/$version/issues/", method = HttpMethod.GET)
218 public void issues(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DaoProvider dao) throws SQLException, IOException, ServletException {
219 final var viewModel = new ProjectDetailsView();
220 populate(viewModel, pathParams, dao);
222 if (!viewModel.isEveryFilterValid()) {
223 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
224 return;
225 }
227 final var project = viewModel.getProjectInfo().getProject();
228 final var version = viewModel.getVersionFilter();
229 final var component = viewModel.getComponentFilter();
231 final var issueDao = dao.getIssueDao();
233 final List<Issue> issues;
234 if (version.equals(ProjectView.NO_VERSION)) {
235 if (component.equals(ProjectView.ALL_COMPONENTS)) {
236 issues = issueDao.list(project, (Version) null);
237 } else if (component.equals(ProjectView.NO_COMPONENT)) {
238 issues = issueDao.list(project, null, null);
239 } else {
240 issues = issueDao.list(project, component, null);
241 }
242 } else if (version.equals(ProjectView.ALL_VERSIONS)) {
243 if (component.equals(ProjectView.ALL_COMPONENTS)) {
244 issues = issueDao.list(project);
245 } else if (component.equals(ProjectView.NO_COMPONENT)) {
246 issues = issueDao.list(project, (Component)null);
247 } else {
248 issues = issueDao.list(project, component);
249 }
250 } else {
251 if (component.equals(ProjectView.ALL_COMPONENTS)) {
252 issues = issueDao.list(project, version);
253 } else if (component.equals(ProjectView.NO_COMPONENT)) {
254 issues = issueDao.list(project, null, version);
255 } else {
256 issues = issueDao.list(project, component, version);
257 }
258 }
260 for (var issue : issues) issueDao.joinVersionInformation(issue);
261 issues.sort(new IssueSorter(
262 new IssueSorter.Criteria(IssueSorter.Field.DONE, true),
263 new IssueSorter.Criteria(IssueSorter.Field.ETA, true),
264 new IssueSorter.Criteria(IssueSorter.Field.UPDATED, false)
265 ));
268 viewModel.getProjectDetails().updateDetails(issues);
269 if (version.getId() > 0)
270 viewModel.getProjectDetails().updateVersionInfo(version);
272 forwardView(req, resp, viewModel, "project-details");
273 }
275 @RequestMapping(requestPath = "$project/versions/", method = HttpMethod.GET)
276 public void versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
277 final var viewModel = new VersionsView();
278 populate(viewModel, pathParameters, dao);
280 final var projectInfo = viewModel.getProjectInfo();
281 if (projectInfo == null) {
282 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
283 return;
284 }
286 final var issueDao = dao.getIssueDao();
287 final var issues = issueDao.list(projectInfo.getProject());
288 for (var issue : issues) issueDao.joinVersionInformation(issue);
289 viewModel.update(projectInfo.getVersions(), issues);
291 forwardView(req, resp, viewModel, "versions");
292 }
294 @RequestMapping(requestPath = "$project/versions/$version/edit", method = HttpMethod.GET)
295 public void editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
296 final var viewModel = new VersionEditView();
297 populate(viewModel, pathParameters, dao);
299 if (viewModel.getProjectInfo() == null || viewModel.getVersionFilter() == null) {
300 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
301 return;
302 }
304 viewModel.setVersion(viewModel.getVersionFilter());
306 forwardView(req, resp, viewModel, "version-form");
307 }
309 @RequestMapping(requestPath = "$project/create-version", method = HttpMethod.GET)
310 public void createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
311 final var viewModel = new VersionEditView();
312 populate(viewModel, pathParameters, dao);
314 if (viewModel.getProjectInfo() == null) {
315 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
316 return;
317 }
319 viewModel.setVersion(new Version(-1));
321 forwardView(req, resp, viewModel, "version-form");
322 }
324 @RequestMapping(requestPath = "commit-version", method = HttpMethod.POST)
325 public void commitVersion(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
327 try {
328 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
329 if (project == null) {
330 // TODO: improve error handling, because not found is not correct for this POST request
331 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
332 return;
333 }
334 final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow());
335 version.setName(getParameter(req, String.class, "name").orElseThrow());
337 final var node = getParameter(req, String.class, "node").orElse(null);
338 version.setNode(sanitizeNode(node, version.getName()));
340 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
341 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
343 final var versionDao = dao.getVersionDao();
344 if (version.getId() > 0) {
345 // TODO: use return value
346 versionDao.update(version);
347 } else {
348 versionDao.save(version, project);
349 }
351 setRedirectLocation(req, "./projects/" + project.getNode() + "/versions/");
352 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
354 renderSite(req, resp);
355 } catch (NoSuchElementException | IllegalArgumentException ex) {
356 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
357 // TODO: implement - fix issue #21
358 }
359 }
361 @RequestMapping(requestPath = "$project/components/", method = HttpMethod.GET)
362 public void components(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
363 final var viewModel = new ComponentsView();
364 populate(viewModel, pathParameters, dao);
366 final var projectInfo = viewModel.getProjectInfo();
367 if (projectInfo == null) {
368 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
369 return;
370 }
372 final var issueDao = dao.getIssueDao();
373 final var issues = issueDao.list(projectInfo.getProject());
374 viewModel.update(projectInfo.getComponents(), issues);
376 forwardView(req, resp, viewModel, "components");
377 }
379 @RequestMapping(requestPath = "$project/components/$component/edit", method = HttpMethod.GET)
380 public void editComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
381 final var viewModel = new ComponentEditView();
382 populate(viewModel, pathParameters, dao);
384 if (viewModel.getProjectInfo() == null || viewModel.getComponentFilter() == null) {
385 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
386 return;
387 }
389 viewModel.setComponent(viewModel.getComponentFilter());
390 viewModel.setUsers(dao.getUserDao().list());
392 forwardView(req, resp, viewModel, "component-form");
393 }
395 @RequestMapping(requestPath = "$project/create-component", method = HttpMethod.GET)
396 public void createComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
397 final var viewModel = new ComponentEditView();
398 populate(viewModel, pathParameters, dao);
400 if (viewModel.getProjectInfo() == null) {
401 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
402 return;
403 }
405 viewModel.setComponent(new Component(-1));
406 viewModel.setUsers(dao.getUserDao().list());
408 forwardView(req, resp, viewModel, "component-form");
409 }
411 @RequestMapping(requestPath = "commit-component", method = HttpMethod.POST)
412 public void commitComponent(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
414 try {
415 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
416 if (project == null) {
417 // TODO: improve error handling, because not found is not correct for this POST request
418 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
419 return;
420 }
421 final var component = new Component(getParameter(req, Integer.class, "id").orElseThrow());
422 component.setName(getParameter(req, String.class, "name").orElseThrow());
424 final var node = getParameter(req, String.class, "node").orElse(null);
425 component.setNode(sanitizeNode(node, component.getName()));
427 component.setColor(getParameter(req, WebColor.class, "color").orElseThrow());
428 getParameter(req, Integer.class, "ordinal").ifPresent(component::setOrdinal);
429 getParameter(req, Integer.class, "lead").map(
430 userid -> userid >= 0 ? new User(userid) : null
431 ).ifPresent(component::setLead);
432 getParameter(req, String.class, "description").ifPresent(component::setDescription);
434 final var componentDao = dao.getComponentDao();
435 if (component.getId() > 0) {
436 // TODO: use return value
437 componentDao.update(component);
438 } else {
439 componentDao.save(component, project);
440 }
442 setRedirectLocation(req, "./projects/" + project.getNode() + "/components/");
443 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
445 renderSite(req, resp);
446 } catch (NoSuchElementException | IllegalArgumentException ex) {
447 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
448 // TODO: implement - fix issue #21
449 }
450 }
452 private void configureIssueEditor(IssueEditView viewModel, Issue issue, DaoProvider dao) throws SQLException {
453 final var project = viewModel.getProjectInfo().getProject();
454 issue.setProject(project); // automatically set current project for new issues
455 viewModel.setIssue(issue);
456 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
457 viewModel.setUsers(dao.getUserDao().list());
458 viewModel.setComponents(dao.getComponentDao().list(project));
459 }
461 @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET)
462 public void viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
463 final var viewModel = new IssueDetailView();
464 populate(viewModel, pathParameters, dao);
466 final var projectInfo = viewModel.getProjectInfo();
467 if (projectInfo == null) {
468 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
469 return;
470 }
472 final var issueDao = dao.getIssueDao();
473 final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue")));
474 if (issue == null) {
475 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
476 return;
477 }
479 issueDao.joinVersionInformation(issue);
480 viewModel.setIssue(issue);
481 viewModel.setComments(issueDao.listComments(issue));
483 viewModel.processMarkdown();
485 forwardView(req, resp, viewModel, "issue-view");
486 }
488 // TODO: why should the issue editor be child of $project?
489 @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET)
490 public void editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
491 final var viewModel = new IssueEditView();
492 populate(viewModel, pathParameters, dao);
494 final var projectInfo = viewModel.getProjectInfo();
495 if (projectInfo == null) {
496 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
497 return;
498 }
500 final var issueDao = dao.getIssueDao();
501 final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue")));
502 if (issue == null) {
503 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
504 return;
505 }
507 issueDao.joinVersionInformation(issue);
508 configureIssueEditor(viewModel, issue, dao);
510 forwardView(req, resp, viewModel, "issue-form");
511 }
513 @RequestMapping(requestPath = "$project/create-issue", method = HttpMethod.GET)
514 public void createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
515 final var viewModel = new IssueEditView();
516 populate(viewModel, pathParameters, dao);
518 final var projectInfo = viewModel.getProjectInfo();
519 if (projectInfo == null) {
520 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
521 return;
522 }
524 final var issue = new Issue(-1);
525 issue.setProject(projectInfo.getProject());
526 configureIssueEditor(viewModel, issue, dao);
528 forwardView(req, resp, viewModel, "issue-form");
529 }
531 @RequestMapping(requestPath = "commit-issue", method = HttpMethod.POST)
532 public void commitIssue(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
533 try {
534 final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow());
535 final var componentId = getParameter(req, Integer.class, "component");
536 final Component component;
537 if (componentId.isPresent()) {
538 component = dao.getComponentDao().find(componentId.get());
539 } else {
540 component = null;
541 }
542 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
543 if (project == null) {
544 // TODO: improve error handling, because not found is not correct for this POST request
545 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
546 return;
547 }
548 issue.setProject(project);
549 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
550 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
551 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
552 issue.setComponent(component);
553 getParameter(req, Integer.class, "assignee").map(userid -> {
554 if (userid >= 0) {
555 return new User(userid);
556 } else if (userid == -2) {
557 return Optional.ofNullable(component).map(Component::getLead).orElse(null);
558 } else {
559 return null;
560 }
561 }
562 ).ifPresent(issue::setAssignee);
563 getParameter(req, String.class, "description").ifPresent(issue::setDescription);
564 getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
566 getParameter(req, Integer[].class, "affected")
567 .map(Stream::of)
568 .map(stream ->
569 stream.map(Version::new).collect(Collectors.toList())
570 ).ifPresent(issue::setAffectedVersions);
571 getParameter(req, Integer[].class, "resolved")
572 .map(Stream::of)
573 .map(stream ->
574 stream.map(Version::new).collect(Collectors.toList())
575 ).ifPresent(issue::setResolvedVersions);
577 final var issueDao = dao.getIssueDao();
578 if (issue.getId() > 0) {
579 // TODO: use return value
580 issueDao.update(issue);
581 } else {
582 issueDao.save(issue, project);
583 }
585 // TODO: fix redirect location
586 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
587 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
589 renderSite(req, resp);
590 } catch (NoSuchElementException | IllegalArgumentException ex) {
591 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
592 // TODO: implement - fix issue #21
593 }
594 }
596 @RequestMapping(requestPath = "commit-issue-comment", method = HttpMethod.POST)
597 public void commentIssue(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
598 final var issueIdParam = getParameter(req, Integer.class, "issueid");
599 if (issueIdParam.isEmpty()) {
600 resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Detected manipulated form.");
601 return;
602 }
603 final var issue = dao.getIssueDao().find(issueIdParam.get());
604 if (issue == null) {
605 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
606 return;
607 }
608 try {
609 final var issueComment = new IssueComment(getParameter(req, Integer.class, "commentid").orElse(-1));
610 issueComment.setComment(getParameter(req, String.class, "comment").orElse(""));
612 if (issueComment.getComment().isBlank()) {
613 throw new IllegalArgumentException("comment.null");
614 }
616 LOG.debug("User {} is commenting on issue #{}", req.getRemoteUser(), issue.getId());
617 if (req.getRemoteUser() != null) {
618 Optional.ofNullable(dao.getUserDao().findByUsername(req.getRemoteUser())).ifPresent(issueComment::setAuthor);
619 }
621 dao.getIssueDao().saveComment(issue, issueComment);
623 // TODO: fix redirect location
624 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
625 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
627 renderSite(req, resp);
628 } catch (NoSuchElementException | IllegalArgumentException ex) {
629 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
630 // TODO: implement - fix issue #21
631 }
632 }
633 }