Merge branch 'master' of git://github.com/dgray16/libreplan into dgray16-master

Conflicts:
	HACKING.rst
	doc/src/technical/howto-start-development-with-intellij-idea.rst

fixed
This commit is contained in:
Jeroen Baten 2015-12-01 11:45:19 +01:00
commit 2025580e5c
68 changed files with 2826 additions and 293 deletions

View file

@ -208,10 +208,6 @@ openSUSE
Microsoft Windows
~~~~~~~~
* Download and install latest Java Runtime Environment 7u79 (JRE7u79)::
# http://www.oracle.com/technetwork/java/javase/downloads/jre7-downloads-1880261.html
* Download and install latest Java Development Kit 7u80 (JDK7u80)::
# http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
@ -244,13 +240,31 @@ Microsoft Windows
CREATE USER libreplan WITH PASSWORD 'libreplan';
GRANT ALL PRIVILEGES ON DATABASE libreplan TO libreplan;
* Download and install Git
REVOKE ALL
ON ALL TABLES IN SCHEMA public
FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA public
TO libreplan;
# https://git-scm.com/download/win
* Download Maven
# https://maven.apache.org/download.cgi
.. WARNING::
Check if latest Maven version is compatible with your JDK
* Connect to database::
# Go to PostgreSQL bin folder and command window from here
# psql -U postgres
* Use SQL sentences::
CREATE DATABASE libreplandev;
CREATE DATABASE libreplandevtest;
CREATE USER libreplan WITH PASSWORD 'libreplan';
GRANT ALL PRIVILEGES ON DATABASE libreplan TO libreplan;
* Restore PostgreSQL dump - scripts/database/postgresql_1.4.1.backup::
@ -279,6 +293,33 @@ Microsoft Windows
# Possible location: C:\Program Files\Apache Software Foundation\Tomcat 6.0\bin\Tomcat6.exe
* Go to http://localhost:8080/libreplan
=======
* Restore PostgreSQL dump - scripts/database/postgresql_1.4.1.backup
* Download source code::
# Open GitBash
# git clone https://github.com/LibrePlan/libreplan.git
* Set JAVA_HOME environment variable::
# You need to set it to your JDK installed directory (e.g. C:\Program Files\Java\jdk1.7.0_80)
* Add path of unpacked distribution’s bin directory of Maven to 'Path' environment variable
# (e.g. C:\Program Files\apache-maven-3.3.3\bin)
* Compile project::
# cd libreplan
# mvn clean install
* Launch application::
# cd libreplan-webapp
# mvn jetty:run
* Go to http://localhost:8080/libreplan-webapp/
CutyCapt compilation
@ -509,6 +550,9 @@ example:
mvn -Ddefault.passwordsControl=false -Ddefault.exampleUsersDisabled=false clean install
* Set *default.emailSendingEnabled* to false::
mvn -Ddefault.emailSendingEnabled=false clean install
Tests
-----

View file

@ -117,6 +117,11 @@ Instructions depending on the distribution:
If you have memory problems review the section `Fix memory errors`_.
Microsoft Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RPM Packages
~~~~~~~~~~~~
@ -316,6 +321,78 @@ openSUSE
* Go to http://localhost:8080/libreplan/
Microsoft Windows
~~~~~~~~~~~
Instructions:
* Download and install latest Java Runtime Environment 7u79 (JRE7u79)::
# http://www.oracle.com/technetwork/java/javase/downloads/jre7-downloads-1880261.html
* Download and install latest PostgreSQL database::
# http://www.enterprisedb.com/products-services-training/pgdownload#windows
* Download and install Apache Tomcat 6::
# http://tomcat.apache.org/download-60.cgi
.. NOTE::
In JDK folder there is JRE folder
* Set up JDBC41 PostgreSQL Driver::
# Download latest driver: https://jdbc.postgresql.org/download.html
# Copy downloaded *.jar file to JRE location: (e.g. C:\Program Files\Java\jre7\lib\ext)
* Download latest ``.war`` file from SourceForge.net (for PostgreSQL) and rename it to libreplan.war::
# http://sourceforge.net/projects/libreplan/files/LibrePlan/
* Create database::
CREATE DATABASE libreplan;
* Use SQL sentences::
CREATE USER libreplan WITH PASSWORD 'libreplan';
GRANT ALL PRIVILEGES ON DATABASE libreplan TO libreplan;
REVOKE ALL
ON ALL TABLES IN SCHEMA public
FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE
ON ALL TABLES IN SCHEMA public
TO libreplan;
* Restore PostgreSQL dump - scripts/database/postgresql_1.4.1.backup::
* Create an Environment Variable JRE_HOME
# You need to set it to your JRE installed directory
* Configure Apache Tomcat Server
# Put libreplan.war file to Apache Tomcat webapps folder (e.g. C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\)
# Go to localhost folder (e.g. C:\Program Files\Apache Software Foundation\Tomcat 6.0\conf\Catalina\localhost\) and create there libreplan.xml file with this lines of code:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="">
<Resource name="jdbc/libreplan-ds" auth="Container"
type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="libreplan" password="libreplan"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost/libreplan" />
</Context>
* Start Apache Tomcat server
# Example location: C:\Program Files\Apache Software Foundation\Tomcat 6.0\bin\Tomcat6.exe
* Go to http://localhost:8080/libreplan
Logs
----

View file

@ -1,103 +1,103 @@
How To Start Development With JetBrains Intellij IDEA
======================================================
.. sectnum::
:Author: Perebykivskiy Vova
:Contact: vova@libreplan-enterprise.com
:Date: 09/09/2015
:Copyright:
Some rights reserved. This document is distributed under the Creative
Commons Attribution-ShareAlike 3.0 licence, available in
http://creativecommons.org/licenses/by-sa/3.0/.
:Abstract:
Quick guide to start the development of LibrePlan_ using JetBrains Intellij IDEA_ IDE.
As this is the most common way of work among LibrePlan developers team.
.. contents:: Table of Contents
Download LibrePlan source code
------------------------------
* You need to download LibrePlan_ source code to start hacking on it. You have two
options:
a) Clone Git repository (recommended)::
git clone git://github.com/LibrePlan/libreplan.git
b) Download last version source code::
http://sourceforge.net/projects/libreplan/files/LibrePlan/libreplan_*.tar.gz
* Download latest libreplan_*.war file for your database (PostgreSQL or MySQL)
http://sourceforge.net/projects/libreplan/files/LibrePlan/
You should review ``HACKING`` file to check that you have installed all the
requirements.
Import LibrePlan project
------------------------
* Run Intellij IDEA
* Select Import Project
* Select directory with source code of Libreplan
# e.g. C\Users\PC-User\IdeaProjects\libreplan
* Select *Import project from external model* > *Maven* and click *Next*
* Then leave all as default
* Then select profiles: dev and for PostgreSQL users - postgresql / Mysql users - mysql
* Then leave all by default
* Then choose your JDK(SDK), 1.7 strongly prefered
* Then define project name or leave default name
Configure project to run
------------------------
* Go to *Run* > *Edit Configurations...*
* Create a new *Maven Build* called *MavenConfig*
* Change the following values:
* Working directory: Choose ``libreplan-webapp`` folder in your workspace
* Command line: ``jetty:stop jetty:run``
* Profiles (optional): ``-userguide -reports -i18n``
(to disable userguide,reports and i18n profiles to save compilation time
as they are not mandatory to run LibrePlan)
* Mark the following checkboxes (recommended):
* Resolve Workspace artifacts
* In "Before launch" section choose "+" and add Build Artifact (war file)
By the next compilation you may remove this Build Artifact from configuration
* Click *Run* and application will be available at
http://localhost:8080/libreplan-webapp/
Develop LibrePlan in Intellij IDEA using MySQL
----------------------------------------
* This tutorial works properly with PostgreSQL, but if you want to develop
LibrePlan using MySQL you have to do 2 small changes:
* In section `Configure project to run`_ you have to set the *Profiles* to:
``-dev -mysql -userguide -reports -i18n``
* Remember that the three last profiles that are being disabled is just to save
compilation time and not mandatory. However, to develop using MySQL you have
to set at least the first two: ``-dev`` and ``-mysql``.
.. _LibrePlan: http://www.libreplan.com/
.. _JetBrains Intellij IDEA: https://www.jetbrains.com/idea/
======================================================
How To Start Development With JetBrains Intellij IDEA
======================================================
.. sectnum::
:Author: Perebykivskiy Vova
:Contact: vova@libreplan-enterprise.com
:Date: 09/09/2015
:Copyright:
Some rights reserved. This document is distributed under the Creative
Commons Attribution-ShareAlike 3.0 licence, available in
http://creativecommons.org/licenses/by-sa/3.0/.
:Abstract:
Quick guide to start the development of LibrePlan_ using JetBrains Intellij IDEA_ IDE.
As this is the most common way of work among LibrePlan developers team.
.. contents:: Table of Contents
Download LibrePlan source code
------------------------------
* You need to download LibrePlan_ source code to start hacking on it. You have two
options:
a) Clone Git repository (recommended)::
git clone git://github.com/LibrePlan/libreplan.git
b) Download last version source code::
http://sourceforge.net/projects/libreplan/files/LibrePlan/libreplan_*.tar.gz
* Download latest libreplan_*.war file for your database (PostgreSQL or MySQL)
http://sourceforge.net/projects/libreplan/files/LibrePlan/
You should review ``HACKING`` file to check that you have installed all the
requirements.
Import LibrePlan project
------------------------
* Run Intellij IDEA
* Select Import Project
* Select directory with source code of Libreplan
# e.g. C\Users\PC-User\IdeaProjects\libreplan
* Select *Import project from external model* > *Maven* and click *Next*
* Then leave all as default
* Then select profiles: dev and for PostgreSQL users - postgresql / Mysql users - mysql
* Then leave all by default
* Then choose your JDK(SDK), 1.7 strongly prefered
* Then define project name or leave default name
Configure project to run
------------------------
* Go to *Run* > *Edit Configurations...*
* Create a new *Maven Build* called *MavenConfig*
* Change the following values:
* Working directory: Choose ``libreplan-webapp`` folder in your workspace
* Command line: ``jetty:stop jetty:run``
* Profiles (optional): ``-userguide -reports -i18n``
(to disable userguide,reports and i18n profiles to save compilation time
as they are not mandatory to run LibrePlan)
* Mark the following checkboxes (recommended):
* Resolve Workspace artifacts
* In "Before launch" section choose "+" and add Build Artifact (war file)
By the next compilation you may remove this Build Artifact from configuration
* Click *Run* and application will be available at
http://localhost:8080/libreplan-webapp/
Develop LibrePlan in Intellij IDEA using MySQL
----------------------------------------
* This tutorial works properly with PostgreSQL, but if you want to develop
LibrePlan using MySQL you have to do 2 small changes:
* In section `Configure project to run`_ you have to set the *Profiles* to:
``-dev -mysql -userguide -reports -i18n``
* Remember that the three last profiles that are being disabled is just to save
compilation time and not mandatory. However, to develop using MySQL you have
to set at least the first two: ``-dev`` and ``-mysql``.
.. _LibrePlan: http://www.libreplan.com/

View file

@ -4,7 +4,7 @@ Connectors
.. contents::
Connectors are Libreplan client applications that could be used to communicate with (web) servers to get
data, process and store them. At this moment there are two connectors, JIRA connector and Tim Enterprise Connector.
data, process and store them. At this moment there are three connectors, JIRA connector, Tim Enterprise Connector and E-mail Connector.
Configuration
=============
@ -171,9 +171,9 @@ in Tim Enterprise server.
Scheduling export
------------------
Export process can also take place through the scheduler. Go to ``Job scheduling`` screen.
Export process can also take place through the scheduler. Go to ``Job Scheduling`` screen.
In that screen you can configure a Tim Export ``job``. The ``job`` searches for last exported
time sheets in the database and re-export them accordingly. see also the Scheduler manual.
time sheets in the database and re-export them accordingly. See also the Scheduler manual.
Import
------
@ -211,5 +211,66 @@ assumed to be a valid ``Exception type`` but the total duration is the sum of al
Contrary to the Libreplan, in Tim Enterprise, the ``total duration`` in case that the worker is on holiday means the worker is
not available for that ``total duration``. But in Libreplan if the worker is on holiday the total duration should be ``Zero``.
The Tim connector also takes care of this translation.
The Tim connector also takes care of this translation.
E-mail connector
==============
E-mail is a method of exchanging digital messages from an author to one or more recipients.
E-mail connector can be used to set Simple Main Transfer Protocol (SMTP) server connection properties.
The *E-mail connector* should be configured properly before being used.
Configuration
-------------
From the configuration's ``Main Settings`` screen choose the tab ``Connectors``.
In the connectors screen select the E-mail connector from the ``pull-down`` list. A ``property editor screen``
is displayed now.
In this screen you can configure the following property values:
* ``Activated``: Y/N, whether you want to use the E-mail connector or not. Default is ``N``.
* ``Protocol``: type of SMTP protocol.
* ``Host``: the absolute path to SMTP server.
* ``Port``: port of SMTP server.
* ``From address``: e-mail address of messages sender.
* ``Username``: username for SMTP server.
* ``Password``: password for SMTP server.
Finally click the ``Test connection`` button to test if you are able to connect to
SMTP server and that your configurations are right.
Edit E-mail template
--------------------
From the project window ``Configuration`` and then ``Edit E-mail Templates`` you are able to modify E-mail templates of
messages.
You are able to choose:
* Template language
* Template type
* E-mail subject
* Template contents
You need to specify language because web application will send e-mail to user in language that user have chosen in
preferences.
You need to choose template type, type is user role, it means that this e-mail will be send only to users who are in\
selected role (type).
You need to set e-mail subject. Subject - a brief summary of the topic of the message.
You need to set e-mail contents. Any information that you want to send to user. Also there are some keywords that you
may use in message; web application will parse it and set a new value instead of keyword.
Scheduling e-mails
------------------
Sending e-mails process can take place only through the scheduler. Go to ``Configuration`` then ``Job Scheduling``
screen.
In that screen you can configure a e-mail sending ``job``. The ``job`` is taking a list of e-mail notifications,
gathering data and sending it to user`s e-mail. See also the Scheduler manual.
.. NOTE::
The success or failure information would be displayed in pop-up window.

View file

@ -26,16 +26,19 @@ import org.apache.commons.lang.BooleanUtils;
/**
* This is a singleton that contains the compilation options passed from Maven.
*
* Currently we have two options:
* Currently we have three options:
* <ul>
* <li>Enable/Disable the warning changing default password</li>
* <li>Enable/Disable default users (such as wsreader, wswriter,
* wssubcontracting, manager, hresources, outsourcing and reports)</li>
* <li>Enable/Disable E-mail sending functionality</li>
* </ul>
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
* @author Manuel Rego Casasnovas <rego@igalia.com>
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
*/
public class Configuration {
private static final Configuration singleton = new Configuration();
@ -44,6 +47,8 @@ public class Configuration {
private Boolean exampleUsersDisabled;
private Boolean emailSendingEnabled;
private Configuration() {
}
@ -59,22 +64,13 @@ public class Configuration {
return singleton.getDefaultPasswordsControl() != null ? singleton
.getDefaultPasswordsControl() : true;
}
public Boolean getDefaultPasswordsControl() {
return defaultPasswordsControl;
}
public void setDefaultPasswordsControl(Boolean defaultPasswordsControl) {
this.defaultPasswordsControl = defaultPasswordsControl;
}
public Boolean getDefaultPasswordsControl() {
return defaultPasswordsControl;
}
public void setExampleUsersDisabled(Boolean exampleUsersDisabled) {
this.exampleUsersDisabled = exampleUsersDisabled;
}
public Boolean getExampleUsersDisabled() {
return exampleUsersDisabled;
}
/**
* Returns the value of example users disabled compilation option
@ -82,5 +78,25 @@ public class Configuration {
public static boolean isExampleUsersDisabled() {
return BooleanUtils.isNotFalse(singleton.getExampleUsersDisabled());
}
public Boolean getExampleUsersDisabled() {
return exampleUsersDisabled;
}
public void setExampleUsersDisabled(Boolean exampleUsersDisabled) {
this.exampleUsersDisabled = exampleUsersDisabled;
}
/**
* Returns the value of E-mail sending disabled compilation option
*/
public static boolean isEmailSendingEnabled(){
return BooleanUtils.isNotFalse(singleton.getEmailSendingEnabled());
}
public Boolean getEmailSendingEnabled(){
return emailSendingEnabled;
}
public void setEmailSendingEnabled(Boolean emailSendingEnabled){
this.emailSendingEnabled = emailSendingEnabled;
}
}

View file

@ -28,6 +28,7 @@ import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

View file

@ -29,8 +29,9 @@ package org.libreplan.business.common.entities;
public enum JobClassNameEnum {
IMPORT_ROSTER_FROM_TIM_JOB("org.libreplan.importers", "ImportRosterFromTimJob"),
EXPORT_TIMESHEET_TO_TIM_JOB("org.libreplan.importers","ExportTimesheetToTimJob"),
SYNC_ORDERELEMENTS_WITH_JIRA_ISSUES_JOB("org.libreplan.importers","JiraOrderElementSynchronizerJob");
EXPORT_TIMESHEET_TO_TIM_JOB("org.libreplan.importers", "ExportTimesheetToTimJob"),
SYNC_ORDERELEMENTS_WITH_JIRA_ISSUES_JOB("org.libreplan.importers", "JiraOrderElementSynchronizerJob"),
SEND_EMAIL_JOB("org.libreplan.importers", "SendEmailJob");
private String packageName;
private String name;

View file

@ -27,6 +27,7 @@ import static org.libreplan.business.i18n.I18nHelper._;
*
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
* @author Manuel Rego Casasnovas <rego@igalia.com>
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
*/
public class PredefinedConnectorProperties {
@ -51,4 +52,12 @@ public class PredefinedConnectorProperties {
*/
public static final String JIRA_CODE_PREFIX = "JIRA-";
// Specific for E-mail
public static String PROTOCOL = _("Protocol");
public static String HOST = _("Host");
public static String PORT = _("Port");
public static String EMAIL_SENDER = _("From address (no reply)");
public static String EMAIL_USERNAME = _("Username (optional)");
public static String EMAIL_PASSWORD = _("Password (optional)");
}

View file

@ -28,6 +28,7 @@ import java.util.List;
*
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
* @author Manuel Rego Casasnovas <rego@igalia.com>
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
*/
public enum PredefinedConnectors {
@ -50,7 +51,16 @@ public enum PredefinedConnectors {
ConnectorProperty
.create(PredefinedConnectorProperties.JIRA_LABELS, ""),
ConnectorProperty.create(
PredefinedConnectorProperties.JIRA_HOURS_TYPE, "Default"));
PredefinedConnectorProperties.JIRA_HOURS_TYPE, "Default")),
EMAIL("E-mail",
ConnectorProperty.create(PredefinedConnectorProperties.ACTIVATED, "N"),
ConnectorProperty.create(PredefinedConnectorProperties.PROTOCOL, ""),
ConnectorProperty.create(PredefinedConnectorProperties.HOST, ""),
ConnectorProperty.create(PredefinedConnectorProperties.PORT, ""),
ConnectorProperty.create(PredefinedConnectorProperties.EMAIL_USERNAME, ""),
ConnectorProperty.create(PredefinedConnectorProperties.EMAIL_PASSWORD, "")
);
private String name;
private List<ConnectorProperty> properties;

View file

@ -0,0 +1,54 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.email.daos;
import org.libreplan.business.common.daos.GenericDAOHibernate;
import org.libreplan.business.email.entities.EmailNotification;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* Dao for {@link EmailNotification}
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 19.10.15.
*/
@Repository
public class EmailNotificationDAO extends GenericDAOHibernate<EmailNotification, Long> implements IEmailNotificationDAO {
@Override
public List<EmailNotification> getAll() {
return list(EmailNotification.class);
}
@Override
public boolean deleteAll() {
List<EmailNotification> notifications = list(EmailNotification.class);
for (Object item : notifications){
getSession().delete(item);
}
if ( list(EmailNotification.class).size() == 0 ) return true;
return false;
}
}

View file

@ -0,0 +1,90 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.email.daos;
import org.libreplan.business.common.daos.GenericDAOHibernate;
import org.libreplan.business.email.entities.EmailTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* DAO for {@link EmailTemplate}
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 24.09.15.
*/
@Repository
public class EmailTemplateDAO extends GenericDAOHibernate<EmailTemplate, Long> implements IEmailTemplateDAO{
@Override
public List<EmailTemplate> getAll() {
return list(EmailTemplate.class);
}
@Override
public String initializeContent() {
try{
List<EmailTemplate> emailTemplates = list(EmailTemplate.class);
for ( int i = 0; i < emailTemplates.size(); i++)
// language.ordinal.equals(3) - English
if ( emailTemplates.get(i).getType().ordinal() == 0 && emailTemplates.get(i).getLanguage().ordinal() == 3)
return emailTemplates.get(i).getContent();
}catch (Exception e){}
return " ";
}
@Override
public String initializeSubject() {
try{
List<EmailTemplate> emailTemplates = list(EmailTemplate.class);
for ( int i = 0; i < emailTemplates.size(); i++)
// language.ordinal.equals(3) - English
if ( emailTemplates.get(i).getType().ordinal() == 0 && emailTemplates.get(i).getLanguage().ordinal() == 3)
return emailTemplates.get(i).getSubject();
}catch (Exception e){}
return " ";
}
@Override
public String getContentBySelectedLanguage(int languageOrdinal, int emailTemplateTypeOrdinal) {
for (int i = 0; i < list(EmailTemplate.class).size(); i++)
if (list(EmailTemplate.class).get(i).getLanguage().ordinal() == languageOrdinal &&
// emailTemplateTypeOrdinal + 1, because first value is 0
list(EmailTemplate.class).get(i).getType().ordinal() == emailTemplateTypeOrdinal + 1)
return list(EmailTemplate.class).get(i).getContent();
return "";
}
@Override
public String getContentBySelectedTemplate(int emailTemplateTypeOrdinal, int languageOrdinal) {
for (int i = 0; i < list(EmailTemplate.class).size(); i++)
// emailTemplateTypeOrdinal + 1, because first value is 0
if ( list(EmailTemplate.class).get(i).getType().ordinal() == emailTemplateTypeOrdinal + 1 &&
list(EmailTemplate.class).get(i).getLanguage().ordinal() == languageOrdinal )
return list(EmailTemplate.class).get(i).getContent();
return "";
}
}

View file

@ -0,0 +1,37 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.email.daos;
import org.libreplan.business.common.daos.IGenericDAO;
import org.libreplan.business.email.entities.EmailNotification;
import java.util.List;
/**
* Contract for {@link EmailNotificationDAO}
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 19.10.15.
*/
public interface IEmailNotificationDAO extends IGenericDAO<EmailNotification, Long> {
List<EmailNotification> getAll();
boolean deleteAll();
}

View file

@ -0,0 +1,44 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.email.daos;
import org.libreplan.business.common.daos.IGenericDAO;
import org.libreplan.business.email.entities.EmailTemplate;
import java.util.List;
/**
* DAO interface for the <code>EmailTemplate</code> entity.
* Contract for {@link EmailTemplateDAO}
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 29.09.15.
*/
public interface IEmailTemplateDAO extends IGenericDAO<EmailTemplate, Long>{
List<EmailTemplate> getAll();
String initializeContent();
String initializeSubject();
String getContentBySelectedLanguage(int languageOrdinal, int emailTemplateTypeOrdinal);
String getContentBySelectedTemplate(int emailTemplateTypeOrdinal, int languageOrdinal);
}

View file

@ -0,0 +1,85 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.email.entities;
import org.libreplan.business.common.BaseEntity;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.entities.Resource;
import java.util.Date;
/**
* EmailNotification entity representing table: notification_queue.
* This class is intended to work as a Hibernate component.
* It represents the Email notification to be send to user.
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 19.10.15.
*/
public class EmailNotification extends BaseEntity {
private EmailTemplateEnum type;
private Date updated;
private Resource resource;
private TaskElement task;
private TaskElement project;
public EmailTemplateEnum getType() {
return type;
}
public void setType(EmailTemplateEnum type) {
this.type = type;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public Resource getResource() {
return resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
public TaskElement getTask() {
return task;
}
public void setTask(TaskElement task) {
this.task = task;
}
public TaskElement getProject() {
return project;
}
public void setProject(TaskElement project) {
this.project = project;
}
}

View file

@ -0,0 +1,71 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.email.entities;
import org.libreplan.business.common.BaseEntity;
import org.libreplan.business.settings.entities.Language;
/**
* EmailTemplate entity, represents a template that LibrePlan user may use.
* This class is intended to work as a Hibernate component.
* It represents the E-mail template to be modified by admin and send to user.
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 29.09.15.
*/
public class EmailTemplate extends BaseEntity {
private EmailTemplateEnum type = EmailTemplateEnum.TEMPLATE_TASK_ASSIGNED_TO_RESOURCE;
private Language language = Language.ENGLISH_LANGUAGE;
private String content;
private String subject;
public EmailTemplateEnum getType() {
return type;
}
public void setType(EmailTemplateEnum type) {
this.type = type;
}
public Language getLanguage() {
return language;
}
public void setLanguage(Language language) {
this.language = language;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}

View file

@ -0,0 +1,47 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.email.entities;
import static org.libreplan.business.i18n.I18nHelper._;
/**
* Available E-mail templates.
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 28.09.15.
*
* TEMPLATE_N(_("Template N")) - for i18n
* TEMPLATE_A("Template A") - for general use (no internationalizing)
*/
public enum EmailTemplateEnum {
TEMPLATE_TASK_ASSIGNED_TO_RESOURCE(_("Task assigned to resource"));
private final String templateType;
EmailTemplateEnum(String templateType) {
this.templateType = templateType;
}
public String getTemplateType() {
return templateType;
}
}

View file

@ -40,7 +40,7 @@ public enum OrderStatusEnum {
ON_HOLD(_("ON HOLD")),
FINISHED(_("FINISHED")),
CANCELLED(_("CANCELLED")),
STORED(_("STORED"));
STORED(_("ARCHIVED"));
private String description;

View file

@ -18,47 +18,6 @@
*/
package org.libreplan.business.users.bootstrap;
import static org.libreplan.business.users.entities.UserRole.ROLE_CALENDARS;
import static org.libreplan.business.users.entities.UserRole.ROLE_CALENDAR_EXCEPTION_DAYS;
import static org.libreplan.business.users.entities.UserRole.ROLE_COMPANIES;
import static org.libreplan.business.users.entities.UserRole.ROLE_COST_CATEGORIES;
import static org.libreplan.business.users.entities.UserRole.ROLE_CREATE_PROJECTS;
import static org.libreplan.business.users.entities.UserRole.ROLE_CRITERIA;
import static org.libreplan.business.users.entities.UserRole.ROLE_EDIT_ALL_PROJECTS;
import static org.libreplan.business.users.entities.UserRole.ROLE_ESTIMATED_PLANNED_HOURS_PER_TASK_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_EXPENSES;
import static org.libreplan.business.users.entities.UserRole.ROLE_HOURS_TYPES;
import static org.libreplan.business.users.entities.UserRole.ROLE_HOURS_WORKED_PER_RESOURCE_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_JOB_SCHEDULING;
import static org.libreplan.business.users.entities.UserRole.ROLE_LABELS;
import static org.libreplan.business.users.entities.UserRole.ROLE_MACHINES;
import static org.libreplan.business.users.entities.UserRole.ROLE_MAIN_SETTINGS;
import static org.libreplan.business.users.entities.UserRole.ROLE_MATERIALS;
import static org.libreplan.business.users.entities.UserRole.ROLE_MATERIALS_NEED_AT_DATE_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_MATERIAL_UNITS;
import static org.libreplan.business.users.entities.UserRole.ROLE_PLANNING;
import static org.libreplan.business.users.entities.UserRole.ROLE_PROFILES;
import static org.libreplan.business.users.entities.UserRole.ROLE_PROGRESS_TYPES;
import static org.libreplan.business.users.entities.UserRole.ROLE_PROJECT_COSTS_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_PROJECT_STATUS_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_QUALITY_FORMS;
import static org.libreplan.business.users.entities.UserRole.ROLE_READ_ALL_PROJECTS;
import static org.libreplan.business.users.entities.UserRole.ROLE_RECEIVED_FROM_CUSTOMERS;
import static org.libreplan.business.users.entities.UserRole.ROLE_RECEIVED_FROM_SUBCONTRACTORS;
import static org.libreplan.business.users.entities.UserRole.ROLE_SEND_TO_CUSTOMERS;
import static org.libreplan.business.users.entities.UserRole.ROLE_SEND_TO_SUBCONTRACTORS;
import static org.libreplan.business.users.entities.UserRole.ROLE_TASK_SCHEDULING_STATUS_IN_PROJECT_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_TEMPLATES;
import static org.libreplan.business.users.entities.UserRole.ROLE_TIMESHEETS;
import static org.libreplan.business.users.entities.UserRole.ROLE_TIMESHEETS_TEMPLATES;
import static org.libreplan.business.users.entities.UserRole.ROLE_TIMESHEET_LINES_LIST;
import static org.libreplan.business.users.entities.UserRole.ROLE_TOTAL_WORKED_HOURS_BY_RESOURCE_IN_A_MONTH_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_USER_ACCOUNTS;
import static org.libreplan.business.users.entities.UserRole.ROLE_VIRTUAL_WORKERS;
import static org.libreplan.business.users.entities.UserRole.ROLE_WORKERS;
import static org.libreplan.business.users.entities.UserRole.ROLE_WORK_AND_PROGRESS_PER_PROJECT_REPORT;
import static org.libreplan.business.users.entities.UserRole.ROLE_WORK_AND_PROGRESS_PER_TASK_REPORT;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@ -66,16 +25,18 @@ import java.util.Set;
import org.libreplan.business.users.entities.Profile;
import org.libreplan.business.users.entities.UserRole;
import static org.libreplan.business.users.entities.UserRole.*;
/**
* Defines the default {@link org.libreplan.business.users.entities.Profile
* Profiles}
*
* @author Manuel Rego Casasnovas <rego@igalia.com>
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
*/
public enum PredefinedProfiles {
SYSTEMS_ADMINISTRATOR("Systems Administrator", ROLE_MAIN_SETTINGS,
ROLE_USER_ACCOUNTS, ROLE_PROFILES, ROLE_JOB_SCHEDULING),
ROLE_USER_ACCOUNTS, ROLE_PROFILES, ROLE_JOB_SCHEDULING, ROLE_EDIT_EMAIL_TEMPLATES),
PROJECT_MANAGER("Project Manager", ROLE_READ_ALL_PROJECTS,
ROLE_EDIT_ALL_PROJECTS, ROLE_CREATE_PROJECTS, ROLE_PLANNING,

View file

@ -28,21 +28,26 @@ import static org.libreplan.business.i18n.I18nHelper._;
*
* @author Fernando Bellas Permuy <fbellas@udc.es>
* @author Manuel Rego Casasnovas <rego@igalia.com>
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
*/
public enum UserRole {
// Access to all pages
ROLE_SUPERUSER(_("Superuser")),
// Web services roles
ROLE_WS_READER(_("Web service reader")),
ROLE_WS_WRITER(_("Web service writer")),
ROLE_WS_SUBCONTRACTING(_("Web service subcontractor operations")),
// Project operations roles
ROLE_READ_ALL_PROJECTS(_("Read all projects")),
ROLE_EDIT_ALL_PROJECTS(_("Edit all projects")),
ROLE_CREATE_PROJECTS(_("Create projects")),
// Special role for bound users
ROLE_BOUND_USER(_("Bound user")),
// Page roles
ROLE_PLANNING(_("Planning")),
ROLE_TEMPLATES(_("Templates")),
@ -81,7 +86,11 @@ public enum UserRole {
ROLE_PROJECT_COSTS_REPORT(_("Project Costs Report")),
ROLE_TASK_SCHEDULING_STATUS_IN_PROJECT_REPORT(_("Task Scheduling Status In Project Report")),
ROLE_MATERIALS_NEED_AT_DATE_REPORT(_("Materials Needed At Date Report")),
ROLE_PROJECT_STATUS_REPORT(_("Project Status Report"));
ROLE_PROJECT_STATUS_REPORT(_("Project Status Report")),
ROLE_EDIT_EMAIL_TEMPLATES(_("Edit E-mail Templates")),
ROLE_EMAIL_TASK_ASSIGNED_TO_RESOURCE(_("Email task assigned to resource"));
private final String displayName;

View file

@ -94,6 +94,9 @@
<value>
org/libreplan/business/common/entities/JobSchedulerConfiguration.hbm.xml
</value>
<value>
org/libreplan/business/email/entities/Email.hbm.xml
</value>
</list>
</property>
</bean>
@ -143,6 +146,9 @@
<property name="exampleUsersDisabled">
<value>${default.exampleUsersDisabled}</value>
</property>
<property name="emailSendingEnabled">
<value>${default.emailSendingEnabled}</value>
</property>
</bean>
<bean id="scenarioManager"

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.libreplan.business.email.entities" default-access="field">
<class name="org.libreplan.business.email.entities.EmailTemplate" abstract="true" table="email_template">
<id name="id" access="property" type="long">
<generator class="hilo" >
<param name="max_lo">100</param>
</generator>
</id>
<property name="type" column="type">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.libreplan.business.email.entities.EmailTemplateEnum</param>
</type>
</property>
<property name="language" column="language">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.libreplan.business.settings.entities.Language</param>
</type>
</property>
<property name="content" column="content" />
<property name="subject" column="subject" />
</class>
<class name="EmailNotification" abstract="true" table="notification_queue">
<id name="id" access="property" type="long">
<generator class="hilo">
<param name="max_lo">100</param>
</generator>
</id>
<property name="type" column="type">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">org.libreplan.business.email.entities.EmailTemplateEnum</param>
</type>
</property>
<property name="updated" column="updated"/>
<many-to-one name="resource"
class="org.libreplan.business.resources.entities.Resource" column="resource" lazy="false"/>
<many-to-one name="task"
class="org.libreplan.business.planner.entities.TaskElement" column="task" lazy="false"/>
<many-to-one name="project"
class="org.libreplan.business.planner.entities.TaskElement" column="project" lazy="false"/>
</class>
</hibernate-mapping>

View file

@ -59,7 +59,7 @@
<property name="surname"/>
<property name="nif"/>
<many-to-one name="user" cascade="save-update"
<many-to-one name="user" cascade="save-update" access="property" lazy="false"
class="org.libreplan.business.users.entities.User"
column="user_id" unique="true" />

View file

@ -90,5 +90,4 @@
<property name="budget" scale="2" access="field" />
</joined-subclass>
</class>
</hibernate-mapping>

View file

@ -40,9 +40,6 @@
<value>
org/libreplan/business/orders/entities/Orders.hbm.xml
</value>
<value>
org/libreplan/business/templates/entities/Templates.hbm.xml
</value>
<value>
org/libreplan/business/planner/entities/Tasks.hbm.xml
</value>

View file

@ -11,6 +11,7 @@
<name>LibrePlan Web Client Module</name>
<profiles>
<profile>
<id>reports</id>
<activation>
@ -71,6 +72,7 @@
</plugins>
</build>
</profile>
<profile>
<id>userguide</id>
<activation>
@ -195,6 +197,7 @@
</plugins>
</build>
</profile>
<profile>
<id>i18n</id>
<activation>
@ -430,6 +433,14 @@
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
<!--Java mail-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.5.0-b01</version>
</dependency>
<!-- JAX-RS API -->
<dependency>
<groupId>javax.ws.rs</groupId>

View file

@ -0,0 +1,33 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.importers;
/**
* Sends E-mail to users with data that storing in notification_queue table
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 13.10.15.
*/
public interface ISendEmail {
void sendEmail();
}

View file

@ -0,0 +1,302 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.importers;
import org.libreplan.business.common.Configuration;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorProperty;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.email.entities.EmailTemplate;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.settings.entities.Language;
import org.libreplan.web.email.IEmailNotificationModel;
import org.libreplan.web.email.IEmailTemplateModel;
import org.libreplan.web.planner.tabs.MultipleTabsPlannerController;
import org.libreplan.web.resources.worker.IWorkerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Transport;
import javax.mail.Session;
import javax.mail.PasswordAuthentication;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.NoSuchProviderException;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
/**
* Sends E-mail to users with data that storing in notification_queue table
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 13.10.15.
*/
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class SendEmail implements ISendEmail {
@Autowired
private IEmailNotificationModel emailNotificationModel;
@Autowired
private IConnectorDAO connectorDAO;
@Autowired
private IWorkerModel workerModel;
@Autowired
private IEmailTemplateModel emailTemplateModel;
private List<EmailNotification> notifications;
private List<EmailTemplate> emailTemplates;
@Override
public void sendEmail() {
if ( Configuration.isEmailSendingEnabled() == true ){
if (validConnection() == true){
notifications = emailNotificationModel.getAll();
for (int i = 0; i < notifications.size(); i++) composeMessageForUser(notifications.get(i));
deleteAllNotificationsAfterSending();
}
}
}
private void composeMessageForUser(EmailNotification notification){
// Gather data about EmailTemplate needs to be used
Resource resource = notification.getResource();
EmailTemplateEnum type = notification.getType();
Locale locale;
Worker currentWorker = getCurrentWorker(resource.getId());
if ( currentWorker.getUser().getApplicationLanguage().equals(Language.BROWSER_LANGUAGE) ) {
locale = new Locale(System.getProperty("user.language"));
} else {
locale = new Locale(currentWorker.getUser().getApplicationLanguage().getLocale().getLanguage());
}
EmailTemplate currentEmailTemplate = findCurrentEmailTemplate(type, locale);
// Modify text that will be composed
String text = currentEmailTemplate.getContent();
if ( type.equals(EmailTemplateEnum.TEMPLATE_TASK_ASSIGNED_TO_RESOURCE) ){
text = text.replaceAll("\\{username\\}", currentWorker.getUser().getLoginName());
text = text.replaceAll("\\{firstname\\}", currentWorker.getUser().getFirstName());
text = text.replaceAll("\\{lastname\\}", currentWorker.getUser().getLastName());
text = text.replaceAll("\\{project\\}", notification.getProject().getName());
text = text.replaceAll("\\{resource\\}", notification.getResource().getName());
text = text.replaceAll("\\{task\\}", notification.getTask().getName());
text = text.replaceAll("\\{url\\}", MultipleTabsPlannerController.WELCOME_URL);
}
// Get/Set connection properties
List<ConnectorProperty> emailConnectorProperties = getEmailConnectorProperties();
String receiver = currentWorker.getUser().getEmail();
String protocol = null;
String host = null;
String port = null;
String sender = null;
String usrnme = null;
String psswrd = null;
for (int i = 0; i < emailConnectorProperties.size(); i++){
switch (i){
case 1: {
protocol = emailConnectorProperties.get(1).getValue();
break;
}
case 2: {
host = emailConnectorProperties.get(2).getValue();
break;
}
case 3: {
port = emailConnectorProperties.get(3).getValue();
break;
}
case 4: {
sender = emailConnectorProperties.get(4).getValue();
break;
}
case 5: {
usrnme = emailConnectorProperties.get(5).getValue();
break;
}
case 6: {
psswrd = emailConnectorProperties.get(6).getValue();
break;
}
}
}
// Set properties of connection
Properties properties = new Properties();
if ( protocol.equals("STARTTLS") ) {
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.socketFactory.port", port);
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.port", port);
}
else if ( protocol.equals("SMTP") ) {
properties.put("mail.smtp.host", host);
properties.put("mail.smtp.port", port);
}
final String username = usrnme;
final String password = psswrd;
/* It is very important to use Session.getInstance instead of Session.getDefaultInstance */
Session mailSession = Session.getInstance(properties,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
// Send message
try{
MimeMessage message = new MimeMessage(mailSession);
message.setFrom(new InternetAddress(sender));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver));
String subject = currentEmailTemplate.getSubject();
message.setSubject(subject);
message.setText(text);
Transport.send(message);
} catch (MessagingException e){throw new RuntimeException(e);}
}
private void deleteAllNotificationsAfterSending(){
emailNotificationModel.deleteAll();
}
private List<ConnectorProperty> getEmailConnectorProperties() {
Connector connector = connectorDAO.findUniqueByName("E-mail");
List<ConnectorProperty> properties = connector.getProperties();
return properties;
}
private EmailTemplate findCurrentEmailTemplate(EmailTemplateEnum templateEnum, Locale locale){
emailTemplates = emailTemplateModel.getAll();
for (EmailTemplate item : emailTemplates)
if ( item.getType().equals(templateEnum) && item.getLanguage().getLocale().equals(locale) )
return item;
return null;
}
private Worker getCurrentWorker(Long resourceID){
List<Worker> workerList = workerModel.getWorkers();
for(int i = 0; i < workerList.size(); i++)
if ( workerList.get(i).getId().equals(resourceID) )
return workerList.get(i);
return null;
}
private boolean validConnection(){
List<ConnectorProperty> emailConnectorProperties = getEmailConnectorProperties();
String protocol = null;
String host = null;
String port = null;
String usrnme = null;
String psswrd = null;
for (int i = 0; i < emailConnectorProperties.size(); i++){
switch (i){
case 1: {
protocol = emailConnectorProperties.get(1).getValue();
break;
}
case 2: {
host = emailConnectorProperties.get(2).getValue();
break;
}
case 3: {
port = emailConnectorProperties.get(3).getValue();
break;
}
case 5: {
usrnme = emailConnectorProperties.get(5).getValue();
break;
}
case 6: {
psswrd = emailConnectorProperties.get(6).getValue();
break;
}
}
}
// Set properties of connection
Properties properties = new Properties();
Transport transport = null;
try {
if (protocol.equals("SMTP")) {
properties.setProperty("mail.smtp.port", port);
properties.setProperty("mail.smtp.host", host);
Session session = Session.getInstance(properties, null);
transport = session.getTransport("smtp");
if (usrnme.equals("") && psswrd.equals("")) transport.connect();
} else if (protocol.equals("STARTTLS")) {
properties.setProperty("mail.smtps.port", port);
properties.setProperty("mail.smtps.host", host);
Session session = Session.getInstance(properties, null);
transport = session.getTransport("smtps");
if (!usrnme.equals("") && psswrd != null) transport.connect(host, usrnme, psswrd);
}
if (transport.isConnected()) return true;
} catch (NoSuchProviderException e) {}
catch (MessagingException e) {}
return false;
}
}

View file

@ -0,0 +1,47 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.importers;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* Sends E-mail to users with data that storing in notification_queue table
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 13.10.15.
*
*/
public class SendEmailJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
ApplicationContext applicationContext = (ApplicationContext) context.getJobDetail().
getJobDataMap().get("applicationContext");
ISendEmail sendEmail = (ISendEmail) applicationContext.getBean("sendEmail");
sendEmail.sendEmail();
}
}

View file

@ -835,8 +835,8 @@ public abstract class BaseCalendarEditionController extends
comboItem.setLabel(parent.getName());
comboItem.setParent(comboParents);
if ((version.getParent()) != null
&& (parent.getId().equals(version.getParent().getId()))) {
if ( (version.getParent() ) != null &&
(parent.getId().equals(version.getParent().getId())) ) {
comboParents.setSelectedItem(comboItem);
}
}
@ -845,7 +845,7 @@ public abstract class BaseCalendarEditionController extends
new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
if (comboParents.getSelectedItem() != null) {
if ( comboParents.getSelectedItem() != null ) {
BaseCalendar parent = (BaseCalendar) comboParents
.getSelectedItem().getValue();
version.setParent(parent);
@ -861,7 +861,7 @@ public abstract class BaseCalendarEditionController extends
}, new Util.Setter<Comboitem>() {
@Override
public void set(Comboitem comboItem) {
if (((comboItem != null)) && (comboItem.getValue() != null)
if ( ((comboItem != null)) && (comboItem.getValue() != null )
&& (comboItem.getValue() instanceof BaseCalendar)) {
BaseCalendar parent = (BaseCalendar) comboItem
.getValue();

View file

@ -227,9 +227,8 @@ public abstract class BaseCRUDController<T extends IHumanIdentifiable> extends
*/
private void saveCommonActions() throws ValidationException {
beforeSaving();
messagesForUser.clearMessages();
save();
messagesForUser.showMessage(
Level.INFO,
_("{0} \"{1}\" saved", getEntityType(), getEntityBeingEdited()

View file

@ -23,15 +23,22 @@ package org.libreplan.web.common;
import static org.libreplan.web.I18nHelper._;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ConcurrentModificationException;
import java.util.Comparator;
import java.util.Properties;
import java.util.ArrayList;
import java.util.Set;
import java.util.Map;
import java.util.Collections;
import java.util.HashSet;
import java.util.Arrays;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.AuthenticationFailedException;
import javax.mail.MessagingException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@ -70,23 +77,27 @@ import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Button;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.ListitemRenderer;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Radio;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Radiogroup;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Row;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.RowRenderer;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.Radio;
import org.zkoss.zul.Button;
import org.zkoss.zul.Label;
import org.zkoss.zul.Rows;
import org.zkoss.zul.SimpleListModel;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.api.Window;
import org.zkoss.zul.impl.InputElement;
@ -97,6 +108,7 @@ import org.zkoss.zul.impl.InputElement;
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
* @author Cristina Alavarino Perez <cristina.alvarino@comtecsf.es>
* @author Ignacio Diaz Teijido <ignacio.diaz@comtecsf.es>
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
*/
public class ConfigurationController extends GenericForwardComposer {
@ -137,6 +149,14 @@ public class ConfigurationController extends GenericForwardComposer {
private Connector selectedConnector;
private Combobox protocolsCombobox;
private Textbox emailUsernameTextbox;
private Textbox emailPasswordTextbox;
private Textbox emailSenderTextbox;
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
@ -221,36 +241,43 @@ public class ConfigurationController extends GenericForwardComposer {
}
public void save() throws InterruptedException {
ConstraintChecker.isValid(configurationWindow);
if (checkValidEntitySequenceRows()) {
try {
configurationModel.confirm();
configurationModel.init();
messages.showMessage(Level.INFO, _("Changes saved"));
if (getSelectedConnector() != null
&& !configurationModel
.scheduleOrUnscheduleJobs(getSelectedConnector())) {
messages.showMessage(
Level.ERROR,
_("Scheduling or unscheduling of jobs for this connector is not completed"));
if ( getSelectedConnector().getName().equals("E-mail") && isEmailFieldsValid() == false) {
messages.showMessage(Level.ERROR, _("Check username/password/sender fields"));
} else {
ConstraintChecker.isValid(configurationWindow);
if (checkValidEntitySequenceRows()) {
try {
configurationModel.confirm();
configurationModel.init();
messages.showMessage(Level.INFO, _("Changes saved"));
if (getSelectedConnector() != null
&& !configurationModel
.scheduleOrUnscheduleJobs(getSelectedConnector())) {
messages.showMessage(
Level.ERROR,
_("Scheduling or unscheduling of jobs for this connector is not completed"));
}
reloadWindow();
reloadEntitySequences();
reloadConnectors();
} catch (ValidationException e) {
messages.showInvalidValues(e);
} catch (ConcurrentModificationException e) {
messages.showMessage(Level.ERROR, e.getMessage());
configurationModel.init();
reloadWindow();
reloadEntitySequences();
reloadConnectors();
}
reloadWindow();
reloadEntitySequences();
reloadConnectors();
} catch (ValidationException e) {
messages.showInvalidValues(e);
} catch (ConcurrentModificationException e) {
messages.showMessage(Level.ERROR, e.getMessage());
configurationModel.init();
reloadWindow();
reloadEntitySequences();
reloadConnectors();
}
}
}
public void cancel() throws InterruptedException {
configurationModel.cancel();
messages.clearMessages();
messages.showMessage(Level.INFO, _("Changes have been canceled"));
reloadWindow();
reloadEntitySequences();
@ -305,12 +332,19 @@ public class ConfigurationController extends GenericForwardComposer {
String password = properties
.get(PredefinedConnectorProperties.PASSWORD);
if (selectedConnector.getName().equals(
PredefinedConnectors.TIM.getName())) {
if ( selectedConnector.getName().equals(
PredefinedConnectors.TIM.getName()) ) {
testTimConnection(url, username, password);
} else if (selectedConnector.getName().equals(
PredefinedConnectors.JIRA.getName())) {
} else if ( selectedConnector.getName().equals(
PredefinedConnectors.JIRA.getName()) ) {
testJiraConnection(url, username, password);
} else if( selectedConnector.getName().equals(
PredefinedConnectors.EMAIL.getName()) ){
String host = properties.get(PredefinedConnectorProperties.HOST);
username = properties.get(PredefinedConnectorProperties.EMAIL_USERNAME);
password = properties.get(PredefinedConnectorProperties.EMAIL_PASSWORD);
String port = properties.get(PredefinedConnectorProperties.PORT);
testEmailConnection(host, port, username, password);
} else {
throw new RuntimeException("Unknown connector");
}
@ -373,6 +407,58 @@ public class ConfigurationController extends GenericForwardComposer {
}
}
/**
* Test E-mail connection
*
* @param host
* the host
* @param port
* the port
* @param username
* the username
* @param password
* the password
*/
private void testEmailConnection(String host, String port, String username, String password){
Properties props = System.getProperties();
Transport transport = null;
try {
if ( protocolsCombobox.getSelectedItem().getLabel().equals("SMTP") ){
props.setProperty("mail.smtp.port", port);
props.setProperty("mail.smtp.host", host);
Session session = Session.getInstance(props, null);
transport = session.getTransport("smtp");
if ( username.equals("") && password.equals("")) transport.connect();
}
else if ( protocolsCombobox.getSelectedItem().getLabel().equals("STARTTLS") ) {
props.setProperty("mail.smtps.port", port);
props.setProperty("mail.smtps.host", host);
Session session = Session.getInstance(props, null);
transport = session.getTransport("smtps");
if ( !username.equals("") && password != null ) transport.connect(host, username, password);
}
messages.clearMessages();
if ( transport.isConnected() ) messages.showMessage(Level.INFO, _("Connection successful!"));
else if ( transport.isConnected() == false ) messages.showMessage(Level.WARNING, _("Connection unsuccessful"));
}
catch (AuthenticationFailedException e){
LOG.error(e);
messages.showMessage(Level.ERROR, _("Invalid credentials"));
}
catch (MessagingException e){
LOG.error(e);
messages.showMessage(Level.ERROR, _("Cannot connect"));
}
catch (Exception e){
LOG.error(e);
messages.showMessage(Level.ERROR, _("Failed to connect"));
}
}
private boolean checkValidEntitySequenceRows() {
Rows rows = entitySequencesGrid.getRows();
for (Row row : (List<Row>) rows.getChildren()) {
@ -1090,11 +1176,15 @@ public class ConfigurationController extends GenericForwardComposer {
row.setValue(property);
Util.appendLabel(row, _(property.getKey()));
appendValueTextbox(row, property);
// FIXME this is not perfect solution
if ( property.getKey().equals("Protocol") ) appendValueCombobox(row, property);
else appendValueTextbox(row, property);
}
private void appendValueTextbox(Row row,
final ConnectorProperty property) {
final Textbox textbox = new Textbox();
textbox.setWidth("400px");
textbox.setConstraint(checkPropertyValue(property));
@ -1112,37 +1202,108 @@ public class ConfigurationController extends GenericForwardComposer {
property.setValue(value);
}
});
if (property.getKey().equals(
PredefinedConnectorProperties.PASSWORD)) {
if ( property.getKey().equals(
PredefinedConnectorProperties.PASSWORD) ||
property.getKey().equals(
PredefinedConnectorProperties.EMAIL_PASSWORD) ) {
textbox.setType("password");
}
// Need for method validateEmailFields()
if ( property.getKey().equals(
PredefinedConnectorProperties.EMAIL_USERNAME) ) emailUsernameTextbox = textbox;
if ( property.getKey().equals(
PredefinedConnectorProperties.EMAIL_PASSWORD) ) emailPasswordTextbox = textbox;
if ( property.getKey().equals(
PredefinedConnectorProperties.EMAIL_SENDER) ) emailSenderTextbox = textbox;
row.appendChild(textbox);
}
private void appendValueCombobox(Row row,
final ConnectorProperty property){
final Combobox combobox = new Combobox();
combobox.setWidth("400px");
final List<String> protocols = new ArrayList<String>();
protocols.add("SMTP");
protocols.add("STARTTLS");
for (String item : protocols){
Comboitem comboitem = new Comboitem();
comboitem.setValue(item);
comboitem.setLabel(item);
comboitem.setParent(combobox);
if ( (!property.getValue().equals("")) &&
(item.equals(property.getValue())) ){
combobox.setSelectedItem(comboitem);
}
}
combobox.addEventListener(Events.ON_SELECT,
new EventListener() {
@Override
public void onEvent(Event event) throws Exception {
if (combobox.getSelectedItem() != null){
property.setValue(combobox.getSelectedItem().getValue().toString());
}
}
});
Util.bind(combobox, new Util.Getter<Comboitem>() {
@Override
public Comboitem get() {
return combobox.getSelectedItem();
}
}, new Util.Setter<Comboitem>(){
@Override
public void set(Comboitem item) {
if ( (item != null) && (item.getValue() != null) &&
(item.getValue() instanceof String) ){
property.setValue(combobox.getSelectedItem().getValue().toString());
}
}
});
row.appendChild(combobox);
// Need for testing E-mail connection
protocolsCombobox = combobox;
}
public Constraint checkPropertyValue(
final ConnectorProperty property) {
final String key = property.getKey();
return new Constraint() {
@Override
public void validate(Component comp, Object value) {
if (key.equals(PredefinedConnectorProperties.ACTIVATED)) {
if (!((String) value).equalsIgnoreCase("Y")
&& !((String) value).equalsIgnoreCase("N")) {
if ( key.equals(PredefinedConnectorProperties.ACTIVATED) ) {
if ( !((String) value).equalsIgnoreCase("Y")
&& !((String) value).equalsIgnoreCase("N") ) {
throw new WrongValueException(comp, _(
"Only {0} allowed", "Y/N"));
}
} else if (key
.equals(PredefinedConnectorProperties.SERVER_URL)
|| key.equals(PredefinedConnectorProperties.USERNAME)
|| key.equals(PredefinedConnectorProperties.PASSWORD)
|| key.equals(PredefinedConnectorProperties.JIRA_HOURS_TYPE)) {
} else if ( key
.equals(PredefinedConnectorProperties.SERVER_URL) ||
key.equals(PredefinedConnectorProperties.USERNAME) ||
key.equals(PredefinedConnectorProperties.PASSWORD) ||
key.equals(PredefinedConnectorProperties.JIRA_HOURS_TYPE) ||
key.equals(PredefinedConnectorProperties.HOST) ||
key.equals(PredefinedConnectorProperties.PORT) ||
key.equals(PredefinedConnectorProperties.EMAIL_SENDER) ) {
((InputElement) comp).setConstraint("no empty:"
+ _("cannot be empty"));
} else if (key
.equals(PredefinedConnectorProperties.TIM_NR_DAYS_TIMESHEET)
|| key.equals(PredefinedConnectorProperties.TIM_NR_DAYS_ROSTER)) {
if (!isNumeric((String) value)) {
} else if ( key
.equals(PredefinedConnectorProperties.TIM_NR_DAYS_TIMESHEET) ||
key.equals(PredefinedConnectorProperties.TIM_NR_DAYS_ROSTER) ||
key.equals(PredefinedConnectorProperties.PORT) ) {
if ( !isNumeric((String) value) ) {
throw new WrongValueException(comp,
_("Only digits allowed"));
}
@ -1163,4 +1324,17 @@ public class ConfigurationController extends GenericForwardComposer {
};
}
private boolean isEmailFieldsValid(){
if ( protocolsCombobox.getSelectedItem().getLabel().equals("STARTTLS") &&
emailUsernameTextbox.getValue() != null &&
emailPasswordTextbox.getValue() != null &&
emailUsernameTextbox.getValue().length() != 0 &&
emailPasswordTextbox.getValue().length() != 0 &&
emailSenderTextbox.getValue().matches("^\\S+@\\S+\\.\\S+$") )
return true;
else return false;
}
}

View file

@ -59,6 +59,7 @@ import org.zkoss.zul.Vbox;
* Controller for customMenu <br />
* @author Lorenzo Tilve Álvaro <ltilve@igalia.com>
* @author Fernando Bellas Permuy <fbellas@udc.es>
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
*/
public class CustomMenuController extends Div implements IMenuItemsRegister {
@ -420,6 +421,11 @@ public class CustomMenuController extends Div implements IMenuItemsRegister {
"/common/job_scheduling.zul",
"19-scheduler.html"));
}
if (SecurityUtils.isSuperuserOrUserInRoles(UserRole.ROLE_EDIT_EMAIL_TEMPLATES)) {
configurationItems.add(subItem(_("Edit E-mail Templates"),
"/email/email_templates.zul",
"email-templates.html"));
}
if (!configurationItems.isEmpty()) {
topItem(_("Configuration"), "/common/configuration.zul", "",

View file

@ -19,6 +19,7 @@
package org.libreplan.web.common;
import java.util.ArrayList;
import java.util.List;
import org.libreplan.business.common.daos.IConnectorDAO;
@ -34,6 +35,7 @@ import org.libreplan.importers.IImportRosterFromTim;
import org.libreplan.importers.IJiraOrderElementSynchronizer;
import org.libreplan.importers.ISchedulerManager;
import org.libreplan.importers.SynchronizationInfo;
import org.libreplan.importers.ISendEmail;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
@ -42,6 +44,8 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import static org.libreplan.web.I18nHelper._;
/**
* Model for UI operations related to {@link JobSchedulerConfiguration}.
*
@ -75,6 +79,9 @@ public class JobSchedulerModel implements IJobSchedulerModel {
private List<SynchronizationInfo> synchronizationInfos;
@Autowired
private ISendEmail email;
@Override
@Transactional(readOnly = true)
public List<JobSchedulerConfiguration> getJobSchedulerConfigurations() {
@ -105,6 +112,13 @@ public class JobSchedulerModel implements IJobSchedulerModel {
.syncOrderElementsWithJiraIssues();
return;
}
if ( name.equals(JobClassNameEnum.SEND_EMAIL_JOB.getName()) ) {
synchronizationInfos = new ArrayList<SynchronizationInfo>();
synchronizationInfos.add(new SynchronizationInfo(_("Send E-mail")));
email.sendEmail();
return;
}
throw new RuntimeException("Unknown action");
}

View file

@ -0,0 +1,299 @@
package org.libreplan.web.dashboard;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.web.orders.IOrderModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Label;
import org.zkoss.zul.Rows;
import org.zkoss.zul.Row;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 20.11.15.
*/
@org.springframework.stereotype.Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class DashboardControllerGlobal extends GenericForwardComposer {
@Autowired
private IOrderModel orderModel;
private Grid pipelineGrid;
private Checkbox storedColumnVisible;
private List<Order> preSalesOrders = new ArrayList<Order>();
private List<Order> offeredOrders = new ArrayList<Order>();
private List<Order> outsourcedOrders = new ArrayList<Order>();
private List<Order> acceptedOrders = new ArrayList<Order>();
private List<Order> startedOrders = new ArrayList<Order>();
private List<Order> onHoldOrders = new ArrayList<Order>();
private List<Order> finishedOrders = new ArrayList<Order>();
private List<Order> cancelledOrders = new ArrayList<Order>();
private List<Order> storedOrders = new ArrayList<Order>();
@Override
public void doAfterCompose(Component component) throws Exception {
super.doAfterCompose(component);
component.setVariable("dashboardControllerGlobal", this, true);
fillOrderLists();
setupPipelineGrid();
showStoredColumn();
}
public List<Order> getOrders(){
return orderModel.getOrders();
}
private void fillOrderLists() {
for (Order orderItem : getOrders()){
switch (orderItem.getState()){
case PRE_SALES: {
preSalesOrders.add(orderItem);
break;
}
case OFFERED: {
offeredOrders.add(orderItem);
break;
}
case OUTSOURCED: {
outsourcedOrders.add(orderItem);
break;
}
case ACCEPTED: {
acceptedOrders.add(orderItem);
break;
}
case STARTED: {
startedOrders.add(orderItem);
break;
}
case ON_HOLD: {
onHoldOrders.add(orderItem);
break;
}
case FINISHED: {
finishedOrders.add(orderItem);
break;
}
case CANCELLED: {
cancelledOrders.add(orderItem);
break;
}
case STORED: {
storedOrders.add(orderItem);
break;
}
}
}
}
private void setupPipelineGrid() throws ParseException {
int rowsCount = findMaxList(preSalesOrders.size(), offeredOrders.size(), outsourcedOrders.size(), acceptedOrders.size(),
startedOrders.size(), onHoldOrders.size(), finishedOrders.size(), cancelledOrders.size(), storedOrders.size());
Rows rows = new Rows();
for (int i = 0; i < rowsCount; i++){
Row row = new Row();
for (int columns = 0; columns < 9; columns++) row.appendChild(new Label());
rows.appendChild(row);
}
pipelineGrid.appendChild(rows);
// Fill data into first column and so on with other columns divided by Enter in code
if ( preSalesOrders.size() > 0 )
for (int i = 0; i < preSalesOrders.size(); i++){
String outputInit = getOrderInitDate(preSalesOrders.get(i));
String outputDeadline = getOrderDeadline(preSalesOrders.get(i));
( (Label) pipelineGrid.getCell(i, 0) ).setValue(preSalesOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + preSalesOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 0) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 0) ).setClass("label-highlight");
}
if ( offeredOrders.size() > 0 )
for (int i = 0; i < offeredOrders.size(); i++){
String outputInit = getOrderInitDate(offeredOrders.get(i));
String outputDeadline = getOrderDeadline(offeredOrders.get(i));
( (Label) pipelineGrid.getCell(i, 1) ).setValue(offeredOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + offeredOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 1) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 1) ).setClass("label-highlight");
}
if ( outsourcedOrders.size() > 0 )
for (int i = 0; i < outsourcedOrders.size(); i++){
String outputInit = getOrderInitDate(outsourcedOrders.get(i));
String outputDeadline = getOrderDeadline(outsourcedOrders.get(i));
( (Label) pipelineGrid.getCell(i, 2) ).setValue(outsourcedOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + outsourcedOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 2) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 2) ).setClass("label-highlight");
}
if ( acceptedOrders.size() > 0 )
for (int i = 0; i < acceptedOrders.size(); i++){
String outputInit = getOrderInitDate(acceptedOrders.get(i));
String outputDeadline = getOrderDeadline(acceptedOrders.get(i));
( (Label) pipelineGrid.getCell(i, 3) ).setValue(acceptedOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + acceptedOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 3) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 3) ).setClass("label-highlight");
}
if ( startedOrders.size() > 0 )
for (int i = 0; i < startedOrders.size(); i++){
String outputInit = getOrderInitDate(startedOrders.get(i));
String outputDeadline = getOrderDeadline(startedOrders.get(i));
( (Label) pipelineGrid.getCell(i, 4) ).setValue(startedOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + startedOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 4) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 4) ).setClass("label-highlight");
}
if ( onHoldOrders.size() > 0 )
for (int i = 0; i < onHoldOrders.size(); i++){
String outputInit = getOrderInitDate(onHoldOrders.get(i));
String outputDeadline = getOrderDeadline(onHoldOrders.get(i));
( (Label) pipelineGrid.getCell(i, 5) ).setValue(onHoldOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + onHoldOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 5) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 5) ).setClass("label-highlight");
}
if ( finishedOrders.size() > 0 )
for (int i = 0; i < finishedOrders.size(); i++){
String outputInit = getOrderInitDate(finishedOrders.get(i));
String outputDeadline = getOrderDeadline(finishedOrders.get(i));
( (Label) pipelineGrid.getCell(i, 6) ).setValue(finishedOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + finishedOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 6) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 6) ).setClass("label-highlight");
}
if ( cancelledOrders.size() > 0 )
for (int i = 0; i < cancelledOrders.size(); i++){
String outputInit = getOrderInitDate(cancelledOrders.get(i));
String outputDeadline = getOrderDeadline(cancelledOrders.get(i));
( (Label) pipelineGrid.getCell(i, 7) ).setValue(cancelledOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + cancelledOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 7) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 7) ).setClass("label-highlight");
}
}
private String getOrderInitDate(Order order) throws ParseException {
// Remove time, timezone from full-date string
DateFormat inputFormatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
DateFormat outputFormatter = new SimpleDateFormat("EEE MMM dd yyyy");
String input = "";
String outputInit = "";
String outputDeadline = "";
Date date = null;
input = order.getInitDate().toString();
date = inputFormatter.parse(input);
return outputInit = outputFormatter.format(date);
}
private String getOrderDeadline(Order order) throws ParseException {
// Remove time, timezone from full-date string
DateFormat inputFormatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
DateFormat outputFormatter = new SimpleDateFormat("EEE MMM dd yyyy");
String input = "";
String outputInit = "";
String outputDeadline = "";
Date date = null;
input = order.getDeadline().toString();
date = inputFormatter.parse(input);
return outputDeadline = outputFormatter.format(date);
}
public void showStoredColumn() throws ParseException {
if ( storedColumnVisible.isChecked() ){
if ( storedOrders.size() > 0 ){
for (int i = 0; i < storedOrders.size(); i++){
String outputInit = getOrderInitDate(storedOrders.get(i));
String outputDeadline = getOrderDeadline(storedOrders.get(i));
pipelineGrid.getCell(i, 8).setVisible(true);
( (Label) pipelineGrid.getCell(i, 8) ).setValue(storedOrders.get(i).getName());
String tooltipText = "Start date: " + outputInit +
"\n" + "End date: " + outputDeadline +
"\n" + "Progress: " + storedOrders.get(i).getAdvancePercentage() + " %";
( (Label) pipelineGrid.getCell(i, 8) ).setTooltiptext(tooltipText);
( (Label) pipelineGrid.getCell(i, 8) ).setClass("label-highlight");
}
}
}
else if ( !storedColumnVisible.isChecked() ){
for (int i = 0; i < storedOrders.size(); i++)
pipelineGrid.getCell(i, 8).setVisible(false);
}
}
private int findMaxList(int preSales, int offered, int outsourced, int accepted, int started, int onHold, int finished,
int cancelled, int stored){
int[] sizes = {preSales, offered, outsourced, accepted, started, onHold, finished, cancelled, stored};
int max = sizes[0];
for (int i = 1; i < sizes.length; i++)
if ( sizes[i] > max ) max = sizes[i];
return max;
}
}

View file

@ -0,0 +1,110 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.email;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.email.daos.IEmailNotificationDAO;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.entities.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
/**
* Model for operations related to {@link EmailNotification}.
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 21.10.15.
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class EmailNotificationModel implements IEmailNotificationModel {
@Autowired
private IEmailNotificationDAO emailNotificationDAO;
private EmailTemplateEnum type;
private Date updated;
private Resource resource;
private TaskElement task;
private TaskElement project;
private EmailNotification emailNotification = new EmailNotification();
@Override
@Transactional
public void confirmSave() throws ValidationException {
emailNotificationDAO.save(emailNotification);
}
@Override
@Transactional
public List<EmailNotification> getAll() {
return emailNotificationDAO.getAll();
}
@Override
@Transactional
public boolean deleteAll() {
return emailNotificationDAO.deleteAll();
}
@Override
public void setType(EmailTemplateEnum type) {
this.emailNotification.setType(type);
}
@Override
public void setUpdated(Date updated) {
this.emailNotification.setUpdated(updated);
}
@Override
public void setResource(Resource resource) {
this.emailNotification.setResource(resource);
}
@Override
public void setTask(TaskElement task) {
this.emailNotification.setTask(task);
}
@Override
public void setProject(TaskElement project) {
this.emailNotification.setProject(project);
}
}

View file

@ -0,0 +1,180 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.email;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.settings.entities.Language;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.web.common.IMessagesForUser;
import org.libreplan.web.common.Level;
import org.libreplan.web.common.MessagesForUser;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.ListitemRenderer;
import org.zkoss.zul.Textbox;
import java.util.List;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import static org.libreplan.web.I18nHelper._;
/**
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 25.09.15.
*/
public class EmailTemplateController extends GenericForwardComposer{
private IEmailTemplateModel emailTemplateModel;
private IMessagesForUser messages;
private Component messagesContainer;
private Textbox contentsTextbox;
private Textbox subjectTextbox;
public static ListitemRenderer languagesRenderer = new ListitemRenderer() {
@Override
public void render(org.zkoss.zul.Listitem item, Object data)
throws Exception {
Language language = (Language) data;
String displayName = language.getDisplayName();
item.setLabel(displayName);
}
};
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
comp.setVariable("emailTemplateController", this, true);
messages = new MessagesForUser(messagesContainer);
contentsTextbox.setValue(getInitialContentData());
subjectTextbox.setValue(getInitialSubjectData());
}
public boolean save(){
try {
setSelectedContent();
setSelectedSubject();
emailTemplateModel.confirmSave();
messages.clearMessages();
messages.showMessage(Level.INFO, _("E-mail template saved"));
return true;
} catch (ValidationException e) {
messages.showInvalidValues(e);
} catch (InstanceNotFoundException e) {}
return false;
}
public void cancel() throws InterruptedException {
Executions.getCurrent().sendRedirect("../planner/index.zul");
}
public Language getSelectedLanguage() {
return emailTemplateModel.getLanguage();
}
public void setSelectedLanguage(Language language){
emailTemplateModel.setLanguage(language);
getContentDataBySelectedLanguage();
}
public static ListitemRenderer getLanguagesRenderer() {
return languagesRenderer;
}
public List<Language> getLanguages() {
List<Language> languages = new LinkedList<Language>(Arrays.asList(Language.values()));
Collections.sort(languages, new Comparator<Language>() {
@Override
public int compare(Language o1, Language o2) {
if (o1.equals(Language.BROWSER_LANGUAGE)) {
return -1;
}
if (o2.equals(Language.BROWSER_LANGUAGE)) {
return 1;
}
return o1.getDisplayName().compareTo(o2.getDisplayName());
}
});
languages.remove(0);
return languages;
}
public EmailTemplateEnum getSelectedEmailTemplateEnum() {
return emailTemplateModel.getEmailTemplateEnum();
}
public void setSelectedEmailTemplateEnum(EmailTemplateEnum emailTemplateEnum){
emailTemplateModel.setEmailTemplateEnum(emailTemplateEnum);
getContentDataBySelectedTemplate();
}
public ListitemRenderer getEmailTemplateEnumRenderer() {
return new ListitemRenderer() {
@Override
public void render(Listitem item, Object data) throws Exception {
EmailTemplateEnum template = (EmailTemplateEnum) data;
item.setLabel(_(template.getTemplateType()));
item.setValue(template);
}
};
}
public List<EmailTemplateEnum> getEmailTemplateEnum() {
return Arrays.asList(EmailTemplateEnum.values());
}
public void setSelectedContent(){
emailTemplateModel.setContent(contentsTextbox.getValue());
}
public String getInitialContentData(){
return emailTemplateModel.initializeContent();
}
public void setSelectedSubject(){
emailTemplateModel.setSubject(subjectTextbox.getValue());
}
public String getInitialSubjectData(){
return emailTemplateModel.initializeSubject();
}
private void getContentDataBySelectedLanguage(){
contentsTextbox.setValue(emailTemplateModel.getContentBySelectedLanguage(getSelectedLanguage().ordinal(), getSelectedEmailTemplateEnum().ordinal()));
}
private void getContentDataBySelectedTemplate(){
contentsTextbox.setValue( emailTemplateModel.getContentBySelectedTemplate( getSelectedEmailTemplateEnum().ordinal(), getSelectedLanguage().ordinal() ) );
}
}

View file

@ -0,0 +1,162 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.email;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.settings.entities.Language;
import org.libreplan.business.email.daos.IEmailTemplateDAO;
import org.libreplan.business.email.entities.EmailTemplate;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* Model for operations related to {@link EmailTemplate}.
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 25.09.15.
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@OnConcurrentModification(goToPage = "/email/email_templates.zul")
public class EmailTemplateModel implements IEmailTemplateModel {
@Autowired
private IEmailTemplateDAO emailTemplateDAO;
private Language language = Language.ENGLISH_LANGUAGE;
private EmailTemplateEnum emailTemplateEnum = EmailTemplateEnum.TEMPLATE_TASK_ASSIGNED_TO_RESOURCE;
private String content;
private String subject;
private EmailTemplate emailTemplate = new EmailTemplate();
@Override
@Transactional
public void confirmSave() throws InstanceNotFoundException {
/* If current EmailTemplate entity (id) is existing in DB than it needs to update.
* Else current EmailTemplate entity (id) is creating and getting new values from form.
*/
List<EmailTemplate> emailTemplates = emailTemplateDAO.getAll();
EmailTemplate emailTemplateFromDatabase = null;
for (int i = 0; i < emailTemplates.size(); i++) {
if ( emailTemplate.getLanguage() == emailTemplates.get(i).getLanguage() &&
emailTemplate.getType() == emailTemplates.get(i).getType() ) {
emailTemplateFromDatabase = emailTemplateDAO.find(emailTemplates.get(i).getId());
}
}
if ( emailTemplateFromDatabase != null ){
EmailTemplate temporaryEntity = emailTemplate;
emailTemplate = emailTemplateFromDatabase;
emailTemplate.setType(temporaryEntity.getType());
emailTemplate.setLanguage(temporaryEntity.getLanguage());
emailTemplate.setContent(temporaryEntity.getContent());
emailTemplate.setSubject(temporaryEntity.getSubject());
} else {
EmailTemplate temporaryEntity = emailTemplate;
emailTemplate = new EmailTemplate();
emailTemplate.setType(temporaryEntity.getType());
emailTemplate.setLanguage(temporaryEntity.getLanguage());
emailTemplate.setContent(temporaryEntity.getContent());
emailTemplate.setSubject(temporaryEntity.getSubject());
}
emailTemplateDAO.save(emailTemplate);
}
@Override
@Transactional
public List<EmailTemplate> getAll() {
return emailTemplateDAO.getAll();
}
@Override
public Language getLanguage() {
return this.emailTemplate.getLanguage();
}
@Override
public void setLanguage(Language language){ this.emailTemplate.setLanguage(language);}
@Override
public EmailTemplateEnum getEmailTemplateEnum() {
return this.emailTemplate.getType();
}
@Override
public void setEmailTemplateEnum(EmailTemplateEnum emailTemplateEnum) {
this.emailTemplate.setType(emailTemplateEnum);
}
@Override
public String getContent() {
return this.emailTemplate.getContent();
}
@Override
public void setContent(String content) {
this.emailTemplate.setContent(content);
}
@Override
public String getSubject() {
return this.emailTemplate.getSubject();
}
@Override
public void setSubject(String subject) {
this.emailTemplate.setSubject(subject);
}
@Override
@Transactional
public String initializeContent() {
return emailTemplateDAO.initializeContent();
}
@Override
@Transactional
public String initializeSubject() { return emailTemplateDAO.initializeSubject(); }
@Override
@Transactional
public String getContentBySelectedLanguage(int languageOrdinal, int emailTemplateTypeOrdinal) {
return emailTemplateDAO.getContentBySelectedLanguage(languageOrdinal, emailTemplateTypeOrdinal);
}
@Override
@Transactional
public String getContentBySelectedTemplate(int emailTemplateTypeOrdinal, int languageOrdinal) {
return emailTemplateDAO.getContentBySelectedTemplate(emailTemplateTypeOrdinal, languageOrdinal);
}
}

View file

@ -0,0 +1,52 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.email;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.entities.Resource;
import java.util.Date;
import java.util.List;
/**
* Contract for {@link EmailNotification}
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 21.10.15.
*/
public interface IEmailNotificationModel {
void confirmSave() throws ValidationException;
List<EmailNotification> getAll();
boolean deleteAll();
void setType(EmailTemplateEnum type);
void setUpdated(Date date);
void setResource(Resource resource);
void setTask(TaskElement task);
void setProject(TaskElement project);
}

View file

@ -0,0 +1,60 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2015 LibrePlan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.email;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.email.entities.EmailTemplate;
import org.libreplan.business.settings.entities.Language;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import java.util.List;
/**
* Contract for {@link EmailTemplate}
*
* Created by
* @author Vova Perebykivskiy <vova@libreplan-enterprise.com>
* on 28.09.15.
*/
public interface IEmailTemplateModel {
void confirmSave() throws ValidationException, InstanceNotFoundException;
List<EmailTemplate> getAll();
String initializeContent();
String initializeSubject();
String getContentBySelectedLanguage(int languageOrdinal, int emailTemplateTypeOrdinal);
String getContentBySelectedTemplate(int emailTemplateTypeOrdinal, int languageOrdinal);
String getContent();
void setContent(String content);
Language getLanguage();
void setLanguage(Language language);
EmailTemplateEnum getEmailTemplateEnum();
void setEmailTemplateEnum(EmailTemplateEnum emailTemplateEnum);
String getSubject();
void setSubject(String subject);
}

View file

@ -523,6 +523,8 @@ public class FormBinder {
}
});
allocationProduced(allocationResult);
TaskPropertiesController.allocationResult = allocationResult;
}
/**

View file

@ -33,6 +33,7 @@ import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.resources.daos.IResourcesSearcher;
import org.libreplan.web.dashboard.DashboardController;
import org.libreplan.web.dashboard.DashboardControllerGlobal;
import org.libreplan.web.planner.order.OrderPlanningController;
import org.libreplan.web.planner.order.PlanningStateCreator;
import org.libreplan.web.planner.order.PlanningStateCreator.PlanningState;
@ -55,17 +56,19 @@ public class DashboardTabCreator {
public static ITab create(Mode mode,
PlanningStateCreator planningStateCreator,
DashboardController dashboardController,
DashboardControllerGlobal dashboardControllerGlobal,
OrderPlanningController orderPlanningController,
Component breadcrumbs,
IResourcesSearcher resourcesSearcher) {
return new DashboardTabCreator(mode, planningStateCreator,
dashboardController, orderPlanningController, breadcrumbs,
resourcesSearcher).build();
dashboardController, dashboardControllerGlobal, orderPlanningController,
breadcrumbs, resourcesSearcher).build();
}
private final PlanningStateCreator planningStateCreator;
private final Mode mode;
private final DashboardController dashboardController;
private final DashboardControllerGlobal dashboardControllerGlobal;
private final OrderPlanningController orderPlanningController;
private final Component breadcrumbs;
private final IResourcesSearcher resourcesSearcher;
@ -73,12 +76,14 @@ public class DashboardTabCreator {
private DashboardTabCreator(Mode mode,
PlanningStateCreator planningStateCreator,
DashboardController dashboardController,
DashboardControllerGlobal dashboardControllerGlobal,
OrderPlanningController orderPlanningController,
Component breadcrumbs,
IResourcesSearcher resourcesSearcher) {
this.mode = mode;
this.planningStateCreator = planningStateCreator;
this.dashboardController = dashboardController;
this.dashboardControllerGlobal = dashboardControllerGlobal;
this.orderPlanningController = orderPlanningController;
this.breadcrumbs = breadcrumbs;
this.resourcesSearcher = resourcesSearcher;
@ -86,7 +91,7 @@ public class DashboardTabCreator {
private ITab build() {
return TabOnModeType.forMode(mode)
.forType(ModeType.GLOBAL, createDashboardTab())
.forType(ModeType.GLOBAL, createDashboardGlobalTab())
.forType(ModeType.ORDER, createDashboardTab())
.create();
}
@ -129,6 +134,34 @@ public class DashboardTabCreator {
}
};
}
private ITab createDashboardGlobalTab(){
IComponentCreator componentCreator = new IComponentCreator() {
@Override
public org.zkoss.zk.ui.Component create(
org.zkoss.zk.ui.Component parent) {
Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("dashboardControllerGlobal", dashboardControllerGlobal);
return Executions.createComponents(
"/dashboard/_dashboardforglobal.zul", parent,
arguments);
}
};
return new CreatedOnDemandTab(_("Dashboard"), "global-dashboard",
componentCreator) {
@Override
protected void afterShowAction() {
breadcrumbs.getChildren().clear();
breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
breadcrumbs.appendChild(new Label(getSchedulingLabel()));
breadcrumbs.appendChild(new Image(BREADCRUMBS_SEPARATOR));
breadcrumbs.appendChild(new Label(_("Dashboard")));
}
};
}
private List<TaskElement> getCriticalPath(final Order order, final Desktop desktop) {
CriticalPathBuilder builder = CriticalPathBuilder.create(

View file

@ -40,6 +40,7 @@ import org.libreplan.web.common.ConfirmCloseUtil;
import org.libreplan.web.common.entrypoints.EntryPointsHandler;
import org.libreplan.web.common.entrypoints.URLHandlerRegistry;
import org.libreplan.web.dashboard.DashboardController;
import org.libreplan.web.dashboard.DashboardControllerGlobal;
import org.libreplan.web.limitingresources.LimitingResourcesController;
import org.libreplan.web.montecarlo.MonteCarloController;
import org.libreplan.web.orders.OrderCRUDController;
@ -67,6 +68,7 @@ import org.zkoss.ganttz.extensions.TabProxy;
import org.zkoss.ganttz.util.LongOperationFeedback;
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
@ -84,6 +86,8 @@ import org.zkoss.zk.ui.util.Composer;
public class MultipleTabsPlannerController implements Composer,
IGlobalViewEntryPoints {
public static String WELCOME_URL = "-- no URL provided --";
private final class TabWithLoadingFeedback extends TabProxy {
private boolean feedback = true;
@ -183,6 +187,9 @@ public class MultipleTabsPlannerController implements Composer,
@Autowired
private DashboardController dashboardController;
@Autowired
private DashboardControllerGlobal dashboardControllerGlobal;
private org.zkoss.zk.ui.Component breadcrumbs;
@Autowired
@ -293,7 +300,7 @@ public class MultipleTabsPlannerController implements Composer,
}, parameters);
dashboardTab = DashboardTabCreator.create(mode, planningStateCreator,
dashboardController, orderPlanningController, breadcrumbs,
dashboardController, dashboardControllerGlobal, orderPlanningController, breadcrumbs,
resourcesSearcher);
final boolean isMontecarloVisible = isMonteCarloVisible();
@ -321,7 +328,7 @@ public class MultipleTabsPlannerController implements Composer,
resourceLoadTab, typeChanged));
}
tabsConfiguration.add(visibleOnlyAtOrderMode(advancedAllocationTab))
.add(visibleOnlyAtOrderMode(dashboardTab));
.add(tabWithNameReloading(dashboardTab, typeChanged));
if (isMontecarloVisible) {
tabsConfiguration.add(visibleOnlyAtOrderMode(monteCarloTab));
@ -419,6 +426,10 @@ public class MultipleTabsPlannerController implements Composer,
@Override
@Transactional(readOnly=true)
public void doAfterCompose(org.zkoss.zk.ui.Component comp) {
Execution execution = Executions.getCurrent();
WELCOME_URL = "http://" + execution.getServerName() + ":" + execution.getServerPort() + Executions.encodeURL("/planner/index.zul");
tabsSwitcher = (TabSwitcher) comp;
breadcrumbs = comp.getPage().getFellow("breadcrumbs");
tabsSwitcher

View file

@ -33,6 +33,7 @@ import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes;
import org.libreplan.business.advance.entities.AdvanceType;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOrderElementException;
import org.libreplan.business.email.entities.EmailTemplateEnum;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.planner.entities.ITaskPositionConstrained;
@ -40,10 +41,18 @@ import org.libreplan.business.planner.entities.PositionConstraintType;
import org.libreplan.business.planner.entities.Task;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.planner.entities.TaskPositionConstraint;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.scenarios.IScenarioManager;
import org.libreplan.business.users.entities.User;
import org.libreplan.business.users.entities.UserRole;
import org.libreplan.business.workingday.IntraDayDate;
import org.libreplan.web.I18nHelper;
import org.libreplan.web.common.Util;
import org.libreplan.web.email.IEmailNotificationModel;
import org.libreplan.web.orders.IOrderModel;
import org.libreplan.web.planner.allocation.AllocationResult;
import org.libreplan.web.resources.worker.IWorkerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
@ -117,6 +126,16 @@ public class TaskPropertiesController extends GenericForwardComposer {
private boolean disabledConstraintsAndAllocations = false;
public static AllocationResult allocationResult;
private IEmailNotificationModel emailNotificationModel;
private IOrderModel orderModel;
private IWorkerModel workerModel;
public void init(final EditTaskController editTaskController,
IContextWithPlannerTask<TaskElement> context,
TaskElement taskElement) {
@ -414,6 +433,8 @@ public class TaskPropertiesController extends GenericForwardComposer {
}
public void accept() {
EmailNotificationAddNewWithTaskAssignedToResource();
boolean ok = true;
if (currentTaskElement instanceof ITaskPositionConstrained) {
ok = saveConstraintChanges();
@ -709,4 +730,49 @@ public class TaskPropertiesController extends GenericForwardComposer {
return Util.getMoneyFormat();
}
private void EmailNotificationAddNewWithTaskAssignedToResource(){
if ( allocationResult != null ) {
/* Check if resources in allocation are bound by user and are in role ROLE_EMAIL_TASK_ASSIGNED_TO_RESOURCE
* setUser method calling manually because, after initialization user will be null
* Then send valid data to notification_queue table */
List<Worker> workersList = workerModel.getWorkers();
Worker currentWorker;
Resource currentResource;
User currentUser;
for (int i = 0; i < workersList.size(); i++)
for (int j = 0; j < allocationResult.getSpecificAllocations().size(); j++){
currentWorker = workersList.get(i);
currentResource = allocationResult.getSpecificAllocations().get(j).getResource();
if ( currentWorker.getId().equals(currentResource.getId()) ){
workersList.get(i).setUser(workerModel.getBoundUserFromDB(currentWorker));
currentUser = currentWorker.getUser();
if ( currentUser != null &&
currentUser.isInRole(UserRole.ROLE_EMAIL_TASK_ASSIGNED_TO_RESOURCE) ) {
emailNotificationModel.setType(EmailTemplateEnum.TEMPLATE_TASK_ASSIGNED_TO_RESOURCE);
emailNotificationModel.setUpdated(new Date());
emailNotificationModel.setResource(allocationResult.getSpecificAllocations().get(j).getResource());
emailNotificationModel.setTask(currentTaskElement.getTaskSource().getTask());
emailNotificationModel.setProject(currentTaskElement.getParent().getTaskSource().getTask());
emailNotificationModel.confirmSave();
}
}
}
}
}
}

View file

@ -26,7 +26,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Filter;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.labels.entities.Label;
@ -38,8 +37,6 @@ import org.libreplan.web.common.Level;
import org.libreplan.web.common.MessagesForUser;
import org.libreplan.web.common.components.bandboxsearch.BandboxSearch;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Session;
import org.zkoss.zk.ui.Sessions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;

View file

@ -8474,8 +8474,8 @@ msgid "CANCELLED"
msgstr "CANCEL·LAT"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:41
msgid "STORED"
msgstr "EMMAGATZEMAT"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/SchedulingState.java:366
msgid "Fully scheduled"

View file

@ -8361,8 +8361,8 @@ msgid "SUBCONTRACTED PENDING PROJECT"
msgstr "SUBKONTRAKTOVANÝ NEVYŘÍZENÝ PROJEKT"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:35
msgid "STORED"
msgstr "ULOŽENO"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/SchedulingState.java:366
msgid "Fully scheduled"

View file

@ -8362,7 +8362,7 @@ msgid "SUBCONTRACTED PENDING PROJECT"
msgstr "UNTERVERGEBENES, AUSTEHENDES PROJEKT "
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:35
msgid "STORED"
msgid "ARCHIVED"
msgstr "GESPEICHERT"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/SchedulingState.java:366

View file

@ -9191,8 +9191,8 @@ msgid "CANCELLED"
msgstr "CANCELADO"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "STORED"
msgstr "ARCHIVADO"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/CriterionRequirementHandler.java:539
msgid "The criterion already exists into another task"

View file

@ -9191,8 +9191,8 @@ msgid "CANCELLED"
msgstr "ANNULE"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "STORED"
msgstr "ENREGISTRE"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/CriterionRequirementHandler.java:539
msgid "The criterion already exists into another task"

View file

@ -9190,8 +9190,8 @@ msgid "CANCELLED"
msgstr "CANCELADO"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "STORED"
msgstr "ARCHIVADO"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/CriterionRequirementHandler.java:539
msgid "The criterion already exists into another task"

View file

@ -9188,7 +9188,7 @@ msgid "CANCELLED"
msgstr "CANCELLATO"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "STORED"
msgid "ARCHIVED"
msgstr "IMMAGAZZINATO"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/CriterionRequirementHandler.java:539

View file

@ -889,6 +889,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/resources/worker/_edition.zul:122
#: libreplan-webapp/src/main/webapp/resources/worker/_edition.zul:158
#: libreplan-webapp/src/main/webapp/users/_editUser.zul:84
#: libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java:56
msgid "E-mail"
msgstr ""
@ -1363,6 +1364,7 @@ msgid "First expense"
msgstr ""
#: libreplan-webapp/src/main/webapp/common/configuration.zul:296
#: libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java:55
msgid "Host"
msgstr ""
@ -7762,6 +7764,7 @@ msgstr ""
#: libreplan-webapp/src/main/webapp/orders/_orderElementDetails.zul:59
#: libreplan-webapp/src/main/webapp/qualityforms/_listQualityForm.zul:37
#: libreplan-webapp/src/main/webapp/qualityforms/_editQualityForm.zul:49
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:83
msgid "Description"
msgstr ""
@ -9185,7 +9188,7 @@ msgid "CANCELLED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "STORED"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/CriterionRequirementHandler.java:539
@ -9212,3 +9215,75 @@ msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/settings/entities/Language.java:36
msgid "Use browser language configuration"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/templates/entities/EmailTemplateEnum.java:17
msgid "Task assigned to resource"
msgstr ""
#: libreplan-webapp/src/main/java/org/libreplan/web/common/CustomMenuController.java:425
msgid "Edit E-mail Templates"
msgstr ""
#: libreplan-webapp/src/main/java/org/libreplan/web/templates/EmailTemplateController.java:72
msgid "E-mail template saved"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java:57
msgid "Port"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java:56
msgid "Protocol"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:79
msgid "Possible content keywords"
msgstr ""
#: libreplan-webapp/src/main/webapp/java/org/libreplan/web/planner/tabs/MultipleTabsPlannerController:90
msgid "-- no URL provided --"
msgstr ""
#: libreplan-webapp/src/main/java/org/libreplan/web/common/ConfigurationController.java:1307
msgid "Not correct E-mail address"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:82
msgid "Keyword"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:89
msgid "Username of user"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:94
msgid "First name of user"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:99
msgid "Last name of user"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:104
msgid "Name of project"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:109
msgid "Name of resource"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:114
msgid "Name of task"
msgstr ""
#: libreplan-webapp/src/main/webapp/email/email_templates.zul:119
msgid "Welcome page"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "ARCHIVED"
msgstr ""
#: libreplan-webapp/src/main/webapp/dashboard/_pipeline.zul:2
msgid "Show archived column data"
msgstr ""

View file

@ -9006,8 +9006,8 @@ msgid "CANCELLED"
msgstr "AVLYST"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "STORED"
msgstr "LAGRET"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/SchedulingState.java:366
msgid "Fully scheduled"

View file

@ -9188,8 +9188,8 @@ msgid "CANCELLED"
msgstr "AFGEBROKEN"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "STORED"
msgstr "OPGESLAGEN"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/CriterionRequirementHandler.java:539
msgid "The criterion already exists into another task"

View file

@ -7109,8 +7109,8 @@ msgid "SUBCONTRACTED PENDING PROJECT"
msgstr "Nierozstrzygnięty pracowany"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:35
msgid "STORED"
msgstr "Przechowywane"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/SchedulingState.java:215
msgid "it's already somewhat scheduled"

View file

@ -8476,8 +8476,8 @@ msgid "CANCELLED"
msgstr "CANCELADO"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:41
msgid "STORED"
msgstr "Arquivado"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/SchedulingState.java:366
msgid "Fully scheduled"

View file

@ -6711,3 +6711,7 @@ msgstr "Итоговая стоимость"
#: libreplan-webapp/src/main/webapp/excetiondays/_listExceptionDayTypes.zul:54
msgid "Delete"
msgstr "Удалить"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:43
msgid "ARCHIVED"
msgstr "Заархивированный"

View file

@ -8474,8 +8474,8 @@ msgid "CANCELLED"
msgstr "已取消"
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java:41
msgid "STORED"
msgstr "STORED"
msgid "ARCHIVED"
msgstr ""
#: libreplan-business/src/main/java/org/libreplan/business/orders/entities/SchedulingState.java:366
msgid "Fully scheduled"

View file

@ -55,6 +55,8 @@
<!-- Pages -->
<intercept-url pattern="/templates/*"
access="ROLE_SUPERUSER,ROLE_TEMPLATES" />
<intercept-url pattern="/email/*"
access="ROLE_SUPERUSER"/>
<intercept-url pattern="/resources/worker/worker.zul"
access="ROLE_SUPERUSER,ROLE_WORKERS" />
<intercept-url pattern="/resources/machine/*"

View file

@ -97,39 +97,51 @@
<columns>
<column label="${i18n:_('Field')}" width="150px"/>
<column label="${i18n:_('Allowed values')}" />
<column label="${i18n:_('Allowed Special Characters')}" />
</columns>
<rows>
<row>
<label value="${i18n:_('Seconds')}"/>
<label value="0-59"/>
<label value=", - * /"/>
</row>
<row>
<label value="${i18n:_('Minutes')}"/>
<label value="0-59"/>
<label value=", - * /"/>
</row>
<row>
<label value="${i18n:_('Hours')}"/>
<label value="0-23"/>
<label value=", - * /"/>
</row>
<row>
<label value="${i18n:_('Day of month')}"/>
<label value="1-31"/>
<label value=", - * ? / L W"/>
</row>
<row>
<label value="${i18n:_('Month')}"/>
<span>1-12 (<label value="${i18n:_('or names')}"/> [JAN-DEC])</span>
<label value=", - *"/>
</row>
<row>
<label value="${i18n:_('Day of week')}"/>
<span>0-7 (<label value="${i18n:_('0 or 7 is Sunday, or use names')}"/> [SUN-SAT])</span>
<span>1-7 (<label value="${i18n:_('1 or 7 is Sunday, or use names')}"/> [SUN-SAT])</span>
<label value=", - * ? / L #"/>
</row>
<row>
<label value="${i18n:_('Year (optional)')}"/>
<label value="1970-2099"/>
<label value=", - *"/>
</row>
</rows>
</grid>
<div>
<div>
${i18n:_("The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify “no specific value”. ")}
</div>
${i18n:_("For more details on cron expression click")}
<a href="http://www.manpagez.com/man/5/crontab/">${i18n:_('here')}.</a>
</div>

View file

@ -999,7 +999,7 @@ span.z-dottree-line {
}
span.perspective, span.perspective-active {
margin: 0 2px;
margin: 4px 2px;
}
.perspectives-label {
@ -1060,11 +1060,23 @@ span.perspective, span.perspective-active {
.perspective-active.montecarlo-simulation .z-button-cm {
background-image: url(../img/ico_montecarlo-simulation.png);
}
.perspective.global-dashboard .z-button-cm,
.perspective-active.global-dashboard .z-button-cm {
background-image: url(../img/ico_global-dashboard.png);
}
.perspective.order-dashboard .z-button-cm,
.perspective-active.order-dashboard .z-button-cm {
.perspective-active.order-dashboard .z-button-cm{
background-image: url(../img/ico_order-dashboard.png);
}
.label-highlight:hover{
background-color: #aacbff;
}
.global-dashboard-grid{
margin-top: 5px;
}
.perspectives-column {
display:none;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,43 @@
<!--
This file is part of LibrePlan
Copyright (C) 2015 LibrePlan
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?taglib uri="/WEB-INF/tld/i18n.tld" prefix="i18n"?>
<?component name="pipeline" inline="true" macroURI="_pipeline.zul"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" root="./wnd" ?>
<zk>
<div height="100%" style="overflow:visible">
<div height="30px" sclass="toolbar-box" />
<window id="wnd" self="@{define(content)}" vflex="1">
<tabbox width="100%">
<tabs>
<tab label="${i18n:_('Pipeline')}"/>
</tabs>
<tabpanels>
<tabpanel>
<pipeline/>
</tabpanel>
</tabpanels>
</tabbox>
</window>
</div>
</zk>

View file

@ -0,0 +1,19 @@
<window apply="org.libreplan.web.dashboard.DashboardControllerGlobal" contentStyle="overflow:auto;">
<checkbox id="storedColumnVisible" label="${i18n:_('Show archived column data')}" checked="true" onCheck="dashboardControllerGlobal.showStoredColumn()"/>
<grid id="pipelineGrid" sclass="global-dashboard-grid">
<columns>
<column label="${i18n:_('PRE-SALES')}"/>
<column label="${i18n:_('OFFERED')}"/>
<column label="${i18n:_('OUTSOURCED')}"/>
<column label="${i18n:_('ACCEPTED')}"/>
<column label="${i18n:_('STARTED')}"/>
<column label="${i18n:_('ON HOLD')}"/>
<column label="${i18n:_('FINISHED')}"/>
<column label="${i18n:_('CANCELLED')}"/>
<column label="${i18n:_('ARCHIVED')}"/>
</columns>
</grid>
</window>

View file

@ -0,0 +1,135 @@
<!--
This file is part of LibrePlan
Copyright (C) 2015 LibrePlan
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<?page id="editEmailTemplate" title="${i18n:_('LibrePlan: Email Templates')}" ?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/common/layout/template.zul"?>
<?link rel="shortcut icon" href="/common/img/favicon.ico" type="image/x-icon"?>
<?link rel="stylesheet" type="text/css" href="/common/css/libreplan.css"?>
<?link rel="stylesheet" type="text/css" href="/common/css/libreplan_zk.css"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
<window self="@{define(content)}" apply="org.libreplan.web.email.EmailTemplateController"
title="${i18n:_('Edit E-mail template')}">
<vbox id="messagesContainer" />
<tabbox>
<tabs>
<tab label="${i18n:_('Template data')}"/>
</tabs>
<tabpanels>
<tabpanel>
<groupbox>
<caption label="General user data" />
<grid>
<columns>
<column width="220px"></column>
<column width="420px"></column>
</columns>
<rows>
<row>
<label value="Select template language"/>
<listbox mold="select"
id="templateLanguageListbox"
model="@{emailTemplateController.languages}"
itemRenderer="@{emailTemplateController.languagesRenderer}"
selectedItem="@{emailTemplateController.selectedLanguage}">
</listbox>
</row>
<row>
<label value="Select template type"/>
<listbox id="emailTemplateTypeListbox"
mold="select"
model="@{emailTemplateController.emailTemplateEnum}"
itemRenderer="@{emailTemplateController.emailTemplateEnumRenderer}"
selectedItem="@{emailTemplateController.selectedEmailTemplateEnum}"/>
</row>
<row>
<label value="${i18n:_('E-mail subject')}"/>
<textbox id="subjectTextbox"
width="400px;" />
</row>
<row>
<label value="${i18n:_('Template contents')}"/>
<textbox id="contentsTextbox"
rows="15" width="400px;"
tabindex="11"/>
<groupbox closable="false" width="270px">
<caption label="${i18n:_('Possible content keywords')}"/>
<grid width="250px">
<columns>
<column label="${i18n:_('Keyword')}"/>
<column label="${i18n:_('Description')}"/>
</columns>
<rows>
<row>
<label value="{username}"/>
<label value="${i18n:_('Username of user')}"/>
</row>
<row>
<label value="{firstname}"/>
<label value="${i18n:_('First name of user')}"/>
</row>
<row>
<label value="{lastname}"/>
<label value="${i18n:_('Last name of user')}"/>
</row>
<row>
<label value="{project}"/>
<label value="${i18n:_('Name of project')}"/>
</row>
<row>
<label value="{resource}"/>
<label value="${i18n:_('Name of resource')}"/>
</row>
<row>
<label value="{task}"/>
<label value="${i18n:_('Name of task')}"/>
</row>
<row>
<label value="{url}"/>
<label value="${i18n:_('Welcome page')}"/>
</row>
</rows>
</grid>
</groupbox>
</row>
</rows>
</grid>
</groupbox>
</tabpanel>
</tabpanels>
</tabbox>
<button onClick="emailTemplateController.save()" autodisable="self" label="${i18n:_('Save')}" sclass="save-button global-action"/>
<button onClick="emailTemplateController.cancel()" label="${i18n:_('Cancel')}" sclass="cancel-button global-action"/>
</window>
</zk>

View file

@ -34,7 +34,6 @@ import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.libreplan.importers.TimSoapClient;
import org.libreplan.importers.tim.DataDTO;
import org.libreplan.importers.tim.DepartmentDTO;
import org.libreplan.importers.tim.DurationDTO;
@ -95,7 +94,7 @@ public class TimSoapClientTest {
return timeRegistrationDTO;
}
private RosterRequestDTO createtRosterRequest() {
private RosterRequestDTO createRosterRequest() {
RosterDTO rosterDTO = new RosterDTO();
rosterDTO.setStartDate(new LocalDate());
rosterDTO.setEndDate(new LocalDate().plusDays(7));
@ -186,7 +185,7 @@ public class TimSoapClientTest {
.sendRequestReceiveResponse(properties.getProperty("url"),
properties.getProperty("username"),
properties.getProperty("password"),
createtRosterRequest(), RosterResponseDTO.class);
createRosterRequest(), RosterResponseDTO.class);
if (rosterResponseDTO == null) {
fail("Roster Response is null");
}

View file

@ -41,9 +41,6 @@
<value>
org/libreplan/business/orders/entities/Orders.hbm.xml
</value>
<value>
org/libreplan/business/templates/entities/Templates.hbm.xml
</value>
<value>
org/libreplan/business/planner/entities/Tasks.hbm.xml
</value>

11
pom.xml
View file

@ -37,6 +37,7 @@
<default.passwordsControl>true</default.passwordsControl>
<default.exampleUsersDisabled>true</default.exampleUsersDisabled>
<default.emailSendingEnabled>true</default.emailSendingEnabled>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -233,18 +234,18 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.4.Final</version>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.4.Final</version>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
<version>4.3.2.Final</version>
</dependency>
<dependency>
@ -328,7 +329,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- datasource for testing -->
@ -600,7 +601,7 @@
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>1.8.0</version>
<version>1.8.6</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>