From 2f51c93cfe18c52d365ca68c9261cd4c8b82973c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Henke?= Date: Mon, 2 May 2022 14:43:43 +0200 Subject: [PATCH] added notes --- .../spring/contact/ContactController.java | 2 - .../timetrack/spring/note/INoteService.java | 19 ++ .../timetrack/spring/note/NoteBean.java | 106 ++++++++++ .../timetrack/spring/note/NoteController.java | 83 ++++++++ .../spring/note/impl/NoteGateway.java | 194 ++++++++++++++++++ .../spring/note/impl/NoteService.java | 83 ++++++++ src/main/resources/static/css/style.css | 10 +- src/main/resources/templates/layout/main.html | 6 +- src/main/resources/templates/note/item.html | 64 ++++++ src/main/resources/templates/note/list.html | 76 +++++++ 10 files changed, 637 insertions(+), 6 deletions(-) create mode 100644 src/main/java/de/jottyfan/timetrack/spring/note/INoteService.java create mode 100644 src/main/java/de/jottyfan/timetrack/spring/note/NoteBean.java create mode 100644 src/main/java/de/jottyfan/timetrack/spring/note/NoteController.java create mode 100644 src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteGateway.java create mode 100644 src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteService.java create mode 100644 src/main/resources/templates/note/item.html create mode 100644 src/main/resources/templates/note/list.html diff --git a/src/main/java/de/jottyfan/timetrack/spring/contact/ContactController.java b/src/main/java/de/jottyfan/timetrack/spring/contact/ContactController.java index 427a0e4..cf29d27 100644 --- a/src/main/java/de/jottyfan/timetrack/spring/contact/ContactController.java +++ b/src/main/java/de/jottyfan/timetrack/spring/contact/ContactController.java @@ -93,9 +93,7 @@ public class ContactController { @RolesAllowed("timetrack_user") @GetMapping(value = "/contact/delete/{id}") public String doDelete(@PathVariable Integer id, Model model) { - LOGGER.info("up to delete bean {}", id); Integer amount = contactService.doDelete(id); - LOGGER.info("deleted {} rows", amount); return amount.equals(1) ? getList(model) : toItem(id, model); } } diff --git a/src/main/java/de/jottyfan/timetrack/spring/note/INoteService.java b/src/main/java/de/jottyfan/timetrack/spring/note/INoteService.java new file mode 100644 index 0000000..3dafc46 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/spring/note/INoteService.java @@ -0,0 +1,19 @@ +package de.jottyfan.timetrack.spring.note; + +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +/** + * + * @author henkej + * + */ +public interface INoteService { + public List getList(); + public Integer doUpsert(NoteBean bean); + public Integer doDelete(Integer pk); + public Integer getAmount(); + public String getCurrentUser(HttpServletRequest request); + public NoteBean getBean(Integer id); +} diff --git a/src/main/java/de/jottyfan/timetrack/spring/note/NoteBean.java b/src/main/java/de/jottyfan/timetrack/spring/note/NoteBean.java new file mode 100644 index 0000000..02958d5 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/spring/note/NoteBean.java @@ -0,0 +1,106 @@ +package de.jottyfan.timetrack.spring.note; + +import java.io.Serializable; + +import de.jottyfan.timetrack.db.note.enums.EnumCategory; +import de.jottyfan.timetrack.db.note.enums.EnumNotetype; + +/** + * + * @author henkej + * + */ +public class NoteBean implements Serializable, Comparable { + private static final long serialVersionUID = 1L; + + private Integer pk; + private String title; + private EnumCategory category; + private String content; + private EnumNotetype type; + + public NoteBean() { + super(); + this.pk = null; + } + + public NoteBean(Integer pk) { + super(); + this.pk = pk; + } + + @Override + public int compareTo(NoteBean o) { + return o == null ? 0 : getPk().compareTo(o.getPk()); + } + + /** + * @return the pk + */ + public Integer getPk() { + return pk; + } + + /** + * @param pk the pk to set + */ + public void setPk(Integer pk) { + this.pk = pk; + } + + /** + * @return the title + */ + public String getTitle() { + return title; + } + + /** + * @param title the title to set + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * @return the category + */ + public EnumCategory getCategory() { + return category; + } + + /** + * @param category the category to set + */ + public void setCategory(EnumCategory category) { + this.category = category; + } + + /** + * @return the content + */ + public String getContent() { + return content; + } + + /** + * @param content the content to set + */ + public void setContent(String content) { + this.content = content; + } + + /** + * @return the type + */ + public EnumNotetype getType() { + return type; + } + + /** + * @param type the type to set + */ + public void setType(EnumNotetype type) { + this.type = type; + } +} diff --git a/src/main/java/de/jottyfan/timetrack/spring/note/NoteController.java b/src/main/java/de/jottyfan/timetrack/spring/note/NoteController.java new file mode 100644 index 0000000..2b8aae1 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/spring/note/NoteController.java @@ -0,0 +1,83 @@ +package de.jottyfan.timetrack.spring.note; + +import java.util.Arrays; +import java.util.List; + +import javax.annotation.security.RolesAllowed; +import javax.servlet.http.HttpServletRequest; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import de.jottyfan.timetrack.db.note.enums.EnumCategory; +import de.jottyfan.timetrack.db.note.enums.EnumNotetype; + +/** + * + * @author henkej + * + */ +@Controller +public class NoteController { + private static final Logger LOGGER = LogManager.getLogger(NoteController.class); + + private final HttpServletRequest request; + + @Autowired + private INoteService noteService; + + @Autowired + public NoteController(HttpServletRequest request) { + this.request = request; + } + + @RolesAllowed("timetrack_user") + @RequestMapping(value = "/note/list") + public String getList(Model model) { + List list = noteService.getList(); + model.addAttribute("noteList", list); + return "note/list"; + } + + @RolesAllowed("timetrack_user") + @RequestMapping(value = "/note/add", method = RequestMethod.GET) + public String toAdd(Model model) { + return toItem(null, model); + } + + @RolesAllowed("timetrack_user") + @GetMapping("/note/edit/{id}") + public String toItem(@PathVariable Integer id, Model model) { + NoteBean bean = noteService.getBean(id); + if (bean == null) { + bean = new NoteBean(); // the add case + } + model.addAttribute("noteBean", bean); + model.addAttribute("types", Arrays.asList(EnumNotetype.values())); + model.addAttribute("categories", Arrays.asList(EnumCategory.values())); + return "note/item"; + } + + @RolesAllowed("timetrack_user") + @RequestMapping(value = "/note/upsert", method = RequestMethod.POST) + public String doUpsert(Model model, @ModelAttribute NoteBean bean) { + Integer amount = noteService.doUpsert(bean); + return amount.equals(1) ? getList(model) : toItem(bean.getPk(), model); + } + + @RolesAllowed("timetrack_user") + @GetMapping(value = "/note/delete/{id}") + public String doDelete(@PathVariable Integer id, Model model) { + Integer amount = noteService.doDelete(id); + return amount.equals(1) ? getList(model) : toItem(id, model); + } + +} diff --git a/src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteGateway.java b/src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteGateway.java new file mode 100644 index 0000000..ec0c1c7 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteGateway.java @@ -0,0 +1,194 @@ +package de.jottyfan.timetrack.spring.note.impl; + +import static de.jottyfan.timetrack.db.note.Tables.T_NOTE; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jooq.DSLContext; +import org.jooq.DeleteConditionStep; +import org.jooq.InsertValuesStep4; +import org.jooq.Record1; +import org.jooq.Record5; +import org.jooq.SelectConditionStep; +import org.jooq.SelectJoinStep; +import org.jooq.UpdateConditionStep; +import org.jooq.exception.DataAccessException; +import org.jooq.impl.DSL; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +import de.jottyfan.timetrack.db.note.enums.EnumCategory; +import de.jottyfan.timetrack.db.note.enums.EnumNotetype; +import de.jottyfan.timetrack.db.note.tables.records.TNoteRecord; +import de.jottyfan.timetrack.spring.note.NoteBean; + +/** + * + * @author jotty + * + */ +@Repository +public class NoteGateway { + private static final Logger LOGGER = LogManager.getLogger(NoteGateway.class); + private final DSLContext jooq; + + public NoteGateway(@Autowired DSLContext jooq) throws Exception { + this.jooq = jooq; + } + + public DSLContext getJooq() { + return this.jooq; + } + + /** + * get sorted list of notes + * + * @return a list (an empty one at least) + * @throws SQLException + * @throws ClassNotFoundException + * @throws DataAccessException + */ + public List getAll() throws DataAccessException, ClassNotFoundException, SQLException { + SelectJoinStep> sql = getJooq() + // @formatter:off + .select(T_NOTE.PK, + T_NOTE.TITLE, + T_NOTE.CATEGORY, + T_NOTE.CONTENT, + T_NOTE.NOTETYPE) + .from(T_NOTE); + // @formatter:on + LOGGER.debug("{}", sql.toString()); + List list = new ArrayList<>(); + for (Record5 r : sql.fetch()) { + NoteBean bean = new NoteBean(r.get(T_NOTE.PK)); + bean.setTitle(r.get(T_NOTE.TITLE)); + bean.setCategory(r.get(T_NOTE.CATEGORY)); + bean.setContent(r.get(T_NOTE.CONTENT)); + bean.setType(r.get(T_NOTE.NOTETYPE)); + list.add(bean); + } + list.sort((o1, o2) -> o1 == null ? 0 : o1.compareTo(o2)); + return list; + } + + /** + * delete a note from the database + * + * @param pk the id of the contact + * @return the number of affected database rows, should be 1 + * @throws SQLException + * @throws ClassNotFoundException + * @throws DataAccessException + */ + public Integer delete(Integer pk) throws DataAccessException, ClassNotFoundException, SQLException { + DeleteConditionStep sql = getJooq() + // @formatter:off + .deleteFrom(T_NOTE) + .where(T_NOTE.PK.eq(pk)); + // @formatter:on + LOGGER.debug("{}", sql.toString()); + return sql.execute(); + } + + /** + * add a note to the database + * + * @param bean the contact information + * @return the number of affected database rows, should be 1 + * @throws SQLException + * @throws ClassNotFoundException + * @throws DataAccessException + */ + public Integer add(NoteBean bean) throws DataAccessException, ClassNotFoundException, SQLException { + InsertValuesStep4 sql = getJooq() + // @formatter:off + .insertInto(T_NOTE, + T_NOTE.TITLE, + T_NOTE.CATEGORY, + T_NOTE.CONTENT, + T_NOTE.NOTETYPE) + .values(bean.getTitle(), bean.getCategory(), bean.getContent(), bean.getType()); + // @formatter:on + LOGGER.debug("{}", sql.toString()); + return sql.execute(); + } + + /** + * update a note in the database, referencing its pk + * + * @param bean the contact information + * @return the number of affected database rows, should be 1 + * @throws SQLException + * @throws ClassNotFoundException + * @throws DataAccessException + */ + public Integer update(NoteBean bean) throws DataAccessException, ClassNotFoundException, SQLException { + UpdateConditionStep sql = getJooq() + // @formatter:off + .update(T_NOTE) + .set(T_NOTE.TITLE, bean.getTitle()) + .set(T_NOTE.CATEGORY, bean.getCategory()) + .set(T_NOTE.CONTENT, bean.getContent()) + .set(T_NOTE.NOTETYPE, bean.getType()) + .where(T_NOTE.PK.eq(bean.getPk())); + // @formatter:on + LOGGER.debug("{}", sql.toString()); + return sql.execute(); + } + + /** + * get number of entries in t_note + * + * @return number of entries + * @throws SQLException + * @throws ClassNotFoundException + * @throws DataAccessException + */ + public Integer getAmount() throws DataAccessException, ClassNotFoundException, SQLException { + SelectJoinStep> sql = getJooq() + // @formatter:off + .selectCount() + .from(T_NOTE); + // @formatter:on + LOGGER.debug("{}", sql.toString()); + return sql.fetchOne(DSL.count()); + } + + /** + * get all enum types + * + * @return list of enum types + */ + public List getTypes() { + return new ArrayList<>(Arrays.asList(EnumNotetype.values())); + } + + public NoteBean getBean(Integer id) { + SelectConditionStep> sql = getJooq() + // @formatter:off + .select(T_NOTE.PK, + T_NOTE.TITLE, + T_NOTE.CATEGORY, + T_NOTE.CONTENT, + T_NOTE.NOTETYPE) + .from(T_NOTE) + .where(T_NOTE.PK.eq(id)); + // @formatter:on + LOGGER.debug("{}", sql.toString()); + for (Record5 r : sql.fetch()) { + NoteBean bean = new NoteBean(r.get(T_NOTE.PK)); + bean.setTitle(r.get(T_NOTE.TITLE)); + bean.setCategory(r.get(T_NOTE.CATEGORY)); + bean.setContent(r.get(T_NOTE.CONTENT)); + bean.setType(r.get(T_NOTE.NOTETYPE)); + return bean; + } + return null; + } +} diff --git a/src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteService.java b/src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteService.java new file mode 100644 index 0000000..06a7b32 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/spring/note/impl/NoteService.java @@ -0,0 +1,83 @@ +package de.jottyfan.timetrack.spring.note.impl; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jooq.DSLContext; +import org.keycloak.KeycloakSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import de.jottyfan.timetrack.spring.note.INoteService; +import de.jottyfan.timetrack.spring.note.NoteBean; + +/** + * + * @author henkej + * + */ +@Service +@Transactional(transactionManager = "transactionManager") +public class NoteService implements INoteService { + private static final Logger LOGGER = LogManager.getLogger(NoteService.class); + + @Autowired + private DSLContext dsl; + + @Override + public String getCurrentUser(HttpServletRequest request) { + KeycloakSecurityContext ksc = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName()); + return ksc == null ? "" : ksc.getIdToken().getPreferredUsername(); + } + + @Override + public List getList() { + try { + return new NoteGateway(dsl).getAll(); + } catch (Exception e) { + LOGGER.error(e); + return new ArrayList<>(); + } + } + + @Override + public Integer doUpsert(NoteBean bean) { + try { + NoteGateway gw = new NoteGateway(dsl); + return bean.getPk() == null ? gw.add(bean) : gw.update(bean); + } catch (Exception e) { + LOGGER.error(e); + return 0; + } + } + + @Override + public Integer doDelete(Integer pk) { + try { + return new NoteGateway(dsl).delete(pk); + } catch (Exception e) { + LOGGER.error(e); + return 0; + } + } + + @Override + public Integer getAmount() { + return getList().size(); + } + + @Override + public NoteBean getBean(Integer id) { + try { + return new NoteGateway(dsl).getBean(id); + } catch (Exception e) { + LOGGER.error(e); + return null; + } + } +} diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css index 1d89060..f5969a5 100644 --- a/src/main/resources/static/css/style.css +++ b/src/main/resources/static/css/style.css @@ -4,13 +4,17 @@ html { body { background-color: #99c1f1; - height: calc(100% - 76px); + height: calc(100% - 56px); } .float-right { float: right; } +.noty { + background-image: linear-gradient(to bottom, #ffc, #ee0) !important; +} + .glassy { background-color: rgba(1,1,1,0.1); } @@ -128,6 +132,10 @@ body { .version { font-size: small; color: silver; + position: absolute; + padding-top: 36px; + padding-left: 22px; + z-index: 0; } .fc-content { diff --git a/src/main/resources/templates/layout/main.html b/src/main/resources/templates/layout/main.html index eae87dc..f52509b 100644 --- a/src/main/resources/templates/layout/main.html +++ b/src/main/resources/templates/layout/main.html @@ -20,9 +20,8 @@