diff --git a/HACKING.rst b/HACKING.rst index 8326ba0b9..082212cb7 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -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 ----- diff --git a/INSTALL.rst b/INSTALL.rst index 93be682a6..ab8a3d74b 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -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: + + + + + + +* 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 ---- diff --git a/doc/src/technical/howto-start-development-with-intellij-idea.rst b/doc/src/technical/howto-start-development-with-intellij-idea.rst index 00f341db4..d33d7c3a5 100644 --- a/doc/src/technical/howto-start-development-with-intellij-idea.rst +++ b/doc/src/technical/howto-start-development-with-intellij-idea.rst @@ -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/ \ No newline at end of file +====================================================== +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/ diff --git a/doc/src/user/en/18-connectors.rst b/doc/src/user/en/18-connectors.rst index 7206ec0fa..ca302cb57 100644 --- a/doc/src/user/en/18-connectors.rst +++ b/doc/src/user/en/18-connectors.rst @@ -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. \ No newline at end of file diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/Configuration.java b/libreplan-business/src/main/java/org/libreplan/business/common/Configuration.java index 80c084ffd..90709ff25 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/Configuration.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/Configuration.java @@ -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: * * * @author Susana Montes Pedreira * @author Manuel Rego Casasnovas + * @author Vova Perebykivskiy */ + 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; + } } diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/daos/IntegrationEntityDAO.java b/libreplan-business/src/main/java/org/libreplan/business/common/daos/IntegrationEntityDAO.java index 02dc456b8..3d5b913d0 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/daos/IntegrationEntityDAO.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/daos/IntegrationEntityDAO.java @@ -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; diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobClassNameEnum.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobClassNameEnum.java index 038d7c413..26f4f041e 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobClassNameEnum.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/JobClassNameEnum.java @@ -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; diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java index ef0b84200..9611c0384 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectorProperties.java @@ -27,6 +27,7 @@ import static org.libreplan.business.i18n.I18nHelper._; * * @author Miciele Ghiorghis * @author Manuel Rego Casasnovas + * @author Vova Perebykivskiy */ 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)"); + } diff --git a/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectors.java b/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectors.java index b51adc8a1..1d44db2ad 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectors.java +++ b/libreplan-business/src/main/java/org/libreplan/business/common/entities/PredefinedConnectors.java @@ -28,6 +28,7 @@ import java.util.List; * * @author Miciele Ghiorghis * @author Manuel Rego Casasnovas + * @author Vova Perebykivskiy */ 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 properties; diff --git a/libreplan-business/src/main/java/org/libreplan/business/email/daos/EmailNotificationDAO.java b/libreplan-business/src/main/java/org/libreplan/business/email/daos/EmailNotificationDAO.java new file mode 100644 index 000000000..e67a9047b --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/email/daos/EmailNotificationDAO.java @@ -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 . + */ + +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 + * on 19.10.15. + */ +@Repository +public class EmailNotificationDAO extends GenericDAOHibernate implements IEmailNotificationDAO { + + @Override + public List getAll() { + return list(EmailNotification.class); + } + + @Override + public boolean deleteAll() { + List notifications = list(EmailNotification.class); + for (Object item : notifications){ + getSession().delete(item); + } + + if ( list(EmailNotification.class).size() == 0 ) return true; + return false; + } + +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/email/daos/EmailTemplateDAO.java b/libreplan-business/src/main/java/org/libreplan/business/email/daos/EmailTemplateDAO.java new file mode 100644 index 000000000..df4751ff5 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/email/daos/EmailTemplateDAO.java @@ -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 . + */ + +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 + * on 24.09.15. + */ +@Repository +public class EmailTemplateDAO extends GenericDAOHibernate implements IEmailTemplateDAO{ + + @Override + public List getAll() { + return list(EmailTemplate.class); + } + + @Override + public String initializeContent() { + try{ + List 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 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 ""; + } + +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/email/daos/IEmailNotificationDAO.java b/libreplan-business/src/main/java/org/libreplan/business/email/daos/IEmailNotificationDAO.java new file mode 100644 index 000000000..5b4a545a1 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/email/daos/IEmailNotificationDAO.java @@ -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 . + */ + +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 + * on 19.10.15. + */ +public interface IEmailNotificationDAO extends IGenericDAO { + List getAll(); + boolean deleteAll(); +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/email/daos/IEmailTemplateDAO.java b/libreplan-business/src/main/java/org/libreplan/business/email/daos/IEmailTemplateDAO.java new file mode 100644 index 000000000..57acd30a9 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/email/daos/IEmailTemplateDAO.java @@ -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 . + */ + +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 EmailTemplate entity. + * Contract for {@link EmailTemplateDAO} + * + * Created by + * @author Vova Perebykivskiy + * on 29.09.15. + */ +public interface IEmailTemplateDAO extends IGenericDAO{ + + List getAll(); + + String initializeContent(); + String initializeSubject(); + + String getContentBySelectedLanguage(int languageOrdinal, int emailTemplateTypeOrdinal); + String getContentBySelectedTemplate(int emailTemplateTypeOrdinal, int languageOrdinal); +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailNotification.java b/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailNotification.java new file mode 100644 index 000000000..817fb4dc2 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailNotification.java @@ -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 . + */ + +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 + * 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; + } +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailTemplate.java b/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailTemplate.java new file mode 100644 index 000000000..a4f6d2c10 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailTemplate.java @@ -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 . + */ + +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 + * 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; + } +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailTemplateEnum.java b/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailTemplateEnum.java new file mode 100644 index 000000000..1402115fa --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/email/entities/EmailTemplateEnum.java @@ -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 . + */ + +package org.libreplan.business.email.entities; + +import static org.libreplan.business.i18n.I18nHelper._; + +/** + * Available E-mail templates. + * + * Created by + * @author Vova Perebykivskiy + * 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; + } +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java index 9f9386ef1..70084e8f7 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java +++ b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderStatusEnum.java @@ -40,7 +40,7 @@ public enum OrderStatusEnum { ON_HOLD(_("ON HOLD")), FINISHED(_("FINISHED")), CANCELLED(_("CANCELLED")), - STORED(_("STORED")); + STORED(_("ARCHIVED")); private String description; diff --git a/libreplan-business/src/main/java/org/libreplan/business/users/bootstrap/PredefinedProfiles.java b/libreplan-business/src/main/java/org/libreplan/business/users/bootstrap/PredefinedProfiles.java index b7c0f7fee..fbeb451a4 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/users/bootstrap/PredefinedProfiles.java +++ b/libreplan-business/src/main/java/org/libreplan/business/users/bootstrap/PredefinedProfiles.java @@ -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 + * @author Vova Perebykivskiy */ 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, diff --git a/libreplan-business/src/main/java/org/libreplan/business/users/entities/UserRole.java b/libreplan-business/src/main/java/org/libreplan/business/users/entities/UserRole.java index 9010c7b8f..dc7994017 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/users/entities/UserRole.java +++ b/libreplan-business/src/main/java/org/libreplan/business/users/entities/UserRole.java @@ -28,21 +28,26 @@ import static org.libreplan.business.i18n.I18nHelper._; * * @author Fernando Bellas Permuy * @author Manuel Rego Casasnovas + * @author Vova Perebykivskiy */ 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; diff --git a/libreplan-business/src/main/resources/libreplan-business-spring-config.xml b/libreplan-business/src/main/resources/libreplan-business-spring-config.xml index 8e739f774..c7e391a87 100644 --- a/libreplan-business/src/main/resources/libreplan-business-spring-config.xml +++ b/libreplan-business/src/main/resources/libreplan-business-spring-config.xml @@ -94,6 +94,9 @@ org/libreplan/business/common/entities/JobSchedulerConfiguration.hbm.xml + + org/libreplan/business/email/entities/Email.hbm.xml + @@ -143,6 +146,9 @@ ${default.exampleUsersDisabled} + + ${default.emailSendingEnabled} + + + + + + + + + 100 + + + + + + org.libreplan.business.email.entities.EmailTemplateEnum + + + + + + org.libreplan.business.settings.entities.Language + + + + + + + + + + + + + 100 + + + + + + org.libreplan.business.email.entities.EmailTemplateEnum + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libreplan-business/src/main/resources/org/libreplan/business/resources/entities/Resources.hbm.xml b/libreplan-business/src/main/resources/org/libreplan/business/resources/entities/Resources.hbm.xml index 85eb2b513..833b6495e 100644 --- a/libreplan-business/src/main/resources/org/libreplan/business/resources/entities/Resources.hbm.xml +++ b/libreplan-business/src/main/resources/org/libreplan/business/resources/entities/Resources.hbm.xml @@ -59,7 +59,7 @@ - diff --git a/libreplan-business/src/main/resources/org/libreplan/business/templates/entities/Templates.hbm.xml b/libreplan-business/src/main/resources/org/libreplan/business/templates/entities/Templates.hbm.xml index 16025d827..1d5b2dbbf 100644 --- a/libreplan-business/src/main/resources/org/libreplan/business/templates/entities/Templates.hbm.xml +++ b/libreplan-business/src/main/resources/org/libreplan/business/templates/entities/Templates.hbm.xml @@ -90,5 +90,4 @@ - diff --git a/libreplan-business/src/test/resources/libreplan-business-spring-config-test.xml b/libreplan-business/src/test/resources/libreplan-business-spring-config-test.xml index fa7a5ee8b..32ad8eb9c 100644 --- a/libreplan-business/src/test/resources/libreplan-business-spring-config-test.xml +++ b/libreplan-business/src/test/resources/libreplan-business-spring-config-test.xml @@ -40,9 +40,6 @@ org/libreplan/business/orders/entities/Orders.hbm.xml - - org/libreplan/business/templates/entities/Templates.hbm.xml - org/libreplan/business/planner/entities/Tasks.hbm.xml diff --git a/libreplan-webapp/pom.xml b/libreplan-webapp/pom.xml index 078cb252d..f80cf8816 100644 --- a/libreplan-webapp/pom.xml +++ b/libreplan-webapp/pom.xml @@ -11,6 +11,7 @@ LibrePlan Web Client Module + reports @@ -71,6 +72,7 @@ + userguide @@ -195,6 +197,7 @@ + i18n @@ -430,6 +433,14 @@ javax.servlet servlet-api + + + + javax.mail + mail + 1.5.0-b01 + + javax.ws.rs diff --git a/libreplan-webapp/src/main/java/org/libreplan/importers/ISendEmail.java b/libreplan-webapp/src/main/java/org/libreplan/importers/ISendEmail.java new file mode 100644 index 000000000..7fe5cbba0 --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/importers/ISendEmail.java @@ -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 . + */ + +package org.libreplan.importers; + + +/** + * Sends E-mail to users with data that storing in notification_queue table + * + * Created by + * @author Vova Perebykivskiy + * on 13.10.15. + */ + +public interface ISendEmail { + void sendEmail(); +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/importers/SendEmail.java b/libreplan-webapp/src/main/java/org/libreplan/importers/SendEmail.java new file mode 100644 index 000000000..d9ee56d32 --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/importers/SendEmail.java @@ -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 . + */ + +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 + * 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 notifications; + private List 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 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 getEmailConnectorProperties() { + + Connector connector = connectorDAO.findUniqueByName("E-mail"); + + List 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 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 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; + } +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/importers/SendEmailJob.java b/libreplan-webapp/src/main/java/org/libreplan/importers/SendEmailJob.java new file mode 100644 index 000000000..fa7dab5b8 --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/importers/SendEmailJob.java @@ -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 . + */ + +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 + * 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(); + } + +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/calendars/BaseCalendarEditionController.java b/libreplan-webapp/src/main/java/org/libreplan/web/calendars/BaseCalendarEditionController.java index ff8060ac1..11c623946 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/calendars/BaseCalendarEditionController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/calendars/BaseCalendarEditionController.java @@ -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() { @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(); diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/common/BaseCRUDController.java b/libreplan-webapp/src/main/java/org/libreplan/web/common/BaseCRUDController.java index 4589ee6fb..d9203150f 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/common/BaseCRUDController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/common/BaseCRUDController.java @@ -227,9 +227,8 @@ public abstract class BaseCRUDController extends */ private void saveCommonActions() throws ValidationException { beforeSaving(); - + messagesForUser.clearMessages(); save(); - messagesForUser.showMessage( Level.INFO, _("{0} \"{1}\" saved", getEntityType(), getEntityBeingEdited() diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/common/ConfigurationController.java b/libreplan-webapp/src/main/java/org/libreplan/web/common/ConfigurationController.java index a1ef7b11d..d2187e6cc 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/common/ConfigurationController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/common/ConfigurationController.java @@ -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 * @author Cristina Alavarino Perez * @author Ignacio Diaz Teijido + * @author Vova Perebykivskiy */ 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) 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 protocols = new ArrayList(); + 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() { + @Override + public Comboitem get() { + return combobox.getSelectedItem(); + } + }, new Util.Setter(){ + + @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; + } + } diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/common/CustomMenuController.java b/libreplan-webapp/src/main/java/org/libreplan/web/common/CustomMenuController.java index c680966fb..c62280ee5 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/common/CustomMenuController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/common/CustomMenuController.java @@ -59,6 +59,7 @@ import org.zkoss.zul.Vbox; * Controller for customMenu
* @author Lorenzo Tilve Álvaro * @author Fernando Bellas Permuy + * @author Vova Perebykivskiy */ 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", "", diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerModel.java index 5601cd3cb..0cea1d00a 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/common/JobSchedulerModel.java @@ -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 synchronizationInfos; + @Autowired + private ISendEmail email; + @Override @Transactional(readOnly = true) public List getJobSchedulerConfigurations() { @@ -105,6 +112,13 @@ public class JobSchedulerModel implements IJobSchedulerModel { .syncOrderElementsWithJiraIssues(); return; } + if ( name.equals(JobClassNameEnum.SEND_EMAIL_JOB.getName()) ) { + synchronizationInfos = new ArrayList(); + synchronizationInfos.add(new SynchronizationInfo(_("Send E-mail"))); + email.sendEmail(); + return; + } + throw new RuntimeException("Unknown action"); } diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardControllerGlobal.java b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardControllerGlobal.java new file mode 100644 index 000000000..71d9c793b --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardControllerGlobal.java @@ -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 + * 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 preSalesOrders = new ArrayList(); + private List offeredOrders = new ArrayList(); + private List outsourcedOrders = new ArrayList(); + private List acceptedOrders = new ArrayList(); + private List startedOrders = new ArrayList(); + private List onHoldOrders = new ArrayList(); + private List finishedOrders = new ArrayList(); + private List cancelledOrders = new ArrayList(); + private List storedOrders = new ArrayList(); + + @Override + public void doAfterCompose(Component component) throws Exception { + super.doAfterCompose(component); + component.setVariable("dashboardControllerGlobal", this, true); + fillOrderLists(); + setupPipelineGrid(); + showStoredColumn(); + } + + public List 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; + } +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailNotificationModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailNotificationModel.java new file mode 100644 index 000000000..d40b15a92 --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailNotificationModel.java @@ -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 . + */ + +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 + * 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 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); + } + +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailTemplateController.java b/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailTemplateController.java new file mode 100644 index 000000000..69e4b82aa --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailTemplateController.java @@ -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 . + */ + +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 + * 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 getLanguages() { + List languages = new LinkedList(Arrays.asList(Language.values())); + Collections.sort(languages, new Comparator() { + @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 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() ) ); + } +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailTemplateModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailTemplateModel.java new file mode 100644 index 000000000..c54985bf2 --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/web/email/EmailTemplateModel.java @@ -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 . + */ + +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 + * 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 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 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); + } +} + + diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/email/IEmailNotificationModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/email/IEmailNotificationModel.java new file mode 100644 index 000000000..f4ed94648 --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/web/email/IEmailNotificationModel.java @@ -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 . + */ + +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 + * on 21.10.15. + */ +public interface IEmailNotificationModel { + + void confirmSave() throws ValidationException; + + List getAll(); + + boolean deleteAll(); + + void setType(EmailTemplateEnum type); + void setUpdated(Date date); + void setResource(Resource resource); + void setTask(TaskElement task); + void setProject(TaskElement project); + +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/email/IEmailTemplateModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/email/IEmailTemplateModel.java new file mode 100644 index 000000000..09f9f0491 --- /dev/null +++ b/libreplan-webapp/src/main/java/org/libreplan/web/email/IEmailTemplateModel.java @@ -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 . + */ + +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 + * on 28.09.15. + */ +public interface IEmailTemplateModel { + + void confirmSave() throws ValidationException, InstanceNotFoundException; + + List 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); +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/allocation/FormBinder.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/allocation/FormBinder.java index 177db8c36..a11c78919 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/allocation/FormBinder.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/allocation/FormBinder.java @@ -523,6 +523,8 @@ public class FormBinder { } }); allocationProduced(allocationResult); + + TaskPropertiesController.allocationResult = allocationResult; } /** diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/DashboardTabCreator.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/DashboardTabCreator.java index 25084ad33..21ecc1c92 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/DashboardTabCreator.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/DashboardTabCreator.java @@ -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 arguments = new HashMap(); + 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 getCriticalPath(final Order order, final Desktop desktop) { CriticalPathBuilder builder = CriticalPathBuilder.create( diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/MultipleTabsPlannerController.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/MultipleTabsPlannerController.java index de74b9be5..7b5db901a 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/MultipleTabsPlannerController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/tabs/MultipleTabsPlannerController.java @@ -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 diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/taskedition/TaskPropertiesController.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/taskedition/TaskPropertiesController.java index ea07b713e..4934390af 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/taskedition/TaskPropertiesController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/taskedition/TaskPropertiesController.java @@ -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 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 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(); + } + } + } + } + } + } diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/users/settings/SettingsController.java b/libreplan-webapp/src/main/java/org/libreplan/web/users/settings/SettingsController.java index abf2f1625..6cfa2cf61 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/users/settings/SettingsController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/users/settings/SettingsController.java @@ -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; diff --git a/libreplan-webapp/src/main/resources/i18n/ca.po b/libreplan-webapp/src/main/resources/i18n/ca.po index 19e33dfc6..b55907eb0 100644 --- a/libreplan-webapp/src/main/resources/i18n/ca.po +++ b/libreplan-webapp/src/main/resources/i18n/ca.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/cs.po b/libreplan-webapp/src/main/resources/i18n/cs.po index 673917ffd..0d33c9645 100644 --- a/libreplan-webapp/src/main/resources/i18n/cs.po +++ b/libreplan-webapp/src/main/resources/i18n/cs.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/de.po b/libreplan-webapp/src/main/resources/i18n/de.po index 3bfe4ed56..55c76e3a3 100644 --- a/libreplan-webapp/src/main/resources/i18n/de.po +++ b/libreplan-webapp/src/main/resources/i18n/de.po @@ -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 diff --git a/libreplan-webapp/src/main/resources/i18n/es.po b/libreplan-webapp/src/main/resources/i18n/es.po index 7aff1ea06..46f9d3706 100644 --- a/libreplan-webapp/src/main/resources/i18n/es.po +++ b/libreplan-webapp/src/main/resources/i18n/es.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/fr.po b/libreplan-webapp/src/main/resources/i18n/fr.po index 7df3a8513..555eb2c9a 100644 --- a/libreplan-webapp/src/main/resources/i18n/fr.po +++ b/libreplan-webapp/src/main/resources/i18n/fr.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/gl.po b/libreplan-webapp/src/main/resources/i18n/gl.po index d64a556c7..46178db1e 100644 --- a/libreplan-webapp/src/main/resources/i18n/gl.po +++ b/libreplan-webapp/src/main/resources/i18n/gl.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/it.po b/libreplan-webapp/src/main/resources/i18n/it.po index 059fe0574..8c2b38a34 100644 --- a/libreplan-webapp/src/main/resources/i18n/it.po +++ b/libreplan-webapp/src/main/resources/i18n/it.po @@ -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 diff --git a/libreplan-webapp/src/main/resources/i18n/keys.pot b/libreplan-webapp/src/main/resources/i18n/keys.pot index 5f9ef0927..abbce181b 100644 --- a/libreplan-webapp/src/main/resources/i18n/keys.pot +++ b/libreplan-webapp/src/main/resources/i18n/keys.pot @@ -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 "" diff --git a/libreplan-webapp/src/main/resources/i18n/nb.po b/libreplan-webapp/src/main/resources/i18n/nb.po index 6bf45d399..2e5407cf7 100644 --- a/libreplan-webapp/src/main/resources/i18n/nb.po +++ b/libreplan-webapp/src/main/resources/i18n/nb.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/nl.po b/libreplan-webapp/src/main/resources/i18n/nl.po index 80c57ee0a..e2c0da5b5 100644 --- a/libreplan-webapp/src/main/resources/i18n/nl.po +++ b/libreplan-webapp/src/main/resources/i18n/nl.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/pl.po b/libreplan-webapp/src/main/resources/i18n/pl.po index f6dc79f3f..4a5033559 100644 --- a/libreplan-webapp/src/main/resources/i18n/pl.po +++ b/libreplan-webapp/src/main/resources/i18n/pl.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/pt.po b/libreplan-webapp/src/main/resources/i18n/pt.po index bab7846da..4686264bf 100644 --- a/libreplan-webapp/src/main/resources/i18n/pt.po +++ b/libreplan-webapp/src/main/resources/i18n/pt.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/i18n/ru.po b/libreplan-webapp/src/main/resources/i18n/ru.po index 55c22ce77..948e3dbac 100644 --- a/libreplan-webapp/src/main/resources/i18n/ru.po +++ b/libreplan-webapp/src/main/resources/i18n/ru.po @@ -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 "Заархивированный" diff --git a/libreplan-webapp/src/main/resources/i18n/zh.po b/libreplan-webapp/src/main/resources/i18n/zh.po index 05c8efeab..091933f81 100644 --- a/libreplan-webapp/src/main/resources/i18n/zh.po +++ b/libreplan-webapp/src/main/resources/i18n/zh.po @@ -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" diff --git a/libreplan-webapp/src/main/resources/libreplan-webapp-spring-security-config.xml b/libreplan-webapp/src/main/resources/libreplan-webapp-spring-security-config.xml index 76c1333e1..8cea71490 100644 --- a/libreplan-webapp/src/main/resources/libreplan-webapp-spring-security-config.xml +++ b/libreplan-webapp/src/main/resources/libreplan-webapp-spring-security-config.xml @@ -55,6 +55,8 @@ + +
+
+ ${i18n:_("The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify “no specific value”. ")} +
+ ${i18n:_("For more details on cron expression click")} ${i18n:_('here')}.
diff --git a/libreplan-webapp/src/main/webapp/common/css/libreplan_zk.css b/libreplan-webapp/src/main/webapp/common/css/libreplan_zk.css index 8b2ac1658..838b699f6 100644 --- a/libreplan-webapp/src/main/webapp/common/css/libreplan_zk.css +++ b/libreplan-webapp/src/main/webapp/common/css/libreplan_zk.css @@ -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; diff --git a/libreplan-webapp/src/main/webapp/common/img/ico_global-dashboard.png b/libreplan-webapp/src/main/webapp/common/img/ico_global-dashboard.png new file mode 100644 index 000000000..da155dc06 Binary files /dev/null and b/libreplan-webapp/src/main/webapp/common/img/ico_global-dashboard.png differ diff --git a/libreplan-webapp/src/main/webapp/dashboard/_dashboardforglobal.zul b/libreplan-webapp/src/main/webapp/dashboard/_dashboardforglobal.zul new file mode 100644 index 000000000..2a6e55be5 --- /dev/null +++ b/libreplan-webapp/src/main/webapp/dashboard/_dashboardforglobal.zul @@ -0,0 +1,43 @@ + + + + + + + + +
+
+ + + + + + + + + + + + + + +
+ diff --git a/libreplan-webapp/src/main/webapp/dashboard/_pipeline.zul b/libreplan-webapp/src/main/webapp/dashboard/_pipeline.zul new file mode 100644 index 000000000..7b2e5a08a --- /dev/null +++ b/libreplan-webapp/src/main/webapp/dashboard/_pipeline.zul @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/libreplan-webapp/src/main/webapp/email/email_templates.zul b/libreplan-webapp/src/main/webapp/email/email_templates.zul new file mode 100644 index 000000000..6b754eb50 --- /dev/null +++ b/libreplan-webapp/src/main/webapp/email/email_templates.zul @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +