1.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Sat May 30 18:12:38 2020 +0200 1.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Mon Jun 01 14:46:58 2020 +0200 1.3 @@ -32,6 +32,7 @@ 1.4 import de.uapcore.lightpit.*; 1.5 import de.uapcore.lightpit.dao.DataAccessObjects; 1.6 import de.uapcore.lightpit.entities.*; 1.7 +import de.uapcore.lightpit.viewmodel.*; 1.8 import org.slf4j.Logger; 1.9 import org.slf4j.LoggerFactory; 1.10 1.11 @@ -42,7 +43,10 @@ 1.12 import java.io.IOException; 1.13 import java.sql.Date; 1.14 import java.sql.SQLException; 1.15 -import java.util.*; 1.16 +import java.util.ArrayList; 1.17 +import java.util.List; 1.18 +import java.util.NoSuchElementException; 1.19 +import java.util.Objects; 1.20 import java.util.stream.Collectors; 1.21 import java.util.stream.Stream; 1.22 1.23 @@ -59,41 +63,81 @@ 1.24 public static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected_project"); 1.25 public static final String SESSION_ATTR_SELECTED_ISSUE = fqn(ProjectsModule.class, "selected_issue"); 1.26 public static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version"); 1.27 - public static final String SESSION_ATTR_HIDE_ZEROS = fqn(ProjectsModule.class, "stats_hide_zeros"); 1.28 1.29 private class SessionSelection { 1.30 final HttpSession session; 1.31 + final HttpServletRequest req; 1.32 + final DataAccessObjects dao; 1.33 Project project; 1.34 Version version; 1.35 Issue issue; 1.36 1.37 - SessionSelection(HttpServletRequest req, Project project) { 1.38 - this.session = req.getSession(); 1.39 - this.project = project; 1.40 + SessionSelection(HttpServletRequest req, DataAccessObjects dao) { 1.41 + this.req = req; 1.42 + this.dao = dao; 1.43 + session = req.getSession(); 1.44 + } 1.45 + 1.46 + void newProject() { 1.47 + project = null; 1.48 version = null; 1.49 issue = null; 1.50 updateAttributes(); 1.51 + project = new Project(-1); 1.52 + updateAttributes(); 1.53 } 1.54 1.55 - SessionSelection(HttpServletRequest req, DataAccessObjects dao) throws SQLException { 1.56 - this.session = req.getSession(); 1.57 - final var issueDao = dao.getIssueDao(); 1.58 - final var projectDao = dao.getProjectDao(); 1.59 - final var issueSelection = getParameter(req, Integer.class, "issue"); 1.60 - if (issueSelection.isPresent()) { 1.61 - issue = issueDao.find(issueSelection.get()); 1.62 - } else { 1.63 - final var issue = (Issue) session.getAttribute(SESSION_ATTR_SELECTED_ISSUE); 1.64 - this.issue = issue == null ? null : issueDao.find(issue.getId()); 1.65 + void newVersion() throws SQLException { 1.66 + project = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); 1.67 + syncProject(); 1.68 + version = null; 1.69 + issue = null; 1.70 + updateAttributes(); 1.71 + version = new Version(-1); 1.72 + version.setProject(project); 1.73 + updateAttributes(); 1.74 + } 1.75 + 1.76 + void newIssue() throws SQLException { 1.77 + project = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); 1.78 + syncProject(); 1.79 + version = null; 1.80 + issue = null; 1.81 + updateAttributes(); 1.82 + issue = new Issue(-1); 1.83 + issue.setProject(project); 1.84 + updateAttributes(); 1.85 + } 1.86 + 1.87 + void selectVersion(Version selectedVersion) throws SQLException { 1.88 + issue = null; 1.89 + version = selectedVersion; 1.90 + if (!version.getProject().equals(project)) { 1.91 + project = dao.getProjectDao().find(version.getProject().getId()); 1.92 } 1.93 - if (issue != null) { 1.94 - version = null; // show the issue globally 1.95 - project = projectDao.find(issue.getProject().getId()); 1.96 + // our object contains more details 1.97 + version.setProject(project); 1.98 + updateAttributes(); 1.99 + } 1.100 + 1.101 + void selectIssue(Issue selectedIssue) throws SQLException { 1.102 + issue = selectedIssue; 1.103 + if (!issue.getProject().equals(project)) { 1.104 + project = dao.getProjectDao().find(issue.getProject().getId()); 1.105 } 1.106 + // our object contains more details 1.107 + issue.setProject(project); 1.108 + if (!issue.getResolvedVersions().contains(version) && !issue.getScheduledVersions().contains(version) 1.109 + && !issue.getAffectedVersions().contains(version)) { 1.110 + version = null; 1.111 + } 1.112 + updateAttributes(); 1.113 + } 1.114 1.115 + void syncProject() throws SQLException { 1.116 final var projectSelection = getParameter(req, Integer.class, "pid"); 1.117 if (projectSelection.isPresent()) { 1.118 - final var selectedProject = projectDao.find(projectSelection.get()); 1.119 + final var selectedProject = dao.getProjectDao().find(projectSelection.get()); 1.120 if (!Objects.equals(selectedProject, project)) { 1.121 // reset version and issue if project changed 1.122 version = null; 1.123 @@ -101,51 +145,57 @@ 1.124 } 1.125 project = selectedProject; 1.126 } else { 1.127 - final var sessionProject = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); 1.128 - project = sessionProject == null ? null : projectDao.find(sessionProject.getId()); 1.129 + project = project == null ? null : dao.getProjectDao().find(project.getId()); 1.130 } 1.131 + } 1.132 + 1.133 + void syncVersion() throws SQLException { 1.134 + final var versionSelection = getParameter(req, Integer.class, "vid"); 1.135 + if (versionSelection.isPresent()) { 1.136 + if (versionSelection.get() < 0) { 1.137 + version = null; 1.138 + } else { 1.139 + final var selectedVersion = dao.getVersionDao().find(versionSelection.get()); 1.140 + if (!Objects.equals(selectedVersion, version)) { 1.141 + issue = null; 1.142 + } 1.143 + selectVersion(selectedVersion); 1.144 + } 1.145 + } else { 1.146 + version = version == null ? null : dao.getVersionDao().find(version.getId()); 1.147 + } 1.148 + } 1.149 + 1.150 + void syncIssue() throws SQLException { 1.151 + final var issueSelection = getParameter(req, Integer.class, "issue"); 1.152 + if (issueSelection.isPresent()) { 1.153 + final var selectedIssue = dao.getIssueDao().find(issueSelection.get()); 1.154 + dao.getIssueDao().joinVersionInformation(selectedIssue); 1.155 + selectIssue(selectedIssue); 1.156 + } else { 1.157 + issue = issue == null ? null : dao.getIssueDao().find(issue.getId()); 1.158 + } 1.159 + } 1.160 + 1.161 + void sync() throws SQLException { 1.162 + project = (Project) session.getAttribute(SESSION_ATTR_SELECTED_PROJECT); 1.163 + version = (Version) session.getAttribute(SESSION_ATTR_SELECTED_VERSION); 1.164 + issue = (Issue) session.getAttribute(SESSION_ATTR_SELECTED_ISSUE); 1.165 + 1.166 + syncProject(); 1.167 + syncVersion(); 1.168 + syncIssue(); 1.169 + 1.170 updateAttributes(); 1.171 } 1.172 1.173 - void selectVersion(Version version) { 1.174 - this.project = version.getProject(); 1.175 - this.version = version; 1.176 - this.issue = null; 1.177 - updateAttributes(); 1.178 - } 1.179 - 1.180 - void selectIssue(Issue issue) { 1.181 - this.project = issue.getProject(); 1.182 - this.issue = issue; 1.183 - this.version = null; 1.184 - updateAttributes(); 1.185 - } 1.186 - 1.187 - void updateAttributes() { 1.188 + private void updateAttributes() { 1.189 session.setAttribute(SESSION_ATTR_SELECTED_PROJECT, project); 1.190 session.setAttribute(SESSION_ATTR_SELECTED_VERSION, version); 1.191 session.setAttribute(SESSION_ATTR_SELECTED_ISSUE, issue); 1.192 } 1.193 } 1.194 1.195 - private void setAttributeHideZeros(HttpServletRequest req) { 1.196 - final Boolean value; 1.197 - final var param = getParameter(req, Boolean.class, "reduced"); 1.198 - if (param.isPresent()) { 1.199 - value = param.get(); 1.200 - req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); 1.201 - } else { 1.202 - final var sessionValue = req.getSession().getAttribute(SESSION_ATTR_HIDE_ZEROS); 1.203 - if (sessionValue != null) { 1.204 - value = (Boolean) sessionValue; 1.205 - } else { 1.206 - value = false; 1.207 - req.getSession().setAttribute(SESSION_ATTR_HIDE_ZEROS, value); 1.208 - } 1.209 - } 1.210 - req.setAttribute("statsHideZeros", value); 1.211 - } 1.212 - 1.213 @Override 1.214 protected String getResourceBundleName() { 1.215 return "localization.projects"; 1.216 @@ -162,10 +212,10 @@ 1.217 * Creates the breadcrumb menu. 1.218 * 1.219 * @param level the current active level (0: root, 1: project, 2: version, 3: issue list, 4: issue) 1.220 - * @param sessionSelection the currently selected objects 1.221 + * @param selection the currently selected objects 1.222 * @return a dynamic breadcrumb menu trying to display as many levels as possible 1.223 */ 1.224 - private List<MenuEntry> getBreadcrumbs(int level, SessionSelection sessionSelection) { 1.225 + private List<MenuEntry> getBreadcrumbs(int level, SessionSelection selection) { 1.226 MenuEntry entry; 1.227 1.228 final var breadcrumbs = new ArrayList<MenuEntry>(); 1.229 @@ -174,47 +224,49 @@ 1.230 breadcrumbs.add(entry); 1.231 if (level == BREADCRUMB_LEVEL_ROOT) entry.setActive(true); 1.232 1.233 - if (sessionSelection.project != null) { 1.234 - if (sessionSelection.project.getId() < 0) { 1.235 + if (selection.project != null) { 1.236 + if (selection.project.getId() < 0) { 1.237 entry = new MenuEntry(new ResourceKey("localization.projects", "button.create"), 1.238 "projects/edit"); 1.239 } else { 1.240 - entry = new MenuEntry(sessionSelection.project.getName(), 1.241 - "projects/view?pid=" + sessionSelection.project.getId()); 1.242 + entry = new MenuEntry(selection.project.getName(), 1.243 + "projects/view?pid=" + selection.project.getId()); 1.244 } 1.245 if (level == BREADCRUMB_LEVEL_PROJECT) entry.setActive(true); 1.246 breadcrumbs.add(entry); 1.247 } 1.248 1.249 - if (sessionSelection.version != null) { 1.250 - if (sessionSelection.version.getId() < 0) { 1.251 + if (selection.version != null) { 1.252 + if (selection.version.getId() < 0) { 1.253 entry = new MenuEntry(new ResourceKey("localization.projects", "button.version.create"), 1.254 "projects/versions/edit"); 1.255 } else { 1.256 - entry = new MenuEntry(sessionSelection.version.getName(), 1.257 - // TODO: change link to issue overview for that version 1.258 - "projects/versions/edit?id=" + sessionSelection.version.getId()); 1.259 + entry = new MenuEntry(selection.version.getName(), 1.260 + "projects/versions/view?vid=" + selection.version.getId()); 1.261 } 1.262 if (level == BREADCRUMB_LEVEL_VERSION) entry.setActive(true); 1.263 breadcrumbs.add(entry); 1.264 } 1.265 1.266 - if (sessionSelection.project != null) { 1.267 + if (selection.project != null) { 1.268 + String path = "projects/issues/?pid=" + selection.project.getId(); 1.269 + if (selection.version != null) { 1.270 + path += "&vid="+selection.version.getId(); 1.271 + } 1.272 entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"), 1.273 - // TODO: maybe also add selected version 1.274 - "projects/issues/?pid=" + sessionSelection.project.getId()); 1.275 + path); 1.276 if (level == BREADCRUMB_LEVEL_ISSUE_LIST) entry.setActive(true); 1.277 breadcrumbs.add(entry); 1.278 } 1.279 1.280 - if (sessionSelection.issue != null) { 1.281 - if (sessionSelection.issue.getId() < 0) { 1.282 + if (selection.issue != null) { 1.283 + if (selection.issue.getId() < 0) { 1.284 entry = new MenuEntry(new ResourceKey("localization.projects", "button.issue.create"), 1.285 "projects/issues/edit"); 1.286 } else { 1.287 - entry = new MenuEntry("#" + sessionSelection.issue.getId(), 1.288 + entry = new MenuEntry("#" + selection.issue.getId(), 1.289 // TODO: maybe change link to a view rather than directly opening the editor 1.290 - "projects/issues/edit?id=" + sessionSelection.issue.getId()); 1.291 + "projects/issues/edit?issue=" + selection.issue.getId()); 1.292 } 1.293 if (level == BREADCRUMB_LEVEL_ISSUE) entry.setActive(true); 1.294 breadcrumbs.add(entry); 1.295 @@ -226,8 +278,22 @@ 1.296 @RequestMapping(method = HttpMethod.GET) 1.297 public ResponseType index(HttpServletRequest req, DataAccessObjects dao) throws SQLException { 1.298 final var sessionSelection = new SessionSelection(req, dao); 1.299 - final var projectList = dao.getProjectDao().list(); 1.300 - req.setAttribute("projects", projectList); 1.301 + sessionSelection.sync(); 1.302 + 1.303 + final var projectDao = dao.getProjectDao(); 1.304 + final var versionDao = dao.getVersionDao(); 1.305 + 1.306 + final var projectList = projectDao.list(); 1.307 + 1.308 + final var viewModel = new ProjectIndexView(); 1.309 + for (var project : projectList) { 1.310 + final var info = new ProjectInfo(project); 1.311 + info.setVersions(versionDao.list(project)); 1.312 + info.setIssueSummary(projectDao.getIssueSummary(project)); 1.313 + viewModel.getProjects().add(info); 1.314 + } 1.315 + 1.316 + setViewModel(req, viewModel); 1.317 setContentPage(req, "projects"); 1.318 setStylesheet(req, "projects"); 1.319 1.320 @@ -236,17 +302,24 @@ 1.321 return ResponseType.HTML; 1.322 } 1.323 1.324 - private void configureEditForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 1.325 - req.setAttribute("project", selection.project); 1.326 - req.setAttribute("users", dao.getUserDao().list()); 1.327 + private ProjectEditView configureEditForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 1.328 + final var viewModel = new ProjectEditView(); 1.329 + viewModel.setProject(selection.project); 1.330 + viewModel.setUsers(dao.getUserDao().list()); 1.331 + setViewModel(req, viewModel); 1.332 setContentPage(req, "project-form"); 1.333 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, selection)); 1.334 + return viewModel; 1.335 } 1.336 1.337 @RequestMapping(requestPath = "edit", method = HttpMethod.GET) 1.338 public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException { 1.339 - final var selection = new SessionSelection(req, findByParameter(req, Integer.class, "id", 1.340 - dao.getProjectDao()::find).orElse(new Project(-1))); 1.341 + final var selection = new SessionSelection(req, dao); 1.342 + if (getParameter(req, Integer.class, "pid").isEmpty()) { 1.343 + selection.newProject(); 1.344 + } else { 1.345 + selection.sync(); 1.346 + } 1.347 1.348 configureEditForm(req, dao, selection); 1.349 1.350 @@ -272,10 +345,12 @@ 1.351 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 1.352 LOG.debug("Successfully updated project {}", project.getName()); 1.353 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { 1.354 - // TODO: set request attribute with error text 1.355 LOG.warn("Form validation failure: {}", ex.getMessage()); 1.356 LOG.debug("Details:", ex); 1.357 - configureEditForm(req, dao, new SessionSelection(req, project)); 1.358 + final var selection = new SessionSelection(req, dao); 1.359 + selection.project = project; 1.360 + final var vm = configureEditForm(req, dao, selection); 1.361 + vm.setErrorText(ex.getMessage()); // TODO: error text 1.362 } 1.363 1.364 return ResponseType.HTML; 1.365 @@ -283,127 +358,143 @@ 1.366 1.367 @RequestMapping(requestPath = "view", method = HttpMethod.GET) 1.368 public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { 1.369 - final var sessionSelection = new SessionSelection(req, dao); 1.370 - if (sessionSelection.project == null) { 1.371 + final var selection = new SessionSelection(req, dao); 1.372 + selection.sync(); 1.373 + 1.374 + if (selection.project == null) { 1.375 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); 1.376 return ResponseType.NONE; 1.377 } 1.378 1.379 final var versionDao = dao.getVersionDao(); 1.380 - final var versions = versionDao.list(sessionSelection.project); 1.381 - final var statsAffected = new ArrayList<VersionStatistics>(); 1.382 - final var statsScheduled = new ArrayList<VersionStatistics>(); 1.383 - final var statsResolved = new ArrayList<VersionStatistics>(); 1.384 - for (Version version : versions) { 1.385 - statsAffected.add(versionDao.statsOpenedIssues(version)); 1.386 - statsScheduled.add(versionDao.statsScheduledIssues(version)); 1.387 - statsResolved.add(versionDao.statsResolvedIssues(version)); 1.388 - } 1.389 + final var issueDao = dao.getIssueDao(); 1.390 1.391 - setAttributeHideZeros(req); 1.392 + final var viewModel = new ProjectView(selection.project); 1.393 + final var issues = issueDao.list(selection.project); 1.394 + for (var issue : issues) issueDao.joinVersionInformation(issue); 1.395 + viewModel.setIssues(issues); 1.396 + viewModel.setVersions(versionDao.list(selection.project)); 1.397 + viewModel.updateVersionInfo(); 1.398 + setViewModel(req, viewModel); 1.399 1.400 - req.setAttribute("project", sessionSelection.project); 1.401 - req.setAttribute("versions", versions); 1.402 - req.setAttribute("statsAffected", statsAffected); 1.403 - req.setAttribute("statsScheduled", statsScheduled); 1.404 - req.setAttribute("statsResolved", statsResolved); 1.405 - 1.406 - req.setAttribute("issueStatusEnum", IssueStatus.values()); 1.407 - req.setAttribute("issueCategoryEnum", IssueCategory.values()); 1.408 - 1.409 - setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, sessionSelection)); 1.410 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_PROJECT, selection)); 1.411 setContentPage(req, "project-details"); 1.412 setStylesheet(req, "projects"); 1.413 1.414 return ResponseType.HTML; 1.415 } 1.416 1.417 - private void configureEditVersionForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 1.418 - final var versionDao = dao.getVersionDao(); 1.419 - req.setAttribute("projects", dao.getProjectDao().list()); 1.420 - req.setAttribute("version", selection.version); 1.421 - req.setAttribute("versionStatusEnum", VersionStatus.values()); 1.422 + @RequestMapping(requestPath = "versions/view", method = HttpMethod.GET) 1.423 + public ResponseType viewVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { 1.424 + final var selection = new SessionSelection(req, dao); 1.425 + selection.sync(); 1.426 + if (selection.version == null) { 1.427 + resp.sendError(HttpServletResponse.SC_NOT_FOUND); 1.428 + return ResponseType.NONE; 1.429 + } 1.430 1.431 - req.setAttribute("issueStatusEnum", IssueStatus.values()); 1.432 - req.setAttribute("issueCategoryEnum", IssueCategory.values()); 1.433 - req.setAttribute("statsAffected", versionDao.statsOpenedIssues(selection.version)); 1.434 - req.setAttribute("statsScheduled", versionDao.statsScheduledIssues(selection.version)); 1.435 - req.setAttribute("statsResolved", versionDao.statsResolvedIssues(selection.version)); 1.436 - setAttributeHideZeros(req); 1.437 + final var issueDao = dao.getIssueDao(); 1.438 + final var viewModel = new VersionView(selection.version); 1.439 + final var issues = issueDao.list(selection.version); 1.440 + for (var issue : issues) issueDao.joinVersionInformation(issue); 1.441 + viewModel.setIssues(issues); 1.442 + setViewModel(req, viewModel); 1.443 1.444 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_VERSION, selection)); 1.445 + setContentPage(req, "version"); 1.446 + setStylesheet(req, "projects"); 1.447 + 1.448 + return ResponseType.HTML; 1.449 + } 1.450 + 1.451 + private VersionEditView configureEditVersionForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 1.452 + final var viewModel = new VersionEditView(selection.version); 1.453 + if (selection.version.getProject() == null) { 1.454 + viewModel.setProjects(dao.getProjectDao().list()); 1.455 + } 1.456 + setViewModel(req, viewModel); 1.457 setContentPage(req, "version-form"); 1.458 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_VERSION, selection)); 1.459 + return viewModel; 1.460 } 1.461 1.462 @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET) 1.463 - public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.464 - final var sessionSelection = new SessionSelection(req, dao); 1.465 + public ResponseType editVersion(HttpServletRequest req, DataAccessObjects dao) throws SQLException { 1.466 + final var selection = new SessionSelection(req, dao); 1.467 + if (getParameter(req, Integer.class, "vid").isEmpty()) { 1.468 + selection.newVersion(); 1.469 + } else { 1.470 + selection.sync(); 1.471 + } 1.472 1.473 - sessionSelection.selectVersion(findByParameter(req, Integer.class, "id", dao.getVersionDao()::find) 1.474 - .orElse(new Version(-1, sessionSelection.project))); 1.475 - configureEditVersionForm(req, dao, sessionSelection); 1.476 + configureEditVersionForm(req, dao, selection); 1.477 1.478 return ResponseType.HTML; 1.479 } 1.480 1.481 @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST) 1.482 public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.483 - final var sessionSelection = new SessionSelection(req, dao); 1.484 1.485 - var version = new Version(-1, sessionSelection.project); 1.486 + var version = new Version(-1); 1.487 try { 1.488 - version = new Version(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); 1.489 + version = new Version(getParameter(req, Integer.class, "id").orElseThrow()); 1.490 + version.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow())); 1.491 version.setName(getParameter(req, String.class, "name").orElseThrow()); 1.492 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal); 1.493 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow())); 1.494 dao.getVersionDao().saveOrUpdate(version); 1.495 1.496 // specifying the pid parameter will purposely reset the session selected version! 1.497 - setRedirectLocation(req, "./projects/view?pid="+sessionSelection.project.getId()); 1.498 + setRedirectLocation(req, "./projects/view?pid="+version.getProject().getId()); 1.499 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 1.500 - LOG.debug("Successfully updated version {} for project {}", version.getName(), sessionSelection.project.getName()); 1.501 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { 1.502 - // TODO: set request attribute with error text 1.503 LOG.warn("Form validation failure: {}", ex.getMessage()); 1.504 LOG.debug("Details:", ex); 1.505 - sessionSelection.selectVersion(version); 1.506 - configureEditVersionForm(req, dao, sessionSelection); 1.507 + final var selection = new SessionSelection(req, dao); 1.508 + selection.selectVersion(version); 1.509 + final var viewModel = configureEditVersionForm(req, dao, selection); 1.510 + // TODO: set Error Text 1.511 } 1.512 1.513 return ResponseType.HTML; 1.514 } 1.515 1.516 - private void configureEditIssueForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 1.517 + private IssueEditView configureEditIssueForm(HttpServletRequest req, DataAccessObjects dao, SessionSelection selection) throws SQLException { 1.518 + final var viewModel = new IssueEditView(selection.issue); 1.519 1.520 - if (selection.issue.getProject() == null || selection.issue.getProject().getId() < 0) { 1.521 - req.setAttribute("projects", dao.getProjectDao().list()); 1.522 - req.setAttribute("versions", Collections.<Version>emptyList()); 1.523 + if (selection.issue.getProject() == null) { 1.524 + viewModel.setProjects(dao.getProjectDao().list()); 1.525 } else { 1.526 - req.setAttribute("projects", Collections.<Project>emptyList()); 1.527 - req.setAttribute("versions", dao.getVersionDao().list(selection.issue.getProject())); 1.528 + viewModel.setVersions(dao.getVersionDao().list(selection.issue.getProject())); 1.529 } 1.530 - 1.531 - dao.getIssueDao().joinVersionInformation(selection.issue); 1.532 - req.setAttribute("issue", selection.issue); 1.533 - req.setAttribute("issueStatusEnum", IssueStatus.values()); 1.534 - req.setAttribute("issueCategoryEnum", IssueCategory.values()); 1.535 - req.setAttribute("users", dao.getUserDao().list()); 1.536 + viewModel.setUsers(dao.getUserDao().list()); 1.537 + setViewModel(req, viewModel); 1.538 1.539 setContentPage(req, "issue-form"); 1.540 setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE, selection)); 1.541 + return viewModel; 1.542 } 1.543 1.544 @RequestMapping(requestPath = "issues/", method = HttpMethod.GET) 1.545 public ResponseType issues(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { 1.546 - final var sessionSelection = new SessionSelection(req, dao); 1.547 - if (sessionSelection.project == null) { 1.548 + final var selection = new SessionSelection(req, dao); 1.549 + selection.sync(); 1.550 + if (selection.project == null) { 1.551 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); 1.552 return ResponseType.NONE; 1.553 } 1.554 1.555 - req.setAttribute("issues", dao.getIssueDao().list(sessionSelection.project)); 1.556 + final var viewModel = new IssuesView(); 1.557 + viewModel.setProject(selection.project); 1.558 + if (selection.version == null) { 1.559 + viewModel.setIssues(dao.getIssueDao().list(selection.project)); 1.560 + } else { 1.561 + viewModel.setVersion(selection.version); 1.562 + viewModel.setIssues(dao.getIssueDao().list(selection.version)); 1.563 + } 1.564 + setViewModel(req, viewModel); 1.565 1.566 - setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE_LIST, sessionSelection)); 1.567 + setBreadcrumbs(req, getBreadcrumbs(BREADCRUMB_LEVEL_ISSUE_LIST, selection)); 1.568 setContentPage(req, "issues"); 1.569 setStylesheet(req, "projects"); 1.570 1.571 @@ -412,22 +503,25 @@ 1.572 1.573 @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET) 1.574 public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.575 - final var sessionSelection = new SessionSelection(req, dao); 1.576 + final var selection = new SessionSelection(req, dao); 1.577 + if (getParameter(req, Integer.class, "issue").isEmpty()) { 1.578 + selection.newIssue(); 1.579 + } else { 1.580 + selection.sync(); 1.581 + } 1.582 1.583 - sessionSelection.selectIssue(findByParameter(req, Integer.class, "id", 1.584 - dao.getIssueDao()::find).orElse(new Issue(-1, sessionSelection.project))); 1.585 - configureEditIssueForm(req, dao, sessionSelection); 1.586 + configureEditIssueForm(req, dao, selection); 1.587 1.588 return ResponseType.HTML; 1.589 } 1.590 1.591 @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST) 1.592 public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { 1.593 - final var sessionSelection = new SessionSelection(req, dao); 1.594 1.595 - Issue issue = new Issue(-1, sessionSelection.project); 1.596 + Issue issue = new Issue(-1); 1.597 try { 1.598 - issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow(), sessionSelection.project); 1.599 + issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow()); 1.600 + issue.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow())); 1.601 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory); 1.602 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus); 1.603 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow()); 1.604 @@ -440,17 +534,17 @@ 1.605 getParameter(req, Integer[].class, "affected") 1.606 .map(Stream::of) 1.607 .map(stream -> 1.608 - stream.map(id -> new Version(id, sessionSelection.project)).collect(Collectors.toList()) 1.609 + stream.map(Version::new).collect(Collectors.toList()) 1.610 ).ifPresent(issue::setAffectedVersions); 1.611 getParameter(req, Integer[].class, "scheduled") 1.612 .map(Stream::of) 1.613 .map(stream -> 1.614 - stream.map(id -> new Version(id, sessionSelection.project)).collect(Collectors.toList()) 1.615 + stream.map(Version::new).collect(Collectors.toList()) 1.616 ).ifPresent(issue::setScheduledVersions); 1.617 getParameter(req, Integer[].class, "resolved") 1.618 .map(Stream::of) 1.619 .map(stream -> 1.620 - stream.map(id -> new Version(id, sessionSelection.project)).collect(Collectors.toList()) 1.621 + stream.map(Version::new).collect(Collectors.toList()) 1.622 ).ifPresent(issue::setResolvedVersions); 1.623 1.624 dao.getIssueDao().saveOrUpdate(issue); 1.625 @@ -458,13 +552,14 @@ 1.626 // specifying the issue parameter keeps the edited issue as breadcrumb 1.627 setRedirectLocation(req, "./projects/issues/?issue="+issue.getId()); 1.628 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 1.629 - LOG.debug("Successfully updated issue {} for project {}", issue.getId(), sessionSelection.project.getName()); 1.630 } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { 1.631 // TODO: set request attribute with error text 1.632 LOG.warn("Form validation failure: {}", ex.getMessage()); 1.633 LOG.debug("Details:", ex); 1.634 - sessionSelection.selectIssue(issue); 1.635 - configureEditIssueForm(req, dao, sessionSelection); 1.636 + final var selection = new SessionSelection(req, dao); 1.637 + selection.selectIssue(issue); 1.638 + final var viewModel = configureEditIssueForm(req, dao, selection); 1.639 + // TODO: set Error Text 1.640 } 1.641 1.642 return ResponseType.HTML;