Thu, 15 Oct 2020 20:02:30 +0200
changes request mapping to contain project and version ID as path parameters (this removes the session storage)
--- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Thu Oct 15 20:02:30 2020 +0200 @@ -194,12 +194,15 @@ try { PathPattern pathPattern = new PathPattern(mapping.get().requestPath()); - if (mappings - .computeIfAbsent(mapping.get().method(), k -> new HashMap<>()) - .putIfAbsent(pathPattern, method) != null) { - LOG.warn("{} {} has multiple mappings", + final var methodMappings = mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>()); + final var currentMapping = methodMappings.putIfAbsent(pathPattern, method); + if (currentMapping != null) { + LOG.warn("Cannot map {} {} to {} in class {} - this would override the mapping to {}", mapping.get().method(), - mapping.get().requestPath() + mapping.get().requestPath(), + method.getName(), + getClass().getSimpleName(), + currentMapping.getName() ); } @@ -296,6 +299,32 @@ req.setAttribute(Constants.REQ_ATTR_VIEWMODEL, viewModel); } + private <T> Optional<T> parseParameter(String paramValue, Class<T> clazz) { + if (paramValue == null) return Optional.empty(); + if (clazz.equals(Boolean.class)) { + if (paramValue.toLowerCase().equals("false") || paramValue.equals("0")) { + return Optional.of((T) Boolean.FALSE); + } else { + return Optional.of((T) Boolean.TRUE); + } + } + if (clazz.equals(String.class)) return Optional.of((T) paramValue); + if (java.sql.Date.class.isAssignableFrom(clazz)) { + try { + return Optional.of((T) java.sql.Date.valueOf(paramValue)); + } catch (IllegalArgumentException ex) { + return Optional.empty(); + } + } + try { + final Constructor<T> ctor = clazz.getConstructor(String.class); + return Optional.of(ctor.newInstance(paramValue)); + } catch (ReflectiveOperationException e) { + // does not type check and is not convertible - treat as if the parameter was never set + return Optional.empty(); + } + } + /** * Obtains a request parameter of the specified type. * The specified type must have a single-argument constructor accepting a string to perform conversion. @@ -322,30 +351,7 @@ } return Optional.of(array); } else { - final String paramValue = req.getParameter(name); - if (paramValue == null) return Optional.empty(); - if (clazz.equals(Boolean.class)) { - if (paramValue.toLowerCase().equals("false") || paramValue.equals("0")) { - return Optional.of((T) Boolean.FALSE); - } else { - return Optional.of((T) Boolean.TRUE); - } - } - if (clazz.equals(String.class)) return Optional.of((T) paramValue); - if (java.sql.Date.class.isAssignableFrom(clazz)) { - try { - return Optional.of((T) java.sql.Date.valueOf(paramValue)); - } catch (IllegalArgumentException ex) { - return Optional.empty(); - } - } - try { - final Constructor<T> ctor = clazz.getConstructor(String.class); - return Optional.of(ctor.newInstance(paramValue)); - } catch (ReflectiveOperationException e) { - // does not type check and is not convertible - treat as if the parameter was never set - return Optional.empty(); - } + return parseParameter(req.getParameter(name), clazz); } }
--- a/src/main/java/de/uapcore/lightpit/Functions.java Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/Functions.java Thu Oct 15 20:02:30 2020 +0200 @@ -74,6 +74,14 @@ return req.getServletPath() + Optional.ofNullable(req.getPathInfo()).orElse(""); } + public static int parseIntOrZero(String str) { + try { + return Integer.parseInt(str); + } catch (NumberFormatException ex) { + return 0; + } + } + /** * This class is not instantiatable. */
--- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Thu Oct 15 20:02:30 2020 +0200 @@ -44,12 +44,9 @@ import java.sql.Date; import java.sql.SQLException; import java.util.NoSuchElementException; -import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -import static de.uapcore.lightpit.Functions.fqn; - @WebServlet( name = "ProjectsModule", urlPatterns = "/projects/*" @@ -58,45 +55,26 @@ private static final Logger LOG = LoggerFactory.getLogger(ProjectsModule.class); - private static final String SESSION_ATTR_SELECTED_PROJECT = fqn(ProjectsModule.class, "selected_project"); - private static final String SESSION_ATTR_SELECTED_VERSION = fqn(ProjectsModule.class, "selected_version"); - private static final String SESSION_ATTR_SELECTED_COMPONENT = fqn(ProjectsModule.class, "selected_component"); - private static final String PARAMETER_SELECTED_PROJECT = "pid"; - private static final String PARAMETER_SELECTED_VERSION = "vid"; - private static final String PARAMETER_SELECTED_COMPONENT = "cid"; - @Override protected String getResourceBundleName() { return "localization.projects"; } - private int syncParamWithSession(HttpServletRequest req, String param, String attr) { - final var session = req.getSession(); - final var idParam = getParameter(req, Integer.class, param); - final int id; - if (idParam.isPresent()) { - id = idParam.get(); - session.setAttribute(attr, id); - } else { - id = Optional.ofNullable(session.getAttribute(attr)).map(x->(Integer)x).orElse(-1); - } - return id; - } - - private void populate(ProjectView viewModel, HttpServletRequest req, DataAccessObjects dao) throws SQLException { + private void populate(ProjectView viewModel, PathParameters pathParameters, DataAccessObjects dao) throws SQLException { final var projectDao = dao.getProjectDao(); final var versionDao = dao.getVersionDao(); final var componentDao = dao.getComponentDao(); projectDao.list().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add); + if (pathParameters == null) + return; + // Select Project - final int pid = syncParamWithSession(req, PARAMETER_SELECTED_PROJECT, SESSION_ATTR_SELECTED_PROJECT); - if (pid >= 0) { + final int pid = Functions.parseIntOrZero(pathParameters.get("project")); + if (pid > 0) { final var project = projectDao.find(pid); - if (project == null) { - req.setAttribute(SESSION_ATTR_SELECTED_PROJECT, -1); - } else { + if (project != null) { final var info = new ProjectInfo(project); info.setVersions(versionDao.list(project)); info.setComponents(componentDao.list(project)); @@ -106,22 +84,19 @@ } // Select Version - final int vid = syncParamWithSession(req, PARAMETER_SELECTED_VERSION, SESSION_ATTR_SELECTED_VERSION); + final int vid = Functions.parseIntOrZero(pathParameters.get("version")); if (vid > 0) { viewModel.setVersionFilter(versionDao.find(vid)); - } else { - // NULL for version means: show all unassigned - viewModel.setVersionFilter(null); + } + // TODO: don't treat unknown == unassigned - send 404 for unknown and introduce special word for unassigned + + // Select Component + final int cid = Functions.parseIntOrZero(pathParameters.get("component")); + if (cid > 0) { + viewModel.setComponentFilter(componentDao.find(cid)); } - // Select Component - final int cid = syncParamWithSession(req, PARAMETER_SELECTED_COMPONENT, SESSION_ATTR_SELECTED_COMPONENT); - if (cid > 0) { - viewModel.setComponentFilter(componentDao.find(cid)); - } else if (cid <= 0) { - // -1 means: filter for unassigned, null means: show all - viewModel.setComponentFilter(new Component(-1)); - } + // TODO: distinguish all/unassigned for components } private ResponseType forwardView(HttpServletRequest req, ProjectView viewModel, String name) { @@ -135,7 +110,7 @@ @RequestMapping(method = HttpMethod.GET) public ResponseType index(HttpServletRequest req, DataAccessObjects dao) throws SQLException { final var viewModel = new ProjectView(); - populate(viewModel, req, dao); + populate(viewModel, null, dao); final var projectDao = dao.getProjectDao(); final var versionDao = dao.getVersionDao(); @@ -148,30 +123,38 @@ return forwardView(req, viewModel, "projects"); } - private void configure(ProjectEditView viewModel, Project project, DataAccessObjects dao) throws SQLException { + private void configureProjectEditor(ProjectEditView viewModel, Project project, DataAccessObjects dao) throws SQLException { viewModel.setProject(project); viewModel.setUsers(dao.getUserDao().list()); } - @RequestMapping(requestPath = "edit", method = HttpMethod.GET) - public ResponseType edit(HttpServletRequest req, DataAccessObjects dao) throws SQLException { + @RequestMapping(requestPath = "$project/edit", method = HttpMethod.GET) + public ResponseType edit(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObjects dao) throws IOException, SQLException { final var viewModel = new ProjectEditView(); - populate(viewModel, req, dao); + populate(viewModel, pathParams, dao); + + if (viewModel.getProjectInfo() == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; + } - final var project = Optional.ofNullable(viewModel.getProjectInfo()) - .map(ProjectInfo::getProject) - .orElse(new Project(-1)); - configure(viewModel, project, dao); + configureProjectEditor(viewModel, viewModel.getProjectInfo().getProject(), dao); + return forwardView(req, viewModel, "project-form"); + } + @RequestMapping(requestPath = "create", method = HttpMethod.GET) + public ResponseType create(HttpServletRequest req, DataAccessObjects dao) throws SQLException { + final var viewModel = new ProjectEditView(); + populate(viewModel, null, dao); + configureProjectEditor(viewModel, new Project(-1), dao); return forwardView(req, viewModel, "project-form"); } @RequestMapping(requestPath = "commit", method = HttpMethod.POST) - public ResponseType commit(HttpServletRequest req, DataAccessObjects dao) throws SQLException { + public ResponseType commit(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException { - Project project = new Project(-1); try { - project = new Project(getParameter(req, Integer.class, "pid").orElseThrow()); + final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow()); project.setName(getParameter(req, String.class, "name").orElseThrow()); getParameter(req, String.class, "description").ifPresent(project::setDescription); getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl); @@ -187,30 +170,25 @@ return ResponseType.HTML; } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { - LOG.warn("Form validation failure: {}", ex.getMessage()); - LOG.debug("Details:", ex); - final var viewModel = new ProjectEditView(); - populate(viewModel, req, dao); - configure(viewModel, project, dao); - // TODO: error text - return forwardView(req, viewModel, "project-form"); + resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); + // TODO: implement - fix issue #21 + return ResponseType.NONE; } } - @RequestMapping(requestPath = "view", method = HttpMethod.GET) - public ResponseType view(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { + @RequestMapping(requestPath = "$project/versions/$version", method = HttpMethod.GET) + public ResponseType view(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObjects dao) throws SQLException, IOException { final var viewModel = new ProjectDetailsView(); - populate(viewModel, req, dao); + populate(viewModel, pathParams, dao); + final var version = viewModel.getVersionFilter(); - if (viewModel.getProjectInfo() == null) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); + if (viewModel.getProjectInfo() == null || version == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); return ResponseType.NONE; } final var issueDao = dao.getIssueDao(); - final var version = viewModel.getVersionFilter(); - final var detailView = viewModel.getProjectDetails(); final var issues = issueDao.list(version); for (var issue : issues) issueDao.joinVersionInformation(issue); @@ -224,15 +202,14 @@ return forwardView(req, viewModel, "project-details"); } - @RequestMapping(requestPath = "versions", method = HttpMethod.GET) - public ResponseType versions(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { + @RequestMapping(requestPath = "$project/versions/", method = HttpMethod.GET) + public ResponseType versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { final var viewModel = new VersionsView(); - populate(viewModel, req, dao); - viewModel.setVersionFilter(null); + populate(viewModel, pathParameters, dao); final var projectInfo = viewModel.getProjectInfo(); if (projectInfo == null) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); + resp.sendError(HttpServletResponse.SC_NOT_FOUND); return ResponseType.NONE; } @@ -244,49 +221,60 @@ return forwardView(req, viewModel, "versions"); } - @RequestMapping(requestPath = "versions/edit", method = HttpMethod.GET) - public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException, SQLException { + @RequestMapping(requestPath = "$project/versions/$version/edit", method = HttpMethod.GET) + public ResponseType editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { final var viewModel = new VersionEditView(); - populate(viewModel, req, dao); + populate(viewModel, pathParameters, dao); - if (viewModel.getProjectInfo() == null) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, "No project selected."); + if (viewModel.getProjectInfo() == null || viewModel.getVersionFilter() == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); return ResponseType.NONE; } - viewModel.setVersion(Optional.ofNullable(viewModel.getVersionFilter()).orElse(new Version(-1))); + viewModel.setVersion(viewModel.getVersionFilter()); return forwardView(req, viewModel, "version-form"); } - @RequestMapping(requestPath = "versions/commit", method = HttpMethod.POST) - public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { + @RequestMapping(requestPath = "$project/create-version", method = HttpMethod.GET) + public ResponseType createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { + final var viewModel = new VersionEditView(); + populate(viewModel, pathParameters, dao); - var version = new Version(-1); + if (viewModel.getProjectInfo() == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; + } + + viewModel.setVersion(viewModel.getVersionFilter()); + + return forwardView(req, viewModel, "version-form"); + } + + @RequestMapping(requestPath = "commit-version", method = HttpMethod.POST) + public ResponseType commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException { + try { final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow()); - version = new Version(getParameter(req, Integer.class, "id").orElseThrow()); + final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow()); version.setName(getParameter(req, String.class, "name").orElseThrow()); getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal); version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow())); dao.getVersionDao().saveOrUpdate(version, project); - setRedirectLocation(req, "./projects/versions?pid=" + project.getId()); + // TODO: improve building the redirect location + setRedirectLocation(req, "./projects/" + project.getId() + "/versions/"); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { - LOG.warn("Form validation failure: {}", ex.getMessage()); - LOG.debug("Details:", ex); - final var viewModel = new VersionEditView(); - populate(viewModel, req, dao); - viewModel.setVersion(version); - // TODO: set Error Text - return forwardView(req, viewModel, "version-form"); + resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); + // TODO: implement - fix issue #21 + return ResponseType.NONE; } return ResponseType.HTML; } - private void configure(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException { + private void configureProjectEditor(IssueEditView viewModel, Issue issue, DataAccessObjects dao) throws SQLException { issue.setProject(viewModel.getProjectInfo().getProject()); viewModel.setIssue(issue); viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions()); @@ -296,30 +284,52 @@ } } - @RequestMapping(requestPath = "issues/edit", method = HttpMethod.GET) - public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException { + @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET) + public ResponseType editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { final var viewModel = new IssueEditView(); - populate(viewModel, req, dao); + populate(viewModel, pathParameters, dao); - final var issueParam = getParameter(req, Integer.class, "issue"); - if (issueParam.isPresent()) { - final var issueDao = dao.getIssueDao(); - final var issue = issueDao.find(issueParam.get()); - issueDao.joinVersionInformation(issue); - req.getSession().setAttribute(SESSION_ATTR_SELECTED_PROJECT, issue.getProject().getId()); - configure(viewModel, issue, dao); - } else { - configure(viewModel, new Issue(-1), dao); + final var projectInfo = viewModel.getProjectInfo(); + if (projectInfo == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; } + final var issueDao = dao.getIssueDao(); + final var issue = issueDao.find(Functions.parseIntOrZero(pathParameters.get("issue"))); + if (issue == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; + } + + issueDao.joinVersionInformation(issue); + configureProjectEditor(viewModel, issue, dao); + return forwardView(req, viewModel, "issue-form"); } - @RequestMapping(requestPath = "issues/commit", method = HttpMethod.POST) - public ResponseType commitIssue(HttpServletRequest req, DataAccessObjects dao) throws SQLException { - Issue issue = new Issue(-1); + @RequestMapping(requestPath = "$project/create-issue", method = HttpMethod.GET) + public ResponseType createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObjects dao) throws IOException, SQLException { + final var viewModel = new IssueEditView(); + populate(viewModel, pathParameters, dao); + + final var projectInfo = viewModel.getProjectInfo(); + if (projectInfo == null) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + return ResponseType.NONE; + } + + final var issue = new Issue(-1); + issue.setProject(projectInfo.getProject()); + configureProjectEditor(viewModel, issue, dao); + + return forwardView(req, viewModel, "issue-form"); + } + + @RequestMapping(requestPath = "commit-issue", method = HttpMethod.POST) + public ResponseType commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws IOException { try { - issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow()); + final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow()); issue.setProject(new Project(getParameter(req, Integer.class, "pid").orElseThrow())); getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory); getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus); @@ -343,24 +353,19 @@ dao.getIssueDao().saveOrUpdate(issue, issue.getProject()); - // specifying the issue parameter keeps the edited issue as menu item - setRedirectLocation(req, "./projects/view?pid=" + issue.getProject().getId()); + // TODO: fix issue #14 + setRedirectLocation(req, "./projects/" + issue.getProject().getId() + "/versions/"); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); return ResponseType.HTML; } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { - // TODO: set request attribute with error text - LOG.warn("Form validation failure: {}", ex.getMessage()); - LOG.debug("Details:", ex); - final var viewModel = new IssueEditView(); - populate(viewModel, req, dao); - configure(viewModel, issue, dao); - // TODO: set Error Text - return forwardView(req, viewModel, "issue-form"); + resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); + // TODO: implement - fix issue #21 + return ResponseType.NONE; } } - @RequestMapping(requestPath = "issues/comment", method = HttpMethod.POST) + @RequestMapping(requestPath = "commit-issue-comment", method = HttpMethod.POST) public ResponseType commentIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObjects dao) throws SQLException, IOException { final var issueIdParam = getParameter(req, Integer.class, "issueid"); if (issueIdParam.isEmpty()) { @@ -383,20 +388,15 @@ dao.getIssueDao().saveComment(issueComment); - // specifying the issue parameter keeps the edited issue as menu item - setRedirectLocation(req, "./projects/issues/edit?issue=" + issue.getId()); + // TODO: fix redirect location (e.g. after fixing #24) + setRedirectLocation(req, "./projects/" + issue.getProject().getId()+"/issues/"+issue.getId()+"/edit"); setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); return ResponseType.HTML; } catch (NoSuchElementException | IllegalArgumentException | SQLException ex) { - // TODO: set request attribute with error text - LOG.warn("Form validation failure: {}", ex.getMessage()); - LOG.debug("Details:", ex); - final var viewModel = new IssueEditView(); - populate(viewModel, req, dao); - configure(viewModel, issue, dao); - // TODO: set Error Text - return forwardView(req, viewModel, "issue-form"); + resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); + // TODO: implement - fix issue #21 + return ResponseType.NONE; } } }
--- a/src/main/webapp/WEB-INF/jsp/issue-form.jsp Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/issue-form.jsp Thu Oct 15 20:02:30 2020 +0200 @@ -31,7 +31,8 @@ <jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.IssueEditView" scope="request"/> <c:set var="issue" scope="page" value="${viewmodel.issue}" /> -<form action="./projects/issues/commit" method="post"> +<%-- TODO: change to ./issues/commit --%> +<form action="./projects/commit-issue" method="post"> <table class="formtable fullwidth"> <colgroup> <col> @@ -152,15 +153,8 @@ <tr> <td colspan="2"> <input type="hidden" name="id" value="${issue.id}"/> - <c:choose> - <c:when test="${not empty issue.project}"> - <c:set var="cancelUrl">./projects/view?pid=${issue.project.id}</c:set> - </c:when> - <c:otherwise> - <c:set var="cancelUrl">./projects/</c:set> - </c:otherwise> - </c:choose> - <a href="${cancelUrl}" class="button"> + <%-- TODO: fix #14 --%> + <a href="./projects/${issue.project.id}/versions/" class="button"> <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> </a> <button type="submit"><fmt:message bundle="${lightpit_bundle}" key="button.okay"/></button> @@ -172,7 +166,7 @@ <hr class="comments-separator"/> <h2><fmt:message key="issue.comments"/></h2> <c:if test="${viewmodel.issue.id ge 0}"> -<form id="comment-form" action="./projects/issues/comment" method="post"> +<form id="comment-form" action="./projects/commit-issue-comment" method="post"> <table class="formtable fullwidth"> <tbody> <tr>
--- a/src/main/webapp/WEB-INF/jsp/issues.jsp Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/issues.jsp Thu Oct 15 20:02:30 2020 +0200 @@ -28,6 +28,9 @@ <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> +<h1>TODO: REWRITE THIS PAGE</h1> +<%-- +TODO: rewrite <jsp:useBean id="viewmodel" type="de.uapcore.lightpit.viewmodel.IssuesView" scope="request"/> <c:set var="project" scope="page" value="${viewmodel.project}"/> <c:set var="version" scope="page" value="${viewmodel.version}"/> @@ -50,4 +53,5 @@ </div> <c:set var="issues" value="${viewmodel.issues}"/> -<%@include file="../jspf/issue-list.jspf"%> \ No newline at end of file +<%@include file="../jspf/issue-list.jspf"%> +--%> \ No newline at end of file
--- a/src/main/webapp/WEB-INF/jsp/project-details.jsp Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/project-details.jsp Thu Oct 15 20:02:30 2020 +0200 @@ -35,10 +35,10 @@ <div id="tool-area"> <c:if test="${not empty viewmodel.versionFilter}"> - <a href="./projects/versions/edit?vid=${viewmodel.versionFilter.id}" class="button"><fmt:message key="button.version.edit"/></a> + <a href="./projects/${project.id}/versions/${viewmodel.versionFilter.id}/edit" class="button"><fmt:message key="button.version.edit"/></a> </c:if> - <a href="./projects/versions/edit?vid=-1" class="button"><fmt:message key="button.version.create"/></a> - <a href="./projects/issues/edit?pid=${project.id}" class="button"><fmt:message key="button.issue.create"/></a> + <a href="./projects/${project.id}/create-version" class="button"><fmt:message key="button.version.create"/></a> + <a href="./projects/${project.id}/create-issue" class="button"><fmt:message key="button.issue.create"/></a> </div> <h2><fmt:message key="progress" /></h2>
--- a/src/main/webapp/WEB-INF/jsp/project-navmenu.jsp Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/project-navmenu.jsp Thu Oct 15 20:02:30 2020 +0200 @@ -33,20 +33,20 @@ <c:forEach var="projectInfo" items="${viewmodel.projectList}"> <c:set var="isActive" value="${viewmodel.projectInfo.project eq projectInfo.project}" /> <div class="menuEntry level-0" <c:if test="${isActive}">data-active</c:if> > - <a href="projects/versions?pid=${projectInfo.project.id}"> + <a href="projects/${projectInfo.project.id}/versions/"> <c:out value="${projectInfo.project.name}"/> </a> </div> <c:if test="${isActive}"> <!-- VERSIONS --> <div class="menuEntry level-1"> - <a href="projects/versions?pid=${projectInfo.project.id}"> + <a href="projects/${projectInfo.project.id}/versions/"> <fmt:message key="navmenu.versions"/> </a> </div> <div class="menuEntry level-2"> <div class="navmenu-icon" style="background: black"></div> - <a href="projects/view?pid=${projectInfo.project.id}&vid=-1"> + <a href="projects/${projectInfo.project.id}/versions/unassigned"> <fmt:message key="navmenu.unassigned" /> </a> </div> @@ -55,26 +55,27 @@ <div class="menuEntry level-2" <c:if test="${isVersionActive}">data-active</c:if> title="<fmt:message key="version.status.${version.status}" />"> <div class="navmenu-icon version-${version.status}"></div> - <a href="projects/view?pid=${projectInfo.project.id}&vid=${version.id}"> + <a href="projects/${projectInfo.project.id}/versions/${version.id}"> <c:out value="${version.name}"/> </a> </div> </c:forEach> - <!-- COMPONENTS --> + <%-- COMPONENTS + TODO: find a way to combine version and component into one URL <div class="menuEntry level-1"> - <a href="projects/components?pid=${projectInfo.project.id}"> + <a href="projects/${projectInfo.project.id}/components/"> <fmt:message key="navmenu.components"/> </a> </div> <div class="menuEntry level-2"> <div class="navmenu-icon" style="background: black"></div> - <a href="projects/view?pid=${projectInfo.project.id}&cid=0"> + <a href="projects/${projectInfo.project.id}/components/"> <fmt:message key="navmenu.all" /> </a> </div> <div class="menuEntry level-2"> <div class="navmenu-icon" style="background: black"></div> - <a href="projects/view?pid=${projectInfo.project.id}&cid=-1"> + <a href="projects/${projectInfo.project.id}/components/unassigned"> <fmt:message key="navmenu.unassigned" /> </a> </div> @@ -87,5 +88,6 @@ </a> </div> </c:forEach> + --%> </c:if> </c:forEach>
--- a/src/main/webapp/WEB-INF/jsp/projects.jsp Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/projects.jsp Thu Oct 15 20:02:30 2020 +0200 @@ -37,7 +37,7 @@ </c:if> <div id="tool-area"> - <a href="./projects/edit?pid=-1" class="button"><fmt:message key="button.create"/></a> + <a href="./projects/create" class="button"><fmt:message key="button.create"/></a> </div> <c:if test="${not empty viewmodel.projectList}"> @@ -68,8 +68,8 @@ <c:forEach var="projectInfo" items="${viewmodel.projectList}"> <c:set var="project" scope="page" value="${projectInfo.project}"/> <tr class="nowrap"> - <td style="width: 2em;"><a href="./projects/edit?pid=${project.id}">✎</a></td> - <td><a href="./projects/versions?pid=${project.id}"><c:out value="${project.name}"/></a> + <td style="width: 2em;"><a href="./projects/${project.id}/edit">✎</a></td> + <td><a href="./projects/${project.id}/versions/"><c:out value="${project.name}"/></a> </td> <td> <c:if test="${not empty project.repoUrl}"> @@ -79,12 +79,12 @@ </td> <td class="hright"> <c:if test="${not empty projectInfo.latestVersion}"> - <a href="./projects/view?pid=${project.id}&vid=${projectInfo.latestVersion.id}"><c:out value="${projectInfo.latestVersion.name}"/></a> + <a href="./projects/${project.id}/versions/${projectInfo.latestVersion.id}/"><c:out value="${projectInfo.latestVersion.name}"/></a> </c:if> </td> <td class="hright"> <c:if test="${not empty projectInfo.nextVersion}"> - <a href="./projects/view?pid=${project.id}&vid=${projectInfo.nextVersion.id}"><c:out value="${projectInfo.nextVersion.name}"/></a> + <a href="./projects/${project.id}/versions/${projectInfo.nextVersion.id}/"><c:out value="${projectInfo.nextVersion.name}"/></a> </c:if> </td> <td class="hright">${projectInfo.issueSummary.open}</td>
--- a/src/main/webapp/WEB-INF/jsp/version-form.jsp Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/version-form.jsp Thu Oct 15 20:02:30 2020 +0200 @@ -32,7 +32,7 @@ <c:set var="version" scope="page" value="${viewmodel.version}"/> <c:set var="project" scope="page" value="${viewmodel.projectInfo.project}"/> -<form action="./projects/versions/commit" method="post"> +<form action="./projects/commit-version" method="post"> <table class="formtable" style="width: 35ch"> <colgroup> <col> @@ -73,7 +73,7 @@ <tr> <td colspan="2"> <input type="hidden" name="id" value="${version.id}"/> - <a href="./projects/versions?pid=${project.id}" class="button"> + <a href="./projects/${project.id}/versions/" class="button"> <fmt:message bundle="${lightpit_bundle}" key="button.cancel"/> </a> <button type="submit"><fmt:message bundle="${lightpit_bundle}" key="button.okay"/></button>
--- a/src/main/webapp/WEB-INF/jsp/versions.jsp Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/versions.jsp Thu Oct 15 20:02:30 2020 +0200 @@ -34,8 +34,8 @@ <%@include file="../jspf/project-header.jspf"%> <div id="tool-area"> - <a href="./projects/versions/edit?vid=-1" class="button"><fmt:message key="button.version.create"/></a> - <a href="./projects/issues/edit?pid=${project.id}" class="button"><fmt:message key="button.issue.create"/></a> + <a href="./projects/${project.id}/create-version" class="button"><fmt:message key="button.version.create"/></a> + <a href="./projects/${project.id}/create-issue" class="button"><fmt:message key="button.issue.create"/></a> </div> <h2><fmt:message key="progress" /></h2> @@ -78,9 +78,9 @@ <tbody> <c:forEach var="versionInfo" items="${viewmodel.versionInfo}" > <tr> - <td rowspan="2" style="width: 2em;"><a href="./projects/versions/edit?vid=${versionInfo.version.id}">✎</a></td> + <td rowspan="2" style="width: 2em;"><a href="./projects/${project.id}/versions/${versionInfo.version.id}/edit">✎</a></td> <td rowspan="2"> - <a href="projects/view?pid=${viewmodel.projectInfo.project.id}&vid=${versionInfo.version.id}"> + <a href="./projects/${project.id}/versions/${versionInfo.version.id}"> <c:out value="${versionInfo.version.name}"/> </a> <div class="version-tag version-${versionInfo.version.status}">
--- a/src/main/webapp/WEB-INF/jspf/issue-list.jspf Thu Oct 15 18:36:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jspf/issue-list.jspf Thu Oct 15 20:02:30 2020 +0200 @@ -18,7 +18,7 @@ <tr> <td> <span class="phase-${issue.status.phase}"> - <a href="./projects/issues/edit?issue=${issue.id}"> + <a href="./projects/${issue.project.id}/issues/${issue.id}/edit"> #${issue.id} - <c:out value="${issue.subject}" /> </a> </span>