from branch of project todolist

This commit is contained in:
2019-02-04 12:17:31 +01:00
commit 770510fa42
96 changed files with 10243 additions and 0 deletions

View File

@ -0,0 +1,18 @@
package de.jottyfan.timetrack.help;
public enum Application
{
CONNECTION("connection");
private final String value;
private Application(String value)
{
this.value = value;
}
public String get()
{
return value;
}
}

View File

@ -0,0 +1,37 @@
package de.jottyfan.timetrack.help;
import java.io.*;
import javax.servlet.*;
/**
*
* @author henkej
*
*/
public class EncodingFilter implements Filter
{
private String encoding;
@Override
public void destroy()
{
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
servletRequest.setCharacterEncoding(encoding);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
encoding = filterConfig.getInitParameter("encoding");
if (encoding == null)
{
encoding = "UTF-8";
}
}
}

View File

@ -0,0 +1,20 @@
package de.jottyfan.timetrack.help;
/**
*
* @author henkej
*
*/
public abstract class Navigation
{
/**
* navigate to page referenced by p
*
* @param p
* @return
*/
public String navigateTo(Pages p)
{
return p.get();
}
}

View File

@ -0,0 +1,90 @@
package de.jottyfan.timetrack.help;
/**
*
* @author henkej
*
*/
public enum Pages
{
/**
* contact list
*/
CONTACT_LIST("/pages/contact/list.jsf"),
/**
* contact item
*/
CONTACT_ITEM("/pages/contact/item.jsf"),
/**
* note list
*/
NOTE_LIST("/pages/note/list.jsf"),
/**
* note item
*/
NOTE_ITEM("/pages/note/item.jsf"),
/**
* todo list
*/
TODO_LIST("/pages/todo/list.jsf"),
/**
* todo item
*/
TODO_ITEM("/pages/todo/item.jsf"),
/**
* done init
*/
DONE_INIT("/pages/done/init.jsf"),
/**
* done edit
*/
DONE_EDIT("/pages/done/edit.jsf"),
/**
* done delete
*/
DONE_DELETE("/pages/done/delete.jsf"),
/**
* done add
*/
DONE_ADD("/pages/done/add.jsf"),
/**
* done clear
*/
DONE_CLEAR("/pages/done/clear.jsf"),
/**
* organize init
*/
ORGANIZE_LIST("/pages/organize/list.jsf"),
/**
* organize week
*/
ORGANIZE_WEEK("/pages/organize/week.jsf"),
/**
* organize delete
*/
ORGANIZE_DELETE("/pages/organize/delete.jsf"),
/**
* organize add
*/
ORGANIZE_ADD("/pages/organize/add.jsf"),
/**
* organize edit
*/
ORGANIZE_EDIT("/pages/organize/edit.jsf"),
/**
* start
*/
START("/pages/start.jsf");
private final String value;
private Pages(String value)
{
this.value = value;
}
public String get()
{
return value;
}
}

View File

@ -0,0 +1,55 @@
package de.jottyfan.timetrack.help;
import java.util.*;
import javax.faces.bean.*;
/**
*
* @author henkej
*
*/
@ManagedBean
@SessionScoped
public class ThemeBean
{
private String currentTheme;
public List<String> getValidThemes(){
List<String> list = new ArrayList<>();
list.add("cerulean");
list.add("cosmo");
list.add("cyborg");
list.add("darkly");
list.add("default");
list.add("flatly");
list.add("journal");
list.add("lumen");
list.add("other");
list.add("paper");
list.add("readable");
list.add("sandstone");
list.add("simplex");
list.add("slate");
list.add("spacelab");
list.add("superhero");
list.add("united");
list.add("yeti");
return list;
}
public void setCurrentTheme(String currentTheme)
{
this.currentTheme = currentTheme;
}
/**
* contains current theme for web.xml's theme chooser
*
* @return current theme
*/
public String getCurrentTheme()
{
return currentTheme == null ? "default" : (getValidThemes().contains(currentTheme) ? currentTheme : "default");
}
}

View File

@ -0,0 +1,10 @@
package de.jottyfan.timetrack.modules;
/**
*
* @author henkej
*
*/
public interface Bean
{
}

View File

@ -0,0 +1,24 @@
package de.jottyfan.timetrack.modules;
/**
*
* @author henkej
*
*/
public interface ControlInterface
{
/**
* navigate to init page of module
*
* @return
* @throws DBException
*/
public String toList();
/**
* return model of bean container
*
* @return
*/
public Model getModel();
}

View File

@ -0,0 +1,44 @@
package de.jottyfan.timetrack.modules;
import javax.faces.context.FacesContext;
import org.jooq.DSLContext;
import org.jooq.TableLike;
import de.jooqFaces.EJooqApplicationScope;
/**
*
* @author henkej
*
*/
public class JooqGateway
{
private final FacesContext facesContext;
public JooqGateway(FacesContext facesContext)
{
this.facesContext = facesContext;
}
public DSLContext getJooq()
{
return (DSLContext) facesContext.getExternalContext().getApplicationMap().get(EJooqApplicationScope.JOOQ_FACES_DSLCONTEXT.get());
}
public Integer getFkLogin() {
// TODO: make a login, add the profile id to the session and read it here from facesContext
return 1;
}
/**
* return amount of "select count(1) as amount " + subQuery
*
* @param subQuery
* @return number of entries
*/
public Long getAmount(TableLike<?> table)
{
return getJooq().selectCount().from(table).fetchOne(0, long.class);
}
}

View File

@ -0,0 +1,16 @@
package de.jottyfan.timetrack.modules;
/**
*
* @author henkej
*
*/
public interface Model
{
/**
* get bean of model
*
* @return bean
*/
public Bean getBean();
}

View File

@ -0,0 +1,79 @@
package de.jottyfan.timetrack.modules;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.jasypt.util.password.StrongPasswordEncryptor;
/**
*
* @author henkej
*
*/
@ManagedBean
@SessionScoped
public class SessionBean implements Serializable {
private static final long serialVersionUID = 1L;
private Integer login;
private String username;
private String secret;
private String forename;
private String surname;
public Boolean getHasLogin() {
return login != null;
}
public Boolean getHasNoLogin() {
return login == null;
}
public Integer getLogin() {
return login;
}
public void setLogin(Integer login) {
this.login = login;
}
public String getSecret() {
StrongPasswordEncryptor spe = new StrongPasswordEncryptor();
return spe.encryptPassword(secret);
}
public boolean checkSecret(String encrypted) {
StrongPasswordEncryptor spe = new StrongPasswordEncryptor();
return spe.checkPassword(secret, encrypted);
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}

View File

@ -0,0 +1,52 @@
package de.jottyfan.timetrack.modules;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import de.jottyfan.timetrack.help.Pages;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
/**
*
* @author henkej
*
*/
@ManagedBean
@RequestScoped
public class SessionControl {
@ManagedProperty(value = "#{facesContext}")
private FacesContext facesContext;
@ManagedProperty(value = "#{sessionBean}")
private SessionBean bean;
public String doLogin() {
SessionModel model = new SessionModel();
model.doLogin(facesContext, bean);
return Pages.START.get();
}
public String doLogout() {
bean.setLogin(null);
return Pages.START.get();
}
public FacesContext getFacesContext() {
return facesContext;
}
public void setFacesContext(FacesContext facesContext) {
this.facesContext = facesContext;
}
public SessionBean getBean() {
return bean;
}
public void setBean(SessionBean bean) {
this.bean = bean;
}
}

View File

@ -0,0 +1,59 @@
package de.jottyfan.timetrack.modules;
import static de.jottyfan.timetrack.db.profile.Tables.T_LOGIN;
import javax.faces.context.FacesContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.Record4;
import org.jooq.SelectConditionStep;
import org.jooq.exception.DataAccessException;
/**
*
* @author henkej
*
*/
public class SessionGateway extends JooqGateway {
private static final Logger LOGGER = LogManager.getLogger();
public SessionGateway(FacesContext facesContext) {
super(facesContext);
}
/**
* seek login and set bean's login to that; if not found, return false
*
* @param bean
* the bean
* @return true or false
*/
public boolean seekAndSetLogin(SessionBean bean) {
SelectConditionStep<Record4<Integer, String, String, String>> sql = getJooq()
// @formatter:off
.select(T_LOGIN.PK,
T_LOGIN.FORENAME,
T_LOGIN.SURNAME,
T_LOGIN.PASSWORD)
.from(T_LOGIN)
.where(T_LOGIN.LOGIN.eq(bean.getUsername()));
// @formatter:on
LOGGER.debug(sql.toString());
Record4<Integer, String, String, String> r = sql.fetchOne();
if (r != null) {
String encrypted = r.get(T_LOGIN.PASSWORD);
if (bean.checkSecret(encrypted)) {
bean.setLogin(r.get(T_LOGIN.PK));
bean.setForename(r.get(T_LOGIN.FORENAME));
bean.setSurname(r.get(T_LOGIN.SURNAME));
return true;
} else {
throw new DataAccessException("wrong password");
}
} else {
return false;
}
}
}

View File

@ -0,0 +1,25 @@
package de.jottyfan.timetrack.modules;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import org.jooq.exception.DataAccessException;
/**
*
* @author henkej
*
*/
public class SessionModel {
public boolean doLogin(FacesContext facesContext, SessionBean bean) {
try {
return new SessionGateway(facesContext).seekAndSetLogin(bean);
} catch (DataAccessException e) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on login", e.getMessage());
facesContext.addMessage(null, msg);
return false;
}
}
}

View File

@ -0,0 +1,81 @@
package de.jottyfan.timetrack.modules.contact;
import java.io.Serializable;
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
import de.jottyfan.timetrack.modules.Bean;
/**
*
* @author jotty
*
*/
public class ContactBean implements Bean, Serializable, Comparable<ContactBean> {
private static final long serialVersionUID = 1L;
private final Integer pk;
private String forename;
private String surname;
private String contact;
private EnumContacttype type;
public ContactBean(Integer pk) {
super();
this.pk = pk;
}
@Override
public int compareTo(ContactBean o) {
return o == null ? 0 : getSortname().compareTo(o.getSortname());
}
public String getSortname() {
StringBuilder buf = new StringBuilder();
buf.append(surname).append(forename);
return buf.toString().toLowerCase();
}
public String getFullname() {
StringBuilder buf = new StringBuilder();
buf.append(forename).append(" ");
buf.append(surname);
return buf.toString();
}
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public EnumContacttype getType() {
return type;
}
public void setType(EnumContacttype type) {
this.type = type;
}
public Integer getPk() {
return pk;
}
}

View File

@ -0,0 +1,79 @@
package de.jottyfan.timetrack.modules.contact;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import de.jooqFaces.JooqFacesContext;
import de.jottyfan.timetrack.help.Navigation;
import de.jottyfan.timetrack.help.Pages;
import de.jottyfan.timetrack.modules.ControlInterface;
/**
*
* @author jotty
*
*/
@ManagedBean
@RequestScoped
public class ContactControl extends Navigation implements ControlInterface, Serializable {
private static final long serialVersionUID = 1L;
@ManagedProperty(value = "#{contactModel}")
private ContactModel model;
@ManagedProperty(value = "#{facesContext}")
private JooqFacesContext facesContext;
public String toStart() {
return navigateTo(Pages.START);
}
public String toList() {
boolean ready = model.init(facesContext);
return ready ? navigateTo(Pages.CONTACT_LIST) : toStart();
}
public String toItem(ContactBean bean) {
model.setBean(bean);
return navigateTo(Pages.CONTACT_ITEM);
}
public String toItem() {
model.setBean(new ContactBean(null));
return navigateTo(Pages.CONTACT_ITEM);
}
public String doAdd() {
boolean ready = model.add(facesContext);
return ready ? toList() : navigateTo(Pages.CONTACT_ITEM);
}
public String doUpdate() {
boolean ready = model.update(facesContext);
return ready ? toList() : navigateTo(Pages.CONTACT_ITEM);
}
public String doDelete() {
boolean ready = model.delete(facesContext);
return ready ? toList() : navigateTo(Pages.CONTACT_ITEM);
}
public Integer getAmount() {
return model.getAmount(facesContext);
}
public ContactModel getModel() {
return model;
}
public void setModel(ContactModel model) {
this.model = model;
}
public void setFacesContext(JooqFacesContext facesContext) {
this.facesContext = facesContext;
}
}

View File

@ -0,0 +1,149 @@
package de.jottyfan.timetrack.modules.contact;
import static de.jottyfan.timetrack.db.contact.Tables.T_CONTACT;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.faces.context.FacesContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DeleteConditionStep;
import org.jooq.InsertValuesStep4;
import org.jooq.Record1;
import org.jooq.Record5;
import org.jooq.SelectJoinStep;
import org.jooq.UpdateConditionStep;
import org.jooq.impl.DSL;
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
import de.jottyfan.timetrack.db.contact.tables.records.TContactRecord;
import de.jottyfan.timetrack.modules.JooqGateway;
/**
*
* @author jotty
*
*/
public class ContactGateway extends JooqGateway {
private static final Logger LOGGER = LogManager.getLogger(ContactGateway.class);
public ContactGateway(FacesContext facesContext) {
super(facesContext);
}
/**
* get sorted list of contacts
*
* @return a list (an empty one at least)
*/
public List<ContactBean> getAll() {
SelectJoinStep<Record5<Integer, String, String, String, EnumContacttype>> sql = getJooq()
// @formatter:off
.select(T_CONTACT.PK,
T_CONTACT.FORENAME,
T_CONTACT.SURNAME,
T_CONTACT.CONTACT,
T_CONTACT.TYPE)
.from(T_CONTACT);
// @formatter:on
LOGGER.debug("{}", sql.toString());
List<ContactBean> list = new ArrayList<>();
for (Record5<Integer, String, String, String, EnumContacttype> r : sql.fetch()) {
ContactBean bean = new ContactBean(r.get(T_CONTACT.PK));
bean.setForename(r.get(T_CONTACT.FORENAME));
bean.setSurname(r.get(T_CONTACT.SURNAME));
bean.setContact(r.get(T_CONTACT.CONTACT));
bean.setType(r.get(T_CONTACT.TYPE));
list.add(bean);
}
list.sort((o1, o2) -> o1 == null ? 0 : o1.compareTo(o2));
return list;
}
/**
* delete a contact from the database
*
* @param pk
* the id of the contact
* @return the number of affected database rows, should be 1
*/
public Integer delete(Integer pk) {
DeleteConditionStep<TContactRecord> sql = getJooq()
// @formatter:off
.deleteFrom(T_CONTACT)
.where(T_CONTACT.PK.eq(pk));
// @formatter:on
LOGGER.debug("{}", sql.toString());
return sql.execute();
}
/**
* add a contact to the database
*
* @param bean
* the contact information
* @return the number of affected database rows, should be 1
*/
public Integer add(ContactBean bean) {
InsertValuesStep4<TContactRecord, String, String, String, EnumContacttype> sql = getJooq()
// @formatter:off
.insertInto(T_CONTACT,
T_CONTACT.FORENAME,
T_CONTACT.SURNAME,
T_CONTACT.CONTACT,
T_CONTACT.TYPE)
.values(bean.getForename(), bean.getSurname(), bean.getContact(), bean.getType());
// @formatter:on
LOGGER.debug("{}", sql.toString());
return sql.execute();
}
/**
* update a contact in the database, referencing its pk
*
* @param bean
* the contact information
* @return the number of affected database rows, should be 1
*/
public Integer update(ContactBean bean) {
UpdateConditionStep<TContactRecord> sql = getJooq()
// @formatter:off
.update(T_CONTACT)
.set(T_CONTACT.FORENAME, bean.getForename())
.set(T_CONTACT.SURNAME, bean.getSurname())
.set(T_CONTACT.CONTACT, bean.getContact())
.set(T_CONTACT.TYPE, bean.getType())
.where(T_CONTACT.PK.eq(bean.getPk()));
// @formatter:on
LOGGER.debug("{}", sql.toString());
return sql.execute();
}
/**
* get number of entries in t_contact
*
* @return number of entries
*/
public Integer getAmount() {
SelectJoinStep<Record1<Integer>> sql = getJooq()
// @formatter:off
.selectCount()
.from(T_CONTACT);
// @formatter:on
LOGGER.debug("{}", sql.toString());
return sql.fetchOne(DSL.count());
}
/**
* get all enum types
*
* @return list of enum types
*/
public List<EnumContacttype> getTypes() {
return new ArrayList<>(Arrays.asList(EnumContacttype.values()));
}
}

View File

@ -0,0 +1,110 @@
package de.jottyfan.timetrack.modules.contact;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.jooq.exception.DataAccessException;
import de.jooqFaces.JooqFacesContext;
import de.jottyfan.timetrack.db.contact.enums.EnumContacttype;
import de.jottyfan.timetrack.modules.Model;
/**
*
* @author jotty
*
*/
@ManagedBean
@SessionScoped
public class ContactModel implements Model, Serializable {
private static final long serialVersionUID = 1L;
private ContactBean bean;
private List<ContactBean> list;
private List<EnumContacttype> types;
public boolean init(JooqFacesContext facesContext) {
bean = new ContactBean(null);
try {
ContactGateway gw = new ContactGateway(facesContext);
list = gw.getAll();
types = gw.getTypes();
return true;
} catch (DataAccessException e) {
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on loading data from db", e.getMessage()));
list = new ArrayList<>();
types = new ArrayList<>();
return false;
}
}
public boolean delete(JooqFacesContext facesContext) {
try {
Integer affected = new ContactGateway(facesContext).delete(bean.getPk());
return affected.equals(1);
} catch (DataAccessException e) {
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on deleting data from db", e.getMessage()));
return false;
}
}
public boolean add(JooqFacesContext facesContext) {
try {
Integer affected = new ContactGateway(facesContext).add(bean);
return affected.equals(1);
} catch (DataAccessException e) {
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on adding data to db", e.getMessage()));
return false;
}
}
public boolean update(JooqFacesContext facesContext) {
try {
Integer affected = new ContactGateway(facesContext).update(bean);
return affected.equals(1);
} catch (DataAccessException e) {
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on updating data to db", e.getMessage()));
return false;
}
}
public Integer getAmount(JooqFacesContext facesContext) {
try {
return new ContactGateway(facesContext).getAmount();
} catch (DataAccessException e) {
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error on getting size of contacts", e.getMessage()));
return 0;
}
}
public List<ContactBean> getList() {
return list;
}
public void setBean(ContactBean bean) {
this.bean = bean;
}
@Override
public ContactBean getBean() {
return bean;
}
public List<EnumContacttype> getTypes() {
return types;
}
public void setTypes(List<EnumContacttype> types) {
this.types = types;
}
}

View File

@ -0,0 +1,37 @@
package de.jottyfan.timetrack.modules.done;
/**
*
* @author henkej
*
*/
public class DailySummaryBean {
private final String projectName;
private final String moduleName;
private final String jobName;
private final String duration;
public DailySummaryBean(String projectName, String moduleName, String jobName, String duration) {
super();
this.projectName = projectName;
this.moduleName = moduleName;
this.jobName = jobName;
this.duration = duration;
}
public String getProjectName() {
return projectName;
}
public String getModuleName() {
return moduleName;
}
public String getJobName() {
return jobName;
}
public String getDuration() {
return duration;
};
}

View File

@ -0,0 +1,166 @@
package de.jottyfan.timetrack.modules.done;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import de.jottyfan.timetrack.db.done.tables.records.TDoneRecord;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
import de.jottyfan.timetrack.modules.Bean;
/**
*
* @author henkej
*
*/
public class DoneBean implements Bean, Serializable, Comparable<DoneBean> {
private static final long serialVersionUID = 1L;
private Integer pk;
private Timestamp timeFrom;
private Timestamp timeUntil;
private TProjectRecord project;
private TModuleRecord module;
private TJobRecord activity;
public DoneBean() {
}
public DoneBean(TDoneRecord r, Map<Integer, TProjectRecord> projectMap, Map<Integer, TModuleRecord> moduleMap,
Map<Integer, TJobRecord> jobMap) {
this.pk = r.getPk();
this.timeFrom = r.getTimeFrom();
this.timeUntil = r.getTimeUntil();
this.project = projectMap.get(r.getFkProject());
this.module = moduleMap.get(r.getFkModule());
this.activity = jobMap.get(r.getFkJob());
}
public String getTimeSummary() {
StringBuilder buf = new StringBuilder();
if (timeFrom != null) {
buf.append(new SimpleDateFormat("HH:mm").format(timeFrom));
}
if (timeUntil != null) {
buf.append(" - ");
buf.append(new SimpleDateFormat("HH:mm").format(timeUntil));
}
return buf.toString();
}
@Override
public int compareTo(DoneBean o) {
return o == null || timeFrom == null || o.getTimeFrom() == null ? 0 : timeFrom.compareTo(o.getTimeFrom());
}
public String getTimeDiff() {
LocalDateTime earlier = timeFrom != null ? timeFrom.toLocalDateTime() : LocalDateTime.now();
LocalDateTime later = timeUntil != null ? timeUntil.toLocalDateTime() : LocalDateTime.now();
Duration diff = Duration.between(earlier, later);
return String.format("%02d:%02d", diff.toHours(), diff.toMinutes() % 60);
}
public LocalDateTime getLocalDateTimeFromHHmm(String s) {
if (s == null || s.trim().isEmpty()) {
return null;
}
String[] hm = s.split(":");
Integer hours = 0;
Integer minutes = 0;
if (hm.length > 0) {
hours = Integer.valueOf(hm[0]);
}
if (hm.length > 1) {
minutes = Integer.valueOf(hm[1]);
}
LocalDateTime ldt = LocalDateTime.now();
ldt = ldt.withHour(hours);
ldt = ldt.withMinute(minutes);
ldt = ldt.withSecond(0);
ldt = ldt.withNano(0);
return ldt;
}
public String getProjectName() {
return project == null ? "" : project.getName();
}
public String getModuleName() {
return module == null ? "" : module.getName();
}
public String getJobName() {
return activity == null ? "" : activity.getName();
}
public String getTimeFromString() {
return timeFrom == null ? "" : new SimpleDateFormat("HH:mm").format(timeFrom);
}
public void setTimeFromString(String s) {
LocalDateTime ldt = getLocalDateTimeFromHHmm(s);
this.timeFrom = ldt == null ? null : Timestamp.valueOf(ldt);
}
public String getTimeUntilString() {
return timeUntil == null ? "" : new SimpleDateFormat("HH:mm").format(timeUntil);
}
public void setTimeUntilString(String s) {
LocalDateTime ldt = getLocalDateTimeFromHHmm(s);
this.timeUntil = ldt == null ? null : Timestamp.valueOf(ldt);
}
public Integer getPk() {
return this.pk;
}
public void setPk(Integer pk) {
this.pk = pk;
}
public Timestamp getTimeFrom() {
return timeFrom;
}
public void setTimeFrom(Timestamp timeFrom) {
this.timeFrom = timeFrom;
}
public Timestamp getTimeUntil() {
return timeUntil;
}
public void setTimeUntil(Timestamp timeUntil) {
this.timeUntil = timeUntil;
}
public TProjectRecord getProject() {
return project;
}
public void setProject(TProjectRecord project) {
this.project = project;
}
public TModuleRecord getModule() {
return module;
}
public void setModule(TModuleRecord module) {
this.module = module;
}
public TJobRecord getActivity() {
return activity;
}
public void setActivity(TJobRecord activity) {
this.activity = activity;
}
}

View File

@ -0,0 +1,95 @@
package de.jottyfan.timetrack.modules.done;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import de.jottyfan.timetrack.help.Navigation;
import de.jottyfan.timetrack.help.Pages;
import de.jottyfan.timetrack.modules.ControlInterface;
/**
*
* @author henkej
*
*/
@ManagedBean
@RequestScoped
public class DoneControl extends Navigation implements ControlInterface, Serializable {
private static final long serialVersionUID = 1L;
@ManagedProperty(value = "#{doneModel}")
private DoneModel model;
@ManagedProperty(value = "#{facesContext}")
private FacesContext facesContext;
public String toStart() {
return navigateTo(Pages.START);
}
public String toList() {
boolean ready = model.init(facesContext);
return ready ? navigateTo(Pages.DONE_INIT) : toStart();
}
public String toAdd() {
DoneBean bean = new DoneBean();
bean.setTimeFrom(getCurrentDate());
model.setBean(bean);
boolean ready = model.loadDefaults(facesContext);
return ready ? navigateTo(Pages.DONE_ADD) : toList();
}
public String toEdit(DoneBean bean) {
model.setBean(bean);
boolean ready = model.loadDefaults(facesContext);
return ready ? navigateTo(Pages.DONE_EDIT) : toList();
}
public String toDelete(DoneBean bean) {
model.setBean(bean);
return navigateTo(Pages.DONE_DELETE);
}
public String doUpdate() {
boolean ready = model.update(facesContext);
return ready ? toList() : toEdit(model.getBean());
}
public String doDelete() {
boolean ready = model.delete(facesContext);
return ready ? toList() : toDelete(model.getBean());
}
public String doAdd() {
boolean ready = model.insert(facesContext);
return ready ? toList() : toAdd();
}
public String getCurrentTimeAsString() {
return new SimpleDateFormat("HH:mm:ss").format(getCurrentDate());
}
public Timestamp getCurrentDate() {
return Timestamp.valueOf(LocalDateTime.now());
}
public DoneModel getModel() {
return model;
}
public void setModel(DoneModel model) {
this.model = model;
}
public void setFacesContext(FacesContext facesContext) {
this.facesContext = facesContext;
}
}

View File

@ -0,0 +1,290 @@
package de.jottyfan.timetrack.modules.done;
import static de.jottyfan.timetrack.db.done.Tables.T_DONE;
import static de.jottyfan.timetrack.db.done.Tables.T_JOB;
import static de.jottyfan.timetrack.db.done.Tables.T_MODULE;
import static de.jottyfan.timetrack.db.done.Tables.T_PROJECT;
import static de.jottyfan.timetrack.db.done.Tables.V_TASKLIST;
import static de.jottyfan.timetrack.db.done.Tables.V_TOTALOFDAY;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DeleteConditionStep;
import org.jooq.InsertValuesStep6;
import org.jooq.Record;
import org.jooq.Record4;
import org.jooq.SelectConditionStep;
import org.jooq.SelectWhereStep;
import org.jooq.UpdateConditionStep;
import org.jooq.exception.DataAccessException;
import de.jottyfan.timetrack.db.done.tables.records.TDoneRecord;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
import de.jottyfan.timetrack.modules.JooqGateway;
/**
*
* @author henkej
*
*/
public class DoneGateway extends JooqGateway {
private final static Logger LOGGER = LogManager.getLogger(DoneGateway.class);
public DoneGateway(FacesContext facesContext) {
super(facesContext);
}
/**
* get all modules from db
*
* @return modules
*/
public List<TModuleRecord> getAllModules() throws DataAccessException {
List<TModuleRecord> list = new ArrayList<>();
SelectWhereStep<TModuleRecord> sql = getJooq().selectFrom(T_MODULE);
LOGGER.debug(sql.toString());
for (TModuleRecord r : sql.fetch()) {
list.add(r);
}
list.sort((o1, o2) -> o1 == null || o2 == null || o1.getName() == null || o2.getName() == null ? 0
: o1.getName().compareTo(o2.getName()));
return list;
}
/**
* get all activities from db
*
* @return activities
*/
public List<TJobRecord> getAllActivities() throws DataAccessException {
List<TJobRecord> list = new ArrayList<>();
SelectWhereStep<TJobRecord> sql = getJooq().selectFrom(T_JOB);
LOGGER.debug(sql.toString());
for (TJobRecord r : sql.fetch()) {
list.add(r);
}
list.sort((o1, o2) -> o1 == null || o2 == null || o1.getName() == null || o2.getName() == null ? 0
: o1.getName().compareTo(o2.getName()));
return list;
}
/**
* get all projects from db
*
* @return projects
*/
public List<TProjectRecord> getAllProjects() throws DataAccessException {
List<TProjectRecord> list = new ArrayList<>();
SelectWhereStep<TProjectRecord> sql = getJooq().selectFrom(T_PROJECT);
LOGGER.debug(sql.toString());
for (TProjectRecord r : sql.fetch()) {
list.add(r);
}
list.sort((o1, o2) -> o1 == null || o2 == null || o1.getName() == null || o2.getName() == null ? 0
: o1.getName().compareTo(o2.getName()));
return list;
}
private Map<Integer, TProjectRecord> generateProjectMap(List<TProjectRecord> list) {
Map<Integer, TProjectRecord> map = new HashMap<>();
for (TProjectRecord r : list) {
map.put(r.getPk(), r);
}
return map;
}
private Map<Integer, TModuleRecord> generateModuleMap(List<TModuleRecord> list) {
Map<Integer, TModuleRecord> map = new HashMap<>();
for (TModuleRecord r : list) {
map.put(r.getPk(), r);
}
return map;
}
private Map<Integer, TJobRecord> generateJobMap(List<TJobRecord> list) {
Map<Integer, TJobRecord> map = new HashMap<>();
for (TJobRecord r : list) {
map.put(r.getPk(), r);
}
return map;
}
/**
* get all from t_done of the given day
*
* @param day
* the day; if null, the current date is used
*
* @return a list of found times, an empty one at least
*/
public List<DoneBean> getAll(LocalDateTime day) throws DataAccessException {
Map<Integer, TProjectRecord> projectMap = generateProjectMap(getAllProjects());
Map<Integer, TModuleRecord> moduleMap = generateModuleMap(getAllModules());
Map<Integer, TJobRecord> jobMap = generateJobMap(getAllActivities());
if (day == null) {
day = LocalDateTime.now();
}
LocalDateTime yesterday = day.minusDays(1).withHour(23).withMinute(0).withSecond(0).withNano(0);
LocalDateTime tomorrow = day.plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
List<DoneBean> list = new ArrayList<>();
SelectConditionStep<TDoneRecord> sql = getJooq()
// @formatter:off
.selectFrom(T_DONE)
.where(T_DONE.FK_LOGIN.eq(getFkLogin()))
.and(T_DONE.TIME_FROM.isNull()
.or(T_DONE.TIME_FROM.greaterThan(Timestamp.valueOf(yesterday))
.and(T_DONE.TIME_FROM.lessThan(Timestamp.valueOf(tomorrow)))))
.and(T_DONE.TIME_UNTIL.isNull()
.or(T_DONE.TIME_UNTIL.lessThan(Timestamp.valueOf(tomorrow))
.and(T_DONE.TIME_UNTIL.greaterThan(Timestamp.valueOf(yesterday)))));
// @formatter:on
LOGGER.debug(sql.toString());
for (TDoneRecord r : sql.fetch()) {
list.add(new DoneBean(r, projectMap, moduleMap, jobMap));
}
list.sort((o1, o2) -> o1 == null || o2 == null ? 0 : o1.compareTo(o2));
return list;
}
/**
* insert data into t_done
*
* @param bean
*/
public void insert(DoneBean bean) throws DataAccessException {
Integer fkProject = bean.getProject() == null ? null : bean.getProject().getPk();
Integer fkModule = bean.getModule() == null ? null : bean.getModule().getPk();
Integer fkJob = bean.getActivity() == null ? null : bean.getActivity().getPk();
Integer fkLogin = getFkLogin();
InsertValuesStep6<TDoneRecord, Timestamp, Timestamp, Integer, Integer, Integer, Integer> sql = getJooq()
// @formatter:off
.insertInto(T_DONE,
T_DONE.TIME_FROM,
T_DONE.TIME_UNTIL,
T_DONE.FK_PROJECT,
T_DONE.FK_MODULE,
T_DONE.FK_JOB,
T_DONE.FK_LOGIN)
.values(bean.getTimeFrom(), bean.getTimeUntil(), fkProject, fkModule, fkJob, fkLogin);
// @formatter:on
LOGGER.debug(sql.toString());
sql.execute();
}
/**
* update bean in t_done
*
* @param bean
*/
public void update(DoneBean bean) throws DataAccessException {
UpdateConditionStep<TDoneRecord> sql = getJooq()
// @formatter:off
.update(T_DONE)
.set(T_DONE.TIME_FROM, bean.getTimeFrom())
.set(T_DONE.TIME_UNTIL, bean.getTimeUntil())
.set(T_DONE.FK_PROJECT, bean.getProject() == null ? null : bean.getProject().getPk())
.set(T_DONE.FK_JOB, bean.getActivity() == null ? null : bean.getActivity().getPk())
.set(T_DONE.FK_MODULE, bean.getModule() == null ? null : bean.getModule().getPk())
.where(T_DONE.PK.eq(bean.getPk()));
// @formatter:on
LOGGER.debug(sql.toString());
sql.execute();
}
/**
* delete bean from t_done
*
* @param bean
*/
public void delete(DoneBean bean) throws DataAccessException {
DeleteConditionStep<TDoneRecord> sql = getJooq().deleteFrom(T_DONE).where(T_DONE.PK.eq(bean.getPk()));
LOGGER.debug(sql.toString());
sql.execute();
}
/**
* get day summary
*
* @param day
* the day
* @return the day summary if found, an empty map otherwise
*/
public WholeDaySummaryBean getDaySummary(Date day) {
SelectConditionStep<Record4<String, String, String, String>> sql = getJooq()
// @formatter:off
.select(V_TOTALOFDAY.STARTTIME,
V_TOTALOFDAY.ENDTIME,
V_TOTALOFDAY.WORKTIME,
V_TOTALOFDAY.BREAKTIME)
.from(V_TOTALOFDAY)
.where(V_TOTALOFDAY.DAY.eq(new SimpleDateFormat("yyyy-MM-dd").format(day)))
.and(V_TOTALOFDAY.FK_LOGIN.eq(getFkLogin()));
// @formatter:on
LOGGER.debug(sql.toString());
Record r = sql.fetchOne();
if (r != null) {
String startTime = r.get(V_TOTALOFDAY.STARTTIME);
String endTime = r.get(V_TOTALOFDAY.ENDTIME);
String workTime = r.get(V_TOTALOFDAY.WORKTIME);
String breakTime = r.get(V_TOTALOFDAY.BREAKTIME);
return new WholeDaySummaryBean(startTime, endTime, workTime, breakTime);
}
return new WholeDaySummaryBean("", "", "", "");
}
private String toStringFromDuration(Duration i) {
StringBuilder buf = new StringBuilder();
if (i != null) {
buf.append(i.toHours()).append(":");
buf.append(i.toMinutes() % 60);
}
return buf.toString();
}
/**
* get all jobs of day
*
* @param day
* the day
* @return list of found jobs; an empty list at least
*/
public List<DailySummaryBean> getAllJobs(Date day) {
SelectConditionStep<Record4<String, String, String, String>> sql = getJooq()
// @formatter:off
.select(V_TASKLIST.DURATION,
V_TASKLIST.PROJECT_NAME,
V_TASKLIST.MODULE_NAME,
V_TASKLIST.JOB_NAME)
.from(V_TASKLIST)
.where(V_TASKLIST.DAY.eq(new SimpleDateFormat("yyyy-MM-dd").format(day)))
.and(V_TASKLIST.FK_LOGIN.eq(getFkLogin()));
// @formatter:on
LOGGER.debug(sql.toString());
List<DailySummaryBean> list = new ArrayList<>();
for (Record4<String, String, String, String> r : sql.fetch()) {
String duration = r.get(V_TASKLIST.DURATION);
String projectName = r.get(V_TASKLIST.PROJECT_NAME);
String moduleName = r.get(V_TASKLIST.MODULE_NAME);
String jobName = r.get(V_TASKLIST.JOB_NAME);
list.add(new DailySummaryBean(projectName, moduleName, jobName, duration));
}
return list;
}
}

View File

@ -0,0 +1,205 @@
package de.jottyfan.timetrack.modules.done;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.jooq.exception.DataAccessException;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
import de.jottyfan.timetrack.modules.Model;
/**
*
* @author henkej
*
*/
@ManagedBean
@SessionScoped
public class DoneModel implements Model, Serializable {
private static final long serialVersionUID = 1L;
private DoneBean bean;
private List<DoneBean> beans;
private List<TProjectRecord> projects;
private List<TModuleRecord> modules;
private List<TJobRecord> activities;
private List<TimeBean> times;
private List<DailySummaryBean> allJobs;
private WholeDaySummaryBean daySummary;
private Date day;
public boolean init(FacesContext facesContext) {
try {
day = day == null ? new Date() : day;
beans = getAllOfDay(facesContext, day);
DoneGateway gw = new DoneGateway(facesContext);
modules = gw.getAllModules();
activities = gw.getAllActivities();
projects = gw.getAllProjects();
daySummary = gw.getDaySummary(day);
allJobs = gw.getAllJobs(day);
return true;
} catch (DataAccessException e) {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public boolean loadDefaults(FacesContext facesContext) {
try {
defineTimes();
return true;
} catch (DataAccessException e) {
facesContext.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "error loading defaults", e.getMessage()));
return false;
}
}
private void defineTimes() {
times = new ArrayList<>();
Integer currentHour = getCurrentTime().get(GregorianCalendar.HOUR_OF_DAY);
Integer currentMinute = getCurrentTime().get(GregorianCalendar.MINUTE);
if (currentMinute < 15) {
currentMinute = 0;
} else if (currentMinute < 30) {
currentMinute = 15;
} else if (currentMinute < 45) {
currentMinute = 30;
} else {
currentMinute = 45;
}
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 120), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 105), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 90), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 75), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 60), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 45), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 30), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute - 15), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute), "default"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute + 15), "default"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute + 30), "link"));
times.add(new TimeBean(defineNewTime(currentHour, currentMinute + 45), "link"));
}
private Calendar getCurrentTime() {
return new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"));
}
private Calendar defineNewTime(Integer hours, Integer minutes) {
Calendar cal = new GregorianCalendar();
if (minutes < 0) {
hours--;
minutes += 60;
} else if (minutes > 59) {
hours++;
minutes -= 60;
}
cal.set(0, 0, 0, hours, minutes, 0);
return cal;
}
/**
* get all entries of t_done
*
* @param facesContext
* @param day
* the day to look up for
* @param login
* the user to look up for
* @return all entries
*/
private List<DoneBean> getAllOfDay(FacesContext facesContext, Date day) throws DataAccessException {
LocalDateTime ldt = day.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
return new DoneGateway(facesContext).getAll(ldt);
}
public boolean insert(FacesContext facesContext) {
try {
new DoneGateway(facesContext).insert(bean);
return true;
} catch (DataAccessException e) {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public boolean update(FacesContext facesContext) {
try {
new DoneGateway(facesContext).update(bean);
return true;
} catch (DataAccessException e) {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public boolean delete(FacesContext facesContext) {
try {
new DoneGateway(facesContext).delete(bean);
return true;
} catch (DataAccessException e) {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public void setBean(DoneBean bean) {
this.bean = bean;
}
public DoneBean getBean() {
return bean;
}
public List<TProjectRecord> getProjects() {
return projects;
}
public List<TModuleRecord> getModules() {
return modules;
}
public List<TJobRecord> getActivities() {
return activities;
}
public List<DailySummaryBean> getAllJobs() {
return allJobs;
}
public WholeDaySummaryBean getDaySummary() {
return daySummary;
}
public List<DoneBean> getBeans() {
return beans;
}
public List<TimeBean> getTimes() {
return times;
}
public Date getDay() {
return day;
}
public void setDay(Date day) {
this.day = day;
}
}

View File

@ -0,0 +1,32 @@
package de.jottyfan.timetrack.modules.done;
import java.text.SimpleDateFormat;
import java.util.Calendar;
/**
*
* @author henkej
*
*/
public class TimeBean {
private final String value;
private final String look;
public TimeBean(String value, String look) {
super();
this.value = value;
this.look = look;
}
public TimeBean(Calendar calendar, String look) {
this(new SimpleDateFormat("HH:mm").format(calendar.getTime()), look);
}
public String getValue() {
return value;
}
public String getLook() {
return look;
}
}

View File

@ -0,0 +1,63 @@
package de.jottyfan.timetrack.modules.done;
/**
*
* @author henkej
*
*/
public class WholeDaySummaryBean {
private final String startTime;
private final String endTime;
private final String workTime;
private final String breakTime;
public WholeDaySummaryBean(String startTime, String endTime, String workTime, String breakTime) {
super();
this.startTime = startTime;
this.endTime = endTime;
this.workTime = workTime;
this.breakTime = breakTime;
}
public String getOvertime() {
if (workTime != null && !workTime.trim().isEmpty() && workTime.contains(":")) {
try {
Integer hours = Integer.valueOf(workTime.substring(0, workTime.indexOf(":")));
Integer minutes = Integer.valueOf(workTime.substring(workTime.indexOf(":") + 1));
Integer wholeMinutes = hours * 60 + minutes;
Integer overtime = wholeMinutes - (7 * 60 + 48);
Integer overtimeHours = overtime / 60;
Integer overtimeMinutes = overtime % 60;
StringBuilder buf = new StringBuilder();
if (overtime < 0) {
buf.append("-");
overtimeHours *= -1;
overtimeMinutes *= -1;
}
buf.append(String.format("%02d", overtimeHours));
buf.append(":");
buf.append(String.format("%02d", overtimeMinutes));
return buf.toString();
} catch (NumberFormatException e) {
return "";
}
}
return "-07:48";
}
public String getStartTime() {
return startTime;
}
public String getEndTime() {
return endTime;
}
public String getWorkTime() {
return workTime;
}
public String getBreakTime() {
return breakTime;
}
}

View File

@ -0,0 +1,91 @@
package de.jottyfan.timetrack.modules.note;
import java.io.*;
import java.util.*;
import de.jottyfan.timetrack.db.note.enums.EnumCategory;
import de.jottyfan.timetrack.db.note.enums.EnumNotetype;
import de.jottyfan.timetrack.modules.Bean;
/**
*
* @author henkej
*
*/
public class NoteBean implements Bean, Serializable
{
private static final long serialVersionUID = 1L;
private final Integer pk;
private String title;
private EnumCategory category;
private EnumNotetype type;
private String content;
private Date lastchange;
public NoteBean(Integer pk)
{
super();
this.pk = pk;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public EnumCategory getCategory()
{
return category;
}
public void setCategory(EnumCategory category)
{
this.category = category;
}
public EnumNotetype getType()
{
return type;
}
public void setType(EnumNotetype type)
{
this.type = type;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
public Date getLastchange()
{
return lastchange;
}
public void setLastchange(Date lastchange)
{
this.lastchange = lastchange;
}
public static long getSerialversionuid()
{
return serialVersionUID;
}
public Integer getPk()
{
return pk;
}
}

View File

@ -0,0 +1,122 @@
package de.jottyfan.timetrack.modules.note;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import de.jottyfan.timetrack.help.Navigation;
import de.jottyfan.timetrack.help.Pages;
import de.jottyfan.timetrack.modules.ControlInterface;
import de.jottyfan.timetrack.modules.Model;
/**
*
* @author henkej
*
*/
@ManagedBean
@RequestScoped
public class NoteControl extends Navigation implements ControlInterface, Serializable
{
private static final long serialVersionUID = 1L;
@ManagedProperty(value = "#{noteModel}")
private NoteModel model;
@ManagedProperty(value = "#{facesContext}")
private FacesContext facesContext;
public String toStart()
{
return navigateTo(Pages.START);
}
public String toList()
{
boolean ready = model.init(facesContext);
return ready ? navigateTo(Pages.NOTE_LIST) : "";
}
public String toItem(NoteBean bean)
{
model.setBean(bean);
return navigateTo(Pages.NOTE_ITEM);
}
public String toAdd()
{
return toItem(new NoteBean(null));
}
public String doAdd()
{
boolean ready = model.add(facesContext);
return ready ? toList() : toItem(model.getBean());
}
public String doUpdate()
{
boolean ready = model.update(facesContext);
return ready ? toList() : toItem(model.getBean());
}
public String doDelete()
{
boolean ready = model.delete(facesContext);
return ready ? toList() : toItem(model.getBean());
}
/**
* trim s to maxLength; if s > maxLength, append ...
*
* @param s
* @param maxLength
* @return
*/
public String trimTo(String s, Integer maxLength)
{
if (s == null)
{
return s;
}
else
{
String firstLine = s.contains("\n") ? s.substring(0, s.indexOf("\n")) : s;
if (firstLine.length() > maxLength)
{
return firstLine.substring(0, maxLength).concat("...");
}
else if (s.contains("\n"))
{
return firstLine.concat("...");
}
else
{
return firstLine;
}
}
}
public Long getAmount() {
return model.getAmount(facesContext);
}
@Override
public Model getModel()
{
return model;
}
public void setModel(NoteModel model)
{
this.model = model;
}
public void setFacesContext(FacesContext facesContext)
{
this.facesContext = facesContext;
}
}

View File

@ -0,0 +1,102 @@
package de.jottyfan.timetrack.modules.note;
import static de.jottyfan.timetrack.db.note.Tables.T_NOTE;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DeleteConditionStep;
import org.jooq.InsertValuesStep4;
import org.jooq.Record;
import org.jooq.SelectJoinStep;
import org.jooq.UpdateConditionStep;
import org.jooq.exception.DataAccessException;
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.modules.JooqGateway;
/**
*
* @author henkej
*
*/
public class NoteGateway extends JooqGateway
{
private static final Logger LOGGER = LogManager.getLogger(NoteGateway.class);
public NoteGateway(FacesContext facesContext)
{
super(facesContext);
}
/**
* insert into t_note
*
* @param noteBean
* @throws DataAccessException
* @returns amount of affected rows in db
*/
public void insert(NoteBean bean) throws DataAccessException
{
InsertValuesStep4<TNoteRecord, String, EnumCategory, EnumNotetype, String> sql = getJooq().insertInto(T_NOTE, T_NOTE.TITLE, T_NOTE.CATEGORY, T_NOTE.NOTETYPE, T_NOTE.CONTENT).values(bean.getTitle(), bean.getCategory(), bean.getType(),
bean.getContent());
LOGGER.debug(sql.toString());
sql.execute();
}
/**
* update content of bean
*
* @param bean
* @throws DataAccessException
*/
public void update(NoteBean bean) throws DataAccessException
{
UpdateConditionStep<TNoteRecord> sql = getJooq().update(T_NOTE).set(T_NOTE.TITLE, bean.getTitle()).set(T_NOTE.CONTENT, bean.getContent()).where(T_NOTE.PK.eq(bean.getPk()));
LOGGER.debug(sql.toString());
sql.execute();
}
/**
* delete from t_note
*
* @param pk
* @throws DataAccessException
*/
public void delete(Integer pk) throws DataAccessException
{
DeleteConditionStep<TNoteRecord> sql = getJooq().deleteFrom(T_NOTE).where(T_NOTE.PK.eq(pk));
LOGGER.debug(sql.toString());
sql.execute();
}
/**
* get all from t_note
*
* @return
* @throws DataAccessException
*/
public List<NoteBean> getAll() throws DataAccessException
{
SelectJoinStep<Record> sql = getJooq().select().from(T_NOTE);
LOGGER.debug(sql.toString());
List<NoteBean> list = new ArrayList<>();
for (Record 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));
bean.setLastchange(r.get(T_NOTE.LASTCHANGE));
list.add(bean);
}
return list;
}
}

View File

@ -0,0 +1,106 @@
package de.jottyfan.timetrack.modules.note;
import java.io.Serializable;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.jooq.exception.DataAccessException;
import de.jottyfan.timetrack.db.note.Tables;
import de.jottyfan.timetrack.modules.Model;
/**
*
* @author henkej
*
*/
@ManagedBean
@SessionScoped
public class NoteModel implements Model, Serializable
{
private static final long serialVersionUID = 1L;
private List<NoteBean> beans;
private NoteBean bean;
public boolean init(FacesContext facesContext)
{
try
{
beans = new NoteGateway(facesContext).getAll();
return true;
}
catch (DataAccessException e)
{
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public boolean add(FacesContext facesContext)
{
try
{
new NoteGateway(facesContext).insert(bean);
return true;
}
catch (DataAccessException e)
{
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public boolean update(FacesContext facesContext)
{
try
{
new NoteGateway(facesContext).update(bean);
return true;
}
catch (DataAccessException e)
{
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public boolean delete(FacesContext facesContext)
{
try
{
new NoteGateway(facesContext).delete(bean.getPk());
return true;
}
catch (DataAccessException e)
{
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "error", e.getMessage()));
return false;
}
}
public Long getAmount(FacesContext facesContext)
{
return new NoteGateway(facesContext).getAmount(Tables.T_NOTE);
}
@Override
public NoteBean getBean()
{
return bean;
}
public void setBean(NoteBean bean)
{
this.bean = bean;
}
public List<NoteBean> getBeans()
{
return beans;
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="rsslogger">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{dd.MM.yyyy HH:mm:ss,SSS} [%5p] %t (%C.%M:%L) %m%n" />
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<lifecycle>
<phase-listener>de.jooqFaces.JooqFacesRenderResponsePhaseListener</phase-listener>
<phase-listener>de.jooqFaces.JooqFacesRestoreViewPhaseListener</phase-listener>
</lifecycle>
<factory>
<faces-context-factory>de.jooqFaces.JooqFacesContextFactory</faces-context-factory>
</factory>
</faces-config>

View File

@ -0,0 +1,69 @@
<?xml version='1.0' encoding='UTF-8'?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>timetrack</display-name>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>de.jottyfan.timetrack.help.EncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>580</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>pages/start.jsf</welcome-file>
</welcome-file-list>
<context-param>
<param-name>org.apache.myfaces.RENDER_VIEWSTATE_ID</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Production</param-value>
<!-- <param-value>Development</param-value> -->
</context-param>
<context-param>
<param-name>org.apache.myfaces.LOG_WEB_CONTEXT_PARAMS</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>BootsFaces_USETHEME</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>BootsFaces_THEME</param-name>
<param-value>#{themeBean.currentTheme}</param-value>
</context-param>
<context-param>
<param-name>jooqFacesProperties</param-name>
<param-value>/etc/tomcat8/timetrack.properties</param-value>
</context-param>
<listener>
<listener-class>de.jooqFaces.PropertiesDeploymentListener</listener-class>
</listener>
</web-app>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Kontakte</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top"></ui:define>
<ui:define name="main">
<b:panel title="Kontakt" look="primary">
<h:form>
<b:panelGrid colSpans="3,9">
<h:outputText value="Vorname" />
<b:inputText value="#{contactModel.bean.forename}" />
<h:outputText value="Nachname" />
<b:inputText value="#{contactModel.bean.surname}" />
<h:outputText value="Kontakt" />
<b:inputText value="#{contactModel.bean.contact}" />
<h:outputText value="Typ" />
<b:selectOneMenu value="#{contactModel.bean.type}">
<f:selectItems value="#{contactModel.types}" var="t" itemValue="#{t}" itemLabel="#{t.literal}" />
</b:selectOneMenu>
<h:outputText value="" />
<b:buttonGroup>
<b:commandButton action="#{contactControl.toList}" value="Abbrechen" />
<b:commandButton action="#{contactControl.doAdd}" value="Hinzufügen" look="success" iconAwesome="plus"
rendered="#{contactModel.bean.pk == null}" />
<b:commandButton action="#{contactControl.doUpdate}" value="Übernehmen" look="primary" iconAwesome="pencil"
rendered="#{contactModel.bean.pk != null}" />
<b:dropButton value="Löschen" iconAwesome="trash" look="danger" rendered="#{contactModel.bean.pk != null}">
<b:navCommandLink action="#{contactControl.doDelete}" value="ja, wirklich" />
</b:dropButton>
</b:buttonGroup>
</b:panelGrid>
</h:form>
</b:panel>
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,41 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Kontakte</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top">
</ui:define>
<ui:define name="main">
<b:panel title="Kontakte" look="primary">
<b:form>
<b:dataTable value="#{contactModel.list}" var="bean" lang="de">
<b:dataTableColumn label="Vorname">
<b:commandButton action="#{(contactControl.toItem(bean))}" value="#{bean.forename}" look="link" />
</b:dataTableColumn>
<b:dataTableColumn label="Nachname">
<b:commandButton action="#{(contactControl.toItem(bean))}" value="#{bean.surname}" look="link" />
</b:dataTableColumn>
<b:dataTableColumn label="Kontakt">
<b:commandButton action="#{(contactControl.toItem(bean))}" value="#{bean.contact}" look="link" />
</b:dataTableColumn>
<b:dataTableColumn label="Typ">
<b:commandButton action="#{(contactControl.toItem(bean))}" value="#{bean.type.literal}" look="link" rendered="#{bean.type != null}" />
</b:dataTableColumn>
</b:dataTable>
</b:form>
</b:panel>
</ui:define>
<ui:define name="navigation">
<h:form>
<b:buttonGroup>
<b:commandButton action="#{contactControl.toStart}" value="zurück" look="primary" iconAwesome="arrow-left" />
<b:commandButton action="#{contactControl.toItem}" value="hinzufügen" look="success" iconAwesome="plus" />
</b:buttonGroup>
</h:form>
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,79 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core" xmlns:b="http://bootsfaces.net/ui" xmlns:my="http://xmlns.jcp.org/jsf/composite/my"
xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
<h:head>
<title>Arbeitszeit</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top">
</ui:define>
<ui:define name="main">
<b:panel title="Arbeitszeit für #{doneModel.day}, aktualisiert um #{doneControl.currentTimeAsString}" look="success">
<b:form id="formular">
<h:panelGrid columns="2" columnClasses="tdtop, tdtop">
<b:inputText id="time_from" value="#{doneModel.bean.timeFromString}">
<f:facet name="prepend">
<h:outputText value="Von" />
</f:facet>
</b:inputText>
<b:buttonGroup p:class="form-group">
<b:button value="--:--" onclick="document.getElementById('input_formular:time_from').value = ''; return false;"
look="danger" />
<ui:repeat var="time" value="#{doneModel.times}">
<b:button onclick="document.getElementById('input_formular:time_from').value = '#{time.value}'; return false;"
value="#{time.value}" look="#{time.look}" />
</ui:repeat>
</b:buttonGroup>
<b:inputText id="time_until" value="#{doneModel.bean.timeUntilString}">
<f:facet name="prepend">
<h:outputText value="Bis" />
</f:facet>
</b:inputText>
<b:buttonGroup p:class="form-group">
<b:button value="--:--" onclick="document.getElementById('input_formular:time_until').value = ''; return false;"
look="danger" />
<ui:repeat var="time" value="#{doneModel.times}">
<b:button onclick="document.getElementById('input_formular:time_until').value = '#{time.value}'; return false;"
value="#{time.value}" look="#{time.look}" />
</ui:repeat>
</b:buttonGroup>
</h:panelGrid>
<b:panelGrid colSpans="4,4,4" size="xs">
<h:outputText value="Projekt" />
<h:outputText value="Modul" />
<h:outputText value="Tätigkeit" />
<b:selectOneMenu id="project" value="#{doneModel.bean.project}">
<f:selectItem itemValue="" itemLabel="--- bitte wählen ---" />
<f:selectItems value="#{doneModel.projects}" var="i" itemValue="#{i}" itemLabel="#{i.name}" />
</b:selectOneMenu>
<b:selectOneMenu id="module" value="#{doneModel.bean.module}">
<f:selectItem itemValue="" itemLabel="--- bitte wählen ---" />
<f:selectItems value="#{doneModel.modules}" var="i" itemValue="#{i}" itemLabel="#{i.name}" />
</b:selectOneMenu>
<b:selectOneMenu id="activity" value="#{doneModel.bean.activity}">
<f:selectItem itemValue="" itemLabel="--- bitte wählen ---" />
<f:selectItems value="#{doneModel.activities}" var="i" itemValue="#{i}" itemLabel="#{i.name}" />
</b:selectOneMenu>
</b:panelGrid>
<b:buttonGroup>
<b:commandButton action="#{doneControl.toList}" immediate="true" value="Abbrechen" />
<b:commandButton action="#{doneControl.doAdd}" value="Eintrag hinzufügen" look="success" iconAwesome="plus" />
</b:buttonGroup>
<script type="text/javascript">
$(document).ready(function() {
$("[id='formular:projectInner']").attr("size", 25);
$("[id='formular:moduleInner']").attr("size", 25);
$("[id='formular:activityInner']").attr("size", 25);
});
</script>
</b:form>
</b:panel>
</ui:define>
<ui:define name="navigation">
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Arbeitszeit</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top">
Arbeitszeit
</ui:define>
<ui:define name="main">
<b:panel title="Löschen eines Eintrags" look="danger" style="font-size: initial">
<b:panelGrid colSpans="6,6" style="max-width: 200px" size="xs">
<h:outputText value="Von: " />
<h:outputText value="#{doneModel.bean.timeFromString}" style="font-weight: bolder" />
<h:outputText value="Bis: " />
<h:outputText value="#{doneModel.bean.timeUntilString}" style="font-weight: bolder" />
<h:outputText value="Projekt: " />
<h:outputText value="#{doneModel.bean.projectName}" style="font-weight: bolder" />
<h:outputText value="Modul: " />
<h:outputText value="#{doneModel.bean.moduleName}" style="font-weight: bolder" />
<h:outputText value="Tätigkeit: " />
<h:outputText value="#{doneModel.bean.jobName}" style="font-weight: bolder" />
</b:panelGrid>
<b:form>
<b:buttonGroup>
<b:commandButton action="#{doneControl.toInit}" immediate="true" value="Abbrechen" />
<b:commandButton action="#{doneControl.doDelete}" value="Entfernen" look="danger" iconAwesome="trash" />
</b:buttonGroup>
</b:form>
</b:panel>
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,79 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:b="http://bootsfaces.net/ui" xmlns:my="http://xmlns.jcp.org/jsf/composite/my"
xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
<h:head>
<title>Arbeitszeit</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top">
</ui:define>
<ui:define name="main">
<b:panel title="Arbeitszeit für #{doneModel.day}, aktualisiert um #{doneControl.currentTimeAsString}" look="warning">
<b:form id="formular">
<h:panelGrid columns="2" columnClasses="tdtop, tdtop">
<b:inputText id="time_from" value="#{doneModel.bean.timeFromString}">
<f:facet name="prepend">
<h:outputText value="Von" />
</f:facet>
</b:inputText>
<b:buttonGroup p:class="form-group">
<b:button value="--:--" onclick="document.getElementById('input_formular:time_from').value = ''; return false;"
look="danger" />
<ui:repeat var="time" value="#{doneModel.times}">
<b:button onclick="document.getElementById('input_formular:time_from').value = '#{time.value}'; return false;"
value="#{time.value}" look="#{time.look}" />
</ui:repeat>
</b:buttonGroup>
<b:inputText id="time_until" value="#{doneModel.bean.timeUntilString}">
<f:facet name="prepend">
<h:outputText value="Bis" />
</f:facet>
</b:inputText>
<b:buttonGroup p:class="form-group">
<b:button value="--:--" onclick="document.getElementById('input_formular:time_until').value = ''; return false;"
look="danger" />
<ui:repeat var="time" value="#{doneModel.times}">
<b:button onclick="document.getElementById('input_formular:time_until').value = '#{time.value}'; return false;"
value="#{time.value}" look="#{time.look}" />
</ui:repeat>
</b:buttonGroup>
</h:panelGrid>
<b:panelGrid colSpans="4,4,4" size="xs">
<h:outputText value="Projekt (#{doneModel.bean.projectName})" />
<h:outputText value="Modul (#{doneModel.bean.moduleName})" />
<h:outputText value="Tätigkeit (#{doneModel.bean.jobName})" />
<b:selectOneMenu id="project" value="#{doneModel.bean.project}">
<f:selectItem itemValue="" itemLabel="--- bitte wählen ---" />
<f:selectItems value="#{doneModel.projects}" var="i" itemValue="#{i}" itemLabel="#{i.name}" />
</b:selectOneMenu>
<b:selectOneMenu id="module" value="#{doneModel.bean.module}">
<f:selectItem itemValue="" itemLabel="--- bitte wählen ---" />
<f:selectItems value="#{doneModel.modules}" var="i" itemValue="#{i}" itemLabel="#{i.name}" />
</b:selectOneMenu>
<b:selectOneMenu id="activity" value="#{doneModel.bean.activity}">
<f:selectItem itemValue="" itemLabel="--- bitte wählen ---" />
<f:selectItems value="#{doneModel.activities}" var="i" itemValue="#{i}" itemLabel="#{i.name}" />
</b:selectOneMenu>
</b:panelGrid>
<b:buttonGroup>
<b:commandButton action="#{doneControl.toList}" immediate="true" value="Abbrechen" />
<b:commandButton action="#{doneControl.doUpdate}" value="Aktualisieren" iconAwesome="pencil" look="warning" />
</b:buttonGroup>
<script type="text/javascript">
$(document).ready(function() {
$("[id='formular:projectInner']").attr("size", 25);
$("[id='formular:moduleInner']").attr("size", 25);
$("[id='formular:activityInner']").attr("size", 25);
});
</script>
</b:form>
</b:panel>
</ui:define>
<ui:define name="navigation">
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,97 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Arbeitszeit</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top"></ui:define>
<ui:define name="main">
<b:panel title="Arbeitszeit" look="primary">
<b:form>
<h:panelGrid columns="3">
<h:outputText value="für den Tag" />
<b:dateTimePicker value="#{doneModel.day}" showTime="false" style="padding-left: 4px" />
<b:commandButton action="#{doneControl.toList}" value="neu laden" look="default" iconAwesome="refresh"
style="padding-left: 4px" />
</h:panelGrid>
<b:tabView>
<b:tab title="Liste">
<b:dataTable value="#{doneModel.beans}" var="b" border="false" info="false" paginated="false" searching="false"
styleClass="doneoverview">
<b:dataTableColumn label="" orderable="false">
<b:commandButton action="#{doneControl.toDelete(b)}" value="Entfernen" look="danger" iconAwesome="trash" />
</b:dataTableColumn>
<b:dataTableColumn label="" value="#{b.timeSummary}" contentStyleClass="doneoverviewtext" orderable="false" />
<b:dataTableColumn label="" value="#{b.projectName}" contentStyleClass="doneoverviewtextemph" orderable="false" />
<b:dataTableColumn label="" value="#{b.timeDiff}" contentStyleClass="doneoverviewtextemph" orderable="false" />
<b:dataTableColumn label="" orderable="false">
<b:commandButton action="#{doneControl.toEdit(b)}" value="Editieren" look="warning" iconAwesome="pencil" />
</b:dataTableColumn>
<b:dataTableColumn label="" value="#{b.moduleName}" contentStyleClass="doneoverviewtext" orderable="false" />
<b:dataTableColumn label="" value="#{b.jobName}" contentStyleClass="doneoverviewtext" orderable="false" />
</b:dataTable>
</b:tab>
<b:tab title="Zusammenfassung">
<b:dataTable value="#{doneModel.allJobs}" var="col" border="false" info="false" paginated="false"
searching="false">
<b:dataTableColumn label="" value="#{col.projectName}" contentStyle="font-size: 120%" orderable="false" />
<b:dataTableColumn label="" value="#{col.moduleName}" contentStyle="font-size: 120%" orderable="false" />
<b:dataTableColumn label="" value="#{col.jobName}" contentStyle="font-size: 120%" orderable="false" />
<b:dataTableColumn label="" value="#{col.duration}" contentStyle="font-size: 120%" orderable="false" />
</b:dataTable>
</b:tab>
</b:tabView>
<b:row rendered="#{doneModel.daySummary != null}">
<b:column colXs="4">
<b:well styleClass="dangerWell">Pause
<h3>
<h:outputText value="#{doneModel.daySummary.breakTime}" />
</h3>
</b:well>
</b:column>
<b:column colXs="4">
<b:well>Startzeit
<h3>
<h:outputText value="#{doneModel.daySummary.startTime}" />
</h3>
</b:well>
</b:column>
<b:column colXs="4">
<b:well>Überstunden
<h3>
<h:outputText value="#{doneModel.daySummary.overtime}" />
</h3>
</b:well>
</b:column>
<b:column colXs="4">
<b:well styleClass="successWell">Arbeitszeit
<h3>
<h:outputText value="#{doneModel.daySummary.workTime}" />
</h3>
</b:well>
</b:column>
<b:column colXs="4">
<b:well>Endzeit
<h3>
<h:outputText value="#{doneModel.daySummary.endTime}" />
</h3>
</b:well>
</b:column>
</b:row>
</b:form>
</b:panel>
</ui:define>
<ui:define name="navigation">
<b:form>
<b:buttonGroup>
<b:commandButton action="#{doneControl.toStart}" value="zurück" look="primary" iconAwesome="arrow-left" />
<b:commandButton action="#{doneControl.toAdd}" value="Neuer Eintrag" look="success" iconAwesome="plus" />
</b:buttonGroup>
</b:form>
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Aufgaben</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top"></ui:define>
<ui:define name="main">
<b:panel title="Notizen" look="primary">
<h:form>
<b:panelGrid colSpans="3,9">
<h:outputText value="Titel" />
<b:inputText value="#{noteModel.bean.title}" />
<h:outputText value="Kategorie" />
<b:selectOneMenu value="#{noteModel.bean.category}">
<f:selectItem itemLabel="PostgreSQL" itemValue="PostgreSQL" />
<f:selectItem itemLabel="R" itemValue="R" />
<f:selectItem itemLabel="Bootsfaces" itemValue="Bootsfaces" />
<f:selectItem itemLabel="MyFaces" itemValue="MyFaces" />
<f:selectItem itemLabel="Java" itemValue="Java" />
<f:selectItem itemLabel="Bash" itemValue="Bash" />
<f:selectItem itemLabel="Apache" itemValue="Apache" />
<f:selectItem itemLabel="Tomcat" itemValue="Tomcat" />
</b:selectOneMenu>
<h:outputText value="Typ" />
<b:selectOneMenu value="#{noteModel.bean.type}">
<f:selectItem itemLabel="Administration" itemValue="Administration" />
<f:selectItem itemLabel="HowTo" itemValue="HowTo" />
</b:selectOneMenu>
<h:outputText value="Inhalt" />
<b:inputTextarea value="#{noteModel.bean.content}" />
<h:outputText value="" />
<b:buttonGroup>
<b:commandButton action="#{noteControl.toList}" value="Abbrechen" />
<b:commandButton action="#{noteControl.doAdd}" value="Hinzufügen" look="success" iconAwesome="plus" rendered="#{noteModel.bean.pk == null}" />
<b:commandButton action="#{noteControl.doUpdate}" value="Übernehmen" look="primary" iconAwesome="pencil" rendered="#{noteModel.bean.pk != null}" />
<b:commandButton action="#{noteControl.doDelete}" value="Löschen" look="danger" iconAwesome="trash" rendered="#{noteModel.bean.pk != null}" />
</b:buttonGroup>
</b:panelGrid>
</h:form>
</b:panel>
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,45 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Aufgaben</title>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top">
<b:messages />
</ui:define>
<ui:define name="main">
<b:panel title="Notizen" look="primary">
<h:form>
<b:dataTable value="#{noteModel.beans}" var="n" lang="de" pageLength="5" pageLengthMenu="5,10,20,50,100" saveState="true" striped="false">
<b:dataTableColumn label="Titel">
<b:commandButton action="#{noteControl.toItem(n)}" value="#{n.title}" look="link" />
</b:dataTableColumn>
<b:dataTableColumn label="Kategorie">
<b:commandButton action="#{noteControl.toItem(n)}" value="#{n.category}" look="link" />
</b:dataTableColumn>
<b:dataTableColumn label="Typ">
<b:commandButton action="#{noteControl.toItem(n)}" value="#{n.type}" look="link" />
</b:dataTableColumn>
<b:dataTableColumn label="Inhalt">
<b:commandButton action="#{noteControl.toItem(n)}" value="#{noteControl.trimTo(n.content, 32)}" look="link" />
</b:dataTableColumn>
<b:dataTableColumn label="Angelegt">
<b:commandButton action="#{noteControl.toItem(n)}" value="#{n.lastchange}" look="link" />
</b:dataTableColumn>
</b:dataTable>
</h:form>
</b:panel>
</ui:define>
<ui:define name="navigation">
<h:form>
<b:buttonGroup>
<b:commandButton action="#{noteControl.toStart}" value="zurück" look="primary" iconAwesome="arrow-left" />
<b:commandButton action="#{noteControl.toAdd}" value="hinzufügen" look="success" iconAwesome="plus" />
</b:buttonGroup>
</h:form>
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
</h:head>
<h:body>
<ui:composition template="/pages/template.xhtml">
<ui:define name="top">
<b:messages />
</ui:define>
<ui:define name="main">
<b:panel title="Einstellungen" collapsed="true" rendered="#{sessionBean.hasLogin}">
<b:form>
<b:selectOneMenu value="#{themeBean.currentTheme}">
<f:selectItems value="#{themeBean.validThemes}" var="t" itemValue="#{t}" itemLabel="#{t}" />
</b:selectOneMenu>
<b:commandButton action="#{doneControl.toStart}" value="ändern" iconAwesome="pencil" look="warning" />
</b:form>
</b:panel>
<b:panel title="Login" rendered="#{sessionBean.hasNoLogin}" styleClass="loginpanel">
<b:form>
<b:selectOneMenu value="#{sessionBean.username}">
<f:facet name="prepend">
<h:outputText value="Username" />
</f:facet>
<f:selectItem itemValue="henkej" itemLabel="Jörg Henke" />
</b:selectOneMenu>
<b:inputSecret value="#{sessionBean.secret}">
<f:facet name="prepend">
<h:outputText value="Passwort" />
</f:facet>
</b:inputSecret>
<b:commandButton action="#{sessionControl.doLogin}" value="Login" look="primary" />
</b:form>
</b:panel>
</ui:define>
<ui:define name="navigation">
<b:form rendered="#{sessionBean.hasLogin}">
<b:buttonGroup>
<b:commandButton action="#{noteControl.toList}" value="#{noteControl.amount} Notizen verwalten" look="primary"
iconAwesome="comments-o" />
<b:commandButton action="#{contactControl.toList}" value="#{contactControl.amount} Kontakte verwalten" look="primary"
iconAwesome="group" />
<b:commandButton action="#{doneControl.toList}" value="Arbeitszeit verwalten" look="primary" iconAwesome="clock-o" />
<b:commandButton action="#{sessionControl.doLogout}" value="abmelden" look="danger" iconAwesome="sign-out" />
</b:buttonGroup>
</b:form>
</ui:define>
</ui:composition>
</h:body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:my="http://xmlns.jcp.org/jsf/composite/my" xmlns:b="http://bootsfaces.net/ui">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</h:head>
<h:body styleClass="body">
<h:outputStylesheet name="css/style.css" />
<h:outputScript library="bsf" name="jq/jquery.js" target="head" />
<div class="page">
<div class="top">
<ui:insert name="top" />
</div>
<div>
<b:messages />
</div>
<div class="body">
<ui:insert name="main" />
</div>
<div class="navigation">
<ui:insert name="navigation" />
</div>
</div>
</h:body>
</html>

View File

@ -0,0 +1,36 @@
.emph {
border-radius: 3px !important;
border: 1px solid #3070b0 !important;
color: #ffffff !important;
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%)
!important;
}
.doneoverview {
max-width: 850px !important;
width: 850px !important;
}
.doneoverviewtext {
font-size: 120%;
}
.doneoverviewtextemph {
font-size: 120%;
font-weight: bolder;
}
.loginpanel {
margin-top: 100px !important;
margin: 0 auto;
max-width: 400px !important;
width: 400px !important;
}
.successWell {
background-image: linear-gradient(to bottom, #ceeaca 0%, #f7fff7 100%) !important;
}
.dangerWell {
background-image: linear-gradient(to bottom, #eacaca 0%, #fff7f7 100%) !important;
}

View File

@ -0,0 +1,29 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:b="http://bootsfaces.net/ui">
<cc:interface>
<cc:attribute name="list" required="true" type="java.util.List" />
<cc:attribute name="value" required="true" default="" />
<cc:attribute name="styleClass" required="false" default="" />
<cc:attribute name="readonly" required="false" default="true" />
</cc:interface>
<cc:implementation>
<h:outputScript library="bsf" name="jq/jquery.js" target="head" />
<script type="text/javascript">
function setValue(dest, content)
{
$("[id='" + dest + "']").val(content);
}
</script>
<b:inputText id="input" value="#{cc.attrs.value}" styleClass="#{cc.attrs.styleClass}" readonly="#{cc.attrs.readonly}">
<f:facet name="prepend">
<b:dropButton value="">
<h:dataTable value="#{cc.attrs.list}" var="l">
<h:column>
<b:button value="#{l}" onclick="setValue('input_#{cc.clientId}:input', '#{l}'); return false;" look="link" />
</h:column>
</h:dataTable>
</b:dropButton>
</f:facet>
</b:inputText>
</cc:implementation>
</ui:composition>