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

changeset 86
0a658e53177c
parent 83
24a3596b8f98
child 88
1438e5a22c55
     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;

mercurial