Thu, 19 Nov 2020 13:58:54 +0100
migrates DAO classes
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) 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) || versionNode == null) {
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) || componentNode == null) {
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, DaoProvider 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, DaoProvider 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, DaoProvider 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, DaoProvider 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, DaoProvider 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 final var projectDao = dao.getProjectDao();
195 if (project.getId() > 0) {
196 // TODO: unused return value
197 projectDao.update(project);
198 } else {
199 projectDao.save(project);
200 }
202 setRedirectLocation(req, "./projects/");
203 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
204 LOG.debug("Successfully updated project {}", project.getName());
206 renderSite(req, resp);
207 } catch (NoSuchElementException | IllegalArgumentException ex) {
208 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
209 // TODO: implement - fix issue #21
210 }
211 }
213 @RequestMapping(requestPath = "$project/$component/$version/issues/", method = HttpMethod.GET)
214 public void issues(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DaoProvider dao) throws SQLException, IOException, ServletException {
215 final var viewModel = new ProjectDetailsView();
216 populate(viewModel, pathParams, dao);
218 if (!viewModel.isEveryFilterValid()) {
219 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
220 return;
221 }
223 final var project = viewModel.getProjectInfo().getProject();
224 final var version = viewModel.getVersionFilter();
225 final var component = viewModel.getComponentFilter();
227 final var issueDao = dao.getIssueDao();
229 final List<Issue> issues;
230 if (version.equals(ProjectView.NO_VERSION)) {
231 if (component.equals(ProjectView.ALL_COMPONENTS)) {
232 issues = issueDao.list(project, (Version) null);
233 } else if (component.equals(ProjectView.NO_COMPONENT)) {
234 issues = issueDao.list(project, null, null);
235 } else {
236 issues = issueDao.list(project, component, null);
237 }
238 } else if (version.equals(ProjectView.ALL_VERSIONS)) {
239 if (component.equals(ProjectView.ALL_COMPONENTS)) {
240 issues = issueDao.list(project);
241 } else if (component.equals(ProjectView.NO_COMPONENT)) {
242 issues = issueDao.list(project, (Component)null);
243 } else {
244 issues = issueDao.list(project, component);
245 }
246 } else {
247 if (component.equals(ProjectView.ALL_COMPONENTS)) {
248 issues = issueDao.list(project, version);
249 } else if (component.equals(ProjectView.NO_COMPONENT)) {
250 issues = issueDao.list(project, null, version);
251 } else {
252 issues = issueDao.list(project, component, version);
253 }
254 }
256 for (var issue : issues) issueDao.joinVersionInformation(issue);
257 issues.sort(new IssueSorter(
258 new IssueSorter.Criteria(IssueSorter.Field.DONE, true),
259 new IssueSorter.Criteria(IssueSorter.Field.ETA, true),
260 new IssueSorter.Criteria(IssueSorter.Field.UPDATED, false)
261 ));
264 viewModel.getProjectDetails().updateDetails(issues);
265 if (version.getId() > 0)
266 viewModel.getProjectDetails().updateVersionInfo(version);
268 forwardView(req, resp, viewModel, "project-details");
269 }
271 @RequestMapping(requestPath = "$project/versions/", method = HttpMethod.GET)
272 public void versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
273 final var viewModel = new VersionsView();
274 populate(viewModel, pathParameters, dao);
276 final var projectInfo = viewModel.getProjectInfo();
277 if (projectInfo == null) {
278 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
279 return;
280 }
282 final var issueDao = dao.getIssueDao();
283 final var issues = issueDao.list(projectInfo.getProject());
284 for (var issue : issues) issueDao.joinVersionInformation(issue);
285 viewModel.update(projectInfo.getVersions(), issues);
287 forwardView(req, resp, viewModel, "versions");
288 }
290 @RequestMapping(requestPath = "$project/versions/$version/edit", method = HttpMethod.GET)
291 public void editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
292 final var viewModel = new VersionEditView();
293 populate(viewModel, pathParameters, dao);
295 if (viewModel.getProjectInfo() == null || viewModel.getVersionFilter() == null) {
296 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
297 return;
298 }
300 viewModel.setVersion(viewModel.getVersionFilter());
302 forwardView(req, resp, viewModel, "version-form");
303 }
305 @RequestMapping(requestPath = "$project/create-version", method = HttpMethod.GET)
306 public void createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
307 final var viewModel = new VersionEditView();
308 populate(viewModel, pathParameters, dao);
310 if (viewModel.getProjectInfo() == null) {
311 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
312 return;
313 }
315 viewModel.setVersion(new Version(-1));
317 forwardView(req, resp, viewModel, "version-form");
318 }
320 @RequestMapping(requestPath = "commit-version", method = HttpMethod.POST)
321 public void commitVersion(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
323 try {
324 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
325 if (project == null) {
326 // TODO: improve error handling, because not found is not correct for this POST request
327 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
328 return;
329 }
330 final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow());
331 version.setName(getParameter(req, String.class, "name").orElseThrow());
333 final var node = getParameter(req, String.class, "node").orElse(null);
334 version.setNode(sanitizeNode(node, version.getName()));
336 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal);
337 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow()));
339 final var versionDao = dao.getVersionDao();
340 if (version.getId() > 0) {
341 // TODO: use return value
342 versionDao.update(version);
343 } else {
344 versionDao.save(version, project);
345 }
347 setRedirectLocation(req, "./projects/" + project.getNode() + "/versions/");
348 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
350 renderSite(req, resp);
351 } catch (NoSuchElementException | IllegalArgumentException ex) {
352 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
353 // TODO: implement - fix issue #21
354 }
355 }
357 @RequestMapping(requestPath = "$project/components/", method = HttpMethod.GET)
358 public void components(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
359 final var viewModel = new ComponentsView();
360 populate(viewModel, pathParameters, dao);
362 final var projectInfo = viewModel.getProjectInfo();
363 if (projectInfo == null) {
364 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
365 return;
366 }
368 final var issueDao = dao.getIssueDao();
369 final var issues = issueDao.list(projectInfo.getProject());
370 viewModel.update(projectInfo.getComponents(), issues);
372 forwardView(req, resp, viewModel, "components");
373 }
375 @RequestMapping(requestPath = "$project/components/$component/edit", method = HttpMethod.GET)
376 public void editComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
377 final var viewModel = new ComponentEditView();
378 populate(viewModel, pathParameters, dao);
380 if (viewModel.getProjectInfo() == null || viewModel.getComponentFilter() == null) {
381 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
382 return;
383 }
385 viewModel.setComponent(viewModel.getComponentFilter());
386 viewModel.setUsers(dao.getUserDao().list());
388 forwardView(req, resp, viewModel, "component-form");
389 }
391 @RequestMapping(requestPath = "$project/create-component", method = HttpMethod.GET)
392 public void createComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
393 final var viewModel = new ComponentEditView();
394 populate(viewModel, pathParameters, dao);
396 if (viewModel.getProjectInfo() == null) {
397 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
398 return;
399 }
401 viewModel.setComponent(new Component(-1));
402 viewModel.setUsers(dao.getUserDao().list());
404 forwardView(req, resp, viewModel, "component-form");
405 }
407 @RequestMapping(requestPath = "commit-component", method = HttpMethod.POST)
408 public void commitComponent(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
410 try {
411 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
412 if (project == null) {
413 // TODO: improve error handling, because not found is not correct for this POST request
414 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
415 return;
416 }
417 final var component = new Component(getParameter(req, Integer.class, "id").orElseThrow());
418 component.setName(getParameter(req, String.class, "name").orElseThrow());
420 final var node = getParameter(req, String.class, "node").orElse(null);
421 component.setNode(sanitizeNode(node, component.getName()));
423 component.setColor(getParameter(req, WebColor.class, "color").orElseThrow());
424 getParameter(req, Integer.class, "ordinal").ifPresent(component::setOrdinal);
425 getParameter(req, Integer.class, "lead").map(
426 userid -> userid >= 0 ? new User(userid) : null
427 ).ifPresent(component::setLead);
428 getParameter(req, String.class, "description").ifPresent(component::setDescription);
430 final var componentDao = dao.getComponentDao();
431 if (component.getId() > 0) {
432 // TODO: use return value
433 componentDao.update(component);
434 } else {
435 componentDao.save(component, project);
436 }
438 setRedirectLocation(req, "./projects/" + project.getNode() + "/components/");
439 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
441 renderSite(req, resp);
442 } catch (NoSuchElementException | IllegalArgumentException ex) {
443 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
444 // TODO: implement - fix issue #21
445 }
446 }
448 private void configureIssueEditor(IssueEditView viewModel, Issue issue, DaoProvider dao) throws SQLException {
449 final var project = viewModel.getProjectInfo().getProject();
450 issue.setProject(project); // automatically set current project for new issues
451 viewModel.setIssue(issue);
452 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions());
453 viewModel.setUsers(dao.getUserDao().list());
454 viewModel.setComponents(dao.getComponentDao().list(project));
455 }
457 @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET)
458 public void viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
459 final var viewModel = new IssueDetailView();
460 populate(viewModel, pathParameters, dao);
462 final var projectInfo = viewModel.getProjectInfo();
463 if (projectInfo == null) {
464 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
465 return;
466 }
468 final var issueDao = dao.getIssueDao();
469 final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue")));
470 if (issue == null) {
471 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
472 return;
473 }
475 issueDao.joinVersionInformation(issue);
476 viewModel.setIssue(issue);
477 viewModel.setComments(issueDao.listComments(issue));
479 forwardView(req, resp, viewModel, "issue-view");
480 }
482 // TODO: why should the issue editor be child of $project?
483 @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET)
484 public void editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
485 final var viewModel = new IssueEditView();
486 populate(viewModel, pathParameters, dao);
488 final var projectInfo = viewModel.getProjectInfo();
489 if (projectInfo == null) {
490 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
491 return;
492 }
494 final var issueDao = dao.getIssueDao();
495 final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue")));
496 if (issue == null) {
497 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
498 return;
499 }
501 issueDao.joinVersionInformation(issue);
502 configureIssueEditor(viewModel, issue, dao);
504 forwardView(req, resp, viewModel, "issue-form");
505 }
507 @RequestMapping(requestPath = "$project/create-issue", method = HttpMethod.GET)
508 public void createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException {
509 final var viewModel = new IssueEditView();
510 populate(viewModel, pathParameters, dao);
512 final var projectInfo = viewModel.getProjectInfo();
513 if (projectInfo == null) {
514 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
515 return;
516 }
518 final var issue = new Issue(-1);
519 issue.setProject(projectInfo.getProject());
520 configureIssueEditor(viewModel, issue, dao);
522 forwardView(req, resp, viewModel, "issue-form");
523 }
525 @RequestMapping(requestPath = "commit-issue", method = HttpMethod.POST)
526 public void commitIssue(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
527 try {
528 final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow());
529 final var componentId = getParameter(req, Integer.class, "component");
530 final Component component;
531 if (componentId.isPresent()) {
532 component = dao.getComponentDao().find(componentId.get());
533 } else {
534 component = null;
535 }
536 final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow());
537 if (project == null) {
538 // TODO: improve error handling, because not found is not correct for this POST request
539 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
540 return;
541 }
542 issue.setProject(project);
543 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory);
544 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus);
545 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow());
546 issue.setComponent(component);
547 getParameter(req, Integer.class, "assignee").map(userid -> {
548 if (userid >= 0) {
549 return new User(userid);
550 } else if (userid == -2) {
551 return Optional.ofNullable(component).map(Component::getLead).orElse(null);
552 } else {
553 return null;
554 }
555 }
556 ).ifPresent(issue::setAssignee);
557 getParameter(req, String.class, "description").ifPresent(issue::setDescription);
558 getParameter(req, Date.class, "eta").ifPresent(issue::setEta);
560 getParameter(req, Integer[].class, "affected")
561 .map(Stream::of)
562 .map(stream ->
563 stream.map(Version::new).collect(Collectors.toList())
564 ).ifPresent(issue::setAffectedVersions);
565 getParameter(req, Integer[].class, "resolved")
566 .map(Stream::of)
567 .map(stream ->
568 stream.map(Version::new).collect(Collectors.toList())
569 ).ifPresent(issue::setResolvedVersions);
571 final var issueDao = dao.getIssueDao();
572 if (issue.getId() > 0) {
573 // TODO: use return value
574 issueDao.update(issue);
575 } else {
576 issueDao.save(issue, project);
577 }
579 // TODO: fix redirect location
580 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
581 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
583 renderSite(req, resp);
584 } catch (NoSuchElementException | IllegalArgumentException ex) {
585 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
586 // TODO: implement - fix issue #21
587 }
588 }
590 @RequestMapping(requestPath = "commit-issue-comment", method = HttpMethod.POST)
591 public void commentIssue(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException {
592 final var issueIdParam = getParameter(req, Integer.class, "issueid");
593 if (issueIdParam.isEmpty()) {
594 resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Detected manipulated form.");
595 return;
596 }
597 final var issue = dao.getIssueDao().find(issueIdParam.get());
598 if (issue == null) {
599 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
600 return;
601 }
602 try {
603 final var issueComment = new IssueComment(getParameter(req, Integer.class, "commentid").orElse(-1));
604 issueComment.setComment(getParameter(req, String.class, "comment").orElse(""));
606 if (issueComment.getComment().isBlank()) {
607 throw new IllegalArgumentException("comment.null");
608 }
610 LOG.debug("User {} is commenting on issue #{}", req.getRemoteUser(), issue.getId());
611 if (req.getRemoteUser() != null) {
612 Optional.ofNullable(dao.getUserDao().findByUsername(req.getRemoteUser())).ifPresent(issueComment::setAuthor);
613 }
615 dao.getIssueDao().saveComment(issue, issueComment);
617 // TODO: fix redirect location
618 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view");
619 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL);
621 renderSite(req, resp);
622 } catch (NoSuchElementException | IllegalArgumentException ex) {
623 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
624 // TODO: implement - fix issue #21
625 }
626 }
627 }