Thu, 14 May 2020 22:48:01 +0200
projects can now be added and updated
1.1 --- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Wed May 13 21:46:26 2020 +0200 1.2 +++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Thu May 14 22:48:01 2020 +0200 1.3 @@ -39,6 +39,7 @@ 1.4 import javax.servlet.http.HttpServletResponse; 1.5 import javax.servlet.http.HttpSession; 1.6 import java.io.IOException; 1.7 +import java.lang.reflect.Constructor; 1.8 import java.lang.reflect.Method; 1.9 import java.lang.reflect.Modifier; 1.10 import java.sql.Connection; 1.11 @@ -225,6 +226,18 @@ 1.12 } 1.13 1.14 /** 1.15 + * @param req the servlet request object 1.16 + * @param location the location where to redirect 1.17 + * @see Constants#REQ_ATTR_REDIRECT_LOCATION 1.18 + */ 1.19 + public void setRedirectLocation(HttpServletRequest req, String location) { 1.20 + if (location.startsWith("./")) { 1.21 + location = location.replaceFirst("\\./", Functions.baseHref(req)); 1.22 + } 1.23 + req.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, location); 1.24 + } 1.25 + 1.26 + /** 1.27 * Specifies the name of an additional stylesheet used by the module. 1.28 * <p> 1.29 * Setting an additional stylesheet is optional, but quite common for HTML 1.30 @@ -240,6 +253,30 @@ 1.31 req.setAttribute(Constants.REQ_ATTR_STYLESHEET, Functions.enforceExt(stylesheet, ".css")); 1.32 } 1.33 1.34 + /** 1.35 + * Obtains a request parameter of the specified type. 1.36 + * The specified type must have a single-argument constructor accepting a string to perform conversion. 1.37 + * The constructor of the specified type may throw an exception on conversion failures. 1.38 + * 1.39 + * @param req the servlet request object 1.40 + * @param clazz the class object of the expected type 1.41 + * @param name the name of the parameter 1.42 + * @param <T> the expected type 1.43 + * @return the parameter value or an empty optional, if no parameter with the specified name was found 1.44 + */ 1.45 + public<T> Optional<T> getParameter(HttpServletRequest req, Class<T> clazz, String name) { 1.46 + final String paramValue = req.getParameter(name); 1.47 + if (paramValue == null) return Optional.empty(); 1.48 + if (clazz.equals(String.class)) return Optional.of((T)paramValue); 1.49 + try { 1.50 + final Constructor<T> ctor = clazz.getConstructor(String.class); 1.51 + return Optional.of(ctor.newInstance(paramValue)); 1.52 + } catch (ReflectiveOperationException e) { 1.53 + throw new RuntimeException(e); 1.54 + } 1.55 + 1.56 + } 1.57 + 1.58 private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp) 1.59 throws IOException, ServletException { 1.60 1.61 @@ -287,6 +324,7 @@ 1.62 } 1.63 1.64 // set some internal request attributes 1.65 + req.setAttribute(Constants.REQ_ATTR_BASE_HREF, Functions.baseHref(req)); 1.66 req.setAttribute(Constants.REQ_ATTR_PATH, Functions.fullPath(req)); 1.67 Optional.ofNullable(moduleInfo).ifPresent((proxy) -> req.setAttribute(Constants.REQ_ATTR_MODULE_INFO, proxy)); 1.68
2.1 --- a/src/main/java/de/uapcore/lightpit/Constants.java Wed May 13 21:46:26 2020 +0200 2.2 +++ b/src/main/java/de/uapcore/lightpit/Constants.java Thu May 14 22:48:01 2020 +0200 2.3 @@ -40,6 +40,7 @@ 2.4 2.5 public static final String DYN_FRAGMENT_PATH_PREFIX = "/WEB-INF/dynamic_fragments/"; 2.6 2.7 + public static final String DYN_FRAGMENT_COMMIT_SUCCESSFUL = "commit-successful"; 2.8 2.9 /** 2.10 * Name for the context parameter specifying the available languages. 2.11 @@ -77,6 +78,11 @@ 2.12 public static final String REQ_ATTR_SUB_MENU = fqn(AbstractLightPITServlet.class, "subMenu"); 2.13 2.14 /** 2.15 + * Key for the request attribute containing the base href. 2.16 + */ 2.17 + public static final String REQ_ATTR_BASE_HREF = fqn(AbstractLightPITServlet.class, "base_href"); 2.18 + 2.19 + /** 2.20 * Key for the request attribute containing the full path information (servlet path + path info). 2.21 */ 2.22 public static final String REQ_ATTR_PATH = fqn(AbstractLightPITServlet.class, "path"); 2.23 @@ -91,6 +97,11 @@ 2.24 */ 2.25 public static final String REQ_ATTR_STYLESHEET = fqn(AbstractLightPITServlet.class, "extraCss"); 2.26 2.27 + /** 2.28 + * Key for a location the page shall redirect to. 2.29 + * Will be used in a meta element. 2.30 + */ 2.31 + public static final String REQ_ATTR_REDIRECT_LOCATION = fqn(AbstractLightPITServlet.class, "redirectLocation"); 2.32 2.33 /** 2.34 * Key for the current language selection within the session.
3.1 --- a/src/main/java/de/uapcore/lightpit/Functions.java Wed May 13 21:46:26 2020 +0200 3.2 +++ b/src/main/java/de/uapcore/lightpit/Functions.java Thu May 14 22:48:01 2020 +0200 3.3 @@ -66,15 +66,12 @@ 3.4 return fqn(clazz.getName(), name); 3.5 } 3.6 3.7 - public static String fullPath(LightPITModule module, RequestMapping mapping) { 3.8 - StringBuilder sb = new StringBuilder(); 3.9 - sb.append(module.modulePath()); 3.10 - sb.append('/'); 3.11 - if (!mapping.requestPath().isEmpty()) { 3.12 - sb.append(mapping.requestPath().isEmpty()); 3.13 - sb.append('/'); 3.14 - } 3.15 - return sb.toString(); 3.16 + public static String baseHref(HttpServletRequest req) { 3.17 + return String.format("%s://%s:%d%s/", 3.18 + req.getScheme(), 3.19 + req.getServerName(), 3.20 + req.getServerPort(), 3.21 + req.getContextPath()); 3.22 } 3.23 3.24 public static String fullPath(HttpServletRequest req) {
4.1 --- a/src/main/java/de/uapcore/lightpit/dao/AbstractDao.java Wed May 13 21:46:26 2020 +0200 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,96 +0,0 @@ 4.4 -/* 4.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 4.6 - * 4.7 - * Copyright 2018 Mike Becker. All rights reserved. 4.8 - * 4.9 - * Redistribution and use in source and binary forms, with or without 4.10 - * modification, are permitted provided that the following conditions are met: 4.11 - * 4.12 - * 1. Redistributions of source code must retain the above copyright 4.13 - * notice, this list of conditions and the following disclaimer. 4.14 - * 4.15 - * 2. Redistributions in binary form must reproduce the above copyright 4.16 - * notice, this list of conditions and the following disclaimer in the 4.17 - * documentation and/or other materials provided with the distribution. 4.18 - * 4.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 4.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 4.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 4.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 4.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 4.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4.29 - * POSSIBILITY OF SUCH DAMAGE. 4.30 - * 4.31 - */ 4.32 -package de.uapcore.lightpit.dao; 4.33 - 4.34 -import java.sql.PreparedStatement; 4.35 -import java.sql.ResultSet; 4.36 -import java.sql.SQLException; 4.37 -import java.sql.Types; 4.38 -import java.util.ArrayList; 4.39 -import java.util.List; 4.40 -import java.util.Optional; 4.41 -import java.util.function.Function; 4.42 - 4.43 -public abstract class AbstractDao<T> implements GenericDao<T> { 4.44 - 4.45 - private final PreparedStatement listQuery; 4.46 - 4.47 - protected AbstractDao(PreparedStatement listQuery) { 4.48 - this.listQuery = listQuery; 4.49 - } 4.50 - 4.51 - public final T mapColumns(ResultSet result) throws SQLException { 4.52 - return mapColumns(result, ""); 4.53 - } 4.54 - 4.55 - public abstract T mapColumns(ResultSet result, String qualifier) throws SQLException; 4.56 - 4.57 - /** 4.58 - * Qualifies a column label if an qualifier is specified. 4.59 - * 4.60 - * @param qualifier an optional qualifier 4.61 - * @param label the column label 4.62 - * @return the label, qualified if necessary 4.63 - */ 4.64 - protected final String qual(String qualifier, String label) { 4.65 - if (qualifier == null || qualifier.isBlank()) { 4.66 - return label; 4.67 - } else { 4.68 - return qualifier + "." + label; 4.69 - } 4.70 - } 4.71 - 4.72 - protected final void setStringOrNull(PreparedStatement stmt, int index, String str) throws SQLException { 4.73 - if (str == null || str.isBlank()) { 4.74 - stmt.setNull(index, Types.VARCHAR); 4.75 - } else { 4.76 - stmt.setString(index, str); 4.77 - } 4.78 - } 4.79 - 4.80 - protected final <T> void setForeignKeyOrNull(PreparedStatement stmt, int index, T instance, Function<? super T, Integer> keyGetter) throws SQLException { 4.81 - Integer key = Optional.ofNullable(instance).map(keyGetter).orElse(null); 4.82 - if (key == null) { 4.83 - stmt.setNull(index, Types.INTEGER); 4.84 - } else { 4.85 - stmt.setInt(index, key); 4.86 - } 4.87 - } 4.88 - 4.89 - @Override 4.90 - public List<T> list() throws SQLException { 4.91 - List<T> list = new ArrayList<>(); 4.92 - try (ResultSet result = listQuery.executeQuery()) { 4.93 - while (result.next()) { 4.94 - list.add(mapColumns(result)); 4.95 - } 4.96 - } 4.97 - return list; 4.98 - } 4.99 -}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/main/java/de/uapcore/lightpit/dao/Functions.java Thu May 14 22:48:01 2020 +0200 5.3 @@ -0,0 +1,62 @@ 5.4 +/* 5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5.6 + * 5.7 + * Copyright 2018 Mike Becker. All rights reserved. 5.8 + * 5.9 + * Redistribution and use in source and binary forms, with or without 5.10 + * modification, are permitted provided that the following conditions are met: 5.11 + * 5.12 + * 1. Redistributions of source code must retain the above copyright 5.13 + * notice, this list of conditions and the following disclaimer. 5.14 + * 5.15 + * 2. Redistributions in binary form must reproduce the above copyright 5.16 + * notice, this list of conditions and the following disclaimer in the 5.17 + * documentation and/or other materials provided with the distribution. 5.18 + * 5.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 5.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 5.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 5.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 5.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 5.29 + * POSSIBILITY OF SUCH DAMAGE. 5.30 + * 5.31 + */ 5.32 +package de.uapcore.lightpit.dao; 5.33 + 5.34 +import java.sql.PreparedStatement; 5.35 +import java.sql.SQLException; 5.36 +import java.sql.Types; 5.37 +import java.util.Optional; 5.38 +import java.util.function.Function; 5.39 + 5.40 +/** 5.41 + * Some DAO utilities. 5.42 + */ 5.43 +public final class Functions { 5.44 + 5.45 + public static void setStringOrNull(PreparedStatement stmt, int index, String str) throws SQLException { 5.46 + if (str == null || str.isBlank()) { 5.47 + stmt.setNull(index, Types.VARCHAR); 5.48 + } else { 5.49 + stmt.setString(index, str); 5.50 + } 5.51 + } 5.52 + 5.53 + public static <T> void setForeignKeyOrNull(PreparedStatement stmt, int index, T instance, Function<? super T, Integer> keyGetter) throws SQLException { 5.54 + Integer key = Optional.ofNullable(instance).map(keyGetter).orElse(null); 5.55 + if (key == null) { 5.56 + stmt.setNull(index, Types.INTEGER); 5.57 + } else { 5.58 + stmt.setInt(index, key); 5.59 + } 5.60 + } 5.61 + 5.62 + private Functions() { 5.63 + 5.64 + } 5.65 +}
6.1 --- a/src/main/java/de/uapcore/lightpit/dao/GenericDao.java Wed May 13 21:46:26 2020 +0200 6.2 +++ b/src/main/java/de/uapcore/lightpit/dao/GenericDao.java Thu May 14 22:48:01 2020 +0200 6.3 @@ -41,6 +41,15 @@ 6.4 List<T> list() throws SQLException; 6.5 6.6 /** 6.7 + * Finds an entity by its integer ID. 6.8 + * 6.9 + * @param id the id 6.10 + * @return the enity or null if there is no such entity 6.11 + * @throws SQLException on any kind of SQL errors 6.12 + */ 6.13 + T find(int id) throws SQLException; 6.14 + 6.15 + /** 6.16 * Inserts an instance into database. 6.17 * 6.18 * @param instance the instance to insert
7.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java Wed May 13 21:46:26 2020 +0200 7.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java Thu May 14 22:48:01 2020 +0200 7.3 @@ -41,9 +41,8 @@ 7.4 private final ProjectDao projectDao; 7.5 7.6 public PGDataAccessObjects(Connection connection) throws SQLException { 7.7 - final PGUserDao pgUserDao = new PGUserDao(connection); 7.8 - userDao = pgUserDao; 7.9 - projectDao = new PGProjectDao(connection, pgUserDao); 7.10 + userDao = new PGUserDao(connection); 7.11 + projectDao = new PGProjectDao(connection); 7.12 } 7.13 7.14 @Override
8.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java Wed May 13 21:46:26 2020 +0200 8.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGProjectDao.java Thu May 14 22:48:01 2020 +0200 8.3 @@ -28,7 +28,7 @@ 8.4 */ 8.5 package de.uapcore.lightpit.dao.postgres; 8.6 8.7 -import de.uapcore.lightpit.dao.AbstractDao; 8.8 +import de.uapcore.lightpit.dao.GenericDao; 8.9 import de.uapcore.lightpit.dao.ProjectDao; 8.10 import de.uapcore.lightpit.entities.Project; 8.11 import de.uapcore.lightpit.entities.User; 8.12 @@ -37,18 +37,31 @@ 8.13 import java.sql.PreparedStatement; 8.14 import java.sql.ResultSet; 8.15 import java.sql.SQLException; 8.16 +import java.util.ArrayList; 8.17 +import java.util.List; 8.18 import java.util.Objects; 8.19 8.20 -public final class PGProjectDao extends AbstractDao<Project> implements ProjectDao { 8.21 +import static de.uapcore.lightpit.dao.Functions.setForeignKeyOrNull; 8.22 +import static de.uapcore.lightpit.dao.Functions.setStringOrNull; 8.23 8.24 - private final PGUserDao userDao; 8.25 +public final class PGProjectDao implements ProjectDao, GenericDao<Project> { 8.26 8.27 - private final PreparedStatement insert; 8.28 - private final PreparedStatement update; 8.29 + private final PreparedStatement insert, update, list, find; 8.30 8.31 - public PGProjectDao(Connection connection, PGUserDao userDao) throws SQLException { 8.32 - super(connection.prepareStatement( 8.33 - "select * from lpit_project join lpit_user owner on lpit_project.owner = owner.userid")); 8.34 + public PGProjectDao(Connection connection) throws SQLException { 8.35 + list = connection.prepareStatement( 8.36 + "select id, name, description, repourl, " + 8.37 + "userid, username, lastname, givenname, mail " + 8.38 + "from lpit_project " + 8.39 + "left join lpit_user owner on lpit_project.owner = owner.userid " + 8.40 + "order by name"); 8.41 + 8.42 + find = connection.prepareStatement( 8.43 + "select id, name, description, repourl, " + 8.44 + "userid, username, lastname, givenname, mail " + 8.45 + "from lpit_project " + 8.46 + "left join lpit_user owner on lpit_project.owner = owner.userid " + 8.47 + "where id = ?"); 8.48 8.49 insert = connection.prepareStatement( 8.50 "insert into lpit_project (name, description, repourl, owner) values (?, ?, ?, ?)" 8.51 @@ -56,17 +69,24 @@ 8.52 update = connection.prepareStatement( 8.53 "update lpit_project set name = ?, description = ?, repourl = ?, owner = ? where id = ?" 8.54 ); 8.55 - 8.56 - this.userDao = userDao; 8.57 } 8.58 8.59 - @Override 8.60 - public Project mapColumns(ResultSet result, String q) throws SQLException { 8.61 - final var proj = new Project(result.getInt(qual(q, "id"))); 8.62 - proj.setName(result.getString(qual(q, "name"))); 8.63 - proj.setDescription(result.getString(qual(q, "description"))); 8.64 - proj.setRepoUrl(result.getString(qual(q, "repourl"))); 8.65 - proj.setOwner(userDao.mapColumns(result, "owner")); 8.66 + public Project mapColumns(ResultSet result) throws SQLException { 8.67 + final var proj = new Project(result.getInt("id")); 8.68 + proj.setName(result.getString("name")); 8.69 + proj.setDescription(result.getString("description")); 8.70 + proj.setRepoUrl(result.getString("repourl")); 8.71 + 8.72 + final int id = result.getInt("userid"); 8.73 + if (id != 0) { 8.74 + final var user = new User(id); 8.75 + user.setUsername(result.getString("username")); 8.76 + user.setGivenname(result.getString("givenname")); 8.77 + user.setLastname(result.getString("lastname")); 8.78 + user.setMail(result.getString("mail")); 8.79 + proj.setOwner(user); 8.80 + } 8.81 + 8.82 return proj; 8.83 } 8.84 8.85 @@ -87,6 +107,30 @@ 8.86 setStringOrNull(update, 2, instance.getDescription()); 8.87 setStringOrNull(update, 3, instance.getRepoUrl()); 8.88 setForeignKeyOrNull(update, 4, instance.getOwner(), User::getUserID); 8.89 + update.setInt(5, instance.getId()); 8.90 return update.executeUpdate() > 0; 8.91 } 8.92 + 8.93 + @Override 8.94 + public List<Project> list() throws SQLException { 8.95 + List<Project> projects = new ArrayList<>(); 8.96 + try (var result = list.executeQuery()) { 8.97 + while (result.next()) { 8.98 + projects.add(mapColumns(result)); 8.99 + } 8.100 + } 8.101 + return projects; 8.102 + } 8.103 + 8.104 + @Override 8.105 + public Project find(int id) throws SQLException { 8.106 + find.setInt(1, id); 8.107 + try (var result = find.executeQuery()) { 8.108 + if (result.next()) { 8.109 + return mapColumns(result); 8.110 + } else { 8.111 + return null; 8.112 + } 8.113 + } 8.114 + } 8.115 }
9.1 --- a/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java Wed May 13 21:46:26 2020 +0200 9.2 +++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java Thu May 14 22:48:01 2020 +0200 9.3 @@ -28,7 +28,7 @@ 9.4 */ 9.5 package de.uapcore.lightpit.dao.postgres; 9.6 9.7 -import de.uapcore.lightpit.dao.AbstractDao; 9.8 +import de.uapcore.lightpit.dao.GenericDao; 9.9 import de.uapcore.lightpit.dao.UserDao; 9.10 import de.uapcore.lightpit.entities.User; 9.11 9.12 @@ -36,26 +36,41 @@ 9.13 import java.sql.PreparedStatement; 9.14 import java.sql.ResultSet; 9.15 import java.sql.SQLException; 9.16 +import java.util.ArrayList; 9.17 +import java.util.List; 9.18 import java.util.Objects; 9.19 9.20 -public final class PGUserDao extends AbstractDao<User> implements UserDao { 9.21 +import static de.uapcore.lightpit.dao.Functions.setStringOrNull; 9.22 9.23 - private final PreparedStatement insert; 9.24 - private final PreparedStatement update; 9.25 +public final class PGUserDao implements UserDao, GenericDao<User> { 9.26 + 9.27 + public static final String[] COLUMNS = { 9.28 + "id", "username", "lastname", "givenname", "mail" 9.29 + }; 9.30 + 9.31 + private final PreparedStatement insert, update, list, find; 9.32 9.33 public PGUserDao(Connection connection) throws SQLException { 9.34 - super(connection.prepareStatement("select * from lpit_user where userid >= 0 order by username")); 9.35 + list = connection.prepareStatement( 9.36 + "select userid, username, lastname, givenname, mail " + 9.37 + "from lpit_user where userid >= 0 " + 9.38 + "order by username"); 9.39 + find = connection.prepareStatement( 9.40 + "select userid, username, lastname, givenname, mail " + 9.41 + "from lpit_user where userid = ? "); 9.42 9.43 insert = connection.prepareStatement("insert into lpit_user (username, lastname, givenname, mail) values (?, ?, ?, ?)"); 9.44 update = connection.prepareStatement("update lpit_user set lastname = ?, givenname = ?, mail = ? where userid = ?"); 9.45 } 9.46 9.47 - @Override 9.48 - public User mapColumns(ResultSet result, String q) throws SQLException { 9.49 - final var user = new User(result.getInt(qual(q, "userid"))); 9.50 - user.setUsername(result.getString(qual(q, "username"))); 9.51 - user.setGivenname(result.getString(qual(q, "givenname"))); 9.52 - user.setLastname(result.getString(qual(q, "lastname"))); 9.53 + public User mapColumns(ResultSet result) throws SQLException { 9.54 + final int id = result.getInt("userid"); 9.55 + if (id == 0) return null; 9.56 + final var user = new User(id); 9.57 + user.setUsername(result.getString("username")); 9.58 + user.setGivenname(result.getString("givenname")); 9.59 + user.setLastname(result.getString("lastname")); 9.60 + user.setMail(result.getString("mail")); 9.61 return user; 9.62 } 9.63 9.64 @@ -77,4 +92,27 @@ 9.65 update.setInt(4, instance.getUserID()); 9.66 return update.executeUpdate() > 0; 9.67 } 9.68 + 9.69 + @Override 9.70 + public List<User> list() throws SQLException { 9.71 + List<User> users = new ArrayList<>(); 9.72 + try (var result = list.executeQuery()) { 9.73 + while (result.next()) { 9.74 + users.add(mapColumns(result)); 9.75 + } 9.76 + } 9.77 + return users; 9.78 + } 9.79 + 9.80 + @Override 9.81 + public User find(int id) throws SQLException { 9.82 + find.setInt(1, id); 9.83 + try (var result = find.executeQuery()) { 9.84 + if (result.next()) { 9.85 + return mapColumns(result); 9.86 + } else { 9.87 + return null; 9.88 + } 9.89 + } 9.90 + } 9.91 }
10.1 --- a/src/main/java/de/uapcore/lightpit/entities/Project.java Wed May 13 21:46:26 2020 +0200 10.2 +++ b/src/main/java/de/uapcore/lightpit/entities/Project.java Thu May 14 22:48:01 2020 +0200 10.3 @@ -28,8 +28,6 @@ 10.4 */ 10.5 package de.uapcore.lightpit.entities; 10.6 10.7 -import java.util.ArrayList; 10.8 -import java.util.List; 10.9 import java.util.Objects; 10.10 10.11 public class Project { 10.12 @@ -40,8 +38,6 @@ 10.13 private String repoUrl; 10.14 private User owner; 10.15 10.16 - private final List<Version> versions = new ArrayList<>(); 10.17 - 10.18 public Project(int id) { 10.19 this.id = id; 10.20 } 10.21 @@ -82,10 +78,6 @@ 10.22 this.owner = owner; 10.23 } 10.24 10.25 - public List<Version> getVersions() { 10.26 - return versions; 10.27 - } 10.28 - 10.29 @Override 10.30 public boolean equals(Object o) { 10.31 if (this == o) return true;
11.1 --- a/src/main/java/de/uapcore/lightpit/entities/User.java Wed May 13 21:46:26 2020 +0200 11.2 +++ b/src/main/java/de/uapcore/lightpit/entities/User.java Thu May 14 22:48:01 2020 +0200 11.3 @@ -80,6 +80,19 @@ 11.4 this.lastname = lastname; 11.5 } 11.6 11.7 + public String getDisplayname() { 11.8 + StringBuilder dn = new StringBuilder(); 11.9 + dn.append(givenname); 11.10 + dn.append(' '); 11.11 + dn.append(lastname); 11.12 + dn.append(' '); 11.13 + if (mail != null && !mail.isBlank()) { 11.14 + dn.append("<"+mail+">"); 11.15 + } 11.16 + final var str = dn.toString().trim(); 11.17 + return str.isBlank() ? username : str; 11.18 + } 11.19 + 11.20 @Override 11.21 public boolean equals(Object o) { 11.22 if (this == o) return true;
12.1 --- a/src/main/java/de/uapcore/lightpit/modules/HomeModule.java Wed May 13 21:46:26 2020 +0200 12.2 +++ b/src/main/java/de/uapcore/lightpit/modules/HomeModule.java Thu May 14 22:48:01 2020 +0200 12.3 @@ -31,6 +31,7 @@ 12.4 import de.uapcore.lightpit.*; 12.5 12.6 import javax.servlet.annotation.WebServlet; 12.7 +import javax.servlet.http.HttpServletRequest; 12.8 12.9 /** 12.10 * Entry point for the application. 12.11 @@ -47,7 +48,10 @@ 12.12 public final class HomeModule extends AbstractLightPITServlet { 12.13 12.14 @RequestMapping(method = HttpMethod.GET) 12.15 - public ResponseType handle() { 12.16 + public ResponseType handle(HttpServletRequest req) { 12.17 + 12.18 + setDynamicFragment(req, "home"); 12.19 + setStylesheet(req, "home"); 12.20 12.21 return ResponseType.HTML; 12.22 }
13.1 --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Wed May 13 21:46:26 2020 +0200 13.2 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Thu May 14 22:48:01 2020 +0200 13.3 @@ -31,9 +31,13 @@ 13.4 13.5 import de.uapcore.lightpit.*; 13.6 import de.uapcore.lightpit.dao.DataAccessObjects; 13.7 +import de.uapcore.lightpit.entities.Project; 13.8 +import de.uapcore.lightpit.entities.User; 13.9 13.10 import javax.servlet.annotation.WebServlet; 13.11 import javax.servlet.http.HttpServletRequest; 13.12 +import java.sql.SQLException; 13.13 +import java.util.Optional; 13.14 13.15 @LightPITModule( 13.16 bundleBaseName = "localization.projects", 13.17 @@ -47,12 +51,59 @@ 13.18 public final class ProjectsModule extends AbstractLightPITServlet { 13.19 13.20 @RequestMapping(method = HttpMethod.GET) 13.21 - public ResponseType index(HttpServletRequest req, DataAccessObjects dao) { 13.22 + public ResponseType index(HttpServletRequest req, DataAccessObjects dao) throws SQLException { 13.23 + final var projectDao = dao.getProjectDao(); 13.24 + 13.25 + req.setAttribute("projects", projectDao.list()); 13.26 + setDynamicFragment(req, "projects"); 13.27 13.28 return ResponseType.HTML; 13.29 } 13.30 13.31 - @RequestMapping(method = HttpMethod.GET, requestPath = "versions", menuKey = "menu.versions") 13.32 + @RequestMapping(requestPath = "edit", method = HttpMethod.GET) 13.33 + public ResponseType displayCreateForm(HttpServletRequest req, DataAccessObjects dao) throws SQLException { 13.34 + final var projectDao = dao.getProjectDao(); 13.35 + 13.36 + Optional<Integer> id = getParameter(req, Integer.class, "id"); 13.37 + if (id.isPresent()) { 13.38 + req.setAttribute("project", Optional.ofNullable(projectDao.find(id.get())).orElse(new Project(-1))); 13.39 + } else { 13.40 + req.setAttribute("project", new Project(-1)); 13.41 + } 13.42 + 13.43 + setDynamicFragment(req, "project-form"); 13.44 + 13.45 + return ResponseType.HTML; 13.46 + } 13.47 + 13.48 + @RequestMapping(requestPath = "commit", method = HttpMethod.POST) 13.49 + public ResponseType commit(HttpServletRequest req, DataAccessObjects dao) { 13.50 + 13.51 + Project project = new Project(-1); 13.52 + try { 13.53 + project = new Project(getParameter(req, Integer.class, "id").orElseThrow()); 13.54 + project.setName(getParameter(req, String.class, "name").orElseThrow()); 13.55 + getParameter(req, String.class, "description").ifPresent(project::setDescription); 13.56 + getParameter(req, String.class, "repoUrl").ifPresent(project::setRepoUrl); 13.57 + getParameter(req, Integer.class, "owner").map( 13.58 + ownerId -> ownerId >= 0 ? new User(ownerId) : null 13.59 + ).ifPresent(project::setOwner); 13.60 + 13.61 + dao.getProjectDao().saveOrUpdate(project); 13.62 + 13.63 + setRedirectLocation(req, "./projects/"); 13.64 + setDynamicFragment(req, Constants.DYN_FRAGMENT_COMMIT_SUCCESSFUL); 13.65 + } catch (NullPointerException | NumberFormatException | SQLException ex) { 13.66 + // TODO: set request attribute with error text 13.67 + req.setAttribute("project", project); 13.68 + setDynamicFragment(req, "project-form"); 13.69 + } 13.70 + 13.71 + return ResponseType.HTML; 13.72 + } 13.73 + 13.74 + 13.75 + @RequestMapping(requestPath = "versions", method = HttpMethod.GET, menuKey = "menu.versions") 13.76 public ResponseType versions(HttpServletRequest req, DataAccessObjects dao) { 13.77 13.78 return ResponseType.HTML;
14.1 --- a/src/main/resources/localization/home.properties Wed May 13 21:46:26 2020 +0200 14.2 +++ b/src/main/resources/localization/home.properties Thu May 14 22:48:01 2020 +0200 14.3 @@ -24,3 +24,5 @@ 14.4 name = Home Page 14.5 description = The default page that is displayed when visiting the site. 14.6 menuLabel = Home 14.7 + 14.8 +version=LightPIT - Version 0.1 (Snapshot) 14.9 \ No newline at end of file
15.1 --- a/src/main/resources/localization/home_de.properties Wed May 13 21:46:26 2020 +0200 15.2 +++ b/src/main/resources/localization/home_de.properties Thu May 14 22:48:01 2020 +0200 15.3 @@ -24,3 +24,5 @@ 15.4 name = Startseite 15.5 description = Die Seite, die dem Benutzer standardm\u00e4\u00dfig beim Besuch angezeigt wird. 15.6 menuLabel = Startseite 15.7 + 15.8 +version=LightPIT - Version 0.1 (Entwicklungsversion)
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/src/main/resources/localization/lightpit.properties Thu May 14 22:48:01 2020 +0200 16.3 @@ -0,0 +1,28 @@ 16.4 +# Copyright 2018 Mike Becker. All rights reserved. 16.5 +# 16.6 +# Redistribution and use in source and binary forms, with or without 16.7 +# modification, are permitted provided that the following conditions are met: 16.8 +# 16.9 +# 1. Redistributions of source code must retain the above copyright 16.10 +# notice, this list of conditions and the following disclaimer. 16.11 +# 16.12 +# 2. Redistributions in binary form must reproduce the above copyright 16.13 +# notice, this list of conditions and the following disclaimer in the 16.14 +# documentation and/or other materials provided with the distribution. 16.15 +# 16.16 +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16.17 +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16.18 +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16.19 +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 16.20 +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 16.21 +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 16.22 +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 16.23 +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 16.24 +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 16.25 +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16.26 + 16.27 +button.okay=OK 16.28 +button.cancel=Cancel 16.29 + 16.30 +commit.success=Operation successful - you will be redirected in a second. 16.31 +commit.redirect-link=If redirection does not work, click the following link: 16.32 \ No newline at end of file
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/src/main/resources/localization/lightpit_de.properties Thu May 14 22:48:01 2020 +0200 17.3 @@ -0,0 +1,28 @@ 17.4 +# Copyright 2018 Mike Becker. All rights reserved. 17.5 +# 17.6 +# Redistribution and use in source and binary forms, with or without 17.7 +# modification, are permitted provided that the following conditions are met: 17.8 +# 17.9 +# 1. Redistributions of source code must retain the above copyright 17.10 +# notice, this list of conditions and the following disclaimer. 17.11 +# 17.12 +# 2. Redistributions in binary form must reproduce the above copyright 17.13 +# notice, this list of conditions and the following disclaimer in the 17.14 +# documentation and/or other materials provided with the distribution. 17.15 +# 17.16 +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17.17 +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17.18 +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17.19 +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17.20 +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17.21 +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 17.22 +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 17.23 +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 17.24 +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 17.25 +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17.26 + 17.27 +button.okay=OK 17.28 +button.cancel=Abbrechen 17.29 + 17.30 +commit.success=Operation erfolgreich - Sie werden jeden Moment weitergeleitet. 17.31 +commit.redirect-link=Falls die Weiterleitung nicht klappt, klicken Sie bitte hier:
18.1 --- a/src/main/resources/localization/projects.properties Wed May 13 21:46:26 2020 +0200 18.2 +++ b/src/main/resources/localization/projects.properties Thu May 14 22:48:01 2020 +0200 18.3 @@ -20,7 +20,20 @@ 18.4 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 18.5 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 18.6 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18.7 + 18.8 name=Project Management 18.9 description=Allows the configuration of projects. 18.10 menuLabel=Projects 18.11 + 18.12 menu.versions=Versions 18.13 + 18.14 +button.create=New Project 18.15 + 18.16 +no-projects=Welcome to LightPIT. Start off by creating a new project! 18.17 + 18.18 +thead.name=Name 18.19 +thead.description=Description 18.20 +thead.repoUrl=Repository 18.21 +thead.owner=Project Lead 18.22 + 18.23 +placeholder.null-owner=Unassigned
19.1 --- a/src/main/resources/localization/projects_de.properties Wed May 13 21:46:26 2020 +0200 19.2 +++ b/src/main/resources/localization/projects_de.properties Thu May 14 22:48:01 2020 +0200 19.3 @@ -20,7 +20,20 @@ 19.4 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 19.5 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 19.6 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19.7 + 19.8 name=Projektverwaltung 19.9 description=Erlaubt die Konfiguration von Projekten. 19.10 menuLabel=Projekte 19.11 -menu.versions=Versionen 19.12 \ No newline at end of file 19.13 + 19.14 +menu.versions=Versionen 19.15 + 19.16 +button.create=Neues Projekt 19.17 + 19.18 +no-projects=Wilkommen bei LightPIT. Beginnen Sie mit der Erstellung eines Projektes! 19.19 + 19.20 +thead.name=Name 19.21 +thead.description=Beschreibung 19.22 +thead.repoUrl=Repository 19.23 +thead.owner=Projektleitung 19.24 + 19.25 +placeholder.null-owner=Nicht Zugewiesen
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/src/main/webapp/WEB-INF/dynamic_fragments/commit-successful.jsp Thu May 14 22:48:01 2020 +0200 20.3 @@ -0,0 +1,34 @@ 20.4 +<%-- 20.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 20.6 + 20.7 +Copyright 2018 Mike Becker. All rights reserved. 20.8 + 20.9 +Redistribution and use in source and binary forms, with or without 20.10 +modification, are permitted provided that the following conditions are met: 20.11 + 20.12 +1. Redistributions of source code must retain the above copyright 20.13 +notice, this list of conditions and the following disclaimer. 20.14 + 20.15 +2. Redistributions in binary form must reproduce the above copyright 20.16 +notice, this list of conditions and the following disclaimer in the 20.17 +documentation and/or other materials provided with the distribution. 20.18 + 20.19 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20.20 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20.21 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20.22 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20.23 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20.24 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20.25 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20.26 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 20.27 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 20.28 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 20.29 +--%> 20.30 +<%@page pageEncoding="UTF-8" %> 20.31 +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 20.32 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 20.33 + 20.34 +<c:set scope="page" var="redirectLocation" value="${requestScope[Constants.REQ_ATTR_REDIRECT_LOCATION]}"/> 20.35 + 20.36 +<fmt:message bundle="${lightpit_bundle}" key="commit.success" /> 20.37 +<fmt:message bundle="${lightpit_bundle}" key="commit.redirect-link" />
21.1 --- a/src/main/webapp/WEB-INF/dynamic_fragments/error.jsp Wed May 13 21:46:26 2020 +0200 21.2 +++ b/src/main/webapp/WEB-INF/dynamic_fragments/error.jsp Thu May 14 22:48:01 2020 +0200 21.3 @@ -25,11 +25,13 @@ 21.4 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21.5 --%> 21.6 <%@page pageEncoding="UTF-8" %> 21.7 +<%@page import="de.uapcore.lightpit.Constants" %> 21.8 <%@page import="de.uapcore.lightpit.modules.ErrorModule" %> 21.9 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 21.10 <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 21.11 <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 21.12 21.13 +<c:set scope="page" var="baseHref" value="${requestScope[Constants.REQ_ATTR_BASE_HREF]}" /> 21.14 <c:set scope="page" var="errorCode" value="${requestScope[ErrorModule.REQ_ATTR_ERROR_CODE]}"/> 21.15 <c:set scope="page" var="returnLink" value="${requestScope[ErrorModule.REQ_ATTR_RETURN_LINK]}"/> 21.16
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/src/main/webapp/WEB-INF/dynamic_fragments/home.jsp Thu May 14 22:48:01 2020 +0200 22.3 @@ -0,0 +1,32 @@ 22.4 +<%-- 22.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 22.6 + 22.7 +Copyright 2018 Mike Becker. All rights reserved. 22.8 + 22.9 +Redistribution and use in source and binary forms, with or without 22.10 +modification, are permitted provided that the following conditions are met: 22.11 + 22.12 +1. Redistributions of source code must retain the above copyright 22.13 +notice, this list of conditions and the following disclaimer. 22.14 + 22.15 +2. Redistributions in binary form must reproduce the above copyright 22.16 +notice, this list of conditions and the following disclaimer in the 22.17 +documentation and/or other materials provided with the distribution. 22.18 + 22.19 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22.20 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22.21 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22.22 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22.23 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22.24 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22.25 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22.26 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22.27 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22.28 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22.29 +--%> 22.30 +<%@page pageEncoding="UTF-8" %> 22.31 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 22.32 + 22.33 +<div class="smalltext"> 22.34 + <fmt:message key="version" /> 22.35 +</div> 22.36 \ No newline at end of file
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 23.2 +++ b/src/main/webapp/WEB-INF/dynamic_fragments/project-form.jsp Thu May 14 22:48:01 2020 +0200 23.3 @@ -0,0 +1,75 @@ 23.4 +<%-- 23.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 23.6 + 23.7 +Copyright 2018 Mike Becker. All rights reserved. 23.8 + 23.9 +Redistribution and use in source and binary forms, with or without 23.10 +modification, are permitted provided that the following conditions are met: 23.11 + 23.12 +1. Redistributions of source code must retain the above copyright 23.13 +notice, this list of conditions and the following disclaimer. 23.14 + 23.15 +2. Redistributions in binary form must reproduce the above copyright 23.16 +notice, this list of conditions and the following disclaimer in the 23.17 +documentation and/or other materials provided with the distribution. 23.18 + 23.19 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23.20 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23.21 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23.22 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23.23 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23.24 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23.25 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23.26 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23.27 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23.28 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23.29 +--%> 23.30 +<%@page pageEncoding="UTF-8" %> 23.31 +<%@page import="de.uapcore.lightpit.Constants" %> 23.32 +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 23.33 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 23.34 + 23.35 +<c:set scope="page" var="moduleInfo" value="${requestScope[Constants.REQ_ATTR_MODULE_INFO]}"/> 23.36 + 23.37 +<jsp:useBean id="project" type="de.uapcore.lightpit.entities.Project" scope="request"/> 23.38 + 23.39 +<form action="./${moduleInfo.modulePath}/commit" method="post"> 23.40 + <table class="formtable" style="width: 80ch"> 23.41 + <colgroup> 23.42 + <col> 23.43 + <col style="width: 100%"> 23.44 + </colgroup> 23.45 + <tbody> 23.46 + <tr> 23.47 + <th><fmt:message key="thead.name"/></th> 23.48 + <td><input name="name" type="text" maxlength="20" required value="${project.name}"/> </td> 23.49 + </tr> 23.50 + <tr> 23.51 + <th class="vtop"><fmt:message key="thead.description"/></th> 23.52 + <td><input type="text" name="description" maxlength="200" value="${project.description}" /> </td> 23.53 + </tr> 23.54 + <tr> 23.55 + <th><fmt:message key="thead.repoUrl"/></th> 23.56 + <td><input name="repoUrl" type="url" maxlength="50" value="${project.repoUrl}" /> </td> 23.57 + </tr> 23.58 + <tr> 23.59 + <th><fmt:message key="thead.owner"/></th> 23.60 + <td> 23.61 + <select name="owner"> 23.62 + <option value="-1"><fmt:message key="placeholder.null-owner" /> </option> 23.63 + <!-- TODO: add user selection --> 23.64 + </select> 23.65 + </td> 23.66 + </tr> 23.67 + </tbody> 23.68 + <tfoot> 23.69 + <tr> 23.70 + <td colspan="2"> 23.71 + <input type="hidden" name="id" value="${project.id}" /> 23.72 + <a href="./${moduleInfo.modulePath}" class="button"><fmt:message bundle="${lightpit_bundle}" key="button.cancel"/></a> 23.73 + <button type="submit"><fmt:message bundle="${lightpit_bundle}" key="button.okay" /></button> 23.74 + </td> 23.75 + </tr> 23.76 + </tfoot> 23.77 + </table> 23.78 +</form>
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/src/main/webapp/WEB-INF/dynamic_fragments/projects.jsp Thu May 14 22:48:01 2020 +0200 24.3 @@ -0,0 +1,83 @@ 24.4 +<%-- 24.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 24.6 + 24.7 +Copyright 2018 Mike Becker. All rights reserved. 24.8 + 24.9 +Redistribution and use in source and binary forms, with or without 24.10 +modification, are permitted provided that the following conditions are met: 24.11 + 24.12 +1. Redistributions of source code must retain the above copyright 24.13 +notice, this list of conditions and the following disclaimer. 24.14 + 24.15 +2. Redistributions in binary form must reproduce the above copyright 24.16 +notice, this list of conditions and the following disclaimer in the 24.17 +documentation and/or other materials provided with the distribution. 24.18 + 24.19 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24.20 +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24.21 +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24.22 +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24.23 +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24.24 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24.25 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24.26 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24.27 +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24.28 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24.29 +--%> 24.30 +<%@page pageEncoding="UTF-8" %> 24.31 +<%@page import="de.uapcore.lightpit.Constants" %> 24.32 +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 24.33 +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 24.34 + 24.35 +<c:set scope="page" var="moduleInfo" value="${requestScope[Constants.REQ_ATTR_MODULE_INFO]}"/> 24.36 + 24.37 +<jsp:useBean id="projects" type="java.util.List<de.uapcore.lightpit.entities.Project>" scope="request"/> 24.38 + 24.39 +<c:if test="${empty projects}"> 24.40 + <div class="info-box"> 24.41 + <fmt:message key="no-projects" /> 24.42 + </div> 24.43 +</c:if> 24.44 + 24.45 +<div id="tool-area"> 24.46 + <a href="./${moduleInfo.modulePath}/edit" class="button"><fmt:message key="button.create" /></a> 24.47 +</div> 24.48 + 24.49 +<c:if test="${not empty projects}"> 24.50 +<table class="datatable medskip"> 24.51 + <colgroup> 24.52 + <col> 24.53 + <col style="width: 15%"> 24.54 + <col style="width: 35%"> 24.55 + <col style="width: 30%"> 24.56 + <col style="width: 20%"> 24.57 + </colgroup> 24.58 + <thead> 24.59 + <tr> 24.60 + <th></th> 24.61 + <th><fmt:message key="thead.name"/></th> 24.62 + <th><fmt:message key="thead.description"/></th> 24.63 + <th><fmt:message key="thead.repoUrl"/></th> 24.64 + <th><fmt:message key="thead.owner"/></th> 24.65 + </tr> 24.66 + </thead> 24.67 + <tbody> 24.68 + <c:forEach var="project" items="${projects}"> 24.69 + <tr> 24.70 + <td><a href="./${moduleInfo.modulePath}/edit?id=${project.id}">✎</a></td> 24.71 + <td><c:out value="${project.name}"/></td> 24.72 + <td><c:out value="${project.description}"/></td> 24.73 + <td> 24.74 + <c:if test="${not empty project.repoUrl}"> 24.75 + <a target="_blank" href="<c:out value="${project.repoUrl}"/>"><c:out value="${project.repoUrl}"/></a> 24.76 + </c:if> 24.77 + </td> 24.78 + <td> 24.79 + <c:if test="${not empty project.owner}"><c:out value="${project.owner.displayname}"/></c:if> 24.80 + <c:if test="${empty project.owner}"><fmt:message key="placeholder.null-owner" /></c:if> 24.81 + </td> 24.82 + </tr> 24.83 + </c:forEach> 24.84 + </tbody> 24.85 +</table> 24.86 +</c:if>
25.1 --- a/src/main/webapp/WEB-INF/jsp/site.jsp Wed May 13 21:46:26 2020 +0200 25.2 +++ b/src/main/webapp/WEB-INF/jsp/site.jsp Thu May 14 22:48:01 2020 +0200 25.3 @@ -31,7 +31,7 @@ 25.4 <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 25.5 25.6 <%-- Make the base href easily available at request scope --%> 25.7 -<c:set scope="request" var="baseHref" value="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/" /> 25.8 +<c:set scope="page" var="baseHref" value="${requestScope[Constants.REQ_ATTR_BASE_HREF]}" /> 25.9 25.10 <%-- Define an alias for the request path --%> 25.11 <c:set scope="page" var="requestPath" value="${requestScope[Constants.REQ_ATTR_PATH]}"/> 25.12 @@ -45,6 +45,9 @@ 25.13 <%-- Define an alias for the fragment name --%> 25.14 <c:set scope="page" var="fragment" value="${requestScope[Constants.REQ_ATTR_FRAGMENT]}"/> 25.15 25.16 +<%-- Define an alias for the optional redirect location --%> 25.17 +<c:set scope="page" var="redirectLocation" value="${requestScope[Constants.REQ_ATTR_REDIRECT_LOCATION]}"/> 25.18 + 25.19 <%-- Define an alias for the additional stylesheet --%> 25.20 <c:set scope="page" var="extraCss" value="${requestScope[Constants.REQ_ATTR_STYLESHEET]}"/> 25.21 25.22 @@ -66,6 +69,9 @@ 25.23 </fmt:bundle> 25.24 </title> 25.25 <meta charset="UTF-8"> 25.26 + <c:if test="${not empty redirectLocation}"> 25.27 + <meta http-equiv="refresh" content="0; URL=${redirectLocation}"> 25.28 + </c:if> 25.29 <link rel="stylesheet" href="lightpit.css" type="text/css"> 25.30 <c:if test="${not empty extraCss}"> 25.31 <link rel="stylesheet" href="${extraCss}" type="text/css"> 25.32 @@ -87,6 +93,7 @@ 25.33 <div id="content-area"> 25.34 <c:if test="${not empty fragment}"> 25.35 <fmt:setBundle scope="request" basename="${moduleInfo.bundleBaseName}"/> 25.36 + <fmt:setBundle scope="request" var="lightpit_bundle" basename="localization.lightpit"/> 25.37 <c:import url="${fragment}" /> 25.38 </c:if> 25.39 </div>
26.1 --- a/src/main/webapp/lightpit.css Wed May 13 21:46:26 2020 +0200 26.2 +++ b/src/main/webapp/lightpit.css Thu May 14 22:48:01 2020 +0200 26.3 @@ -28,22 +28,17 @@ 26.4 */ 26.5 26.6 html { 26.7 - background: #f8f8f8; 26.8 + font-family: sans-serif; 26.9 + background: white; 26.10 + color: #1c204e; 26.11 + margin: 0; 26.12 + padding: 0; 26.13 } 26.14 26.15 body { 26.16 - background: white; 26.17 - font-family: serif; 26.18 - 26.19 - border-color: #505050; 26.20 - border-style: solid; 26.21 - border-width: 1pt; 26.22 - 26.23 - color: #1c202e; 26.24 -} 26.25 - 26.26 -h1, h2, h3, h4, #mainMenu, #subMenu { 26.27 - font-family: sans-serif; 26.28 + height: 100%; 26.29 + margin: 0; 26.30 + padding: 0; 26.31 } 26.32 26.33 a { 26.34 @@ -88,6 +83,33 @@ 26.35 padding: 1em; 26.36 } 26.37 26.38 +button, a.button { 26.39 + display: inline-block; 26.40 + font-size: medium; 26.41 + border-style: outset; 26.42 + border-width: 2pt; 26.43 + border-color: #6060cc; 26.44 + color: inherit; 26.45 + background: #f0f0f0; 26.46 + 26.47 + padding: .25em .5em .25em .5em; 26.48 + cursor: default; 26.49 + text-decoration: none; 26.50 +} 26.51 + 26.52 +button:hover, a.button:hover { 26.53 + background: #f0f0ff; 26.54 +} 26.55 + 26.56 +button[type=submit] { 26.57 + background: #20a0ff; 26.58 + color: white; 26.59 +} 26.60 + 26.61 +button[type=submit]:hover { 26.62 + background: #1090cf; 26.63 +} 26.64 + 26.65 th { 26.66 text-align: left; 26.67 } 26.68 @@ -101,6 +123,7 @@ 26.69 } 26.70 26.71 table.datatable th { 26.72 + white-space: nowrap; 26.73 font-weight: bold; 26.74 background: lightsteelblue; 26.75 } 26.76 @@ -116,6 +139,35 @@ 26.77 background: lightblue; 26.78 } 26.79 26.80 +table.formtable { 26.81 + border-style: none; 26.82 + border-collapse: separate; 26.83 + border-spacing: 1em; 26.84 +} 26.85 + 26.86 +table.formtable th { 26.87 + font-weight: bold; 26.88 + text-align: left; 26.89 + vertical-align: center; 26.90 + white-space: nowrap; 26.91 +} 26.92 + 26.93 +table.formtable tbody td > * { 26.94 + width: 100%; 26.95 +} 26.96 + 26.97 +table.formtable tfoot td { 26.98 + text-align: right; 26.99 +} 26.100 + 26.101 +.fullwidth { 26.102 + width: 100%; 26.103 +} 26.104 + 26.105 +.vtop { 26.106 + vertical-align: top; 26.107 +} 26.108 + 26.109 .hcenter { 26.110 text-align: center; 26.111 } 26.112 @@ -126,4 +178,16 @@ 26.113 26.114 .nowrap { 26.115 white-space: nowrap; 26.116 +} 26.117 + 26.118 +.medskip { 26.119 + margin-top: .5em; 26.120 +} 26.121 + 26.122 +.info-box { 26.123 + margin: 2em; 26.124 + border-style: dashed; 26.125 + border-width: 1pt; 26.126 + border-color: deepskyblue; 26.127 + padding: 1em; 26.128 } 26.129 \ No newline at end of file