Mon, 21 Dec 2020 18:29:34 +0100
major refactoring of DAO architecture - also fixes #114
1.1 --- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sun Dec 20 11:06:25 2020 +0100 1.2 +++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Mon Dec 21 18:29:34 2020 +0100 1.3 @@ -28,8 +28,8 @@ 1.4 */ 1.5 package de.uapcore.lightpit; 1.6 1.7 -import de.uapcore.lightpit.dao.DaoProvider; 1.8 -import de.uapcore.lightpit.dao.postgres.PGDaoProvider; 1.9 +import de.uapcore.lightpit.dao.DataAccessObject; 1.10 +import de.uapcore.lightpit.dao.PostgresDataAccessObject; 1.11 import org.slf4j.Logger; 1.12 import org.slf4j.LoggerFactory; 1.13 1.14 @@ -56,26 +56,6 @@ 1.15 1.16 private static final String SITE_JSP = jspPath("site"); 1.17 1.18 - 1.19 - @FunctionalInterface 1.20 - protected interface SQLFindFunction<K, T> { 1.21 - T apply(K key) throws SQLException; 1.22 - 1.23 - default <V> SQLFindFunction<V, T> compose(Function<? super V, ? extends K> before) throws SQLException { 1.24 - Objects.requireNonNull(before); 1.25 - return (v) -> this.apply(before.apply(v)); 1.26 - } 1.27 - 1.28 - default <V> SQLFindFunction<K, V> andThen(Function<? super T, ? extends V> after) throws SQLException { 1.29 - Objects.requireNonNull(after); 1.30 - return (t) -> after.apply(this.apply(t)); 1.31 - } 1.32 - 1.33 - static <K> Function<K, K> identity() { 1.34 - return (t) -> t; 1.35 - } 1.36 - } 1.37 - 1.38 /** 1.39 * Invocation mapping gathered from the {@link RequestMapping} annotations. 1.40 * <p> 1.41 @@ -101,15 +81,15 @@ 1.42 * @param connection the SQL connection 1.43 * @return a set of data access objects 1.44 */ 1.45 - private DaoProvider createDataAccessObjects(Connection connection) throws SQLException { 1.46 + private DataAccessObject createDataAccessObjects(Connection connection) { 1.47 final var df = (DataSourceProvider) getServletContext().getAttribute(DataSourceProvider.Companion.getSC_ATTR_NAME()); 1.48 if (df.getDialect() == DataSourceProvider.Dialect.Postgres) { 1.49 - return new PGDaoProvider(connection); 1.50 + return new PostgresDataAccessObject(connection); 1.51 } 1.52 throw new UnsupportedOperationException("Non-exhaustive if-else - this is a bug."); 1.53 } 1.54 1.55 - private void invokeMapping(Map.Entry<PathPattern, Method> mapping, HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException { 1.56 + private void invokeMapping(Map.Entry<PathPattern, Method> mapping, HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException { 1.57 final var pathPattern = mapping.getKey(); 1.58 final var method = mapping.getValue(); 1.59 try { 1.60 @@ -122,7 +102,7 @@ 1.61 } else if (paramTypes[i].isAssignableFrom(HttpServletResponse.class)) { 1.62 paramValues[i] = resp; 1.63 } 1.64 - if (paramTypes[i].isAssignableFrom(DaoProvider.class)) { 1.65 + if (paramTypes[i].isAssignableFrom(DataAccessObject.class)) { 1.66 paramValues[i] = dao; 1.67 } 1.68 if (paramTypes[i].isAssignableFrom(PathParameters.class)) { 1.69 @@ -179,9 +159,9 @@ 1.70 boolean paramsInjectible = true; 1.71 for (var param : method.getParameterTypes()) { 1.72 paramsInjectible &= HttpServletRequest.class.isAssignableFrom(param) 1.73 - || HttpServletResponse.class.isAssignableFrom(param) 1.74 - || PathParameters.class.isAssignableFrom(param) 1.75 - || DaoProvider.class.isAssignableFrom(param); 1.76 + || HttpServletResponse.class.isAssignableFrom(param) 1.77 + || PathParameters.class.isAssignableFrom(param) 1.78 + || DataAccessObject.class.isAssignableFrom(param); 1.79 } 1.80 if (paramsInjectible) { 1.81 try { 1.82 @@ -360,7 +340,7 @@ 1.83 * @return the retrieved entity or an empty optional if there is no such entity or the request parameter was missing 1.84 * @throws SQLException if the find function throws an exception 1.85 */ 1.86 - protected <T, R> Optional<R> findByParameter(HttpServletRequest req, Class<T> clazz, String name, SQLFindFunction<? super T, ? extends R> find) throws SQLException { 1.87 + protected <T, R> Optional<R> findByParameter(HttpServletRequest req, Class<T> clazz, String name, Function<? super T, ? extends R> find) { 1.88 final var param = getParameter(req, clazz, name); 1.89 if (param.isPresent()) { 1.90 return Optional.ofNullable(find.apply(param.get()));
2.1 --- a/src/main/java/de/uapcore/lightpit/dao/Functions.java Sun Dec 20 11:06:25 2020 +0100 2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 2.3 @@ -1,101 +0,0 @@ 2.4 -/* 2.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 2.6 - * 2.7 - * Copyright 2018 Mike Becker. All rights reserved. 2.8 - * 2.9 - * Redistribution and use in source and binary forms, with or without 2.10 - * modification, are permitted provided that the following conditions are met: 2.11 - * 2.12 - * 1. Redistributions of source code must retain the above copyright 2.13 - * notice, this list of conditions and the following disclaimer. 2.14 - * 2.15 - * 2. Redistributions in binary form must reproduce the above copyright 2.16 - * notice, this list of conditions and the following disclaimer in the 2.17 - * documentation and/or other materials provided with the distribution. 2.18 - * 2.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2.29 - * POSSIBILITY OF SUCH DAMAGE. 2.30 - * 2.31 - */ 2.32 -package de.uapcore.lightpit.dao; 2.33 - 2.34 -import java.sql.*; 2.35 -import java.util.ArrayList; 2.36 -import java.util.List; 2.37 -import java.util.Optional; 2.38 -import java.util.function.Function; 2.39 - 2.40 -/** 2.41 - * Some DAO utilities. 2.42 - */ 2.43 -public final class Functions { 2.44 - 2.45 - public static String getSafeString(ResultSet rs, String column) throws SQLException { 2.46 - return Optional.ofNullable(rs.getString(column)).orElse(""); 2.47 - } 2.48 - 2.49 - public static void setStringOrNull(PreparedStatement stmt, int index, String str) throws SQLException { 2.50 - if (str == null || str.isBlank()) { 2.51 - stmt.setNull(index, Types.VARCHAR); 2.52 - } else { 2.53 - stmt.setString(index, str); 2.54 - } 2.55 - } 2.56 - 2.57 - public static void setDateOrNull(PreparedStatement stmt, int index, Date date) throws SQLException { 2.58 - if (date == null) { 2.59 - stmt.setNull(index, Types.DATE); 2.60 - } else { 2.61 - stmt.setDate(index, date); 2.62 - } 2.63 - } 2.64 - 2.65 - public static <T> void setForeignKeyOrNull(PreparedStatement stmt, int index, T instance, Function<? super T, Integer> keyGetter) throws SQLException { 2.66 - Integer key = Optional.ofNullable(instance).map(keyGetter).orElse(null); 2.67 - if (key == null) { 2.68 - stmt.setNull(index, Types.INTEGER); 2.69 - } else { 2.70 - stmt.setInt(index, key); 2.71 - } 2.72 - } 2.73 - 2.74 - @FunctionalInterface 2.75 - public interface ResultSetMapper<T> { 2.76 - T apply(ResultSet rs) throws SQLException; 2.77 - } 2.78 - 2.79 - public static <T> List<T> list(PreparedStatement stmt, ResultSetMapper<T> mapper) throws SQLException { 2.80 - List<T> results = new ArrayList<>(); 2.81 - try (var result = stmt.executeQuery()) { 2.82 - while (result.next()) { 2.83 - final var project = mapper.apply(result); 2.84 - results.add(project); 2.85 - } 2.86 - } 2.87 - return results; 2.88 - } 2.89 - 2.90 - public static <T> T find(PreparedStatement stmt, ResultSetMapper<T> mapper) throws SQLException { 2.91 - try (var result = stmt.executeQuery()) { 2.92 - if (result.next()) { 2.93 - final var ent = mapper.apply(result); 2.94 - return ent; 2.95 - } else { 2.96 - return null; 2.97 - } 2.98 - } 2.99 - } 2.100 - 2.101 - private Functions() { 2.102 - 2.103 - } 2.104 -}
3.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Sun Dec 20 11:06:25 2020 +0100 3.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Mon Dec 21 18:29:34 2020 +0100 3.3 @@ -30,8 +30,15 @@ 3.4 3.5 3.6 import de.uapcore.lightpit.*; 3.7 -import de.uapcore.lightpit.dao.DaoProvider; 3.8 +import de.uapcore.lightpit.dao.DataAccessObject; 3.9 import de.uapcore.lightpit.entities.*; 3.10 +import de.uapcore.lightpit.filter.AllFilter; 3.11 +import de.uapcore.lightpit.filter.IssueFilter; 3.12 +import de.uapcore.lightpit.filter.NoneFilter; 3.13 +import de.uapcore.lightpit.filter.SpecificFilter; 3.14 +import de.uapcore.lightpit.types.IssueCategory; 3.15 +import de.uapcore.lightpit.types.IssueStatus; 3.16 +import de.uapcore.lightpit.types.VersionStatus; 3.17 import de.uapcore.lightpit.types.WebColor; 3.18 import de.uapcore.lightpit.viewmodel.*; 3.19 import de.uapcore.lightpit.viewmodel.util.IssueSorter; 3.20 @@ -45,7 +52,6 @@ 3.21 import java.io.IOException; 3.22 import java.sql.Date; 3.23 import java.sql.SQLException; 3.24 -import java.util.List; 3.25 import java.util.NoSuchElementException; 3.26 import java.util.Optional; 3.27 import java.util.stream.Collectors; 3.28 @@ -72,25 +78,21 @@ 3.29 } 3.30 } 3.31 3.32 - private void populate(ProjectView viewModel, PathParameters pathParameters, DaoProvider dao) { 3.33 - final var projectDao = dao.getProjectDao(); 3.34 - final var versionDao = dao.getVersionDao(); 3.35 - final var componentDao = dao.getComponentDao(); 3.36 - 3.37 - projectDao.list().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add); 3.38 + private void populate(ProjectView viewModel, PathParameters pathParameters, DataAccessObject dao) { 3.39 + dao.listProjects().stream().map(ProjectInfo::new).forEach(viewModel.getProjectList()::add); 3.40 3.41 if (pathParameters == null) 3.42 return; 3.43 3.44 // Select Project 3.45 - final var project = projectDao.findByNode(pathParameters.get("project")); 3.46 + final var project = dao.findProjectByNode(pathParameters.get("project")); 3.47 if (project == null) 3.48 return; 3.49 3.50 final var info = new ProjectInfo(project); 3.51 - info.setVersions(versionDao.list(project)); 3.52 - info.setComponents(componentDao.list(project)); 3.53 - info.setIssueSummary(projectDao.getIssueSummary(project)); 3.54 + info.setVersions(dao.listVersions(project)); 3.55 + info.setComponents(dao.listComponents(project)); 3.56 + info.setIssueSummary(dao.collectIssueSummary(project)); 3.57 viewModel.setProjectInfo(info); 3.58 3.59 // Select Version 3.60 @@ -101,7 +103,7 @@ 3.61 } else if ("all-versions".equals(versionNode)) { 3.62 viewModel.setVersionFilter(ProjectView.ALL_VERSIONS); 3.63 } else { 3.64 - viewModel.setVersionFilter(versionDao.findByNode(project, versionNode)); 3.65 + viewModel.setVersionFilter(dao.findVersionByNode(project, versionNode)); 3.66 } 3.67 } 3.68 3.69 @@ -113,7 +115,7 @@ 3.70 } else if ("all-components".equals(componentNode)) { 3.71 viewModel.setComponentFilter(ProjectView.ALL_COMPONENTS); 3.72 } else { 3.73 - viewModel.setComponentFilter(componentDao.findByNode(project, componentNode)); 3.74 + viewModel.setComponentFilter(dao.findComponentByNode(project, componentNode)); 3.75 } 3.76 } 3.77 } 3.78 @@ -137,28 +139,25 @@ 3.79 } 3.80 3.81 @RequestMapping(method = HttpMethod.GET) 3.82 - public void index(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws SQLException, ServletException, IOException { 3.83 + public void index(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws ServletException, IOException { 3.84 final var viewModel = new ProjectView(); 3.85 populate(viewModel, null, dao); 3.86 3.87 - final var projectDao = dao.getProjectDao(); 3.88 - final var versionDao = dao.getVersionDao(); 3.89 - 3.90 for (var info : viewModel.getProjectList()) { 3.91 - info.setVersions(versionDao.list(info.getProject())); 3.92 - info.setIssueSummary(projectDao.getIssueSummary(info.getProject())); 3.93 + info.setVersions(dao.listVersions(info.getProject())); 3.94 + info.setIssueSummary(dao.collectIssueSummary(info.getProject())); 3.95 } 3.96 3.97 forwardView(req, resp, viewModel, "projects"); 3.98 } 3.99 3.100 - private void configureProjectEditor(ProjectEditView viewModel, Project project, DaoProvider dao) throws SQLException { 3.101 + private void configureProjectEditor(ProjectEditView viewModel, Project project, DataAccessObject dao) { 3.102 viewModel.setProject(project); 3.103 - viewModel.setUsers(dao.getUserDao().list()); 3.104 + viewModel.setUsers(dao.listUsers()); 3.105 } 3.106 3.107 @RequestMapping(requestPath = "$project/edit", method = HttpMethod.GET) 3.108 - public void edit(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DaoProvider dao) throws IOException, SQLException, ServletException { 3.109 + public void edit(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObject dao) throws IOException, SQLException, ServletException { 3.110 final var viewModel = new ProjectEditView(); 3.111 populate(viewModel, pathParams, dao); 3.112 3.113 @@ -172,7 +171,7 @@ 3.114 } 3.115 3.116 @RequestMapping(requestPath = "create", method = HttpMethod.GET) 3.117 - public void create(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws SQLException, ServletException, IOException { 3.118 + public void create(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws SQLException, ServletException, IOException { 3.119 final var viewModel = new ProjectEditView(); 3.120 populate(viewModel, null, dao); 3.121 configureProjectEditor(viewModel, new Project(-1), dao); 3.122 @@ -180,7 +179,7 @@ 3.123 } 3.124 3.125 @RequestMapping(requestPath = "commit", method = HttpMethod.POST) 3.126 - public void commit(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException { 3.127 + public void commit(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException { 3.128 3.129 try { 3.130 final var project = new Project(getParameter(req, Integer.class, "pid").orElseThrow()); 3.131 @@ -195,12 +194,10 @@ 3.132 ownerId -> ownerId >= 0 ? new User(ownerId) : null 3.133 ).ifPresent(project::setOwner); 3.134 3.135 - final var projectDao = dao.getProjectDao(); 3.136 if (project.getId() > 0) { 3.137 - // TODO: unused return value 3.138 - projectDao.update(project); 3.139 + dao.updateProject(project); 3.140 } else { 3.141 - projectDao.save(project); 3.142 + dao.insertProject(project); 3.143 } 3.144 3.145 setRedirectLocation(req, "./projects/"); 3.146 @@ -215,7 +212,7 @@ 3.147 } 3.148 3.149 @RequestMapping(requestPath = "$project/$component/$version/issues/", method = HttpMethod.GET) 3.150 - public void issues(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DaoProvider dao) throws SQLException, IOException, ServletException { 3.151 + public void issues(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParams, DataAccessObject dao) throws SQLException, IOException, ServletException { 3.152 final var viewModel = new ProjectDetailsView(); 3.153 populate(viewModel, pathParams, dao); 3.154 3.155 @@ -228,36 +225,64 @@ 3.156 final var version = viewModel.getVersionFilter(); 3.157 final var component = viewModel.getComponentFilter(); 3.158 3.159 - final var issueDao = dao.getIssueDao(); 3.160 + // TODO: use new IssueFilter class for the ViewModel 3.161 3.162 - final List<Issue> issues; 3.163 + final var projectFilter = new SpecificFilter<>(project); 3.164 + final IssueFilter filter; 3.165 if (version.equals(ProjectView.NO_VERSION)) { 3.166 if (component.equals(ProjectView.ALL_COMPONENTS)) { 3.167 - issues = issueDao.list(project, (Version) null); 3.168 + filter = new IssueFilter(projectFilter, 3.169 + new NoneFilter<>(), 3.170 + new AllFilter<>() 3.171 + ); 3.172 } else if (component.equals(ProjectView.NO_COMPONENT)) { 3.173 - issues = issueDao.list(project, null, null); 3.174 + filter = new IssueFilter(projectFilter, 3.175 + new NoneFilter<>(), 3.176 + new NoneFilter<>() 3.177 + ); 3.178 } else { 3.179 - issues = issueDao.list(project, component, null); 3.180 + filter = new IssueFilter(projectFilter, 3.181 + new NoneFilter<>(), 3.182 + new SpecificFilter<>(component) 3.183 + ); 3.184 } 3.185 } else if (version.equals(ProjectView.ALL_VERSIONS)) { 3.186 if (component.equals(ProjectView.ALL_COMPONENTS)) { 3.187 - issues = issueDao.list(project); 3.188 + filter = new IssueFilter(projectFilter, 3.189 + new AllFilter<>(), 3.190 + new AllFilter<>() 3.191 + ); 3.192 } else if (component.equals(ProjectView.NO_COMPONENT)) { 3.193 - issues = issueDao.list(project, (Component)null); 3.194 + filter = new IssueFilter(projectFilter, 3.195 + new AllFilter<>(), 3.196 + new NoneFilter<>() 3.197 + ); 3.198 } else { 3.199 - issues = issueDao.list(project, component); 3.200 + filter = new IssueFilter(projectFilter, 3.201 + new AllFilter<>(), 3.202 + new SpecificFilter<>(component) 3.203 + ); 3.204 } 3.205 } else { 3.206 if (component.equals(ProjectView.ALL_COMPONENTS)) { 3.207 - issues = issueDao.list(project, version); 3.208 + filter = new IssueFilter(projectFilter, 3.209 + new SpecificFilter<>(version), 3.210 + new AllFilter<>() 3.211 + ); 3.212 } else if (component.equals(ProjectView.NO_COMPONENT)) { 3.213 - issues = issueDao.list(project, null, version); 3.214 + filter = new IssueFilter(projectFilter, 3.215 + new SpecificFilter<>(version), 3.216 + new NoneFilter<>() 3.217 + ); 3.218 } else { 3.219 - issues = issueDao.list(project, component, version); 3.220 + filter = new IssueFilter(projectFilter, 3.221 + new SpecificFilter<>(version), 3.222 + new SpecificFilter<>(component) 3.223 + ); 3.224 } 3.225 } 3.226 3.227 - for (var issue : issues) issueDao.joinVersionInformation(issue); 3.228 + final var issues = dao.listIssues(filter); 3.229 issues.sort(new IssueSorter( 3.230 new IssueSorter.Criteria(IssueSorter.Field.DONE, true), 3.231 new IssueSorter.Criteria(IssueSorter.Field.ETA, true), 3.232 @@ -273,7 +298,7 @@ 3.233 } 3.234 3.235 @RequestMapping(requestPath = "$project/versions/", method = HttpMethod.GET) 3.236 - public void versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.237 + public void versions(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException { 3.238 final var viewModel = new VersionsView(); 3.239 populate(viewModel, pathParameters, dao); 3.240 3.241 @@ -283,16 +308,20 @@ 3.242 return; 3.243 } 3.244 3.245 - final var issueDao = dao.getIssueDao(); 3.246 - final var issues = issueDao.list(projectInfo.getProject()); 3.247 - for (var issue : issues) issueDao.joinVersionInformation(issue); 3.248 + final var issues = dao.listIssues( 3.249 + new IssueFilter( 3.250 + new SpecificFilter<>(projectInfo.getProject()), 3.251 + new AllFilter<>(), 3.252 + new AllFilter<>() 3.253 + ) 3.254 + ); 3.255 viewModel.update(projectInfo.getVersions(), issues); 3.256 3.257 forwardView(req, resp, viewModel, "versions"); 3.258 } 3.259 3.260 @RequestMapping(requestPath = "$project/versions/$version/edit", method = HttpMethod.GET) 3.261 - public void editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.262 + public void editVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException { 3.263 final var viewModel = new VersionEditView(); 3.264 populate(viewModel, pathParameters, dao); 3.265 3.266 @@ -307,7 +336,7 @@ 3.267 } 3.268 3.269 @RequestMapping(requestPath = "$project/create-version", method = HttpMethod.GET) 3.270 - public void createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.271 + public void createVersion(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException { 3.272 final var viewModel = new VersionEditView(); 3.273 populate(viewModel, pathParameters, dao); 3.274 3.275 @@ -316,22 +345,22 @@ 3.276 return; 3.277 } 3.278 3.279 - viewModel.setVersion(new Version(-1)); 3.280 + viewModel.setVersion(new Version(-1, viewModel.getProjectInfo().getProject().getId())); 3.281 3.282 forwardView(req, resp, viewModel, "version-form"); 3.283 } 3.284 3.285 @RequestMapping(requestPath = "commit-version", method = HttpMethod.POST) 3.286 - public void commitVersion(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException { 3.287 + public void commitVersion(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException { 3.288 3.289 try { 3.290 - final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow()); 3.291 + final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow()); 3.292 if (project == null) { 3.293 // TODO: improve error handling, because not found is not correct for this POST request 3.294 resp.sendError(HttpServletResponse.SC_NOT_FOUND); 3.295 return; 3.296 } 3.297 - final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow()); 3.298 + final var version = new Version(getParameter(req, Integer.class, "id").orElseThrow(), project.getId()); 3.299 version.setName(getParameter(req, String.class, "name").orElseThrow()); 3.300 3.301 final var node = getParameter(req, String.class, "node").orElse(null); 3.302 @@ -340,12 +369,10 @@ 3.303 getParameter(req, Integer.class, "ordinal").ifPresent(version::setOrdinal); 3.304 version.setStatus(VersionStatus.valueOf(getParameter(req, String.class, "status").orElseThrow())); 3.305 3.306 - final var versionDao = dao.getVersionDao(); 3.307 if (version.getId() > 0) { 3.308 - // TODO: use return value 3.309 - versionDao.update(version); 3.310 + dao.updateVersion(version); 3.311 } else { 3.312 - versionDao.save(version, project); 3.313 + dao.insertVersion(version); 3.314 } 3.315 3.316 setRedirectLocation(req, "./projects/" + project.getNode() + "/versions/"); 3.317 @@ -359,7 +386,7 @@ 3.318 } 3.319 3.320 @RequestMapping(requestPath = "$project/components/", method = HttpMethod.GET) 3.321 - public void components(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.322 + public void components(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException { 3.323 final var viewModel = new ComponentsView(); 3.324 populate(viewModel, pathParameters, dao); 3.325 3.326 @@ -369,15 +396,20 @@ 3.327 return; 3.328 } 3.329 3.330 - final var issueDao = dao.getIssueDao(); 3.331 - final var issues = issueDao.list(projectInfo.getProject()); 3.332 + final var issues = dao.listIssues( 3.333 + new IssueFilter( 3.334 + new SpecificFilter<>(projectInfo.getProject()), 3.335 + new AllFilter<>(), 3.336 + new AllFilter<>() 3.337 + ) 3.338 + ); 3.339 viewModel.update(projectInfo.getComponents(), issues); 3.340 3.341 forwardView(req, resp, viewModel, "components"); 3.342 } 3.343 3.344 @RequestMapping(requestPath = "$project/components/$component/edit", method = HttpMethod.GET) 3.345 - public void editComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.346 + public void editComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException { 3.347 final var viewModel = new ComponentEditView(); 3.348 populate(viewModel, pathParameters, dao); 3.349 3.350 @@ -387,13 +419,13 @@ 3.351 } 3.352 3.353 viewModel.setComponent(viewModel.getComponentFilter()); 3.354 - viewModel.setUsers(dao.getUserDao().list()); 3.355 + viewModel.setUsers(dao.listUsers()); 3.356 3.357 forwardView(req, resp, viewModel, "component-form"); 3.358 } 3.359 3.360 @RequestMapping(requestPath = "$project/create-component", method = HttpMethod.GET) 3.361 - public void createComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.362 + public void createComponent(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException { 3.363 final var viewModel = new ComponentEditView(); 3.364 populate(viewModel, pathParameters, dao); 3.365 3.366 @@ -402,23 +434,23 @@ 3.367 return; 3.368 } 3.369 3.370 - viewModel.setComponent(new Component(-1)); 3.371 - viewModel.setUsers(dao.getUserDao().list()); 3.372 + viewModel.setComponent(new Component(-1, viewModel.getProjectInfo().getProject().getId())); 3.373 + viewModel.setUsers(dao.listUsers()); 3.374 3.375 forwardView(req, resp, viewModel, "component-form"); 3.376 } 3.377 3.378 @RequestMapping(requestPath = "commit-component", method = HttpMethod.POST) 3.379 - public void commitComponent(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException { 3.380 + public void commitComponent(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException { 3.381 3.382 try { 3.383 - final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow()); 3.384 + final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow()); 3.385 if (project == null) { 3.386 // TODO: improve error handling, because not found is not correct for this POST request 3.387 resp.sendError(HttpServletResponse.SC_NOT_FOUND); 3.388 return; 3.389 } 3.390 - final var component = new Component(getParameter(req, Integer.class, "id").orElseThrow()); 3.391 + final var component = new Component(getParameter(req, Integer.class, "id").orElseThrow(), project.getId()); 3.392 component.setName(getParameter(req, String.class, "name").orElseThrow()); 3.393 3.394 final var node = getParameter(req, String.class, "node").orElse(null); 3.395 @@ -431,12 +463,10 @@ 3.396 ).ifPresent(component::setLead); 3.397 getParameter(req, String.class, "description").ifPresent(component::setDescription); 3.398 3.399 - final var componentDao = dao.getComponentDao(); 3.400 if (component.getId() > 0) { 3.401 - // TODO: use return value 3.402 - componentDao.update(component); 3.403 + dao.updateComponent(component); 3.404 } else { 3.405 - componentDao.save(component, project); 3.406 + dao.insertComponent(component); 3.407 } 3.408 3.409 setRedirectLocation(req, "./projects/" + project.getNode() + "/components/"); 3.410 @@ -449,17 +479,17 @@ 3.411 } 3.412 } 3.413 3.414 - private void configureIssueEditor(IssueEditView viewModel, Issue issue, DaoProvider dao) throws SQLException { 3.415 + private void configureIssueEditor(IssueEditView viewModel, Issue issue, DataAccessObject dao) { 3.416 final var project = viewModel.getProjectInfo().getProject(); 3.417 issue.setProject(project); // automatically set current project for new issues 3.418 viewModel.setIssue(issue); 3.419 viewModel.configureVersionSelectors(viewModel.getProjectInfo().getVersions()); 3.420 - viewModel.setUsers(dao.getUserDao().list()); 3.421 - viewModel.setComponents(dao.getComponentDao().list(project)); 3.422 + viewModel.setUsers(dao.listUsers()); 3.423 + viewModel.setComponents(dao.listComponents(project)); 3.424 } 3.425 3.426 @RequestMapping(requestPath = "$project/issues/$issue/view", method = HttpMethod.GET) 3.427 - public void viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.428 + public void viewIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, ServletException { 3.429 final var viewModel = new IssueDetailView(); 3.430 populate(viewModel, pathParameters, dao); 3.431 3.432 @@ -469,16 +499,14 @@ 3.433 return; 3.434 } 3.435 3.436 - final var issueDao = dao.getIssueDao(); 3.437 - final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue"))); 3.438 + final var issue = dao.findIssue(parseIntOrZero(pathParameters.get("issue"))); 3.439 if (issue == null) { 3.440 resp.sendError(HttpServletResponse.SC_NOT_FOUND); 3.441 return; 3.442 } 3.443 3.444 - issueDao.joinVersionInformation(issue); 3.445 viewModel.setIssue(issue); 3.446 - viewModel.setComments(issueDao.listComments(issue)); 3.447 + viewModel.setComments(dao.listComments(issue)); 3.448 3.449 viewModel.processMarkdown(); 3.450 3.451 @@ -487,7 +515,7 @@ 3.452 3.453 // TODO: why should the issue editor be child of $project? 3.454 @RequestMapping(requestPath = "$project/issues/$issue/edit", method = HttpMethod.GET) 3.455 - public void editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.456 + public void editIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException { 3.457 final var viewModel = new IssueEditView(); 3.458 populate(viewModel, pathParameters, dao); 3.459 3.460 @@ -497,21 +525,19 @@ 3.461 return; 3.462 } 3.463 3.464 - final var issueDao = dao.getIssueDao(); 3.465 - final var issue = issueDao.find(parseIntOrZero(pathParameters.get("issue"))); 3.466 + final var issue = dao.findIssue(parseIntOrZero(pathParameters.get("issue"))); 3.467 if (issue == null) { 3.468 resp.sendError(HttpServletResponse.SC_NOT_FOUND); 3.469 return; 3.470 } 3.471 3.472 - issueDao.joinVersionInformation(issue); 3.473 configureIssueEditor(viewModel, issue, dao); 3.474 3.475 forwardView(req, resp, viewModel, "issue-form"); 3.476 } 3.477 3.478 @RequestMapping(requestPath = "$project/create-issue", method = HttpMethod.GET) 3.479 - public void createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DaoProvider dao) throws IOException, SQLException, ServletException { 3.480 + public void createIssue(HttpServletRequest req, HttpServletResponse resp, PathParameters pathParameters, DataAccessObject dao) throws IOException, SQLException, ServletException { 3.481 final var viewModel = new IssueEditView(); 3.482 populate(viewModel, pathParameters, dao); 3.483 3.484 @@ -521,7 +547,8 @@ 3.485 return; 3.486 } 3.487 3.488 - final var issue = new Issue(-1); 3.489 + // TODO: fix #38 - automatically select component (and version) 3.490 + final var issue = new Issue(-1, projectInfo.getProject(), null); 3.491 issue.setProject(projectInfo.getProject()); 3.492 configureIssueEditor(viewModel, issue, dao); 3.493 3.494 @@ -529,27 +556,25 @@ 3.495 } 3.496 3.497 @RequestMapping(requestPath = "commit-issue", method = HttpMethod.POST) 3.498 - public void commitIssue(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException { 3.499 + public void commitIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException { 3.500 try { 3.501 - final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow()); 3.502 - final var componentId = getParameter(req, Integer.class, "component"); 3.503 - final Component component; 3.504 - if (componentId.isPresent()) { 3.505 - component = dao.getComponentDao().find(componentId.get()); 3.506 - } else { 3.507 - component = null; 3.508 - } 3.509 - final var project = dao.getProjectDao().find(getParameter(req, Integer.class, "pid").orElseThrow()); 3.510 + final var project = dao.findProject(getParameter(req, Integer.class, "pid").orElseThrow()); 3.511 if (project == null) { 3.512 // TODO: improve error handling, because not found is not correct for this POST request 3.513 resp.sendError(HttpServletResponse.SC_NOT_FOUND); 3.514 return; 3.515 } 3.516 - issue.setProject(project); 3.517 + final var componentId = getParameter(req, Integer.class, "component"); 3.518 + final Component component; 3.519 + if (componentId.isPresent()) { 3.520 + component = dao.findComponent(componentId.get()); 3.521 + } else { 3.522 + component = null; 3.523 + } 3.524 + final var issue = new Issue(getParameter(req, Integer.class, "id").orElseThrow(), project, component); 3.525 getParameter(req, String.class, "category").map(IssueCategory::valueOf).ifPresent(issue::setCategory); 3.526 getParameter(req, String.class, "status").map(IssueStatus::valueOf).ifPresent(issue::setStatus); 3.527 issue.setSubject(getParameter(req, String.class, "subject").orElseThrow()); 3.528 - issue.setComponent(component); 3.529 getParameter(req, Integer.class, "assignee").map(userid -> { 3.530 if (userid >= 0) { 3.531 return new User(userid); 3.532 @@ -566,23 +591,23 @@ 3.533 getParameter(req, Integer[].class, "affected") 3.534 .map(Stream::of) 3.535 .map(stream -> 3.536 - stream.map(Version::new).collect(Collectors.toList()) 3.537 + stream.map(id -> new Version(id, project.getId())) 3.538 + .collect(Collectors.toList()) 3.539 ).ifPresent(issue::setAffectedVersions); 3.540 getParameter(req, Integer[].class, "resolved") 3.541 .map(Stream::of) 3.542 .map(stream -> 3.543 - stream.map(Version::new).collect(Collectors.toList()) 3.544 + stream.map(id -> new Version(id, project.getId())) 3.545 + .collect(Collectors.toList()) 3.546 ).ifPresent(issue::setResolvedVersions); 3.547 3.548 - final var issueDao = dao.getIssueDao(); 3.549 if (issue.getId() > 0) { 3.550 - // TODO: use return value 3.551 - issueDao.update(issue); 3.552 + dao.updateIssue(issue); 3.553 } else { 3.554 - issueDao.save(issue, project); 3.555 + dao.insertIssue(issue); 3.556 } 3.557 3.558 - // TODO: fix redirect location 3.559 + // TODO: implement #110 3.560 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view"); 3.561 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 3.562 3.563 @@ -594,19 +619,19 @@ 3.564 } 3.565 3.566 @RequestMapping(requestPath = "commit-issue-comment", method = HttpMethod.POST) 3.567 - public void commentIssue(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws IOException, ServletException { 3.568 + public void commentIssue(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws IOException, ServletException { 3.569 final var issueIdParam = getParameter(req, Integer.class, "issueid"); 3.570 if (issueIdParam.isEmpty()) { 3.571 resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Detected manipulated form."); 3.572 return; 3.573 } 3.574 - final var issue = dao.getIssueDao().find(issueIdParam.get()); 3.575 + final var issue = dao.findIssue(issueIdParam.get()); 3.576 if (issue == null) { 3.577 resp.sendError(HttpServletResponse.SC_NOT_FOUND); 3.578 return; 3.579 } 3.580 try { 3.581 - final var issueComment = new IssueComment(getParameter(req, Integer.class, "commentid").orElse(-1)); 3.582 + final var issueComment = new IssueComment(getParameter(req, Integer.class, "commentid").orElse(-1), issue.getId()); 3.583 issueComment.setComment(getParameter(req, String.class, "comment").orElse("")); 3.584 3.585 if (issueComment.getComment().isBlank()) { 3.586 @@ -615,12 +640,11 @@ 3.587 3.588 LOG.debug("User {} is commenting on issue #{}", req.getRemoteUser(), issue.getId()); 3.589 if (req.getRemoteUser() != null) { 3.590 - Optional.ofNullable(dao.getUserDao().findByUsername(req.getRemoteUser())).ifPresent(issueComment::setAuthor); 3.591 + Optional.ofNullable(dao.findUserByName(req.getRemoteUser())).ifPresent(issueComment::setAuthor); 3.592 } 3.593 3.594 - dao.getIssueDao().saveComment(issue, issueComment); 3.595 + dao.insertComment(issueComment); 3.596 3.597 - // TODO: fix redirect location 3.598 setRedirectLocation(req, "./projects/" + issue.getProject().getNode()+"/issues/"+issue.getId()+"/view"); 3.599 setContentPage(req, Constants.JSP_COMMIT_SUCCESSFUL); 3.600
4.1 --- a/src/main/java/de/uapcore/lightpit/modules/UsersModule.java Sun Dec 20 11:06:25 2020 +0100 4.2 +++ b/src/main/java/de/uapcore/lightpit/modules/UsersModule.java Mon Dec 21 18:29:34 2020 +0100 4.3 @@ -32,7 +32,7 @@ 4.4 import de.uapcore.lightpit.Constants; 4.5 import de.uapcore.lightpit.HttpMethod; 4.6 import de.uapcore.lightpit.RequestMapping; 4.7 -import de.uapcore.lightpit.dao.DaoProvider; 4.8 +import de.uapcore.lightpit.dao.DataAccessObject; 4.9 import de.uapcore.lightpit.entities.User; 4.10 import de.uapcore.lightpit.viewmodel.UsersEditView; 4.11 import de.uapcore.lightpit.viewmodel.UsersView; 4.12 @@ -61,11 +61,9 @@ 4.13 } 4.14 4.15 @RequestMapping(method = HttpMethod.GET) 4.16 - public void index(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws SQLException, ServletException, IOException { 4.17 - final var userDao = dao.getUserDao(); 4.18 - 4.19 + public void index(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws SQLException, ServletException, IOException { 4.20 final var viewModel = new UsersView(); 4.21 - viewModel.setUsers(userDao.list()); 4.22 + viewModel.setUsers(dao.listUsers()); 4.23 setViewModel(req, viewModel); 4.24 setContentPage(req, "users"); 4.25 4.26 @@ -73,11 +71,10 @@ 4.27 } 4.28 4.29 @RequestMapping(requestPath = "edit", method = HttpMethod.GET) 4.30 - public void edit(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws SQLException, ServletException, IOException { 4.31 + public void edit(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws SQLException, ServletException, IOException { 4.32 4.33 final var viewModel = new UsersEditView(); 4.34 - viewModel.setUser(findByParameter(req, Integer.class, "id", 4.35 - dao.getUserDao()::find).orElse(new User(-1))); 4.36 + viewModel.setUser(findByParameter(req, Integer.class, "id", dao::findUser).orElse(new User(-1))); 4.37 4.38 setViewModel(req, viewModel); 4.39 setContentPage(req, "user-form"); 4.40 @@ -86,7 +83,7 @@ 4.41 } 4.42 4.43 @RequestMapping(requestPath = "commit", method = HttpMethod.POST) 4.44 - public void commit(HttpServletRequest req, HttpServletResponse resp, DaoProvider dao) throws ServletException, IOException { 4.45 + public void commit(HttpServletRequest req, HttpServletResponse resp, DataAccessObject dao) throws ServletException, IOException { 4.46 4.47 User user = new User(-1); 4.48 try { 4.49 @@ -96,12 +93,10 @@ 4.50 getParameter(req, String.class, "lastname").ifPresent(user::setLastname); 4.51 getParameter(req, String.class, "mail").ifPresent(user::setMail); 4.52 4.53 - final var userDao = dao.getUserDao(); 4.54 if (user.getId() > 0) { 4.55 - // TODO: unused return value 4.56 - userDao.update(user); 4.57 + dao.updateUser(user); 4.58 } else { 4.59 - userDao.save(user); 4.60 + dao.insertUser(user); 4.61 } 4.62 4.63 setRedirectLocation(req, "./teams/");
5.1 --- a/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java Sun Dec 20 11:06:25 2020 +0100 5.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/IssueEditView.java Mon Dec 21 18:29:34 2020 +0100 5.3 @@ -1,6 +1,12 @@ 5.4 package de.uapcore.lightpit.viewmodel; 5.5 5.6 -import de.uapcore.lightpit.entities.*; 5.7 +import de.uapcore.lightpit.entities.Component; 5.8 +import de.uapcore.lightpit.entities.Project; 5.9 +import de.uapcore.lightpit.entities.User; 5.10 +import de.uapcore.lightpit.entities.Version; 5.11 +import de.uapcore.lightpit.types.IssueCategory; 5.12 +import de.uapcore.lightpit.types.IssueStatus; 5.13 +import de.uapcore.lightpit.types.VersionStatus; 5.14 5.15 import java.util.*; 5.16
6.1 --- a/src/main/java/de/uapcore/lightpit/viewmodel/ProjectView.java Sun Dec 20 11:06:25 2020 +0100 6.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/ProjectView.java Mon Dec 21 18:29:34 2020 +0100 6.3 @@ -12,10 +12,12 @@ 6.4 public static final int SELECTED_PAGE_VERSIONS = 1; 6.5 public static final int SELECTED_PAGE_COMPONENTS = 2; 6.6 6.7 - public static final Version ALL_VERSIONS = new Version(0); 6.8 - public static final Version NO_VERSION = new Version(-1); 6.9 - public static final Component ALL_COMPONENTS = new Component(0); 6.10 - public static final Component NO_COMPONENT = new Component(-1); 6.11 + // TODO: use new Filter class 6.12 + 6.13 + public static final Version ALL_VERSIONS = new Version(0,0); 6.14 + public static final Version NO_VERSION = new Version(-1,0); 6.15 + public static final Component ALL_COMPONENTS = new Component(0,0); 6.16 + public static final Component NO_COMPONENT = new Component(-1,0); 6.17 6.18 static { 6.19 ALL_VERSIONS.setNode("all-versions");
7.1 --- a/src/main/java/de/uapcore/lightpit/viewmodel/VersionEditView.java Sun Dec 20 11:06:25 2020 +0100 7.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/VersionEditView.java Mon Dec 21 18:29:34 2020 +0100 7.3 @@ -1,7 +1,7 @@ 7.4 package de.uapcore.lightpit.viewmodel; 7.5 7.6 import de.uapcore.lightpit.entities.Version; 7.7 -import de.uapcore.lightpit.entities.VersionStatus; 7.8 +import de.uapcore.lightpit.types.VersionStatus; 7.9 7.10 public class VersionEditView extends ProjectView { 7.11 private Version version;
8.1 --- a/src/main/java/de/uapcore/lightpit/viewmodel/util/IssueSorter.java Sun Dec 20 11:06:25 2020 +0100 8.2 +++ b/src/main/java/de/uapcore/lightpit/viewmodel/util/IssueSorter.java Mon Dec 21 18:29:34 2020 +0100 8.3 @@ -1,7 +1,7 @@ 8.4 package de.uapcore.lightpit.viewmodel.util; 8.5 8.6 import de.uapcore.lightpit.entities.Issue; 8.7 -import de.uapcore.lightpit.entities.IssueStatusPhase; 8.8 +import de.uapcore.lightpit.types.IssueStatusPhase; 8.9 8.10 import java.util.Arrays; 8.11 import java.util.Comparator;
9.1 --- a/src/main/kotlin/de/uapcore/lightpit/DataSourceProvider.kt Sun Dec 20 11:06:25 2020 +0100 9.2 +++ b/src/main/kotlin/de/uapcore/lightpit/DataSourceProvider.kt Mon Dec 21 18:29:34 2020 +0100 9.3 @@ -128,7 +128,7 @@ 9.4 val sc = sce!!.servletContext 9.5 9.6 val dbSchema = sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA) ?: DB_DEFAULT_SCHEMA 9.7 - sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT)?.let {dbDialect -> 9.8 + sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT)?.let { dbDialect -> 9.9 try { 9.10 dialect = Dialect.valueOf(dbDialect) 9.11 } catch (ex: IllegalArgumentException) {
10.1 --- a/src/main/kotlin/de/uapcore/lightpit/Logging.kt Sun Dec 20 11:06:25 2020 +0100 10.2 +++ b/src/main/kotlin/de/uapcore/lightpit/Logging.kt Mon Dec 21 18:29:34 2020 +0100 10.3 @@ -29,4 +29,5 @@ 10.4 import org.slf4j.LoggerFactory 10.5 10.6 interface LoggingTrait 10.7 -inline fun <reified T : LoggingTrait> T.logger(): Logger = LoggerFactory.getLogger(T::class.java); 10.8 + 10.9 +inline fun <reified T : LoggingTrait> T.logger(): Logger = LoggerFactory.getLogger(T::class.java)
11.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractChildEntityDao.kt Sun Dec 20 11:06:25 2020 +0100 11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 11.3 @@ -1,64 +0,0 @@ 11.4 -/* 11.5 - * Copyright 2020 Mike Becker. All rights reserved. 11.6 - * 11.7 - * Redistribution and use in source and binary forms, with or without 11.8 - * modification, are permitted provided that the following conditions are met: 11.9 - * 11.10 - * 1. Redistributions of source code must retain the above copyright 11.11 - * notice, this list of conditions and the following disclaimer. 11.12 - * 11.13 - * 2. Redistributions in binary form must reproduce the above copyright 11.14 - * notice, this list of conditions and the following disclaimer in the 11.15 - * documentation and/or other materials provided with the distribution. 11.16 - * 11.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 11.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 11.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 11.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 11.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 11.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 11.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 11.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 11.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11.27 - * 11.28 - */ 11.29 - 11.30 -package de.uapcore.lightpit.dao 11.31 - 11.32 - 11.33 -abstract class AbstractChildEntityDao<T, P> : AbstractDao<T>() { 11.34 - 11.35 - /** 11.36 - * Lists all entities being a child of the specified parent. 11.37 - * @param parent the parent 11.38 - * @return the list of child instances 11.39 - */ 11.40 - abstract fun list(parent: P): List<T> 11.41 - 11.42 - /** 11.43 - * Finds an entity by its integer ID. 11.44 - * It is not guaranteed that referenced entities are automatically joined. 11.45 - * 11.46 - * @param id the id 11.47 - * @return the entity or null if there is no such entity 11.48 - */ 11.49 - abstract fun find(id: Int): T? 11.50 - 11.51 - /** 11.52 - * Inserts an instance into database. 11.53 - * It is not guaranteed that generated fields will be updated in the instance. 11.54 - * 11.55 - * @param instance the instance to insert 11.56 - * @param parent a reference to the parent 11.57 - */ 11.58 - abstract fun save(instance: T, parent: P) 11.59 - 11.60 - /** 11.61 - * Updates an instance in the database. 11.62 - * 11.63 - * @param instance the instance to update 11.64 - * @return true if an instance has been updated, false if the instance is not present in database 11.65 - */ 11.66 - abstract fun update(instance: T): Boolean 11.67 -}
12.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractComponentDao.kt Sun Dec 20 11:06:25 2020 +0100 12.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 12.3 @@ -1,34 +0,0 @@ 12.4 -/* 12.5 - * Copyright 2020 Mike Becker. All rights reserved. 12.6 - * 12.7 - * Redistribution and use in source and binary forms, with or without 12.8 - * modification, are permitted provided that the following conditions are met: 12.9 - * 12.10 - * 1. Redistributions of source code must retain the above copyright 12.11 - * notice, this list of conditions and the following disclaimer. 12.12 - * 12.13 - * 2. Redistributions in binary form must reproduce the above copyright 12.14 - * notice, this list of conditions and the following disclaimer in the 12.15 - * documentation and/or other materials provided with the distribution. 12.16 - * 12.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 12.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 12.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 12.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 12.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 12.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 12.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 12.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 12.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12.27 - * 12.28 - */ 12.29 - 12.30 -package de.uapcore.lightpit.dao 12.31 - 12.32 -import de.uapcore.lightpit.entities.Component 12.33 -import de.uapcore.lightpit.entities.Project 12.34 - 12.35 -abstract class AbstractComponentDao : AbstractChildEntityDao<Component, Project>() { 12.36 - abstract fun findByNode(parent: Project, node: String): Component? 12.37 -} 12.38 \ No newline at end of file
13.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractDao.kt Sun Dec 20 11:06:25 2020 +0100 13.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 13.3 @@ -1,65 +0,0 @@ 13.4 -/* 13.5 - * Copyright 2020 Mike Becker. All rights reserved. 13.6 - * 13.7 - * Redistribution and use in source and binary forms, with or without 13.8 - * modification, are permitted provided that the following conditions are met: 13.9 - * 13.10 - * 1. Redistributions of source code must retain the above copyright 13.11 - * notice, this list of conditions and the following disclaimer. 13.12 - * 13.13 - * 2. Redistributions in binary form must reproduce the above copyright 13.14 - * notice, this list of conditions and the following disclaimer in the 13.15 - * documentation and/or other materials provided with the distribution. 13.16 - * 13.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 13.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 13.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 13.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 13.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 13.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 13.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 13.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 13.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 13.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13.27 - * 13.28 - */ 13.29 - 13.30 -package de.uapcore.lightpit.dao 13.31 - 13.32 -import java.sql.PreparedStatement 13.33 -import java.sql.ResultSet 13.34 -import java.sql.Types 13.35 - 13.36 -abstract class AbstractDao<T> { 13.37 - 13.38 - abstract fun mapResult(rs: ResultSet): T 13.39 - 13.40 - protected fun list(stmt: PreparedStatement): List<T> { 13.41 - return sequence { 13.42 - stmt.executeQuery().use { result -> 13.43 - while (result.next()) yield(mapResult(result)) 13.44 - } 13.45 - }.toList() 13.46 - } 13.47 - 13.48 - protected fun find(stmt: PreparedStatement): T? { 13.49 - stmt.executeQuery().use { result -> 13.50 - return if (result.next()) { 13.51 - mapResult(result) 13.52 - } else { 13.53 - null 13.54 - } 13.55 - } 13.56 - } 13.57 - 13.58 - // TODO: create PreparedStatement abstraction that provides some features 13.59 - 13.60 - // TODO: remove the following legacy code helper function 13.61 - protected fun <T> setForeignKeyOrNull(stmt: PreparedStatement, index: Int, instance: T?, keyGetter: (obj: T) -> Int) { 13.62 - if (instance == null) { 13.63 - stmt.setNull(index, Types.INTEGER) 13.64 - } else { 13.65 - stmt.setInt(index, keyGetter(instance)) 13.66 - } 13.67 - } 13.68 -} 13.69 \ No newline at end of file
14.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractEntityDao.kt Sun Dec 20 11:06:25 2020 +0100 14.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 14.3 @@ -1,61 +0,0 @@ 14.4 -/* 14.5 - * Copyright 2020 Mike Becker. All rights reserved. 14.6 - * 14.7 - * Redistribution and use in source and binary forms, with or without 14.8 - * modification, are permitted provided that the following conditions are met: 14.9 - * 14.10 - * 1. Redistributions of source code must retain the above copyright 14.11 - * notice, this list of conditions and the following disclaimer. 14.12 - * 14.13 - * 2. Redistributions in binary form must reproduce the above copyright 14.14 - * notice, this list of conditions and the following disclaimer in the 14.15 - * documentation and/or other materials provided with the distribution. 14.16 - * 14.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 14.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 14.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 14.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 14.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 14.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 14.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 14.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 14.27 - * 14.28 - */ 14.29 - 14.30 -package de.uapcore.lightpit.dao 14.31 - 14.32 -abstract class AbstractEntityDao<T> : AbstractDao<T>() { 14.33 - 14.34 - /** 14.35 - * Lists all entities. 14.36 - * @return a list of all entities 14.37 - */ 14.38 - abstract fun list(): List<T> 14.39 - 14.40 - /** 14.41 - * Finds an entity by its integer ID. 14.42 - * It is not guaranteed that referenced entities are automatically joined. 14.43 - * 14.44 - * @param id the id 14.45 - * @return the entity or null if there is no such entity 14.46 - */ 14.47 - abstract fun find(id: Int): T? 14.48 - 14.49 - /** 14.50 - * Inserts an instance into database. 14.51 - * It is not guaranteed that generated fields will be updated in the instance. 14.52 - * 14.53 - * @param instance the instance to insert 14.54 - */ 14.55 - abstract fun save(instance: T) 14.56 - 14.57 - /** 14.58 - * Updates an instance in the database. 14.59 - * 14.60 - * @param instance the instance to update 14.61 - * @return true if an instance has been updated, false if the instance is not present in database 14.62 - */ 14.63 - abstract fun update(instance: T): Boolean 14.64 -} 14.65 \ No newline at end of file
15.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractIssueDao.kt Sun Dec 20 11:06:25 2020 +0100 15.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 15.3 @@ -1,100 +0,0 @@ 15.4 -/* 15.5 - * Copyright 2020 Mike Becker. All rights reserved. 15.6 - * 15.7 - * Redistribution and use in source and binary forms, with or without 15.8 - * modification, are permitted provided that the following conditions are met: 15.9 - * 15.10 - * 1. Redistributions of source code must retain the above copyright 15.11 - * notice, this list of conditions and the following disclaimer. 15.12 - * 15.13 - * 2. Redistributions in binary form must reproduce the above copyright 15.14 - * notice, this list of conditions and the following disclaimer in the 15.15 - * documentation and/or other materials provided with the distribution. 15.16 - * 15.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 15.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 15.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 15.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 15.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 15.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 15.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15.27 - * 15.28 - */ 15.29 - 15.30 -package de.uapcore.lightpit.dao 15.31 - 15.32 -import de.uapcore.lightpit.entities.* 15.33 -import java.sql.SQLException 15.34 - 15.35 -abstract class AbstractIssueDao : AbstractChildEntityDao<Issue, Project>() { 15.36 - 15.37 - /** 15.38 - * Lists all issues that are related to the specified component and version. 15.39 - * If component or version is null, search for issues that are not assigned to any 15.40 - * component or version, respectively. 15.41 - * 15.42 - * @param project the project 15.43 - * @param component the component 15.44 - * @param version the version 15.45 - * @return a list of issues 15.46 - */ 15.47 - abstract fun list(project: Project, component: Component?, version: Version?): List<Issue> 15.48 - 15.49 - /** 15.50 - * Lists all issues that are related to the specified version. 15.51 - * If the version is null, lists issues that are not assigned to any version. 15.52 - * 15.53 - * @param project the project 15.54 - * @param version the version or null 15.55 - * @return a list of issues 15.56 - */ 15.57 - abstract fun list(project: Project, version: Version?): List<Issue> 15.58 - 15.59 - /** 15.60 - * Lists all issues that are related to the specified component. 15.61 - * If the component is null, lists issues that are not assigned to a component. 15.62 - * 15.63 - * @param project the project 15.64 - * @param component the component or null 15.65 - * @return a list of issues 15.66 - */ 15.67 - abstract fun list(project: Project, component: Component?): List<Issue> 15.68 - 15.69 - /** 15.70 - * Lists all comments for a specific issue in chronological order. 15.71 - * 15.72 - * @param issue the issue 15.73 - * @return the list of comments 15.74 - */ 15.75 - abstract fun listComments(issue: Issue): List<IssueComment> 15.76 - 15.77 - /** 15.78 - * Stores the specified comment in database. 15.79 - * This is an update-or-insert operation. 15.80 - * The "updated" date of the corresponding issue is also updated. 15.81 - * 15.82 - * @param issue the issue to save the comment for 15.83 - * @param comment the comment to save 15.84 - */ 15.85 - abstract fun saveComment(issue: Issue, comment: IssueComment) 15.86 - 15.87 - /** 15.88 - * Saves an instances to the database. 15.89 - * Implementations of this DAO must guarantee that the generated ID is stored in the instance. 15.90 - * 15.91 - * @param instance the instance to insert 15.92 - * @param parent the parent project 15.93 - * @throws SQLException on any kind of SQL error 15.94 - */ 15.95 - abstract override fun save(instance: Issue, parent: Project) 15.96 - 15.97 - /** 15.98 - * Retrieves the affected, scheduled and resolved versions for the specified issue. 15.99 - * 15.100 - * @param issue the issue to join the information for 15.101 - */ 15.102 - abstract fun joinVersionInformation(issue: Issue) 15.103 -} 15.104 \ No newline at end of file
16.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractProjectDao.kt Sun Dec 20 11:06:25 2020 +0100 16.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 16.3 @@ -1,37 +0,0 @@ 16.4 -/* 16.5 - * Copyright 2020 Mike Becker. All rights reserved. 16.6 - * 16.7 - * Redistribution and use in source and binary forms, with or without 16.8 - * modification, are permitted provided that the following conditions are met: 16.9 - * 16.10 - * 1. Redistributions of source code must retain the above copyright 16.11 - * notice, this list of conditions and the following disclaimer. 16.12 - * 16.13 - * 2. Redistributions in binary form must reproduce the above copyright 16.14 - * notice, this list of conditions and the following disclaimer in the 16.15 - * documentation and/or other materials provided with the distribution. 16.16 - * 16.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 16.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 16.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 16.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 16.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 16.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 16.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16.27 - * 16.28 - */ 16.29 - 16.30 -package de.uapcore.lightpit.dao 16.31 - 16.32 -import de.uapcore.lightpit.entities.IssueSummary 16.33 -import de.uapcore.lightpit.entities.Project 16.34 - 16.35 -abstract class AbstractProjectDao : AbstractEntityDao<Project>() { 16.36 - 16.37 - abstract fun getIssueSummary(project: Project): IssueSummary 16.38 - 16.39 - abstract fun findByNode(node: String): Project? 16.40 -} 16.41 \ No newline at end of file
17.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractUserDao.kt Sun Dec 20 11:06:25 2020 +0100 17.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 17.3 @@ -1,33 +0,0 @@ 17.4 -/* 17.5 - * Copyright 2020 Mike Becker. All rights reserved. 17.6 - * 17.7 - * Redistribution and use in source and binary forms, with or without 17.8 - * modification, are permitted provided that the following conditions are met: 17.9 - * 17.10 - * 1. Redistributions of source code must retain the above copyright 17.11 - * notice, this list of conditions and the following disclaimer. 17.12 - * 17.13 - * 2. Redistributions in binary form must reproduce the above copyright 17.14 - * notice, this list of conditions and the following disclaimer in the 17.15 - * documentation and/or other materials provided with the distribution. 17.16 - * 17.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 17.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 17.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 17.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 17.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17.27 - * 17.28 - */ 17.29 - 17.30 -package de.uapcore.lightpit.dao 17.31 - 17.32 -import de.uapcore.lightpit.entities.User 17.33 - 17.34 -abstract class AbstractUserDao : AbstractEntityDao<User>() { 17.35 - abstract fun findByUsername(username: String): User? 17.36 -} 17.37 \ No newline at end of file
18.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/AbstractVersionDao.kt Sun Dec 20 11:06:25 2020 +0100 18.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 18.3 @@ -1,34 +0,0 @@ 18.4 -/* 18.5 - * Copyright 2020 Mike Becker. All rights reserved. 18.6 - * 18.7 - * Redistribution and use in source and binary forms, with or without 18.8 - * modification, are permitted provided that the following conditions are met: 18.9 - * 18.10 - * 1. Redistributions of source code must retain the above copyright 18.11 - * notice, this list of conditions and the following disclaimer. 18.12 - * 18.13 - * 2. Redistributions in binary form must reproduce the above copyright 18.14 - * notice, this list of conditions and the following disclaimer in the 18.15 - * documentation and/or other materials provided with the distribution. 18.16 - * 18.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 18.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 18.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 18.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18.27 - * 18.28 - */ 18.29 - 18.30 -package de.uapcore.lightpit.dao 18.31 - 18.32 -import de.uapcore.lightpit.entities.Project 18.33 -import de.uapcore.lightpit.entities.Version 18.34 - 18.35 -abstract class AbstractVersionDao : AbstractChildEntityDao<Version, Project>() { 18.36 - abstract fun findByNode(parent: Project, node: String): Version? 18.37 -} 18.38 \ No newline at end of file
19.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/DaoProvider.kt Sun Dec 20 11:06:25 2020 +0100 19.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 19.3 @@ -1,35 +0,0 @@ 19.4 -/* 19.5 - * Copyright 2020 Mike Becker. All rights reserved. 19.6 - * 19.7 - * Redistribution and use in source and binary forms, with or without 19.8 - * modification, are permitted provided that the following conditions are met: 19.9 - * 19.10 - * 1. Redistributions of source code must retain the above copyright 19.11 - * notice, this list of conditions and the following disclaimer. 19.12 - * 19.13 - * 2. Redistributions in binary form must reproduce the above copyright 19.14 - * notice, this list of conditions and the following disclaimer in the 19.15 - * documentation and/or other materials provided with the distribution. 19.16 - * 19.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 19.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 19.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 19.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19.27 - * 19.28 - */ 19.29 - 19.30 -package de.uapcore.lightpit.dao 19.31 - 19.32 -interface DaoProvider { 19.33 - val userDao: AbstractUserDao 19.34 - val projectDao: AbstractProjectDao 19.35 - val componentDao: AbstractComponentDao 19.36 - val versionDao: AbstractVersionDao 19.37 - val issueDao: AbstractIssueDao 19.38 -} 19.39 \ No newline at end of file
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/src/main/kotlin/de/uapcore/lightpit/dao/DataAccessObject.kt Mon Dec 21 18:29:34 2020 +0100 20.3 @@ -0,0 +1,65 @@ 20.4 +/* 20.5 + * Copyright 2020 Mike Becker. All rights reserved. 20.6 + * 20.7 + * Redistribution and use in source and binary forms, with or without 20.8 + * modification, are permitted provided that the following conditions are met: 20.9 + * 20.10 + * 1. Redistributions of source code must retain the above copyright 20.11 + * notice, this list of conditions and the following disclaimer. 20.12 + * 20.13 + * 2. Redistributions in binary form must reproduce the above copyright 20.14 + * notice, this list of conditions and the following disclaimer in the 20.15 + * documentation and/or other materials provided with the distribution. 20.16 + * 20.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 20.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 20.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 20.27 + */ 20.28 + 20.29 +package de.uapcore.lightpit.dao 20.30 + 20.31 +import de.uapcore.lightpit.entities.* 20.32 +import de.uapcore.lightpit.filter.IssueFilter 20.33 + 20.34 +interface DataAccessObject { 20.35 + fun listUsers(): List<User> 20.36 + fun findUser(id: Int): User? 20.37 + fun findUserByName(username: String): User? 20.38 + fun insertUser(user: User) 20.39 + fun updateUser(user: User) 20.40 + 20.41 + fun listVersions(project: Project): List<Version> 20.42 + fun findVersion(id: Int): Version? 20.43 + fun findVersionByNode(project: Project, node: String): Version? 20.44 + fun insertVersion(version: Version) 20.45 + fun updateVersion(version: Version) 20.46 + 20.47 + fun listComponents(project: Project): List<Component> 20.48 + fun findComponent(id: Int): Component? 20.49 + fun findComponentByNode(project: Project, node: String): Component? 20.50 + fun insertComponent(component: Component) 20.51 + fun updateComponent(component: Component) 20.52 + 20.53 + fun listProjects(): List<Project> 20.54 + fun findProject(id: Int): Project? 20.55 + fun findProjectByNode(node: String): Project? 20.56 + fun insertProject(project: Project) 20.57 + fun updateProject(project: Project) 20.58 + 20.59 + fun collectIssueSummary(project: Project): IssueSummary 20.60 + 20.61 + fun listIssues(filter: IssueFilter): List<Issue> 20.62 + fun findIssue(id: Int): Issue? 20.63 + fun insertIssue(issue: Issue) 20.64 + fun updateIssue(issue: Issue) 20.65 + 20.66 + fun listComments(issue: Issue): List<IssueComment> 20.67 + fun insertComment(issueComment: IssueComment) 20.68 +} 20.69 \ No newline at end of file
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/src/main/kotlin/de/uapcore/lightpit/dao/Extensions.kt Mon Dec 21 18:29:34 2020 +0100 21.3 @@ -0,0 +1,64 @@ 21.4 +/* 21.5 + * Copyright 2020 Mike Becker. All rights reserved. 21.6 + * 21.7 + * Redistribution and use in source and binary forms, with or without 21.8 + * modification, are permitted provided that the following conditions are met: 21.9 + * 21.10 + * 1. Redistributions of source code must retain the above copyright 21.11 + * notice, this list of conditions and the following disclaimer. 21.12 + * 21.13 + * 2. Redistributions in binary form must reproduce the above copyright 21.14 + * notice, this list of conditions and the following disclaimer in the 21.15 + * documentation and/or other materials provided with the distribution. 21.16 + * 21.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 21.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21.27 + */ 21.28 + 21.29 +package de.uapcore.lightpit.dao 21.30 + 21.31 +import java.sql.Date 21.32 +import java.sql.PreparedStatement 21.33 +import java.sql.ResultSet 21.34 +import java.sql.Types 21.35 + 21.36 +fun PreparedStatement.setStringSafe(idx: Int, str: String) { 21.37 + setString(idx, str) 21.38 +} 21.39 + 21.40 +fun PreparedStatement.setStringOrNull(idx: Int, str: String?) { 21.41 + when (str) { 21.42 + null -> setNull(idx, Types.VARCHAR) 21.43 + else -> setString(idx, str) 21.44 + } 21.45 +} 21.46 + 21.47 +fun PreparedStatement.setIntOrNull(idx: Int, value: Int?) { 21.48 + when (value) { 21.49 + null -> setNull(idx, Types.INTEGER) 21.50 + else -> setInt(idx, value) 21.51 + } 21.52 +} 21.53 + 21.54 +fun PreparedStatement.setDateOrNull(idx: Int, value: Date?) { 21.55 + when (value) { 21.56 + null -> setNull(idx, Types.DATE) 21.57 + else -> setDate(idx, value) 21.58 + } 21.59 +} 21.60 + 21.61 +fun <T : Enum<T>> PreparedStatement.setEnum(idx: Int, e: Enum<T>) { 21.62 + setString(idx, e.name) 21.63 +} 21.64 + 21.65 +inline fun <reified T : Enum<T>> ResultSet.getEnum(col: String): T { 21.66 + return enumValueOf(getString(col)) 21.67 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/src/main/kotlin/de/uapcore/lightpit/dao/PostgresDataAccessObject.kt Mon Dec 21 18:29:34 2020 +0100 22.3 @@ -0,0 +1,739 @@ 22.4 +/* 22.5 + * Copyright 2020 Mike Becker. All rights reserved. 22.6 + * 22.7 + * Redistribution and use in source and binary forms, with or without 22.8 + * modification, are permitted provided that the following conditions are met: 22.9 + * 22.10 + * 1. Redistributions of source code must retain the above copyright 22.11 + * notice, this list of conditions and the following disclaimer. 22.12 + * 22.13 + * 2. Redistributions in binary form must reproduce the above copyright 22.14 + * notice, this list of conditions and the following disclaimer in the 22.15 + * documentation and/or other materials provided with the distribution. 22.16 + * 22.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22.27 + */ 22.28 + 22.29 +package de.uapcore.lightpit.dao 22.30 + 22.31 +import de.uapcore.lightpit.entities.* 22.32 +import de.uapcore.lightpit.filter.* 22.33 +import de.uapcore.lightpit.types.WebColor 22.34 +import java.sql.Connection 22.35 +import java.sql.PreparedStatement 22.36 +import java.sql.ResultSet 22.37 + 22.38 +class PostgresDataAccessObject(private val connection: Connection) : DataAccessObject { 22.39 + 22.40 + //<editor-fold desc="User"> 22.41 + private fun selectUserInfo( 22.42 + rs: ResultSet, 22.43 + idColumn: String = "userid", 22.44 + usernameColumn: String = "username", 22.45 + givennameColumn: String = "givenname", 22.46 + lastnameColumn: String = "lastname", 22.47 + mailColumn: String = "mail" 22.48 + ): User? { 22.49 + val idval = rs.getInt(idColumn) 22.50 + return if (rs.wasNull()) null else { 22.51 + User(idval).apply { 22.52 + username = rs.getString(usernameColumn) 22.53 + givenname = rs.getString(givennameColumn) 22.54 + lastname = rs.getString(lastnameColumn) 22.55 + mail = rs.getString(mailColumn) 22.56 + } 22.57 + } 22.58 + } 22.59 + 22.60 + private fun selectUsers(stmt: PreparedStatement) = sequence { 22.61 + stmt.executeQuery().use { rs -> 22.62 + while (rs.next()) selectUserInfo(rs)?.let { yield(it) } 22.63 + } 22.64 + } 22.65 + 22.66 + //language=SQL 22.67 + private val userQuery = "select userid, username, lastname, givenname, mail from lpit_user" 22.68 + 22.69 + private val stmtUsers by lazy { 22.70 + connection.prepareStatement( 22.71 + """${userQuery} 22.72 + where userid > 0 22.73 + order by username 22.74 + """ 22.75 + ) 22.76 + } 22.77 + private val stmtUserByID by lazy { 22.78 + connection.prepareStatement( 22.79 + """${userQuery} 22.80 + where userid = ? 22.81 + """ 22.82 + ) 22.83 + } 22.84 + private val stmtUserByName by lazy { 22.85 + connection.prepareStatement( 22.86 + """${userQuery} 22.87 + where lower(username) = lower(?) 22.88 + """ 22.89 + ) 22.90 + } 22.91 + private val stmtInsertUser by lazy { 22.92 + connection.prepareStatement( 22.93 + "insert into lpit_user (username, lastname, givenname, mail) values (?, ?, ?, ?)" 22.94 + ) 22.95 + } 22.96 + private val stmtUpdateUser by lazy { 22.97 + connection.prepareStatement( 22.98 + "update lpit_user set lastname = ?, givenname = ?, mail = ? where userid = ?" 22.99 + ) 22.100 + } 22.101 + 22.102 + override fun listUsers() = selectUsers(stmtUsers).toList() 22.103 + override fun findUser(id: Int): User? { 22.104 + stmtUserByID.setInt(1, id) 22.105 + return selectUsers(stmtUserByID).firstOrNull() 22.106 + } 22.107 + 22.108 + override fun findUserByName(username: String): User? { 22.109 + stmtUserByName.setString(1, username) 22.110 + return selectUsers(stmtUserByName).firstOrNull() 22.111 + } 22.112 + 22.113 + override fun insertUser(user: User) { 22.114 + with(user) { 22.115 + stmtInsertUser.setStringSafe(1, username) 22.116 + stmtInsertUser.setStringOrNull(2, lastname) 22.117 + stmtInsertUser.setStringOrNull(3, givenname) 22.118 + stmtInsertUser.setStringOrNull(4, mail) 22.119 + } 22.120 + stmtInsertUser.execute() 22.121 + } 22.122 + 22.123 + override fun updateUser(user: User) { 22.124 + with(user) { 22.125 + stmtUpdateUser.setStringOrNull(1, lastname) 22.126 + stmtUpdateUser.setStringOrNull(2, givenname) 22.127 + stmtUpdateUser.setStringOrNull(3, mail) 22.128 + stmtUpdateUser.setInt(4, id) 22.129 + } 22.130 + stmtUpdateUser.execute() 22.131 + } 22.132 + //</editor-fold> 22.133 + 22.134 + //<editor-fold desc="Version"> 22.135 + private fun selectVersions(stmt: PreparedStatement) = sequence { 22.136 + stmt.executeQuery().use { rs -> 22.137 + while (rs.next()) { 22.138 + yield(Version(rs.getInt("versionid"), rs.getInt("project")).apply { 22.139 + name = rs.getString("name") 22.140 + node = rs.getString("node") 22.141 + ordinal = rs.getInt("ordinal") 22.142 + status = rs.getEnum("status") 22.143 + }) 22.144 + } 22.145 + } 22.146 + } 22.147 + 22.148 + private fun setVersionFields(stmt: PreparedStatement, obj: Version): Int { 22.149 + with(obj) { 22.150 + stmt.setStringSafe(1, name) 22.151 + stmt.setStringSafe(2, node) 22.152 + stmt.setInt(3, ordinal) 22.153 + stmt.setEnum(4, status) 22.154 + } 22.155 + return 5 22.156 + } 22.157 + 22.158 + //language=SQL 22.159 + private val versionQuery = "select versionid, project, name, node, ordinal, status from lpit_version" 22.160 + 22.161 + private val stmtVersions by lazy { 22.162 + connection.prepareStatement( 22.163 + """${versionQuery} 22.164 + where project = ? 22.165 + order by ordinal desc, lower(name) desc 22.166 + """ 22.167 + ) 22.168 + } 22.169 + private val stmtVersionByID by lazy { 22.170 + connection.prepareStatement( 22.171 + """${versionQuery} 22.172 + where versionid = ? 22.173 + """ 22.174 + ) 22.175 + } 22.176 + private val stmtVersionByNode by lazy { 22.177 + connection.prepareStatement( 22.178 + """${versionQuery} 22.179 + where project = ? and node = ? 22.180 + """ 22.181 + ) 22.182 + } 22.183 + private val stmtInsertVersion by lazy { 22.184 + connection.prepareStatement( 22.185 + """ 22.186 + insert into lpit_version (name, node, ordinal, status, project) 22.187 + values (?, ?, ?, ?::version_status, ?) 22.188 + """ 22.189 + ) 22.190 + } 22.191 + private val stmtUpdateVersion by lazy { 22.192 + connection.prepareStatement( 22.193 + """ 22.194 + update lpit_version set name = ?, node = ?, ordinal = ?, status = ?::version_status 22.195 + where versionid = ? 22.196 + """ 22.197 + ) 22.198 + } 22.199 + 22.200 + override fun listVersions(project: Project): List<Version> { 22.201 + stmtVersions.setInt(1, project.id) 22.202 + return selectVersions(stmtVersions).toList() 22.203 + } 22.204 + 22.205 + override fun findVersion(id: Int): Version? { 22.206 + stmtVersionByID.setInt(1, id) 22.207 + return selectVersions(stmtVersionByID).firstOrNull() 22.208 + } 22.209 + 22.210 + override fun findVersionByNode(project: Project, node: String): Version? { 22.211 + stmtVersionByNode.setInt(1, project.id) 22.212 + stmtVersionByNode.setString(2, node) 22.213 + return selectVersions(stmtVersionByNode).firstOrNull() 22.214 + } 22.215 + 22.216 + override fun insertVersion(version: Version) { 22.217 + val col = setVersionFields(stmtInsertVersion, version) 22.218 + stmtInsertVersion.setInt(col, version.projectid) 22.219 + stmtInsertVersion.execute() 22.220 + } 22.221 + 22.222 + override fun updateVersion(version: Version) { 22.223 + val col = setVersionFields(stmtUpdateVersion, version) 22.224 + stmtUpdateVersion.setInt(col, version.id) 22.225 + stmtUpdateVersion.execute() 22.226 + } 22.227 + //</editor-fold> 22.228 + 22.229 + //<editor-fold desc="Component"> 22.230 + private fun selectComponents(stmt: PreparedStatement) = sequence { 22.231 + stmt.executeQuery().use { rs -> 22.232 + while (rs.next()) { 22.233 + yield(Component(rs.getInt("id"), rs.getInt("project")).apply { 22.234 + name = rs.getString("name") 22.235 + node = rs.getString("node") 22.236 + color = try { 22.237 + WebColor(rs.getString("color")) 22.238 + } catch (ex: IllegalArgumentException) { 22.239 + WebColor("000000") 22.240 + } 22.241 + ordinal = rs.getInt("ordinal") 22.242 + description = rs.getString("description") 22.243 + lead = selectUserInfo(rs) 22.244 + }) 22.245 + } 22.246 + } 22.247 + } 22.248 + 22.249 + private fun setComponentFields(stmt: PreparedStatement, obj: Component): Int { 22.250 + with(obj) { 22.251 + stmt.setStringSafe(1, name) 22.252 + stmt.setStringSafe(2, node) 22.253 + stmt.setStringSafe(3, color.hex) 22.254 + stmt.setInt(4, ordinal) 22.255 + stmt.setStringOrNull(5, description) 22.256 + stmt.setIntOrNull(6, obj.lead?.id) 22.257 + } 22.258 + return 7 22.259 + } 22.260 + 22.261 + //language=SQL 22.262 + private val componentQuery = 22.263 + """ 22.264 + select id, project, name, node, color, ordinal, description, 22.265 + userid, username, givenname, lastname, mail 22.266 + from lpit_component 22.267 + left join lpit_user on lead = userid 22.268 + """ 22.269 + 22.270 + private val stmtComponents by lazy { 22.271 + connection.prepareStatement( 22.272 + """${componentQuery} 22.273 + where project = ? 22.274 + order by ordinal, lower(name) 22.275 + """ 22.276 + ) 22.277 + } 22.278 + private val stmtComponentById by lazy { 22.279 + connection.prepareStatement( 22.280 + """${componentQuery} 22.281 + where id = ? 22.282 + """ 22.283 + ) 22.284 + } 22.285 + private val stmtComponentByNode by lazy { 22.286 + connection.prepareStatement( 22.287 + """${componentQuery} 22.288 + where project = ? and node = ? 22.289 + """ 22.290 + ) 22.291 + } 22.292 + private val stmtInsertComponent by lazy { 22.293 + connection.prepareStatement( 22.294 + """ 22.295 + insert into lpit_component (name, node, color, ordinal, description, lead, project) 22.296 + values (?, ?, ?, ?, ?, ?, ?) 22.297 + """ 22.298 + ) 22.299 + } 22.300 + private val stmtUpdateComponent by lazy { 22.301 + connection.prepareStatement( 22.302 + "update lpit_component set name = ?, node = ?, color = ?, ordinal = ?, description = ?, lead = ? where id = ?" 22.303 + ) 22.304 + } 22.305 + 22.306 + override fun listComponents(project: Project): List<Component> { 22.307 + stmtComponents.setInt(1, project.id) 22.308 + return selectComponents(stmtComponents).toList() 22.309 + } 22.310 + 22.311 + override fun findComponent(id: Int): Component? { 22.312 + stmtComponentById.setInt(1, id) 22.313 + return selectComponents(stmtComponentById).firstOrNull() 22.314 + } 22.315 + 22.316 + override fun findComponentByNode(project: Project, node: String): Component? { 22.317 + stmtComponentByNode.setInt(1, project.id) 22.318 + stmtComponentByNode.setString(2, node) 22.319 + return selectComponents(stmtComponentByNode).firstOrNull() 22.320 + } 22.321 + 22.322 + override fun insertComponent(component: Component) { 22.323 + val col = setComponentFields(stmtInsertComponent, component) 22.324 + stmtInsertComponent.setInt(col, component.projectid) 22.325 + stmtInsertComponent.execute() 22.326 + } 22.327 + 22.328 + override fun updateComponent(component: Component) { 22.329 + val col = setComponentFields(stmtUpdateComponent, component) 22.330 + stmtUpdateComponent.setInt(col, component.id) 22.331 + stmtUpdateComponent.execute() 22.332 + } 22.333 + 22.334 + //</editor-fold> 22.335 + 22.336 + //<editor-fold desc="Project"> 22.337 + 22.338 + private fun selectProjects(stmt: PreparedStatement) = sequence { 22.339 + stmt.executeQuery().use { rs -> 22.340 + while (rs.next()) { 22.341 + yield(Project(rs.getInt("projectid")).apply { 22.342 + name = rs.getString("name") 22.343 + node = rs.getString("node") 22.344 + description = rs.getString("description") 22.345 + repoUrl = rs.getString("repourl") 22.346 + owner = selectUserInfo(rs) 22.347 + }) 22.348 + } 22.349 + } 22.350 + } 22.351 + 22.352 + private fun setProjectFields(stmt: PreparedStatement, obj: Project): Int { 22.353 + with(obj) { 22.354 + stmt.setStringSafe(1, name) 22.355 + stmt.setStringSafe(2, node) 22.356 + stmt.setStringOrNull(3, description) 22.357 + stmt.setStringOrNull(4, repoUrl) 22.358 + stmt.setIntOrNull(5, owner?.id) 22.359 + } 22.360 + return 6 22.361 + } 22.362 + 22.363 + //language=SQL 22.364 + private val projectQuery = 22.365 + """ 22.366 + select projectid, name, node, description, repourl, 22.367 + userid, username, lastname, givenname, mail 22.368 + from lpit_project 22.369 + left join lpit_user owner on lpit_project.owner = owner.userid 22.370 + """ 22.371 + 22.372 + private val stmtProjects by lazy { 22.373 + connection.prepareStatement( 22.374 + """${projectQuery} 22.375 + order by lower(name) 22.376 + """ 22.377 + ) 22.378 + } 22.379 + private val stmtProjectByID by lazy { 22.380 + connection.prepareStatement( 22.381 + """${projectQuery} 22.382 + where projectid = ? 22.383 + """ 22.384 + ) 22.385 + } 22.386 + private val stmtProjectByNode by lazy { 22.387 + connection.prepareStatement( 22.388 + """${projectQuery} 22.389 + where node = ? 22.390 + """ 22.391 + ) 22.392 + } 22.393 + private val stmtInsertProject by lazy { 22.394 + connection.prepareStatement( 22.395 + "insert into lpit_project (name, node, description, repourl, owner) values (?, ?, ?, ?, ?)" 22.396 + ) 22.397 + } 22.398 + private val stmtUpdateProject by lazy { 22.399 + connection.prepareStatement( 22.400 + "update lpit_project set name = ?, node = ?, description = ?, repourl = ?, owner = ? where projectid = ?" 22.401 + ) 22.402 + } 22.403 + private val stmtIssueSummary by lazy { 22.404 + connection.prepareStatement( 22.405 + """ 22.406 + select phase, count(*) as total 22.407 + from lpit_issue 22.408 + join lpit_issue_phases using(status) 22.409 + where project = ? 22.410 + group by phase 22.411 + """ 22.412 + ) 22.413 + } 22.414 + 22.415 + override fun listProjects(): List<Project> { 22.416 + return selectProjects(stmtProjects).toList() 22.417 + } 22.418 + 22.419 + override fun findProject(id: Int): Project? { 22.420 + stmtProjectByID.setInt(1, id) 22.421 + return selectProjects(stmtProjectByID).firstOrNull() 22.422 + } 22.423 + 22.424 + override fun findProjectByNode(node: String): Project? { 22.425 + stmtProjectByNode.setString(1, node) 22.426 + return selectProjects(stmtProjectByNode).firstOrNull() 22.427 + } 22.428 + 22.429 + override fun insertProject(project: Project) { 22.430 + setProjectFields(stmtInsertProject, project) 22.431 + stmtInsertProject.execute() 22.432 + } 22.433 + 22.434 + override fun updateProject(project: Project) { 22.435 + val col = setProjectFields(stmtUpdateProject, project) 22.436 + stmtUpdateProject.setInt(col, project.id) 22.437 + stmtUpdateProject.execute() 22.438 + } 22.439 + 22.440 + override fun collectIssueSummary(project: Project): IssueSummary { 22.441 + stmtIssueSummary.setInt(1, project.id) 22.442 + return stmtIssueSummary.executeQuery().use { rs -> 22.443 + val summary = IssueSummary() 22.444 + while (rs.next()) { 22.445 + val phase = rs.getInt("phase") 22.446 + val total = rs.getInt("total") 22.447 + when (phase) { 22.448 + 0 -> summary.open = total 22.449 + 1 -> summary.active = total 22.450 + 2 -> summary.done = total 22.451 + } 22.452 + } 22.453 + summary 22.454 + } 22.455 + } 22.456 + 22.457 + //</editor-fold> 22.458 + 22.459 + //<editor-fold desc="Issue"> 22.460 + 22.461 + private fun selectIssues(stmt: PreparedStatement) = sequence { 22.462 + stmt.executeQuery().use { rs -> 22.463 + while (rs.next()) { 22.464 + val proj = Project(rs.getInt("project")).apply { 22.465 + name = rs.getString("projectname") 22.466 + node = rs.getString("projectnode") 22.467 + } 22.468 + val comp = rs.getInt("component").let { 22.469 + if (rs.wasNull()) null else 22.470 + Component(it, proj.id).apply { 22.471 + name = rs.getString("componentname") 22.472 + node = rs.getString("componentnode") 22.473 + } 22.474 + } 22.475 + val issue = Issue(rs.getInt("issueid"), proj, comp).apply { 22.476 + component = comp 22.477 + status = rs.getEnum("status") 22.478 + category = rs.getEnum("category") 22.479 + subject = rs.getString("subject") 22.480 + description = rs.getString("description") 22.481 + assignee = selectUserInfo(rs) 22.482 + created = rs.getTimestamp("created") 22.483 + updated = rs.getTimestamp("updated") 22.484 + eta = rs.getDate("eta") 22.485 + } 22.486 + queryAffectedVersions.setInt(1, issue.id) 22.487 + issue.affectedVersions = selectVersions(queryAffectedVersions).toList() 22.488 + queryResolvedVersions.setInt(1, issue.id) 22.489 + issue.resolvedVersions = selectVersions(queryResolvedVersions).toList() 22.490 + yield(issue) 22.491 + } 22.492 + } 22.493 + } 22.494 + 22.495 + private fun setIssueFields(stmt: PreparedStatement, obj: Issue): Int { 22.496 + with(obj) { 22.497 + stmt.setIntOrNull(1, component?.id) 22.498 + stmt.setEnum(2, status) 22.499 + stmt.setEnum(3, category) 22.500 + stmt.setStringSafe(4, subject) 22.501 + stmt.setStringOrNull(5, description) 22.502 + stmt.setIntOrNull(6, assignee?.id) 22.503 + stmt.setDateOrNull(7, eta) 22.504 + } 22.505 + return 8 22.506 + } 22.507 + 22.508 + //language=SQL 22.509 + private val issueQuery = 22.510 + """ 22.511 + select issueid, 22.512 + i.project, p.name as projectname, p.node as projectnode, 22.513 + component, c.name as componentname, c.node as componentnode, 22.514 + status, category, subject, i.description, 22.515 + userid, username, givenname, lastname, mail, 22.516 + created, updated, eta 22.517 + from lpit_issue i 22.518 + join lpit_project p on i.project = projectid 22.519 + left join lpit_component c on component = c.id 22.520 + left join lpit_user on userid = assignee 22.521 + """ 22.522 + 22.523 + private val queryResolvedVersions by lazy { 22.524 + connection.prepareStatement( 22.525 + """ 22.526 + select versionid, project, name, status, ordinal, node 22.527 + from lpit_version v join lpit_issue_resolved_version using (versionid) 22.528 + where issueid = ? 22.529 + order by ordinal, name 22.530 + """ 22.531 + ) 22.532 + } 22.533 + 22.534 + private val queryAffectedVersions by lazy { 22.535 + connection.prepareStatement( 22.536 + """ 22.537 + select versionid, project, name, status, ordinal, node 22.538 + from lpit_version join lpit_issue_affected_version using (versionid) 22.539 + where issueid = ? 22.540 + order by ordinal, name 22.541 + """ 22.542 + ) 22.543 + } 22.544 + 22.545 + private val stmtIssues by lazy { 22.546 + connection.prepareStatement( 22.547 + """ 22.548 + with issue_version as ( 22.549 + select issueid, versionid from lpit_issue_affected_version 22.550 + union select issueid, versionid from lpit_issue_resolved_version 22.551 + ) ${issueQuery} left join issue_version using (issueid) 22.552 + where 22.553 + (not ? or projectid = ?) and 22.554 + (not ? or versionid = ?) and (not ? or versionid is null) and 22.555 + (not ? or component = ?) and (not ? or component is null) 22.556 + """ 22.557 + ) 22.558 + } 22.559 + 22.560 + private val fproj = 1 22.561 + private val projectid = 2 22.562 + private val fversion = 3 22.563 + private val versionid = 4 22.564 + private val nversion = 5 22.565 + private val fcomp = 6 22.566 + private val component = 7 22.567 + private val ncomp = 8 22.568 + 22.569 + private fun <T : Entity> applyFilter(filter: Filter<T>, fflag: Int, nflag: Int, idcol: Int) { 22.570 + when (filter) { 22.571 + is AllFilter -> { 22.572 + stmtIssues.setBoolean(fflag, false) 22.573 + stmtIssues.setBoolean(nflag, false) 22.574 + stmtIssues.setInt(idcol, 0) 22.575 + } 22.576 + is NoneFilter -> { 22.577 + stmtIssues.setBoolean(fflag, false) 22.578 + stmtIssues.setBoolean(nflag, true) 22.579 + stmtIssues.setInt(idcol, 0) 22.580 + } 22.581 + is SpecificFilter -> { 22.582 + stmtIssues.setBoolean(fflag, true) 22.583 + stmtIssues.setBoolean(nflag, false) 22.584 + stmtIssues.setInt(idcol, filter.obj.id) 22.585 + } 22.586 + else -> { 22.587 + TODO("Implement range filter.") 22.588 + } 22.589 + } 22.590 + } 22.591 + 22.592 + override fun listIssues(filter: IssueFilter): List<Issue> { 22.593 + when (filter.project) { 22.594 + is AllFilter -> { 22.595 + stmtIssues.setBoolean(fproj, false) 22.596 + stmtIssues.setInt(projectid, 0) 22.597 + } 22.598 + is SpecificFilter -> { 22.599 + stmtIssues.setBoolean(fproj, true) 22.600 + stmtIssues.setInt(projectid, filter.project.obj.id) 22.601 + } 22.602 + else -> throw IllegalArgumentException() 22.603 + } 22.604 + applyFilter(filter.version, fversion, nversion, versionid) 22.605 + applyFilter(filter.component, fcomp, ncomp, component) 22.606 + 22.607 + return selectIssues(stmtIssues).toList() 22.608 + } 22.609 + 22.610 + private val stmtFindIssueByID by lazy { 22.611 + connection.prepareStatement( 22.612 + """${issueQuery} 22.613 + where issueid = ? 22.614 + """ 22.615 + ) 22.616 + } 22.617 + private val stmtInsertIssue by lazy { 22.618 + connection.prepareStatement( 22.619 + """ 22.620 + insert into lpit_issue (component, status, category, subject, description, assignee, eta, project) 22.621 + values (?, ?::issue_status, ?::issue_category, ?, ?, ?, ?, ?) 22.622 + returning issueid 22.623 + """ 22.624 + ) 22.625 + } 22.626 + private val stmtUpdateIssue by lazy { 22.627 + connection.prepareStatement( 22.628 + """ 22.629 + update lpit_issue set updated = now(), 22.630 + component = ?, status = ?::issue_status, category = ?::issue_category, subject = ?, 22.631 + description = ?, assignee = ?, eta = ? 22.632 + where issueid = ? 22.633 + """ 22.634 + ) 22.635 + } 22.636 + private val stmtInsertAffectedVersion by lazy { 22.637 + connection.prepareStatement( 22.638 + "insert into lpit_issue_affected_version (issueid, versionid) values (?,?)" 22.639 + ) 22.640 + } 22.641 + private val stmtInsertResolvedVersion by lazy { 22.642 + connection.prepareStatement( 22.643 + "insert into lpit_issue_resolved_version (issueid, versionid) values (?,?)" 22.644 + ) 22.645 + } 22.646 + private val stmtClearAffectedVersions by lazy { 22.647 + connection.prepareStatement("delete from lpit_issue_affected_version where issueid = ?") 22.648 + } 22.649 + private val stmtClearResolvedVersions by lazy { 22.650 + connection.prepareStatement("delete from lpit_issue_resolved_version where issueid = ?") 22.651 + } 22.652 + 22.653 + override fun findIssue(id: Int): Issue? { 22.654 + stmtFindIssueByID.setInt(1, id) 22.655 + return selectIssues(stmtFindIssueByID).firstOrNull() 22.656 + } 22.657 + 22.658 + private fun insertVersionInfo(issue: Issue) { 22.659 + stmtInsertAffectedVersion.setInt(1, issue.id) 22.660 + stmtInsertResolvedVersion.setInt(1, issue.id) 22.661 + issue.affectedVersions.forEach { 22.662 + stmtInsertAffectedVersion.setInt(2, it.id) 22.663 + stmtInsertAffectedVersion.execute() 22.664 + } 22.665 + issue.resolvedVersions.forEach { 22.666 + stmtInsertResolvedVersion.setInt(2, it.id) 22.667 + stmtInsertResolvedVersion.execute() 22.668 + } 22.669 + } 22.670 + 22.671 + override fun insertIssue(issue: Issue) { 22.672 + val col = setIssueFields(stmtInsertIssue, issue) 22.673 + stmtInsertIssue.setInt(col, issue.project.id) 22.674 + stmtInsertIssue.executeQuery().use { rs -> 22.675 + rs.next() 22.676 + issue.id = rs.getInt(1) 22.677 + } 22.678 + insertVersionInfo(issue) 22.679 + } 22.680 + 22.681 + override fun updateIssue(issue: Issue) { 22.682 + val col = setIssueFields(stmtUpdateIssue, issue) 22.683 + stmtUpdateIssue.setInt(col, issue.id) 22.684 + // TODO: improve by only inserting / deleting changed version information 22.685 + stmtClearAffectedVersions.setInt(1, issue.id) 22.686 + stmtClearResolvedVersions.setInt(1, issue.id) 22.687 + stmtClearAffectedVersions.execute() 22.688 + stmtClearResolvedVersions.execute() 22.689 + insertVersionInfo(issue) 22.690 + } 22.691 + 22.692 + //</editor-fold> 22.693 + 22.694 + //<editor-fold desc="IssueComment"> 22.695 + 22.696 + private fun selectComments(stmt: PreparedStatement) = sequence { 22.697 + stmt.executeQuery().use { rs -> 22.698 + while (rs.next()) { 22.699 + yield(IssueComment(rs.getInt("commentid"), rs.getInt("issueid")).apply { 22.700 + created = rs.getTimestamp("created") 22.701 + updated = rs.getTimestamp("updated") 22.702 + updateCount = rs.getInt("updatecount") 22.703 + comment = rs.getString("comment") 22.704 + author = selectUserInfo(rs) 22.705 + }) 22.706 + } 22.707 + } 22.708 + } 22.709 + 22.710 + private val stmtComments by lazy { 22.711 + connection.prepareStatement( 22.712 + "select * from lpit_issue_comment left join lpit_user using (userid) where issueid = ? order by created" 22.713 + ) 22.714 + } 22.715 + private val stmtInsertComment by lazy { 22.716 + connection.prepareStatement( 22.717 + "insert into lpit_issue_comment (issueid, comment, userid) values (?, ? ,?)" 22.718 + ) 22.719 + } 22.720 + private val stmtUpdateIssueDate by lazy { 22.721 + connection.prepareStatement( 22.722 + "update lpit_issue set updated = now() where issueid = ?" 22.723 + ) 22.724 + } 22.725 + 22.726 + override fun listComments(issue: Issue): List<IssueComment> { 22.727 + stmtComments.setInt(1, issue.id) 22.728 + return selectComments(stmtComments).toList() 22.729 + } 22.730 + 22.731 + override fun insertComment(issueComment: IssueComment) { 22.732 + with(issueComment) { 22.733 + stmtUpdateIssueDate.setInt(1, issueid) 22.734 + stmtInsertComment.setInt(1, issueid) 22.735 + stmtInsertComment.setStringSafe(2, comment) 22.736 + stmtInsertComment.setIntOrNull(3, author?.id) 22.737 + } 22.738 + stmtInsertComment.execute() 22.739 + stmtUpdateIssueDate.execute() 22.740 + } 22.741 + //</editor-fold> 22.742 +} 22.743 \ No newline at end of file
23.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/postgres/PGComponentDao.kt Sun Dec 20 11:06:25 2020 +0100 23.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 23.3 @@ -1,110 +0,0 @@ 23.4 -/* 23.5 - * Copyright 2020 Mike Becker. All rights reserved. 23.6 - * 23.7 - * Redistribution and use in source and binary forms, with or without 23.8 - * modification, are permitted provided that the following conditions are met: 23.9 - * 23.10 - * 1. Redistributions of source code must retain the above copyright 23.11 - * notice, this list of conditions and the following disclaimer. 23.12 - * 23.13 - * 2. Redistributions in binary form must reproduce the above copyright 23.14 - * notice, this list of conditions and the following disclaimer in the 23.15 - * documentation and/or other materials provided with the distribution. 23.16 - * 23.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23.27 - * 23.28 - */ 23.29 - 23.30 -package de.uapcore.lightpit.dao.postgres 23.31 - 23.32 -import de.uapcore.lightpit.dao.AbstractComponentDao 23.33 -import de.uapcore.lightpit.dao.Functions 23.34 -import de.uapcore.lightpit.entities.Component 23.35 -import de.uapcore.lightpit.entities.Project 23.36 -import de.uapcore.lightpit.entities.User 23.37 -import de.uapcore.lightpit.types.WebColor 23.38 -import java.sql.Connection 23.39 -import java.sql.PreparedStatement 23.40 -import java.sql.ResultSet 23.41 - 23.42 -class PGComponentDao(connection: Connection) : AbstractComponentDao() { 23.43 - 23.44 - private val query = "select id, name, node, color, ordinal, description, " + 23.45 - "userid, username, givenname, lastname, mail " + 23.46 - "from lpit_component " + 23.47 - "left join lpit_user on lead = userid" 23.48 - 23.49 - private val listStmt = connection.prepareStatement("$query where project = ? order by ordinal, lower(name)") 23.50 - private val findStmt = connection.prepareStatement("$query where id = ? ") 23.51 - private val findByNodeStmt = connection.prepareStatement("$query where project = ? and node = ?") 23.52 - private val insertStmt = connection.prepareStatement( 23.53 - "insert into lpit_component (name, node, color, ordinal, description, lead, project) values (?, ?, ?, ?, ?, ?, ?)" 23.54 - ) 23.55 - private val updateStmt = connection.prepareStatement( 23.56 - "update lpit_component set name = ?, node = ?, color = ?, ordinal = ?, description = ?, lead = ? where id = ?" 23.57 - ) 23.58 - 23.59 - override fun mapResult(rs: ResultSet): Component { 23.60 - val component = Component(rs.getInt("id")) 23.61 - component.name = rs.getString("name") 23.62 - component.node = rs.getString("node") 23.63 - component.color = try { 23.64 - WebColor(rs.getString("color")) 23.65 - } catch (ex: IllegalArgumentException) { 23.66 - WebColor("000000") 23.67 - } 23.68 - component.ordinal = rs.getInt("ordinal") 23.69 - component.description = rs.getString("description") 23.70 - component.lead = PGUserDao.mapResult(rs).takeUnless { rs.wasNull() } 23.71 - return component 23.72 - } 23.73 - 23.74 - private fun setColumns(stmt: PreparedStatement, instance: Component): Int { 23.75 - var column = 0 23.76 - stmt.setString(++column, instance.name) 23.77 - stmt.setString(++column, instance.node) 23.78 - stmt.setString(++column, instance.color.hex) 23.79 - stmt.setInt(++column, instance.ordinal) 23.80 - Functions.setStringOrNull(stmt, ++column, instance.description) 23.81 - setForeignKeyOrNull(stmt, ++column, instance.lead, User::id) 23.82 - return column 23.83 - } 23.84 - 23.85 - override fun save(instance: Component, parent: Project) { 23.86 - var column = setColumns(insertStmt, instance) 23.87 - insertStmt.setInt(++column, parent.id) 23.88 - insertStmt.executeUpdate() 23.89 - } 23.90 - 23.91 - override fun update(instance: Component): Boolean { 23.92 - var column = setColumns(updateStmt, instance) 23.93 - updateStmt.setInt(++column, instance.id) 23.94 - return updateStmt.executeUpdate() > 0 23.95 - } 23.96 - 23.97 - 23.98 - override fun list(parent: Project): List<Component> { 23.99 - listStmt.setInt(1, parent.id) 23.100 - return super.list(listStmt) 23.101 - } 23.102 - 23.103 - override fun find(id: Int): Component? { 23.104 - findStmt.setInt(1, id) 23.105 - return super.find(findStmt) 23.106 - } 23.107 - 23.108 - override fun findByNode(parent: Project, node: String): Component? { 23.109 - findByNodeStmt.setInt(1, parent.id) 23.110 - findByNodeStmt.setString(2, node) 23.111 - return super.find(findByNodeStmt) 23.112 - } 23.113 -} 23.114 \ No newline at end of file
24.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/postgres/PGDaoProvider.kt Sun Dec 20 11:06:25 2020 +0100 24.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 24.3 @@ -1,38 +0,0 @@ 24.4 -/* 24.5 - * Copyright 2020 Mike Becker. All rights reserved. 24.6 - * 24.7 - * Redistribution and use in source and binary forms, with or without 24.8 - * modification, are permitted provided that the following conditions are met: 24.9 - * 24.10 - * 1. Redistributions of source code must retain the above copyright 24.11 - * notice, this list of conditions and the following disclaimer. 24.12 - * 24.13 - * 2. Redistributions in binary form must reproduce the above copyright 24.14 - * notice, this list of conditions and the following disclaimer in the 24.15 - * documentation and/or other materials provided with the distribution. 24.16 - * 24.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24.27 - * 24.28 - */ 24.29 - 24.30 -package de.uapcore.lightpit.dao.postgres 24.31 - 24.32 -import de.uapcore.lightpit.dao.DaoProvider 24.33 -import java.sql.Connection 24.34 - 24.35 -class PGDaoProvider(connection: Connection) : DaoProvider { 24.36 - override val userDao = PGUserDao(connection) 24.37 - override val projectDao = PGProjectDao(connection) 24.38 - override val componentDao = PGComponentDao(connection) 24.39 - override val versionDao = PGVersionDao(connection) 24.40 - override val issueDao = PGIssueDao(connection) 24.41 -} 24.42 \ No newline at end of file
25.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/postgres/PGIssueDao.kt Sun Dec 20 11:06:25 2020 +0100 25.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 25.3 @@ -1,255 +0,0 @@ 25.4 -/* 25.5 - * Copyright 2020 Mike Becker. All rights reserved. 25.6 - * 25.7 - * Redistribution and use in source and binary forms, with or without 25.8 - * modification, are permitted provided that the following conditions are met: 25.9 - * 25.10 - * 1. Redistributions of source code must retain the above copyright 25.11 - * notice, this list of conditions and the following disclaimer. 25.12 - * 25.13 - * 2. Redistributions in binary form must reproduce the above copyright 25.14 - * notice, this list of conditions and the following disclaimer in the 25.15 - * documentation and/or other materials provided with the distribution. 25.16 - * 25.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25.27 - * 25.28 - */ 25.29 - 25.30 -package de.uapcore.lightpit.dao.postgres 25.31 - 25.32 -import de.uapcore.lightpit.dao.AbstractIssueDao 25.33 -import de.uapcore.lightpit.dao.Functions 25.34 -import de.uapcore.lightpit.entities.* 25.35 -import java.sql.Connection 25.36 -import java.sql.PreparedStatement 25.37 -import java.sql.ResultSet 25.38 -import java.sql.Types 25.39 - 25.40 -class PGIssueDao(connection: Connection) : AbstractIssueDao() { 25.41 - 25.42 - private val query = "select issueid, i.project, p.name as projectname, p.node as projectnode, " + 25.43 - "component, c.name as componentname, c.node as componentnode, " + 25.44 - "status, category, subject, i.description, " + 25.45 - "userid, username, givenname, lastname, mail, " + 25.46 - "created, updated, eta " + 25.47 - "from lpit_issue i " + 25.48 - "join lpit_project p on i.project = projectid " + 25.49 - "left join lpit_component c on component = c.id " + 25.50 - "left join lpit_user on userid = assignee " 25.51 - private val list = connection.prepareStatement(query + 25.52 - "where i.project = ? and coalesce(component, -1) = coalesce(?, component, -1)") 25.53 - private val listForVersion = connection.prepareStatement( 25.54 - "with issue_version as ( " + 25.55 - "select issueid, versionid from lpit_issue_affected_version union " + 25.56 - "select issueid, versionid from lpit_issue_resolved_version) " + 25.57 - query + 25.58 - "left join issue_version using (issueid) " + 25.59 - "where i.project = ? " + 25.60 - "and coalesce(versionid,-1) = ? and coalesce(component, -1) = coalesce(?, component, -1)" 25.61 - ) 25.62 - private val find = connection.prepareStatement(query + "where issueid = ? ") 25.63 - private val insert = connection.prepareStatement( 25.64 - "insert into lpit_issue (project, component, status, category, subject, description, assignee, eta) " + 25.65 - "values (?, ?, ?::issue_status, ?::issue_category, ?, ?, ?, ?) returning issueid" 25.66 - ) 25.67 - private val update = connection.prepareStatement( 25.68 - "update lpit_issue set " + 25.69 - "updated = now(), component = ?, status = ?::issue_status, category = ?::issue_category, " + 25.70 - "subject = ?, description = ?, assignee = ?, eta = ? where issueid = ?" 25.71 - ) 25.72 - private val affectedVersions = connection.prepareStatement( 25.73 - "select versionid, name, status, ordinal, node " + 25.74 - "from lpit_version join lpit_issue_affected_version using (versionid) " + 25.75 - "where issueid = ? " + 25.76 - "order by ordinal, name" 25.77 - ) 25.78 - private val clearAffected = connection.prepareStatement("delete from lpit_issue_affected_version where issueid = ?") 25.79 - private val insertAffected = connection.prepareStatement("insert into lpit_issue_affected_version (issueid, versionid) values (?,?)") 25.80 - 25.81 - private val resolvedVersions = connection.prepareStatement( 25.82 - "select versionid, name, status, ordinal, node " + 25.83 - "from lpit_version v join lpit_issue_resolved_version using (versionid) " + 25.84 - "where issueid = ? " + 25.85 - "order by ordinal, name" 25.86 - ) 25.87 - private val clearResolved = connection.prepareStatement("delete from lpit_issue_resolved_version where issueid = ?") 25.88 - private val insertResolved = connection.prepareStatement("insert into lpit_issue_resolved_version (issueid, versionid) values (?,?)") 25.89 - private val insertComment = connection.prepareStatement( 25.90 - "insert into lpit_issue_comment (issueid, comment, userid) values (?, ? ,?)" 25.91 - ) 25.92 - private val updateComment = connection.prepareStatement( 25.93 - "update lpit_issue_comment set comment = ?, updated = now(), updatecount = updatecount+1 where commentid = ?" 25.94 - ) 25.95 - private val listComments = connection.prepareStatement( 25.96 - "select * from lpit_issue_comment left join lpit_user using (userid) where issueid = ? order by created" 25.97 - ) 25.98 - 25.99 - private val updateIssueLastModified = connection.prepareStatement( 25.100 - "update lpit_issue set updated = now() where issueid = ?" 25.101 - ); 25.102 - 25.103 - override fun mapResult(rs: ResultSet): Issue { 25.104 - val project = Project(rs.getInt("project")) 25.105 - project.name = rs.getString("projectname") 25.106 - project.node = rs.getString("projectnode") 25.107 - val issue = Issue(rs.getInt("issueid")) 25.108 - issue.project = project 25.109 - issue.component = rs.getInt("component").let { id -> 25.110 - if (rs.wasNull()) { 25.111 - null 25.112 - } else { 25.113 - val component = Component(id) 25.114 - component.name = rs.getString("componentname") 25.115 - component.node = rs.getString("componentnode") 25.116 - component 25.117 - } 25.118 - } 25.119 - issue.status = IssueStatus.valueOf(rs.getString("status")) 25.120 - issue.category = IssueCategory.valueOf(rs.getString("category")) 25.121 - issue.subject = rs.getString("subject") 25.122 - issue.description = rs.getString("description") 25.123 - issue.assignee = PGUserDao.mapResult(rs).takeUnless { rs.wasNull() } 25.124 - issue.created = rs.getTimestamp("created") 25.125 - issue.updated = rs.getTimestamp("updated") 25.126 - issue.eta = rs.getDate("eta") 25.127 - return issue 25.128 - } 25.129 - 25.130 - private fun updateVersionLists(instance: Issue) { 25.131 - clearAffected.setInt(1, instance.id) 25.132 - clearResolved.setInt(1, instance.id) 25.133 - insertAffected.setInt(1, instance.id) 25.134 - insertResolved.setInt(1, instance.id) 25.135 - clearAffected.executeUpdate() 25.136 - clearResolved.executeUpdate() 25.137 - for (v: Version in instance.affectedVersions) { 25.138 - insertAffected.setInt(2, v.id) 25.139 - insertAffected.executeUpdate() 25.140 - } 25.141 - for (v: Version in instance.resolvedVersions) { 25.142 - insertResolved.setInt(2, v.id) 25.143 - insertResolved.executeUpdate() 25.144 - } 25.145 - } 25.146 - 25.147 - private fun setData(stmt: PreparedStatement, column: Int, instance: Issue): Int { 25.148 - var col = column 25.149 - setForeignKeyOrNull(stmt, ++col, instance.component, Component::id) 25.150 - stmt.setString(++col, instance.status.name) 25.151 - stmt.setString(++col, instance.category.name) 25.152 - stmt.setString(++col, instance.subject) 25.153 - Functions.setStringOrNull(stmt, ++col, instance.description) 25.154 - setForeignKeyOrNull(stmt, ++col, instance.assignee, User::id) 25.155 - Functions.setDateOrNull(stmt, ++col, instance.eta) 25.156 - return col 25.157 - } 25.158 - 25.159 - override fun save(instance: Issue, parent: Project) { 25.160 - instance.project = parent 25.161 - var column = 0 25.162 - insert.setInt(++column, parent.id) 25.163 - setData(insert, column, instance) 25.164 - // insert and retrieve the ID 25.165 - val rs = insert.executeQuery() 25.166 - rs.next() 25.167 - instance.id = rs.getInt(1) 25.168 - updateVersionLists(instance) 25.169 - } 25.170 - 25.171 - override fun update(instance: Issue): Boolean { 25.172 - var column = setData(update, 0, instance) 25.173 - update.setInt(++column, instance.id) 25.174 - return if (update.executeUpdate() > 0) { 25.175 - updateVersionLists(instance) 25.176 - true 25.177 - } else { 25.178 - false 25.179 - } 25.180 - } 25.181 - 25.182 - override fun list(parent: Project): List<Issue> { 25.183 - list.setInt(1, parent.id) 25.184 - list.setNull(2, Types.INTEGER) 25.185 - return super.list(list) 25.186 - } 25.187 - 25.188 - override fun list(project: Project, component: Component?, version: Version?): List<Issue> { 25.189 - listForVersion.setInt(1, project.id) 25.190 - listForVersion.setInt(2, version?.id ?: -1) 25.191 - listForVersion.setInt(3, component?.id ?: -1) 25.192 - return super.list(listForVersion) 25.193 - } 25.194 - 25.195 - override fun list(project: Project, version: Version?): List<Issue> { 25.196 - listForVersion.setInt(1, project.id) 25.197 - listForVersion.setInt(2, version?.id ?: -1) 25.198 - listForVersion.setNull(3, Types.INTEGER) 25.199 - return super.list(listForVersion) 25.200 - } 25.201 - 25.202 - override fun list(project: Project, component: Component?): List<Issue> { 25.203 - list.setInt(1, project.id) 25.204 - list.setInt(2, component?.id ?: -1) 25.205 - return super.list(list) 25.206 - } 25.207 - 25.208 - override fun find(id: Int): Issue? { 25.209 - find.setInt(1, id) 25.210 - return super.find(find) 25.211 - } 25.212 - 25.213 - private fun listVersions(stmt: PreparedStatement, issue: Issue): List<Version> { 25.214 - stmt.setInt(1, issue.id) 25.215 - return sequence { 25.216 - stmt.executeQuery().use { result -> 25.217 - while (result.next()) yield(PGVersionDao.mapResult(result)) 25.218 - } 25.219 - }.toList() 25.220 - } 25.221 - 25.222 - override fun joinVersionInformation(issue: Issue) { 25.223 - issue.affectedVersions = listVersions(affectedVersions, issue) 25.224 - issue.resolvedVersions = listVersions(resolvedVersions, issue) 25.225 - } 25.226 - 25.227 - override fun listComments(issue: Issue): List<IssueComment> { 25.228 - listComments.setInt(1, issue.id) 25.229 - return sequence { 25.230 - listComments.executeQuery().use { rs -> 25.231 - while (rs.next()) { 25.232 - val comment = IssueComment(rs.getInt("commentid")) 25.233 - comment.created = rs.getTimestamp("created") 25.234 - comment.updated = rs.getTimestamp("updated") 25.235 - comment.updateCount = rs.getInt("updatecount") 25.236 - comment.comment = rs.getString("comment") 25.237 - comment.author = PGUserDao.mapResult(rs).takeUnless { rs.wasNull() } 25.238 - yield(comment) 25.239 - } 25.240 - } 25.241 - }.toList() 25.242 - } 25.243 - 25.244 - override fun saveComment(issue: Issue, comment: IssueComment) { 25.245 - if (comment.id >= 0) { 25.246 - updateComment.setString(1, comment.comment) 25.247 - updateComment.setInt(2, comment.id) 25.248 - updateComment.execute() 25.249 - } else { 25.250 - insertComment.setInt(1, issue.id) 25.251 - insertComment.setString(2, comment.comment) 25.252 - setForeignKeyOrNull(insertComment, 3, comment.author, User::id) 25.253 - insertComment.execute() 25.254 - } 25.255 - updateIssueLastModified.setInt(1, issue.id); 25.256 - updateIssueLastModified.execute(); 25.257 - } 25.258 -} 25.259 \ No newline at end of file
26.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/postgres/PGProjectDao.kt Sun Dec 20 11:06:25 2020 +0100 26.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 26.3 @@ -1,122 +0,0 @@ 26.4 -/* 26.5 - * Copyright 2020 Mike Becker. All rights reserved. 26.6 - * 26.7 - * Redistribution and use in source and binary forms, with or without 26.8 - * modification, are permitted provided that the following conditions are met: 26.9 - * 26.10 - * 1. Redistributions of source code must retain the above copyright 26.11 - * notice, this list of conditions and the following disclaimer. 26.12 - * 26.13 - * 2. Redistributions in binary form must reproduce the above copyright 26.14 - * notice, this list of conditions and the following disclaimer in the 26.15 - * documentation and/or other materials provided with the distribution. 26.16 - * 26.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26.27 - * 26.28 - */ 26.29 - 26.30 -package de.uapcore.lightpit.dao.postgres 26.31 - 26.32 -import de.uapcore.lightpit.dao.AbstractProjectDao 26.33 -import de.uapcore.lightpit.dao.Functions 26.34 -import de.uapcore.lightpit.entities.IssueSummary 26.35 -import de.uapcore.lightpit.entities.Project 26.36 -import de.uapcore.lightpit.entities.User 26.37 -import java.sql.Connection 26.38 -import java.sql.PreparedStatement 26.39 -import java.sql.ResultSet 26.40 - 26.41 -class PGProjectDao(connection: Connection) : AbstractProjectDao() { 26.42 - 26.43 - private val query = "select projectid, name, node, description, repourl, " + 26.44 - "userid, username, lastname, givenname, mail " + 26.45 - "from lpit_project " + 26.46 - "left join lpit_user owner on lpit_project.owner = owner.userid " 26.47 - 26.48 - private val listStmt = connection.prepareStatement("$query order by name") 26.49 - private val findStmt = connection.prepareStatement("$query where projectid = ?") 26.50 - private val findByNodeStmt = connection.prepareStatement("$query where node = ?") 26.51 - private val issueSummaryStmt = connection.prepareStatement( 26.52 - "select phase, count(*) as total " + 26.53 - "from lpit_issue " + 26.54 - "join lpit_issue_phases using(status) " + 26.55 - "where project = ? " + 26.56 - "group by phase " 26.57 - ) 26.58 - private val insertStmt = connection.prepareStatement( 26.59 - "insert into lpit_project (name, node, description, repourl, owner) values (?, ?, ?, ?, ?)" 26.60 - ) 26.61 - private val updateStmt = connection.prepareStatement( 26.62 - "update lpit_project set name = ?, node = ?, description = ?, repourl = ?, owner = ? where projectid = ?" 26.63 - ) 26.64 - 26.65 - override fun mapResult(rs: ResultSet): Project { 26.66 - val proj = Project(rs.getInt("projectid")) 26.67 - proj.name = rs.getString("name") 26.68 - proj.node = rs.getString("node") 26.69 - proj.description = rs.getString("description") 26.70 - proj.repoUrl = rs.getString("repourl") 26.71 - proj.owner = PGUserDao.mapResult(rs).takeUnless { rs.wasNull() } 26.72 - return proj 26.73 - } 26.74 - 26.75 - override fun getIssueSummary(project: Project): IssueSummary { 26.76 - issueSummaryStmt.setInt(1, project.id) 26.77 - val result = issueSummaryStmt.executeQuery() 26.78 - val summary = IssueSummary() 26.79 - while (result.next()) { 26.80 - val phase = result.getInt("phase") 26.81 - val total = result.getInt("total") 26.82 - when (phase) { 26.83 - 0 -> summary.open = total 26.84 - 1 -> summary.active = total 26.85 - 2 -> summary.done = total 26.86 - } 26.87 - } 26.88 - return summary 26.89 - } 26.90 - 26.91 - private fun setColumns(stmt: PreparedStatement, instance: Project): Int { 26.92 - var column = 0 26.93 - stmt.setString(++column, instance.name) 26.94 - stmt.setString(++column, instance.node) 26.95 - Functions.setStringOrNull(stmt, ++column, instance.description) 26.96 - Functions.setStringOrNull(stmt, ++column, instance.repoUrl) 26.97 - setForeignKeyOrNull(stmt, ++column, instance.owner, User::id) 26.98 - return column 26.99 - } 26.100 - 26.101 - override fun save(instance: Project) { 26.102 - setColumns(insertStmt, instance) 26.103 - insertStmt.executeUpdate() 26.104 - } 26.105 - 26.106 - override fun update(instance: Project): Boolean { 26.107 - var column = setColumns(updateStmt, instance) 26.108 - updateStmt.setInt(++column, instance.id) 26.109 - return updateStmt.executeUpdate() > 0 26.110 - } 26.111 - 26.112 - override fun list(): List<Project> { 26.113 - return super.list(listStmt) 26.114 - } 26.115 - 26.116 - override fun find(id: Int): Project? { 26.117 - findStmt.setInt(1, id) 26.118 - return super.find(findStmt) 26.119 - } 26.120 - 26.121 - override fun findByNode(node: String): Project? { 26.122 - findByNodeStmt.setString(1, node) 26.123 - return super.find(findByNodeStmt) 26.124 - } 26.125 -} 26.126 \ No newline at end of file
27.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/postgres/PGUserDao.kt Sun Dec 20 11:06:25 2020 +0100 27.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 27.3 @@ -1,95 +0,0 @@ 27.4 -/* 27.5 - * Copyright 2020 Mike Becker. All rights reserved. 27.6 - * 27.7 - * Redistribution and use in source and binary forms, with or without 27.8 - * modification, are permitted provided that the following conditions are met: 27.9 - * 27.10 - * 1. Redistributions of source code must retain the above copyright 27.11 - * notice, this list of conditions and the following disclaimer. 27.12 - * 27.13 - * 2. Redistributions in binary form must reproduce the above copyright 27.14 - * notice, this list of conditions and the following disclaimer in the 27.15 - * documentation and/or other materials provided with the distribution. 27.16 - * 27.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27.27 - * 27.28 - */ 27.29 - 27.30 -package de.uapcore.lightpit.dao.postgres 27.31 - 27.32 -import de.uapcore.lightpit.dao.AbstractUserDao 27.33 -import de.uapcore.lightpit.dao.Functions 27.34 -import de.uapcore.lightpit.entities.User 27.35 -import java.sql.Connection 27.36 -import java.sql.ResultSet 27.37 - 27.38 -class PGUserDao(connection: Connection) : AbstractUserDao() { 27.39 - 27.40 - companion object { 27.41 - fun mapResult(rs: ResultSet): User { 27.42 - val id = rs.getInt("userid") 27.43 - return if (rs.wasNull()) { 27.44 - User(-1) 27.45 - } else { 27.46 - val user = User(id) 27.47 - user.username = rs.getString("username") 27.48 - user.givenname = Functions.getSafeString(rs, "givenname") 27.49 - user.lastname = Functions.getSafeString(rs, "lastname") 27.50 - user.mail = Functions.getSafeString(rs, "mail") 27.51 - user 27.52 - } 27.53 - } 27.54 - } 27.55 - 27.56 - private val listStmt = connection.prepareStatement( 27.57 - "select userid, username, lastname, givenname, mail " + 27.58 - "from lpit_user where userid >= 0 " + 27.59 - "order by username") 27.60 - private val findStmt = connection.prepareStatement( 27.61 - "select userid, username, lastname, givenname, mail " + 27.62 - "from lpit_user where userid = ? ") 27.63 - private val findByUsernameStmt = connection.prepareStatement( 27.64 - "select userid, username, lastname, givenname, mail " + 27.65 - "from lpit_user where lower(username) = lower(?) ") 27.66 - private val insertStmt = connection.prepareStatement("insert into lpit_user (username, lastname, givenname, mail) values (?, ?, ?, ?)") 27.67 - private val updateStmt = connection.prepareStatement("update lpit_user set lastname = ?, givenname = ?, mail = ? where userid = ?") 27.68 - 27.69 - override fun mapResult(rs: ResultSet): User = Companion.mapResult(rs) 27.70 - 27.71 - override fun save(instance: User) { 27.72 - insertStmt.setString(1, instance.username) 27.73 - Functions.setStringOrNull(insertStmt, 2, instance.lastname) 27.74 - Functions.setStringOrNull(insertStmt, 3, instance.givenname) 27.75 - Functions.setStringOrNull(insertStmt, 4, instance.mail) 27.76 - insertStmt.executeUpdate() 27.77 - } 27.78 - 27.79 - override fun update(instance: User): Boolean { 27.80 - Functions.setStringOrNull(updateStmt, 1, instance.lastname) 27.81 - Functions.setStringOrNull(updateStmt, 2, instance.givenname) 27.82 - Functions.setStringOrNull(updateStmt, 3, instance.mail) 27.83 - updateStmt.setInt(4, instance.id) 27.84 - return updateStmt.executeUpdate() > 0 27.85 - } 27.86 - 27.87 - override fun list(): List<User> = super.list(listStmt) 27.88 - 27.89 - override fun find(id: Int): User? { 27.90 - findStmt.setInt(1, id) 27.91 - return super.find(findStmt) 27.92 - } 27.93 - 27.94 - override fun findByUsername(username: String): User? { 27.95 - findByUsernameStmt.setString(1, username) 27.96 - return super.find(findByUsernameStmt) 27.97 - } 27.98 -} 27.99 \ No newline at end of file
28.1 --- a/src/main/kotlin/de/uapcore/lightpit/dao/postgres/PGVersionDao.kt Sun Dec 20 11:06:25 2020 +0100 28.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 28.3 @@ -1,105 +0,0 @@ 28.4 -/* 28.5 - * Copyright 2020 Mike Becker. All rights reserved. 28.6 - * 28.7 - * Redistribution and use in source and binary forms, with or without 28.8 - * modification, are permitted provided that the following conditions are met: 28.9 - * 28.10 - * 1. Redistributions of source code must retain the above copyright 28.11 - * notice, this list of conditions and the following disclaimer. 28.12 - * 28.13 - * 2. Redistributions in binary form must reproduce the above copyright 28.14 - * notice, this list of conditions and the following disclaimer in the 28.15 - * documentation and/or other materials provided with the distribution. 28.16 - * 28.17 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28.18 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28.19 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28.20 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28.21 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28.22 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28.23 - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28.24 - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28.25 - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28.26 - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28.27 - * 28.28 - */ 28.29 - 28.30 -package de.uapcore.lightpit.dao.postgres 28.31 - 28.32 -import de.uapcore.lightpit.dao.AbstractVersionDao 28.33 -import de.uapcore.lightpit.entities.Project 28.34 -import de.uapcore.lightpit.entities.Version 28.35 -import de.uapcore.lightpit.entities.VersionStatus 28.36 -import java.sql.Connection 28.37 -import java.sql.PreparedStatement 28.38 -import java.sql.ResultSet 28.39 - 28.40 -class PGVersionDao(connection: Connection) : AbstractVersionDao() { 28.41 - 28.42 - companion object { 28.43 - fun mapResult(rs: ResultSet): Version { 28.44 - val id = rs.getInt("versionid") 28.45 - return if (rs.wasNull()) { 28.46 - Version(-1) 28.47 - } else { 28.48 - val version = Version(id) 28.49 - version.name = rs.getString("name") 28.50 - version.node = rs.getString("node") 28.51 - version.ordinal = rs.getInt("ordinal") 28.52 - version.status = VersionStatus.valueOf(rs.getString("status")) 28.53 - version 28.54 - } 28.55 - } 28.56 - } 28.57 - 28.58 - private val query = "select versionid, project, name, node, ordinal, status from lpit_version" 28.59 - private val listStmt = connection.prepareStatement(query + " where project = ? " + 28.60 - "order by ordinal desc, lower(name) desc") 28.61 - private val findStmt = connection.prepareStatement("$query where versionid = ?") 28.62 - private val findByNodeStmt = connection.prepareStatement("$query where project = ? and node = ?") 28.63 - private val insertStmt = connection.prepareStatement( 28.64 - "insert into lpit_version (name, node, ordinal, status, project) values (?, ?, ?, ?::version_status, ?)" 28.65 - ) 28.66 - private val updateStmt = connection.prepareStatement( 28.67 - "update lpit_version set name = ?, node = ?, ordinal = ?, status = ?::version_status where versionid = ?" 28.68 - ) 28.69 - 28.70 - override fun mapResult(rs: ResultSet): Version = Companion.mapResult(rs) 28.71 - 28.72 - private fun setFields(stmt: PreparedStatement, instance: Version): Int { 28.73 - var column = 0 28.74 - stmt.setString(++column, instance.name) 28.75 - stmt.setString(++column, instance.node) 28.76 - stmt.setInt(++column, instance.ordinal) 28.77 - stmt.setString(++column, instance.status.name) 28.78 - return column 28.79 - } 28.80 - 28.81 - override fun save(instance: Version, parent: Project) { 28.82 - var column = setFields(insertStmt, instance) 28.83 - insertStmt.setInt(++column, parent.id) 28.84 - insertStmt.executeUpdate() 28.85 - } 28.86 - 28.87 - override fun update(instance: Version): Boolean { 28.88 - var column = setFields(updateStmt, instance) 28.89 - updateStmt.setInt(++column, instance.id) 28.90 - return updateStmt.executeUpdate() > 0 28.91 - } 28.92 - 28.93 - override fun list(parent: Project): List<Version> { 28.94 - listStmt.setInt(1, parent.id) 28.95 - return super.list(listStmt) 28.96 - } 28.97 - 28.98 - override fun find(id: Int): Version? { 28.99 - findStmt.setInt(1, id) 28.100 - return super.find(findStmt) 28.101 - } 28.102 - 28.103 - override fun findByNode(parent: Project, node: String): Version? { 28.104 - findByNodeStmt.setInt(1, parent.id) 28.105 - findByNodeStmt.setString(2, node) 28.106 - return super.find(findByNodeStmt) 28.107 - } 28.108 -} 28.109 \ No newline at end of file
29.1 --- a/src/main/kotlin/de/uapcore/lightpit/entities/Component.kt Sun Dec 20 11:06:25 2020 +0100 29.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/Component.kt Mon Dec 21 18:29:34 2020 +0100 29.3 @@ -27,7 +27,7 @@ 29.4 29.5 import de.uapcore.lightpit.types.WebColor 29.6 29.7 -data class Component(val id: Int) { 29.8 +data class Component(override val id: Int, var projectid: Int) : Entity { 29.9 var name: String = "" 29.10 var node: String = name 29.11 var color = WebColor("000000")
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/Entity.kt Mon Dec 21 18:29:34 2020 +0100 30.3 @@ -0,0 +1,30 @@ 30.4 +/* 30.5 + * Copyright 2020 Mike Becker. All rights reserved. 30.6 + * 30.7 + * Redistribution and use in source and binary forms, with or without 30.8 + * modification, are permitted provided that the following conditions are met: 30.9 + * 30.10 + * 1. Redistributions of source code must retain the above copyright 30.11 + * notice, this list of conditions and the following disclaimer. 30.12 + * 30.13 + * 2. Redistributions in binary form must reproduce the above copyright 30.14 + * notice, this list of conditions and the following disclaimer in the 30.15 + * documentation and/or other materials provided with the distribution. 30.16 + * 30.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 30.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30.27 + */ 30.28 + 30.29 +package de.uapcore.lightpit.entities 30.30 + 30.31 +interface Entity { 30.32 + val id: Int 30.33 +} 30.34 \ No newline at end of file
31.1 --- a/src/main/kotlin/de/uapcore/lightpit/entities/Issue.kt Sun Dec 20 11:06:25 2020 +0100 31.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/Issue.kt Mon Dec 21 18:29:34 2020 +0100 31.3 @@ -25,81 +25,32 @@ 31.4 31.5 package de.uapcore.lightpit.entities 31.6 31.7 +import de.uapcore.lightpit.types.IssueCategory 31.8 +import de.uapcore.lightpit.types.IssueStatus 31.9 +import de.uapcore.lightpit.types.IssueStatusPhase 31.10 import java.sql.Date 31.11 import java.sql.Timestamp 31.12 import java.time.Instant 31.13 -import kotlin.math.roundToInt 31.14 31.15 -data class IssueStatusPhase(val number: Int) { 31.16 - companion object { 31.17 - val Open = IssueStatusPhase(0) 31.18 - val WorkInProgress = IssueStatusPhase(1) 31.19 - val Done = IssueStatusPhase(2) 31.20 - } 31.21 -} 31.22 - 31.23 -enum class IssueStatus(val phase: IssueStatusPhase) { 31.24 - InSpecification(IssueStatusPhase.Open), 31.25 - ToDo(IssueStatusPhase.Open), 31.26 - Scheduled(IssueStatusPhase.Open), 31.27 - InProgress(IssueStatusPhase.WorkInProgress), 31.28 - InReview(IssueStatusPhase.WorkInProgress), 31.29 - Done(IssueStatusPhase.Done), 31.30 - Rejected(IssueStatusPhase.Done), 31.31 - Withdrawn(IssueStatusPhase.Done), 31.32 - Duplicate(IssueStatusPhase.Done); 31.33 -} 31.34 - 31.35 -enum class IssueCategory { 31.36 - Feature, Improvement, Bug, Task, Test 31.37 -} 31.38 - 31.39 -data class Issue(var id: Int) { 31.40 - 31.41 - var project: Project? = null 31.42 - var component: Component? = null 31.43 +data class Issue(override var id: Int, var project: Project, var component: Component? = null) : Entity { 31.44 31.45 var status = IssueStatus.InSpecification 31.46 var category = IssueCategory.Feature 31.47 31.48 - var subject: String? = null 31.49 + var subject: String = "" 31.50 var description: String? = null 31.51 var assignee: User? = null 31.52 31.53 - var affectedVersions = emptyList<Version>() 31.54 - var resolvedVersions = emptyList<Version>() 31.55 - 31.56 var created: Timestamp = Timestamp.from(Instant.now()) 31.57 var updated: Timestamp = Timestamp.from(Instant.now()) 31.58 var eta: Date? = null 31.59 31.60 + var affectedVersions = emptyList<Version>() 31.61 + var resolvedVersions = emptyList<Version>() 31.62 + 31.63 /** 31.64 * An issue is overdue, if it is not done and the ETA is before the current time. 31.65 */ 31.66 val overdue get() = status.phase != IssueStatusPhase.Done && eta?.before(Date(System.currentTimeMillis())) ?: false 31.67 } 31.68 31.69 -class IssueSummary { 31.70 - var open = 0 31.71 - var active = 0 31.72 - var done = 0 31.73 - 31.74 - val total get() = open + active + done 31.75 - 31.76 - val openPercent get() = 100 - activePercent - donePercent 31.77 - val activePercent get() = if (total > 0) (100f * active / total).roundToInt() else 0 31.78 - val donePercent get() = if (total > 0) (100f * done / total).roundToInt() else 100 31.79 - 31.80 - /** 31.81 - * Adds the specified issue to the summary by incrementing the respective counter. 31.82 - * @param issue the issue 31.83 - */ 31.84 - fun add(issue: Issue) { 31.85 - when (issue.status.phase) { 31.86 - IssueStatusPhase.Open -> open++ 31.87 - IssueStatusPhase.WorkInProgress -> active++ 31.88 - IssueStatusPhase.Done -> done++ 31.89 - } 31.90 - } 31.91 -} 31.92 -
32.1 --- a/src/main/kotlin/de/uapcore/lightpit/entities/IssueComment.kt Sun Dec 20 11:06:25 2020 +0100 32.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/IssueComment.kt Mon Dec 21 18:29:34 2020 +0100 32.3 @@ -28,9 +28,9 @@ 32.4 import java.sql.Timestamp 32.5 import java.time.Instant 32.6 32.7 -data class IssueComment(val id: Int) { 32.8 +data class IssueComment(override val id: Int, val issueid: Int) : Entity { 32.9 var author: User? = null 32.10 - var comment: String? = null 32.11 + var comment: String = "" 32.12 var created: Timestamp = Timestamp.from(Instant.now()) 32.13 var updated: Timestamp = Timestamp.from(Instant.now()) 32.14 var updateCount = 0
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/IssueSummary.kt Mon Dec 21 18:29:34 2020 +0100 33.3 @@ -0,0 +1,53 @@ 33.4 +/* 33.5 + * Copyright 2020 Mike Becker. All rights reserved. 33.6 + * 33.7 + * Redistribution and use in source and binary forms, with or without 33.8 + * modification, are permitted provided that the following conditions are met: 33.9 + * 33.10 + * 1. Redistributions of source code must retain the above copyright 33.11 + * notice, this list of conditions and the following disclaimer. 33.12 + * 33.13 + * 2. Redistributions in binary form must reproduce the above copyright 33.14 + * notice, this list of conditions and the following disclaimer in the 33.15 + * documentation and/or other materials provided with the distribution. 33.16 + * 33.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 33.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 33.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 33.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33.27 + */ 33.28 + 33.29 +package de.uapcore.lightpit.entities 33.30 + 33.31 +import de.uapcore.lightpit.types.IssueStatusPhase 33.32 +import kotlin.math.roundToInt 33.33 + 33.34 +class IssueSummary { 33.35 + var open = 0 33.36 + var active = 0 33.37 + var done = 0 33.38 + 33.39 + val total get() = open + active + done 33.40 + 33.41 + val openPercent get() = 100 - activePercent - donePercent 33.42 + val activePercent get() = if (total > 0) (100f * active / total).roundToInt() else 0 33.43 + val donePercent get() = if (total > 0) (100f * done / total).roundToInt() else 100 33.44 + 33.45 + /** 33.46 + * Adds the specified issue to the summary by incrementing the respective counter. 33.47 + * @param issue the issue 33.48 + */ 33.49 + fun add(issue: Issue) { 33.50 + when (issue.status.phase) { 33.51 + IssueStatusPhase.Open -> open++ 33.52 + IssueStatusPhase.WorkInProgress -> active++ 33.53 + IssueStatusPhase.Done -> done++ 33.54 + } 33.55 + } 33.56 +} 33.57 \ No newline at end of file
34.1 --- a/src/main/kotlin/de/uapcore/lightpit/entities/Project.kt Sun Dec 20 11:06:25 2020 +0100 34.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/Project.kt Mon Dec 21 18:29:34 2020 +0100 34.3 @@ -25,9 +25,9 @@ 34.4 34.5 package de.uapcore.lightpit.entities 34.6 34.7 -data class Project(val id: Int) { 34.8 - var name: String? = null 34.9 - var node: String? = null 34.10 +data class Project(override val id: Int) : Entity { 34.11 + var name: String = "" 34.12 + var node: String = name 34.13 var description: String? = null 34.14 var repoUrl: String? = null 34.15 var owner: User? = null
35.1 --- a/src/main/kotlin/de/uapcore/lightpit/entities/User.kt Sun Dec 20 11:06:25 2020 +0100 35.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/User.kt Mon Dec 21 18:29:34 2020 +0100 35.3 @@ -25,16 +25,17 @@ 35.4 35.5 package de.uapcore.lightpit.entities 35.6 35.7 -data class User(val id: Int) { 35.8 - var username = "" 35.9 - var mail = "" 35.10 - var givenname = "" 35.11 - var lastname = "" 35.12 +data class User(override val id: Int) : Entity { 35.13 + var username: String = "" 35.14 + var mail: String? = null 35.15 + var givenname: String? = null 35.16 + var lastname: String? = null 35.17 35.18 - val shortDisplayname: String get() { 35.19 - val str = "$givenname $lastname" 35.20 - return if (str.isBlank()) username else str.trim() 35.21 - } 35.22 + val shortDisplayname: String 35.23 + get() { 35.24 + val str = "${givenname ?: ""} ${lastname ?: ""}" 35.25 + return if (str.isBlank()) username else str.trim() 35.26 + } 35.27 35.28 - val displayname: String get() = if (mail.isBlank()) shortDisplayname else "$shortDisplayname <$mail>" 35.29 + val displayname: String get() = if (mail.isNullOrBlank()) shortDisplayname else "$shortDisplayname <$mail>" 35.30 } 35.31 \ No newline at end of file
36.1 --- a/src/main/kotlin/de/uapcore/lightpit/entities/Version.kt Sun Dec 20 11:06:25 2020 +0100 36.2 +++ b/src/main/kotlin/de/uapcore/lightpit/entities/Version.kt Mon Dec 21 18:29:34 2020 +0100 36.3 @@ -25,12 +25,9 @@ 36.4 36.5 package de.uapcore.lightpit.entities 36.6 36.7 -enum class VersionStatus { 36.8 - Future, Unreleased, Released, LTS, Deprecated; 36.9 - val isReleased get() = this.ordinal >= Released.ordinal 36.10 -} 36.11 +import de.uapcore.lightpit.types.VersionStatus 36.12 36.13 -data class Version(val id: Int) : Comparable<Version> { 36.14 +data class Version(override val id: Int, var projectid: Int) : Entity, Comparable<Version> { 36.15 var name: String = "" 36.16 var node = name 36.17 var ordinal = 0
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 37.2 +++ b/src/main/kotlin/de/uapcore/lightpit/filter/Filter.kt Mon Dec 21 18:29:34 2020 +0100 37.3 @@ -0,0 +1,32 @@ 37.4 +/* 37.5 + * Copyright 2020 Mike Becker. All rights reserved. 37.6 + * 37.7 + * Redistribution and use in source and binary forms, with or without 37.8 + * modification, are permitted provided that the following conditions are met: 37.9 + * 37.10 + * 1. Redistributions of source code must retain the above copyright 37.11 + * notice, this list of conditions and the following disclaimer. 37.12 + * 37.13 + * 2. Redistributions in binary form must reproduce the above copyright 37.14 + * notice, this list of conditions and the following disclaimer in the 37.15 + * documentation and/or other materials provided with the distribution. 37.16 + * 37.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 37.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 37.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 37.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 37.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 37.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 37.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37.27 + */ 37.28 + 37.29 +package de.uapcore.lightpit.filter 37.30 + 37.31 +sealed class Filter<T> 37.32 +class AllFilter<T> : Filter<T>() 37.33 +class NoneFilter<T> : Filter<T>() 37.34 +data class SpecificFilter<T>(val obj: T) : Filter<T>() 37.35 +data class RangeFilter<T>(val lower: T, val upper: T) : Filter<T>() where T : Comparable<T>
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/src/main/kotlin/de/uapcore/lightpit/filter/IssueFilter.kt Mon Dec 21 18:29:34 2020 +0100 38.3 @@ -0,0 +1,36 @@ 38.4 +/* 38.5 + * Copyright 2020 Mike Becker. All rights reserved. 38.6 + * 38.7 + * Redistribution and use in source and binary forms, with or without 38.8 + * modification, are permitted provided that the following conditions are met: 38.9 + * 38.10 + * 1. Redistributions of source code must retain the above copyright 38.11 + * notice, this list of conditions and the following disclaimer. 38.12 + * 38.13 + * 2. Redistributions in binary form must reproduce the above copyright 38.14 + * notice, this list of conditions and the following disclaimer in the 38.15 + * documentation and/or other materials provided with the distribution. 38.16 + * 38.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 38.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 38.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 38.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 38.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38.27 + */ 38.28 + 38.29 +package de.uapcore.lightpit.filter 38.30 + 38.31 +import de.uapcore.lightpit.entities.Component 38.32 +import de.uapcore.lightpit.entities.Project 38.33 +import de.uapcore.lightpit.entities.Version 38.34 + 38.35 +data class IssueFilter( 38.36 + val project: Filter<Project> = AllFilter(), 38.37 + val version: Filter<Version> = AllFilter(), 38.38 + val component: Filter<Component> = AllFilter() 38.39 +)
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/src/main/kotlin/de/uapcore/lightpit/types/IssueCategory.kt Mon Dec 21 18:29:34 2020 +0100 39.3 @@ -0,0 +1,30 @@ 39.4 +/* 39.5 + * Copyright 2020 Mike Becker. All rights reserved. 39.6 + * 39.7 + * Redistribution and use in source and binary forms, with or without 39.8 + * modification, are permitted provided that the following conditions are met: 39.9 + * 39.10 + * 1. Redistributions of source code must retain the above copyright 39.11 + * notice, this list of conditions and the following disclaimer. 39.12 + * 39.13 + * 2. Redistributions in binary form must reproduce the above copyright 39.14 + * notice, this list of conditions and the following disclaimer in the 39.15 + * documentation and/or other materials provided with the distribution. 39.16 + * 39.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 39.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 39.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 39.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 39.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 39.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39.27 + */ 39.28 + 39.29 +package de.uapcore.lightpit.types 39.30 + 39.31 +enum class IssueCategory { 39.32 + Feature, Improvement, Bug, Task, Test 39.33 +} 39.34 \ No newline at end of file
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 40.2 +++ b/src/main/kotlin/de/uapcore/lightpit/types/IssueStatus.kt Mon Dec 21 18:29:34 2020 +0100 40.3 @@ -0,0 +1,38 @@ 40.4 +/* 40.5 + * Copyright 2020 Mike Becker. All rights reserved. 40.6 + * 40.7 + * Redistribution and use in source and binary forms, with or without 40.8 + * modification, are permitted provided that the following conditions are met: 40.9 + * 40.10 + * 1. Redistributions of source code must retain the above copyright 40.11 + * notice, this list of conditions and the following disclaimer. 40.12 + * 40.13 + * 2. Redistributions in binary form must reproduce the above copyright 40.14 + * notice, this list of conditions and the following disclaimer in the 40.15 + * documentation and/or other materials provided with the distribution. 40.16 + * 40.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 40.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 40.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 40.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 40.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 40.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 40.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40.27 + */ 40.28 + 40.29 +package de.uapcore.lightpit.types 40.30 + 40.31 +enum class IssueStatus(val phase: IssueStatusPhase) { 40.32 + InSpecification(IssueStatusPhase.Open), 40.33 + ToDo(IssueStatusPhase.Open), 40.34 + Scheduled(IssueStatusPhase.Open), 40.35 + InProgress(IssueStatusPhase.WorkInProgress), 40.36 + InReview(IssueStatusPhase.WorkInProgress), 40.37 + Done(IssueStatusPhase.Done), 40.38 + Rejected(IssueStatusPhase.Done), 40.39 + Withdrawn(IssueStatusPhase.Done), 40.40 + Duplicate(IssueStatusPhase.Done); 40.41 +} 40.42 \ No newline at end of file
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 41.2 +++ b/src/main/kotlin/de/uapcore/lightpit/types/IssueStatusPhase.kt Mon Dec 21 18:29:34 2020 +0100 41.3 @@ -0,0 +1,34 @@ 41.4 +/* 41.5 + * Copyright 2020 Mike Becker. All rights reserved. 41.6 + * 41.7 + * Redistribution and use in source and binary forms, with or without 41.8 + * modification, are permitted provided that the following conditions are met: 41.9 + * 41.10 + * 1. Redistributions of source code must retain the above copyright 41.11 + * notice, this list of conditions and the following disclaimer. 41.12 + * 41.13 + * 2. Redistributions in binary form must reproduce the above copyright 41.14 + * notice, this list of conditions and the following disclaimer in the 41.15 + * documentation and/or other materials provided with the distribution. 41.16 + * 41.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 41.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 41.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 41.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 41.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 41.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41.27 + */ 41.28 + 41.29 +package de.uapcore.lightpit.types 41.30 + 41.31 +data class IssueStatusPhase(val number: Int) { 41.32 + companion object { 41.33 + val Open = IssueStatusPhase(0) 41.34 + val WorkInProgress = IssueStatusPhase(1) 41.35 + val Done = IssueStatusPhase(2) 41.36 + } 41.37 +} 41.38 \ No newline at end of file
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 42.2 +++ b/src/main/kotlin/de/uapcore/lightpit/types/VersionStatus.kt Mon Dec 21 18:29:34 2020 +0100 42.3 @@ -0,0 +1,32 @@ 42.4 +/* 42.5 + * Copyright 2020 Mike Becker. All rights reserved. 42.6 + * 42.7 + * Redistribution and use in source and binary forms, with or without 42.8 + * modification, are permitted provided that the following conditions are met: 42.9 + * 42.10 + * 1. Redistributions of source code must retain the above copyright 42.11 + * notice, this list of conditions and the following disclaimer. 42.12 + * 42.13 + * 2. Redistributions in binary form must reproduce the above copyright 42.14 + * notice, this list of conditions and the following disclaimer in the 42.15 + * documentation and/or other materials provided with the distribution. 42.16 + * 42.17 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 42.18 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42.19 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 42.20 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 42.21 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 42.22 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 42.23 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 42.24 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 42.25 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 42.26 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42.27 + */ 42.28 + 42.29 +package de.uapcore.lightpit.types 42.30 + 42.31 +enum class VersionStatus { 42.32 + Future, Unreleased, Released, LTS, Deprecated; 42.33 + 42.34 + val isReleased get() = this.ordinal >= Released.ordinal 42.35 +} 42.36 \ No newline at end of file
43.1 --- a/src/main/webapp/WEB-INF/jsp/project-navmenu.jsp Sun Dec 20 11:06:25 2020 +0100 43.2 +++ b/src/main/webapp/WEB-INF/jsp/project-navmenu.jsp Mon Dec 21 18:29:34 2020 +0100 43.3 @@ -26,7 +26,7 @@ 43.4 --%> 43.5 <%@page pageEncoding="UTF-8" 43.6 import="de.uapcore.lightpit.viewmodel.ProjectView" 43.7 - import="de.uapcore.lightpit.entities.VersionStatus" 43.8 + import="de.uapcore.lightpit.types.VersionStatus" 43.9 %> 43.10 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 43.11 <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>