Fri, 06 Nov 2020 10:50:32 +0100
migrates constants and removes global functions
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2018 Mike Becker. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29 package de.uapcore.lightpit.modules;
32 import de.uapcore.lightpit.*;
33 import de.uapcore.lightpit.dao.DataAccessObjects;
34 import de.uapcore.lightpit.entities.*;
35 import de.uapcore.lightpit.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, DataAccessObjects dao) throws SQLException {
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 ("no-version".equals(versionNode)) {
99 viewModel.setVersionFilter(ProjectView.NO_VERSION);
100 } else if ("all-versions".equals(versionNode)) {
101 viewModel.setVersionFilter(ProjectView.ALL_VERSIONS);
102 } else {
103 viewModel.setVersionFilter(versionDao.findByNode(project, versionNode));
104 }
106 // Select Component
107 final var componentNode = pathParameters.get("component");
108 if ("no-component".equals(componentNode)) {
109 viewModel.setComponentFilter(ProjectView.NO_COMPONENT);
110 } else if ("all-components".equals(componentNode)) {
111 viewModel.setComponentFilter(ProjectView.ALL_COMPONENTS);
112 } else {
113 viewModel.setComponentFilter(componentDao.findByNode(project, componentNode));
114 }
115 }
117 private static String sanitizeNode(String node, String defaultValue) {
118 String result = node == null || node.isBlank() ? defaultValue : node;
119 result = result.replace('/', '-');
120 if (result.equals(".") || result.equals("..")) {
121 return "_"+result;
122 } else {
123 return result;
124 }
125 }
127 private void forwardView(HttpServletRequest req, HttpServletResponse resp, ProjectView viewModel, String name) throws ServletException, IOException {
128 setViewModel(req, viewModel);
129 setContentPage(req, name);
130 setStylesheet(req, "projects");
131 setNavigationMenu(req, "project-navmenu");
132 renderSite(req, resp);
133 }
135 @RequestMapping(method = HttpMethod.GET)
136 public void index(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, ServletException, IOException {
137 final var viewModel = new ProjectView();
138 populate(viewModel, null, dao);
140 final var projectDao = dao.getProjectDao();
141 final var versionDao = dao.getVersionDao();
143 for (var info : viewModel.getProjectList()) {
144 info.setVersions(versionDao.list(info.getProject()));
145 info.setIssueSummary(projectDao.getIssueSummary(info.getProject()));
146 }
148 forwardView(req, resp, viewModel, "projects");
149 }
151 private void configureProjectEditor(ProjectEditView viewModel, Project project, DataAccessObjects dao) throws SQLException {
152 viewModel.setProject(project);
153 viewModel.setUsers(dao.getUserDao().list());
154 }
156 @RequestMapping(requestPath = "$project/edit", method = HttpMethod.GET)
157 public void edit(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObjects dao) throws IOException, SQLException, ServletException {
158 final var viewModel = new ProjectEditView();
159 populate(viewModel, pathParams, dao);
161 if (!viewModel.isProjectInfoPresent()) {
162 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
163 return;
164 }
166 configureProjectEditor(viewModel, viewModel.getProjectInfo().getProject(), dao);
167 forwardView(req, resp, viewModel, "project-form");
168 }
170 @RequestMapping(requestPath = "create", method = HttpMethod.GET)
171 public void create(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, ServletException, IOException {
172 final var viewModel = new ProjectEditView();
173 populate(viewModel, null, dao);
174 configureProjectEditor(viewModel, new Project(-1), dao);
175 forwardView(req, resp, viewModel, "project-form");
176 }
178 @RequestMapping(requestPath = "commit", method = HttpMethod.POST)
179 public void commit(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, ServletException {
181 try {
182 final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow());
183 project.setName(getParameter(req, String.class, "name").orElseThrow());
185 final var node = getParameter(req, String.class, "node").orElse(null);
186 project.setNode(sanitizeNode(node, project.getName()));
188 getParameter(req, String.class, "description").ifPresent(project::setDescription);
189 getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl);
190 getParameter(req, Integer.class, "owner").map(
191 ownerId -> ownerId >= 0 ? new User(ownerId) : null
192 ).ifPresent(project::setOwner);
194 dao.getProjectDao().saveOrUpdate(project);
196 setRedirectLocation(req, "./projects/");
197 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
198 LOG.debug("Successfully updated project {}", project.getName());
200 renderSite(req, resp);
201 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
202 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
203 // TODO: implement - fix issue #21
204 }
205 }
207 @RequestMapping(requestPath = "$project/$component/$version/issues/", method = HttpMethod.GET)
208 public void issues(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObjects dao) throws SQLException, IOException, ServletException {
209 final var viewModel = new ProjectDetailsView();
210 populate(viewModel, pathParams, dao);
212 if (!viewModel.isEveryFilterValid()) {
213 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
214 return;
215 }
217 final var project = viewModel.getProjectInfo().getProject();
218 final var version = viewModel.getVersionFilter();
219 final var component = viewModel.getComponentFilter();
221 final var issueDao = dao.getIssueDao();
223 final List<Issue> issues;
224 if (version.equals(ProjectView.NO_VERSION)) {
225 if (component.equals(ProjectView.ALL_COMPONENTS)) {
226 issues = issueDao.list(project, (Version) null);
227 } else if (component.equals(ProjectView.NO_COMPONENT)) {
228 issues = issueDao.list(project, null, null);
229 } else {
230 issues = issueDao.list(project, component, null);
231 }
232 } else if (version.equals(ProjectView.ALL_VERSIONS)) {
233 if (component.equals(ProjectView.ALL_COMPONENTS)) {
234 issues = issueDao.list(project);
235 } else if (component.equals(ProjectView.NO_COMPONENT)) {
236 issues = issueDao.list(project, (Component)null);
237 } else {
238 issues = issueDao.list(project, component);
239 }
240 } else {
241 if (component.equals(ProjectView.ALL_COMPONENTS)) {
242 issues = issueDao.list(project, version);
243 } else if (component.equals(ProjectView.NO_COMPONENT)) {
244 issues = issueDao.list(project, null, version);
245 } else {
246 issues = issueDao.list(project, component, version);
247 }
248 }
250 for (var issue : issues) issueDao.joinVersionInformation(issue);
251 issues.sort(new IssueSorter(
252 new IssueSorter.Criteria(IssueSorter.Field.DONE, true),
253 new IssueSorter.Criteria(IssueSorter.Field.ETA, true),
254 new IssueSorter.Criteria(IssueSorter.Field.UPDATED, false)
255 ));
258 viewModel.getProjectDetails().updateDetails(issues);
259 if (version.getId() > 0)
260 viewModel.getProjectDetails().updateVersionInfo(version);
262 forwardView(req, resp, viewModel, "project-details");
263 }
265 @RequestMapping(requestPath = "$project/versions/", method = HttpMethod.GET)
266 public void versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
267 final var viewModel = new VersionsView();
268 populate(viewModel, pathParameters, dao);
270 final var projectInfo = viewModel.getProjectInfo();
271 if (projectInfo == null) {
272 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
273 return;
274 }
276 final var issueDao = dao.getIssueDao();
277 final var issues = issueDao.list(projectInfo.getProject());
278 for (var issue : issues) issueDao.joinVersionInformation(issue);
279 viewModel.update(projectInfo.getVersions(), issues);
281 forwardView(req, resp, viewModel, "versions");
282 }
284 @RequestMapping(requestPath = "$project/versions/$version/edit", method = HttpMethod.GET)
285 public void editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
286 final var viewModel = new VersionEditView();
287 populate(viewModel, pathParameters, dao);
289 if (viewModel.getProjectInfo() == null || viewModel.getVersionFilter() == null) {
290 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
291 return;
292 }
294 viewModel.setVersion(viewModel.getVersionFilter());
296 forwardView(req, resp, viewModel, "version-form");
297 }
299 @RequestMapping(requestPath = "$project/create-version", method = HttpMethod.GET)
300 public void createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
301 final var viewModel = new VersionEditView();
302 populate(viewModel, pathParameters, dao);
304 if (viewModel.getProjectInfo() == null) {
305 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
306 return;
307 }
309 viewModel.setVersion(new Version(-1));
311 forwardView(req, resp, viewModel, "version-form");
312 }
314 @RequestMapping(requestPath = "commit-version", method = HttpMethod.POST)
315 public void commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, ServletException {
317 try {
318 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
319 if (project == null) {
320 // TODO: improve error handling, because not found is not correct for this POST request
321 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
322 return;
323 }
324 final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow());
325 version.setName(getParameter(req, String.class, "name").orElseThrow());
327 final var node = getParameter(req, String.class, "node").orElse(null);
328 version.setNode(sanitizeNode(node, version.getName()));
330 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
331 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
332 dao.getVersionDao().saveOrUpdate(version, project);
334 setRedirectLocation(req, "./projects/" + project.getNode() + "/versions/");
335 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
337 renderSite(req, resp);
338 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
339 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
340 // TODO: implement - fix issue #21
341 }
342 }
344 @RequestMapping(requestPath = "$project/components/", method = HttpMethod.GET)
345 public void components(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
346 final var viewModel = new ComponentsView();
347 populate(viewModel, pathParameters, dao);
349 final var projectInfo = viewModel.getProjectInfo();
350 if (projectInfo == null) {
351 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
352 return;
353 }
355 final var issueDao = dao.getIssueDao();
356 final var issues = issueDao.list(projectInfo.getProject());
357 viewModel.update(projectInfo.getComponents(), issues);
359 forwardView(req, resp, viewModel, "components");
360 }
362 @RequestMapping(requestPath = "$project/components/$component/edit", method = HttpMethod.GET)
363 public void editComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
364 final var viewModel = new ComponentEditView();
365 populate(viewModel, pathParameters, dao);
367 if (viewModel.getProjectInfo() == null || viewModel.getComponentFilter() == null) {
368 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
369 return;
370 }
372 viewModel.setComponent(viewModel.getComponentFilter());
373 viewModel.setUsers(dao.getUserDao().list());
375 forwardView(req, resp, viewModel, "component-form");
376 }
378 @RequestMapping(requestPath = "$project/create-component", method = HttpMethod.GET)
379 public void createComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
380 final var viewModel = new ComponentEditView();
381 populate(viewModel, pathParameters, dao);
383 if (viewModel.getProjectInfo() == null) {
384 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
385 return;
386 }
388 viewModel.setComponent(new Component(-1));
389 viewModel.setUsers(dao.getUserDao().list());
391 forwardView(req, resp, viewModel, "component-form");
392 }
394 @RequestMapping(requestPath = "commit-component", method = HttpMethod.POST)
395 public void commitComponent(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, ServletException {
397 try {
398 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
399 if (project == null) {
400 // TODO: improve error handling, because not found is not correct for this POST request
401 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
402 return;
403 }
404 final var component = new Component(getParameter(req, Integer.class, "id").orElseThrow());
405 component.setName(getParameter(req, String.class, "name").orElseThrow());
407 final var node = getParameter(req, String.class, "node").orElse(null);
408 component.setNode(sanitizeNode(node, component.getName()));
410 component.setColor(getParameter(req, WebColor.class, "color").orElseThrow());
411 getParameter(req, Integer.class, "ordinal").ifPresent(component::setOrdinal);
412 getParameter(req, Integer.class, "lead").map(
413 userid -> userid >= 0 ? new User(userid) : null
414 ).ifPresent(component::setLead);
415 getParameter(req, String.class, "description").ifPresent(component::setDescription);
417 dao.getComponentDao().saveOrUpdate(component, project);
419 setRedirectLocation(req, "./projects/" + project.getNode() + "/components/");
420 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
422 renderSite(req, resp);
423 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
424 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
425 // TODO: implement - fix issue #21
426 }
427 }
429 private void configureIssueEditor(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException {
430 final var project = viewModel.getProjectInfo().getProject();
431 issue.setProject(project); // automatically set current project for new issues
432 viewModel.setIssue(issue);
433 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
434 viewModel.setUsers(dao.getUserDao().list());
435 viewModel.setComponents(dao.getComponentDao().list(project));
436 }
438 @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET)
439 public void viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
440 final var viewModel = new IssueDetailView();
441 populate(viewModel, pathParameters, dao);
443 final var projectInfo = viewModel.getProjectInfo();
444 if (projectInfo == null) {
445 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
446 return;
447 }
449 final var issueDao = dao.getIssueDao();
450 final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue")));
451 if (issue == null) {
452 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
453 return;
454 }
456 issueDao.joinVersionInformation(issue);
457 viewModel.setIssue(issue);
458 viewModel.setComments(issueDao.listComments(issue));
460 forwardView(req, resp, viewModel, "issue-view");
461 }
463 // TODO: why should the issue editor be child of $project?
464 @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET)
465 public void editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
466 final var viewModel = new IssueEditView();
467 populate(viewModel, pathParameters, dao);
469 final var projectInfo = viewModel.getProjectInfo();
470 if (projectInfo == null) {
471 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
472 return;
473 }
475 final var issueDao = dao.getIssueDao();
476 final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue")));
477 if (issue == null) {
478 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
479 return;
480 }
482 issueDao.joinVersionInformation(issue);
483 configureIssueEditor(viewModel, issue, dao);
485 forwardView(req, resp, viewModel, "issue-form");
486 }
488 @RequestMapping(requestPath = "$project/create-issue", method = HttpMethod.GET)
489 public void createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException, ServletException {
490 final var viewModel = new IssueEditView();
491 populate(viewModel, pathParameters, dao);
493 final var projectInfo = viewModel.getProjectInfo();
494 if (projectInfo == null) {
495 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
496 return;
497 }
499 final var issue = new Issue(-1);
500 issue.setProject(projectInfo.getProject());
501 configureIssueEditor(viewModel, issue, dao);
503 forwardView(req, resp, viewModel, "issue-form");
504 }
506 @RequestMapping(requestPath = "commit-issue", method = HttpMethod.POST)
507 public void commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, ServletException {
508 try {
509 final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow());
510 final var componentId = getParameter(req, Integer.class, "component");
511 final Component component;
512 if (componentId.isPresent()) {
513 component = dao.getComponentDao().find(componentId.get());
514 } else {
515 component = null;
516 }
517 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
518 if (project == null) {
519 // TODO: improve error handling, because not found is not correct for this POST request
520 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
521 return;
522 }
523 issue.setProject(project);
524 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
525 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
526 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
527 issue.setComponent(component);
528 getParameter(req, Integer.class, "assignee").map(userid -> {
529 if (userid >= 0) {
530 return new User(userid);
531 } else if (userid == -2) {
532 return Optional.ofNullable(component).map(Component::getLead).orElse(null);
533 } else {
534 return null;
535 }
536 }
537 ).ifPresent(issue::setAssignee);
538 getParameter(req, String.class, "description").ifPresent(issue::setDescription);
539 getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
541 getParameter(req, Integer[].class, "affected")
542 .map(Stream::of)
543 .map(stream ->
544 stream.map(Version::new).collect(Collectors.toList())
545 ).ifPresent(issue::setAffectedVersions);
546 getParameter(req, Integer[].class, "resolved")
547 .map(Stream::of)
548 .map(stream ->
549 stream.map(Version::new).collect(Collectors.toList())
550 ).ifPresent(issue::setResolvedVersions);
552 dao.getIssueDao().saveOrUpdate(issue, issue.getProject());
554 // TODO: fix redirect location
555 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
556 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
558 renderSite(req, resp);
559 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
560 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
561 // TODO: implement - fix issue #21
562 }
563 }
565 @RequestMapping(requestPath = "commit-issue-comment", method = HttpMethod.POST)
566 public void commentIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException, ServletException {
567 final var issueIdParam = getParameter(req, Integer.class, "issueid");
568 if (issueIdParam.isEmpty()) {
569 resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Detected manipulated form.");
570 return;
571 }
572 final var issue = dao.getIssueDao().find(issueIdParam.get());
573 if (issue == null) {
574 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
575 return;
576 }
577 try {
578 final var issueComment = new IssueComment(getParameter(req, Integer.class, "commentid").orElse(-1));
579 issueComment.setComment(getParameter(req, String.class, "comment").orElse(""));
581 if (issueComment.getComment().isBlank()) {
582 throw new IllegalArgumentException("comment.null");
583 }
585 LOG.debug("User {} is commenting on issue #{}", req.getRemoteUser(), issue.getId());
586 if (req.getRemoteUser() != null) {
587 dao.getUserDao().findByUsername(req.getRemoteUser()).ifPresent(issueComment::setAuthor);
588 }
590 dao.getIssueDao().saveComment(issue, issueComment);
592 // TODO: fix redirect location
593 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
594 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
596 renderSite(req, resp);
597 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) {
598 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
599 // TODO: implement - fix issue #21
600 }
601 }
602 }