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

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

mercurial