Jira-connector: JIRA moved to connectors

- JIRA is moved to connectors and all files modified that has to do with this change.
- JiraConfiguration file is removed
- ImportedLabel attribute is deleted from Order and order.hbm.xml
- Imstead of importedLabel is now used the key from OrderSyncInfo
- and some more changes where applicable
This commit is contained in:
miciele Ghiorghis 2013-03-13 17:18:13 +01:00 committed by Manuel Rego Casasnovas
parent 3891048f00
commit d764e0a3f8
27 changed files with 295 additions and 468 deletions

View file

@ -104,8 +104,6 @@ public class Configuration extends BaseEntity {
private Boolean generateCodeForExpenseSheets = true;
private JiraConfiguration jiraConfiguration;
/**
* Currency code according to ISO-4217 (3 letters)
*/
@ -505,12 +503,4 @@ public class Configuration extends BaseEntity {
this.secondsPlanningWarning = secondsPlanningWarning;
}
public JiraConfiguration getJiraConfiguration() {
return jiraConfiguration;
}
public void setJiraConfiguration(JiraConfiguration jiraConfiguration) {
this.jiraConfiguration = jiraConfiguration;
}
}

View file

@ -81,13 +81,6 @@ public class ConfigurationBootstrap implements IConfigurationBootstrap {
}
configuration.setLdapConfiguration(ldapConfiguration);
JiraConfiguration jiraConfiguration = configuration
.getJiraConfiguration();
if (jiraConfiguration == null) {
jiraConfiguration = JiraConfiguration.create();
}
configuration.setJiraConfiguration(jiraConfiguration);
configurationDAO.save(configuration);
}

View file

@ -75,8 +75,6 @@ public class ConfigurationTypeOfWorkHoursBootstrap implements
}
configuration.setPersonalTimesheetsTypeOfWorkHours(typeOfWorkHours);
configuration.getJiraConfiguration().setJiraConnectorTypeOfWorkHours(
typeOfWorkHours);
configurationDAO.save(configuration);
}

View file

@ -1,114 +0,0 @@
/*
* This file is part of LibrePlan
*
* Copyright (C) 2013 St. Antoniusziekenhuis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.business.common.entities;
import org.libreplan.business.common.BaseEntity;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
/**
* JiraConfiguration entity
*
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
*/
public class JiraConfiguration extends BaseEntity {
/**
* Code prefix for different entities integrated with JIRA.
*/
public static final String CODE_PREFIX = "JIRA-";
public static JiraConfiguration create() {
return create(new JiraConfiguration());
}
private boolean jiraActivated;
private String jiraUrl;
/**
* Stores one of the next 2 options:
* <ul>
* <li>A comma-separated list of labels</li>
* <li>A URL that will return a comma-separated list of labels</li>
* </ul>
*/
private String jiraLabels;
private String jiraUserId;
private String jiraPassword;
private TypeOfWorkHours jiraConnectorTypeOfWorkHours;
/**
* Constructor for Hibernate. Do not use!
*/
protected JiraConfiguration() {
}
public boolean isJiraActivated() {
return jiraActivated;
}
public void setJiraActivated(boolean jiraActivated) {
this.jiraActivated = jiraActivated;
}
public String getJiraUrl() {
return jiraUrl;
}
public void setJiraUrl(String jiraUrl) {
this.jiraUrl = jiraUrl;
}
public String getJiraLabels() {
return jiraLabels;
}
public void setJiraLabels(String jiraLabels) {
this.jiraLabels = jiraLabels;
}
public String getJiraUserId() {
return jiraUserId;
}
public void setJiraUserId(String jiraUserId) {
this.jiraUserId = jiraUserId;
}
public String getJiraPassword() {
return jiraPassword;
}
public void setJiraPassword(String jiraPassword) {
this.jiraPassword = jiraPassword;
}
public TypeOfWorkHours getJiraConnectorTypeOfWorkHours() {
return jiraConnectorTypeOfWorkHours;
}
public void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
jiraConnectorTypeOfWorkHours = typeOfWorkHours;
}
}

View file

@ -42,4 +42,13 @@ public class PredefinedConnectorProperties {
public static String TIM_PRODUCTIVITY_FACTOR = _("Productivity factor");
public static String TIM_DEPARTAMENTS_IMPORT_ROSTER = _("Department IDs to import toster");
// Specific for JIRA
public static String JIRA_LABELS = _("JIRA labels: comma-separated list of labels or URL");
public static String JIRA_HOURS_TYPE = _("Hours type");
/**
* Code prefix for different entities integrated with JIRA.
*/
public static final String JIRA_CODE_PREFIX = "JIRA-";
}

View file

@ -39,8 +39,18 @@ public enum PredefinedConnectors {
ConnectorProperty.create(PredefinedConnectorProperties.TIM_NR_DAYS_TIMESHEET, "7"),
ConnectorProperty.create(PredefinedConnectorProperties.TIM_NR_DAYS_ROSTER, "90"),
ConnectorProperty.create(PredefinedConnectorProperties.TIM_PRODUCTIVITY_FACTOR, "100"),
ConnectorProperty.create(PredefinedConnectorProperties.TIM_DEPARTAMENTS_IMPORT_ROSTER, "0")
);
ConnectorProperty.create(
PredefinedConnectorProperties.TIM_DEPARTAMENTS_IMPORT_ROSTER,
"0")),
JIRA("Jira",
ConnectorProperty.create(PredefinedConnectorProperties.ACTIVATED, "N"),
ConnectorProperty.create(PredefinedConnectorProperties.SERVER_URL, ""),
ConnectorProperty.create(PredefinedConnectorProperties.USERNAME, ""),
ConnectorProperty.create(PredefinedConnectorProperties.PASSWORD, ""),
ConnectorProperty
.create(PredefinedConnectorProperties.JIRA_LABELS, ""),
ConnectorProperty.create(
PredefinedConnectorProperties.JIRA_HOURS_TYPE, "Default"));
private String name;
private List<ConnectorProperty> properties;

View file

@ -29,8 +29,12 @@ import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.daos.IntegrationEntityDAO;
import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.costcategories.entities.HourCost;
@ -56,6 +60,9 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO<TypeOfWorkHours>
@Autowired
private IConfigurationDAO configurationDAO;
@Autowired
private IConnectorDAO connectorDAO;
@Override
public TypeOfWorkHours findUniqueByCode(TypeOfWorkHours typeOfWorkHours)
throws InstanceNotFoundException {
@ -194,13 +201,17 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO<TypeOfWorkHours>
}
private void checkIsJiraConnectorTypeOfWorkHours(TypeOfWorkHours type) {
Configuration configuration = configurationDAO.getConfiguration();
if (configuration.getJiraConfiguration()
.getJiraConnectorTypeOfWorkHours().getId().equals(type.getId())) {
throw ValidationException
.invalidValue(
"Cannot delete the type of work hours. It is configured as type of work hours for JIRA connector.",
type);
Connector connector = connectorDAO
.findUniqueByName(PredefinedConnectors.JIRA.getName());
if (connector != null) {
String name = connector.getPropertiesAsMap().get(
PredefinedConnectorProperties.JIRA_HOURS_TYPE);
if (name.equals(type.getName())) {
throw ValidationException
.invalidValue(
"Cannot delete the type of work hours. It is configured as type of work hours for JIRA connector.",
type);
}
}
}

View file

@ -30,6 +30,9 @@ import org.hibernate.validator.NotNull;
import org.libreplan.business.common.IHumanIdentifiable;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO;
@ -168,11 +171,13 @@ public class TypeOfWorkHours extends IntegrationEntity implements IHumanIdentifi
@AssertTrue(message = "type of work hours for JIRA connector cannot be disabled")
public boolean checkJiraConnectorTypeOfWorkHoursNotDisabled() {
if (!isNewObject() && !getEnabled()) {
TypeOfWorkHours typeOfWorkHours = Registry.getConfigurationDAO()
.getConfiguration().getJiraConfiguration()
.getJiraConnectorTypeOfWorkHours();
if (typeOfWorkHours.getId().equals(getId())) {
return false;
Connector connector = Registry.getConnectorDAO().findUniqueByName(
PredefinedConnectors.JIRA.getName());
if (connector != null) {
if (this.name.equals(connector.getPropertiesAsMap().get(
PredefinedConnectorProperties.JIRA_HOURS_TYPE))) {
return false;
}
}
}

View file

@ -120,8 +120,6 @@ public class Order extends OrderLineGroup implements Comparable {
private Set<CustomerCommunication> customerCommunications = new HashSet<CustomerCommunication>();
private String importedLabel;
@Valid
private SortedSet<DeadlineCommunication> deliveringDates = new TreeSet<DeadlineCommunication>(
new DeliverDateComparator());
@ -692,13 +690,4 @@ public class Order extends OrderLineGroup implements Comparable {
return true;
}
public String getImportedLabel() {
return importedLabel;
}
public void setImportedLabel(String importedLabel) {
this.importedLabel = importedLabel;
}
}

View file

@ -52,7 +52,7 @@ import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalA
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
import org.libreplan.business.common.entities.JiraConfiguration;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.labels.entities.Label;
import org.libreplan.business.materials.entities.MaterialAssignment;
@ -1686,7 +1686,7 @@ public abstract class OrderElement extends IntegrationEntity implements
if (code == null) {
return false;
}
return code.startsWith(JiraConfiguration.CODE_PREFIX);
return code.startsWith(PredefinedConnectorProperties.JIRA_CODE_PREFIX);
}
}

View file

@ -208,107 +208,6 @@
columnDataType="INTEGER" />
</changeSet>
<!-- Jira configuration-->
<changeSet id="add-new-column-jira_activated" author="miciele">
<comment>
Add new column jira_activated with default value FALSE to configuration table
</comment>
<addColumn tableName="configuration">
<column name="jira_activated" type="BOOLEAN" />
</addColumn>
<addDefaultValue tableName="configuration" columnName="jira_activated"
defaultValueBoolean="FALSE" />
<addNotNullConstraint tableName="configuration"
columnName="jira_activated"
defaultNullValue="FALSE"
columnDataType="BOOLEAN" />
</changeSet>
<changeSet id="add-new-column-jira_url" author="miciele">
<comment>
Add new column jira_url in table configuration
</comment>
<addColumn tableName="configuration">
<column name="jira_url" type="VARCHAR(255)" />
</addColumn>
</changeSet>
<changeSet id="add-new-column-jira_label_url" author="miciele">
<comment>
Add new column jira_label_url in table configuration
</comment>
<addColumn tableName="configuration">
<column name="jira_label_url" type="VARCHAR(255)" />
</addColumn>
</changeSet>
<changeSet id="add-new-column-jira_user_id" author="miciele">
<comment>
Add new column jira_user_id in table configuration
</comment>
<addColumn tableName="configuration">
<column name="jira_user_id" type="VARCHAR(255)" />
</addColumn>
</changeSet>
<changeSet id="add-new-column-jira_password" author="miciele">
<comment>
Add new column jira_user_id in table configuration
</comment>
<addColumn tableName="configuration">
<column name="jira_password" type="VARCHAR(255)" />
</addColumn>
</changeSet>
<changeSet id="add-new-column-imported-label" author="miciele">
<comment>
Add new column imported_label in table order_table
</comment>
<addColumn tableName="order_table">
<column name="imported_label" type="VARCHAR(255)" />
</addColumn>
</changeSet>
<changeSet id="add-jira_connector_type_of_work_hours-to-configuration"
author="mrego">
<comment>
Add new column jira_connector_type_of_work_hours to configuration
table.
</comment>
<addColumn tableName="configuration">
<column name="jira_connector_type_of_work_hours" type="BIGINT" />
</addColumn>
<addForeignKeyConstraint
constraintName="configuration_jira_connector_type_of_work_hours_fkey"
baseTableName="configuration"
baseColumnNames="jira_connector_type_of_work_hours"
referencedTableName="type_of_work_hours"
referencedColumnNames="id" />
</changeSet>
<changeSet id="rename-column-jira_label_url-in-configuration"
author="mrego">
<comment>
Rename column jira_label_url to jira_labels in configuration table
</comment>
<renameColumn tableName="configuration"
oldColumnName="jira_label_url"
newColumnName="jira_labels"
columnDataType="VARCHAR(255)" />
</changeSet>
<changeSet id="change-column-jira_labels-in-configuration-to-text"
author="mrego" dbms="postgresql">
<comment>Change column jira_labels in configuration to TEXT</comment>
<modifyDataType tableName="configuration" columnName="jira_labels"
newDataType="TEXT" />
</changeSet>
<changeSet id="change-column-jira_labels-in-configuration-to-text-in-mysql"
author="mrego" dbms="mysql">
<comment>Change column jira_labels in configuration to TEXT in MySQL</comment>
<sql>ALTER TABLE configuration MODIFY jira_labels TEXT</sql>
</changeSet>
<!-- order sync info -->
<changeSet author="miciele" id="create-table-order-sync-info">
<comment>Create new table order_sync_info</comment>

View file

@ -120,18 +120,6 @@
</set>
</component>
<!-- Jira configuration-->
<component name="jiraConfiguration" class="org.libreplan.business.common.entities.JiraConfiguration">
<property name="jiraActivated" column="jira_activated" not-null="true"/>
<property name="jiraUrl" column="jira_url"/>
<property name="jiraLabels" column="jira_labels" type="text"/>
<property name="jiraUserId" column="jira_user_id"/>
<property name="jiraPassword" column="jira_password"/>
<many-to-one name="jiraConnectorTypeOfWorkHours" cascade="none"
column="jira_connector_type_of_work_hours" />
</component>
</class>
</hibernate-mapping>

View file

@ -126,9 +126,6 @@
</type>
</property>
<!-- extra column to hold imported label -->
<property name="importedLabel" column="imported_label"/>
<!-- Not indexed -->
<many-to-one name="customer" access="field" class="org.libreplan.business.externalcompanies.entities.ExternalCompany"/>

View file

@ -23,8 +23,10 @@ import java.util.List;
import org.libreplan.business.advance.entities.AdvanceMeasurement;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderSyncInfo;
import org.libreplan.importers.jira.IssueDTO;
/**
@ -59,8 +61,10 @@ public interface IJiraOrderElementSynchronizer {
* search criteria for jira issues
*
* @return list of jira issues
* @throws ConnectorException
* if connector not found or contains invalid connection values
*/
List<IssueDTO> getJiraIssues(String label);
List<IssueDTO> getJiraIssues(String label) throws ConnectorException;
/**
* Synchronizes the list of {@link OrderElement}s,
@ -82,6 +86,25 @@ public interface IJiraOrderElementSynchronizer {
*/
void syncOrderElementsWithJiraIssues(List<IssueDTO> issues, Order order);
/**
* Saves synchronization info
*
* @param key
* the key(label)
* @param order
* an order which already synchronized
*/
void saveSyncInfo(String key, Order order);
/**
* Gets the most recent synchronized info
*
* @param order
* the order
* @return recent synchronized time sheet info
*/
OrderSyncInfo getOrderLastSyncInfo(Order order);
/**
* returns synchronization info, success or fail info
*/

View file

@ -21,6 +21,7 @@ package org.libreplan.importers;
import java.util.List;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.workreports.entities.WorkReportType;
import org.libreplan.importers.jira.IssueDTO;
@ -42,7 +43,6 @@ public interface IJiraTimesheetSynchronizer {
/**
* Synchronize jira timesheet with the specified jira <code>issues</code> .
*
*
* Loop through all jira <code>issues</code> and check if timesheet is
* already exist for the specified issue item. If it is, update the
* timesheet with that issue item. If not create new one
@ -51,8 +51,10 @@ public interface IJiraTimesheetSynchronizer {
* the jira issues
* @param order
* an existing order
* @throws ConnectorException
* if not valid connector or connector contains invalid values
*/
void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order);
void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order) throws ConnectorException;
/**
* returns synchronization info, success or fail info

View file

@ -28,6 +28,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
@ -37,12 +38,17 @@ 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.advance.exceptions.DuplicateValueTrueReportGlobalAdvanceException;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.JiraConfiguration;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
import org.libreplan.business.orders.entities.HoursGroup;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderLine;
import org.libreplan.business.orders.entities.OrderSyncInfo;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.importers.jira.IssueDTO;
import org.libreplan.importers.jira.StatusDTO;
@ -64,17 +70,24 @@ import org.springframework.transaction.annotation.Transactional;
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchronizer {
@Autowired
private IConfigurationDAO configurationDAO;
private JiraSyncInfo jiraSyncInfo;
@Autowired
private IConnectorDAO connectorDAO;
@Autowired
IOrderSyncInfoDAO orderSyncInfoDAO;
@Override
@Transactional(readOnly = true)
public List<String> getAllJiraLabels() {
String jiraLabels = configurationDAO.getConfiguration()
.getJiraConfiguration().getJiraLabels();
Connector connector = getJiraConnector();
if (connector == null) {
return null;
}
String jiraLabels = connector.getPropertiesAsMap().get(
PredefinedConnectorProperties.JIRA_LABELS);
String labels;
try {
@ -88,13 +101,26 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
@Override
@Transactional(readOnly = true)
public List<IssueDTO> getJiraIssues(String label) {
JiraConfiguration jiraConfiguration = configurationDAO
.getConfiguration().getJiraConfiguration();
public List<IssueDTO> getJiraIssues(String label) throws ConnectorException {
String url = jiraConfiguration.getJiraUrl();
String username = jiraConfiguration.getJiraUserId();
String password = jiraConfiguration.getJiraPassword();
Connector connector = getJiraConnector();
if (connector == null) {
throw new ConnectorException("Jira connector not found");
}
if (!connector.areConnectionValuesValid()) {
throw new ConnectorException(
"Connection values of JIRA connector are invalid");
}
Map<String, String> properties = connector.getPropertiesAsMap();
String url = properties.get(PredefinedConnectorProperties.SERVER_URL);
String username = properties
.get(PredefinedConnectorProperties.USERNAME);
String password = properties
.get(PredefinedConnectorProperties.PASSWORD);
String path = JiraRESTClient.PATH_SEARCH;
String query = "labels=" + label;
@ -112,7 +138,8 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
jiraSyncInfo = new JiraSyncInfo();
for (IssueDTO issue : issues) {
String code = JiraConfiguration.CODE_PREFIX + order.getCode() + "-"
String code = PredefinedConnectorProperties.JIRA_CODE_PREFIX
+ order.getCode() + "-"
+ issue.getKey();
String name = issue.getFields().getSummary();
@ -397,4 +424,29 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
return jiraSyncInfo;
}
/**
* returns JIRA connector
*/
private Connector getJiraConnector() {
return connectorDAO.findUniqueByName(PredefinedConnectors.JIRA
.getName());
}
@Override
@Transactional
public void saveSyncInfo(String key, Order order) {
OrderSyncInfo orderSyncInfo = OrderSyncInfo.create(order,
PredefinedConnectors.JIRA.getName());
orderSyncInfo.setKey(key);
orderSyncInfoDAO.save(orderSyncInfo);
}
@Override
@Transactional(readOnly = true)
public OrderSyncInfo getOrderLastSyncInfo(Order order) {
return orderSyncInfoDAO.findLastSynchronizedInfoByOrderAndConnectorId(
order, PredefinedConnectors.JIRA.getName());
}
}

View file

@ -22,15 +22,21 @@ package org.libreplan.importers;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.hibernate.NonUniqueResultException;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.JiraConfiguration;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO;
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderSyncInfo;
import org.libreplan.business.resources.daos.IWorkerDAO;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
@ -90,14 +96,17 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
private ITypeOfWorkHoursDAO typeOfWorkHoursDAO;
@Autowired
private IConfigurationDAO configurationDAO;
private IConnectorDAO connectorDAO;
@Autowired
private IOrderSyncInfoDAO orderSyncInfoDAO;
@Autowired
private IAdHocTransactionService adHocTransactionService;
@Override
@Transactional
public void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order) {
public void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order) throws ConnectorException {
jiraSyncInfo = new JiraSyncInfo();
workReportType = getJiraTimesheetsWorkReportType();
@ -109,7 +118,21 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
return;
}
String code = order.getCode() + "-" + order.getImportedLabel();
OrderSyncInfo orderSyncInfo = orderSyncInfoDAO
.findLastSynchronizedInfoByOrderAndConnectorId(order,
PredefinedConnectors.JIRA.getName());
if (orderSyncInfo == null) {
jiraSyncInfo.addSyncFailedReason("Order '" + order.getName()
+ "' not found. Order probalbly not synchronized");
return;
}
if (StringUtils.isBlank(orderSyncInfo.getKey())) {
jiraSyncInfo.addSyncFailedReason("Key for Order '"
+ order.getName() + "' is empty");
return;
}
String code = order.getCode() + "-" + orderSyncInfo.getKey();
WorkReport workReport = updateOrCreateWorkReport(code);
@ -126,7 +149,7 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
+ issue.getKey() + "' issue");
} else {
String codeOrderElement = JiraConfiguration.CODE_PREFIX
String codeOrderElement = PredefinedConnectorProperties.JIRA_CODE_PREFIX
+ order.getCode() + "-" + issue.getKey();
OrderElement orderElement = order.getOrderElement(codeOrderElement);
@ -291,10 +314,31 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
* Returns {@link TypeOfWorkHours} configured for JIRA connector
*
* @return TypeOfWorkHours for JIRA connector
* @throws ConnectorException
*/
private TypeOfWorkHours getTypeOfWorkHours() {
return configurationDAO.getConfiguration().getJiraConfiguration()
.getJiraConnectorTypeOfWorkHours();
private TypeOfWorkHours getTypeOfWorkHours() throws ConnectorException {
Connector connector = connectorDAO
.findUniqueByName(PredefinedConnectors.JIRA.getName());
if (connector == null) {
throw new ConnectorException("Connector not found");
}
TypeOfWorkHours typeOfWorkHours;
String name = connector.getPropertiesAsMap().get(
PredefinedConnectorProperties.JIRA_HOURS_TYPE);
if (StringUtils.isBlank(name)) {
throw new ConnectorException(
"Hours type should not be empty to synchronine timesheets");
}
try {
typeOfWorkHours = typeOfWorkHoursDAO.findUniqueByName(name);
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
return typeOfWorkHours;
}
/**

View file

@ -47,7 +47,6 @@ import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorProperty;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.JiraConfiguration;
import org.libreplan.business.common.entities.LDAPConfiguration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
@ -288,42 +287,6 @@ public class ConfigurationController extends GenericForwardComposer {
}
}
/**
* tests jira connection
*/
public void testJiraConnection() {
JiraConfiguration jiraConfiguration = configurationModel
.getJiraConfiguration();
try {
WebClient client = WebClient.create(jiraConfiguration.getJiraUrl());
client.path(JiraRESTClient.PATH_AUTH_SESSION).accept(
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML);
org.libreplan.ws.common.impl.Util.addAuthorizationHeader(client,
jiraConfiguration.getJiraUserId(),
jiraConfiguration.getJiraPassword());
Response response = client.get();
if (response.getStatus() == Status.OK.getStatusCode()) {
messages.showMessage(Level.INFO,
_("JIRA connection was successful"));
} else {
LOG.info("Status code: " + response.getStatus());
messages.showMessage(Level.ERROR,
_("Cannot connect to JIRA server"));
}
} catch (Exception e) {
LOG.info(e);
messages.showMessage(Level.ERROR,
_("Cannot connect to JIRA server"));
}
}
/**
* Tests connection
*/
@ -344,6 +307,9 @@ public class ConfigurationController extends GenericForwardComposer {
if (selectedConnector.getName().equals(
PredefinedConnectors.TIM.getName())) {
testTimConnection(url, username, password);
} else if (selectedConnector.getName().equals(
PredefinedConnectors.JIRA.getName())) {
testJiraConnection(url, username, password);
} else {
throw new RuntimeException("Unknown connector");
}
@ -367,6 +333,44 @@ public class ConfigurationController extends GenericForwardComposer {
}
}
/**
* Test JIRA connection
*
* @param url
* the url
* @param username
* the username
* @param password
* the password
*/
private void testJiraConnection(String url, String username, String password) {
try {
WebClient client = WebClient.create(url);
client.path(JiraRESTClient.PATH_AUTH_SESSION).accept(
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML);
org.libreplan.ws.common.impl.Util.addAuthorizationHeader(client,
username, password);
Response response = client.get();
if (response.getStatus() == Status.OK.getStatusCode()) {
messages.showMessage(Level.INFO,
_("JIRA connection was successful"));
} else {
LOG.error("Status code: " + response.getStatus());
messages.showMessage(Level.ERROR,
_("Cannot connect to JIRA server"));
}
} catch (Exception e) {
LOG.error(e);
messages.showMessage(Level.ERROR,
_("Cannot connect to JIRA server"));
}
}
private boolean checkValidEntitySequenceRows() {
Rows rows = entitySequencesGrid.getRows();
@ -891,14 +895,6 @@ public class ConfigurationController extends GenericForwardComposer {
configurationModel.setLdapConfiguration(ldapConfiguration);
}
public JiraConfiguration getJiraConfiguration() {
return configurationModel.getJiraConfiguration();
}
public void setJiraConfiguration(JiraConfiguration jiraConfiguration) {
configurationModel.setJiraConfiguration(jiraConfiguration);
}
public RowRenderer getAllUserRolesRenderer() {
return new RowRenderer() {
@Override
@ -1049,14 +1045,6 @@ public class ConfigurationController extends GenericForwardComposer {
configurationModel.setSecondsPlanningWarning(secondsPlanningWarning);
}
public TypeOfWorkHours getJiraConnectorTypeOfWorkHours() {
return configurationModel.getJiraConnectorTypeOfWorkHours();
}
public void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
configurationModel.setJiraConnectorTypeOfWorkHours(typeOfWorkHours);
}
public List<Connector> getConnectors() {
return configurationModel.getConnectors();
}
@ -1130,7 +1118,8 @@ public class ConfigurationController extends GenericForwardComposer {
} else if (key
.equals(PredefinedConnectorProperties.SERVER_URL)
|| key.equals(PredefinedConnectorProperties.USERNAME)
|| key.equals(PredefinedConnectorProperties.PASSWORD)) {
|| key.equals(PredefinedConnectorProperties.PASSWORD)
|| key.equals(PredefinedConnectorProperties.JIRA_HOURS_TYPE)) {
((InputElement) comp).setConstraint("no empty:"
+ _("cannot be empty"));
} else if (key

View file

@ -45,7 +45,6 @@ import org.libreplan.business.common.entities.Configuration;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.JiraConfiguration;
import org.libreplan.business.common.entities.LDAPConfiguration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.entities.ProgressType;
@ -162,8 +161,6 @@ public class ConfigurationModel implements IConfigurationModel {
private void forceLoad(Configuration configuration) {
forceLoad(configuration.getDefaultCalendar());
forceLoad(configuration.getPersonalTimesheetsTypeOfWorkHours());
forceLoad(configuration.getJiraConfiguration()
.getJiraConnectorTypeOfWorkHours());
}
private void forceLoad(BaseCalendar calendar) {
@ -694,38 +691,6 @@ public class ConfigurationModel implements IConfigurationModel {
configuration.setSecondsPlanningWarning(secondsPlanningWarning);
}
@Override
public void setJiraConfiguration(JiraConfiguration jiraConfiguration) {
configuration.setJiraConfiguration(jiraConfiguration);
}
@Override
public JiraConfiguration getJiraConfiguration() {
return configuration.getJiraConfiguration();
}
@Override
public TypeOfWorkHours getJiraConnectorTypeOfWorkHours() {
JiraConfiguration jiraConfiguration = configuration
.getJiraConfiguration();
if (jiraConfiguration != null) {
return jiraConfiguration.getJiraConnectorTypeOfWorkHours();
}
return null;
}
@Override
public void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
if (configuration != null) {
JiraConfiguration jiraConfiguration = configuration
.getJiraConfiguration();
if (jiraConfiguration != null) {
jiraConfiguration
.setJiraConnectorTypeOfWorkHours(typeOfWorkHours);
}
}
}
private void saveConnectors() {
for (Connector connector : connectors) {
connectorDAO.save(connector);

View file

@ -28,7 +28,6 @@ import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.JiraConfiguration;
import org.libreplan.business.common.entities.LDAPConfiguration;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.entities.ProgressType;
@ -187,14 +186,6 @@ public interface IConfigurationModel {
void setSecondsPlanningWarning(
Integer planningWarningExitWithoutSavingSeconds);
void setJiraConfiguration(JiraConfiguration jiraConfiguration);
JiraConfiguration getJiraConfiguration();
TypeOfWorkHours getJiraConnectorTypeOfWorkHours();
void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours);
List<Connector> getConnectors();
Connector getConnectorByName(String name);

View file

@ -148,6 +148,4 @@ public interface IOrderModel extends IIntegrationEntityModel {
boolean isOnlyChildAndParentAlreadyInUseByHoursOrExpenses(
OrderElement orderElement);
boolean isJiraActivated();
}

View file

@ -39,7 +39,10 @@ import javax.ws.rs.WebApplicationException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.externalcompanies.entities.DeadlineCommunication;
import org.libreplan.business.externalcompanies.entities.DeliverDateComparator;
@ -50,6 +53,7 @@ import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.Order.SchedulingMode;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderStatusEnum;
import org.libreplan.business.orders.entities.OrderSyncInfo;
import org.libreplan.business.planner.entities.PositionConstraintType;
import org.libreplan.business.templates.entities.OrderTemplate;
import org.libreplan.business.users.entities.UserRole;
@ -210,7 +214,7 @@ public class OrderCRUDController extends GenericForwardComposer {
private IJiraTimesheetSynchronizer jiraTimesheetSynchronizer;
@Autowired
private IConfigurationDAO configurationDAO;
private IConnectorDAO connectorDAO;
@Override
@ -1706,9 +1710,18 @@ public class OrderCRUDController extends GenericForwardComposer {
private Button startJiraSyncButton, cancelJiraSyncButton, syncWithJiraButton;
private Combobox comboJiraLabel;
private boolean isJiraActivated() {
Connector connector = connectorDAO
.findUniqueByName(PredefinedConnectors.JIRA.getName());
if (connector == null) {
return false;
}
return connector.isActivated();
}
public boolean isJiraDeactivated() {
return !configurationDAO.getConfigurationWithReadOnlyTransaction()
.getJiraConfiguration().isJiraActivated();
return !isJiraActivated();
}
public void syncWithJira() {
@ -1745,13 +1758,21 @@ public class OrderCRUDController extends GenericForwardComposer {
List<IssueDTO> issues = jiraOrderElementSynchronizer
.getJiraIssues(label);
if (issues == null || issues.isEmpty()) {
messagesForUser.showMessage(Level.ERROR,
_("No JIRA issues to import"));
return;
}
order.setCodeAutogenerated(false);
order.setImportedLabel(label);
jiraOrderElementSynchronizer.syncOrderElementsWithJiraIssues(
issues, order);
saveAndContinue(false);
jiraOrderElementSynchronizer.saveSyncInfo(label, order);
if (jirasyncPopup != null) {
jirasyncPopup.close();
}
@ -1769,9 +1790,16 @@ public class OrderCRUDController extends GenericForwardComposer {
LOG.info(e);
messagesForUser.showMessage(Level.ERROR,
_("Cannot connect to JIRA server"));
} catch (ConnectorException e) {
messagesForUser.showMessage(Level.ERROR,
_("Failed: " + e.getMessage()));
}
}
public OrderSyncInfo getOrderLastSyncInfo() {
return jiraOrderElementSynchronizer.getOrderLastSyncInfo(getOrder());
}
private void showSyncInfo() {
Map<String, Object> args = new HashMap<String, Object>();
@ -1861,10 +1889,6 @@ public class OrderCRUDController extends GenericForwardComposer {
}
}
public boolean isJiraActivated() {
return orderModel.isJiraActivated();
}
public void setupTimSynchronizationController() {
if (timSynchronizationController == null) {
timSynchronizationController = new TimSynchronizationController();

View file

@ -36,9 +36,11 @@ import java.util.Set;
import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.daos.IConnectorDAO;
import org.libreplan.business.common.entities.Connector;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.JiraConfiguration;
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
import org.libreplan.business.common.entities.PredefinedConnectors;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderLine;
@ -121,7 +123,7 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
private Popup filterOptionsPopup;
@Autowired
private IConfigurationDAO configurationDAO;
private IConnectorDAO connectorDAO;
public List<org.libreplan.business.labels.entities.Label> getLabels() {
return orderModel.getLabels();
@ -467,9 +469,17 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
String code = orderElement.getCode();
A hyperlink = new A(code);
String jiraUrl = configurationDAO.getConfigurationWithReadOnlyTransaction().getJiraConfiguration().getJiraUrl();
Connector connector = connectorDAO
.findUniqueByName(PredefinedConnectors.JIRA.getName());
if (connector == null) {
return;
}
String codeWithoutPrefix = StringUtils.removeStart(code, JiraConfiguration.CODE_PREFIX);
String jiraUrl = connector.getPropertiesAsMap().get(
PredefinedConnectorProperties.SERVER_URL);
String codeWithoutPrefix = StringUtils.removeStart(code,
PredefinedConnectorProperties.JIRA_CODE_PREFIX);
codeWithoutPrefix = StringUtils.removeStart(codeWithoutPrefix,
orderElement.getOrder().getCode()
+ EntitySequence.CODE_SEPARATOR_CHILDREN);

View file

@ -928,11 +928,4 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
}
}
@Override
@Transactional(readOnly = true)
public boolean isJiraActivated() {
return configurationDAO.getConfiguration().getJiraConfiguration()
.isJiraActivated();
}
}

View file

@ -42,7 +42,6 @@
<tab label="${i18n:_('Main preferences')}" />
<tab label="${i18n:_('Entity sequences')}" />
<tab label="${i18n:_('LDAP configuration')}" />
<tab label="${i18n:_('JIRA connector')}" />
<tab label="${i18n:_('Connectors')}" />
</tabs>
<tabpanels>
@ -415,46 +414,6 @@
</vbox>
</groupbox>
</tabpanel>
<tabpanel id="panelJiraConfiguration">
<grid>
<columns>
<column width="200px" />
<column />
</columns>
<rows>
<row>
<label value="${i18n:_('Activated')}" />
<checkbox id="jiraActivated" checked="@{configurationController.jiraConfiguration.jiraActivated}" width="300px" />
</row>
<row>
<label value="${i18n:_('JIRA URL')}" />
<textbox id="jiraURL" value="@{configurationController.jiraConfiguration.jiraUrl}" width="300px"/>
</row>
<row>
<label value="${i18n:_('JIRA sync account')}" />
<textbox id="jiraSyncAccount" value="@{configurationController.jiraConfiguration.jiraUserId}" width="300px"/>
</row>
<row>
<label value="${i18n:_('JIRA sync password')}" />
<textbox id="jiraSyncPassword" value="@{configurationController.jiraConfiguration.jiraPassword}" type="password" width="300px"/>
</row>
<row>
<label value="${i18n:_('JIRA labels: comma-separated list of labels or URL')}" />
<textbox id="jiraLabels" value="@{configurationController.jiraConfiguration.jiraLabels}" width="600px"/>
</row>
<row>
<label value="${i18n:_('Hours type for JIRA connector')}" />
<bandboxSearch
finder="TypeOfWorkHoursBandboxFinder"
selectedElement="@{configurationController.jiraConnectorTypeOfWorkHours, access='both'}" />
</row>
</rows>
</grid>
<separator />
<button label="${i18n:_('Test connection')}"
onClick="configurationController.testJiraConnection()" />
<separator />
</tabpanel>
<tabpanel id="panelConnectors">
<groupbox style="margin-top: 5px" closable="false">
<caption label="${i18n:_('Application properties')}" />

View file

@ -298,8 +298,9 @@
<row>
<label value="${i18n:_('JIRA label')}" width="50px"/>
<hbox>
<textbox id="txtImportedLabel" value="@{controller.order.importedLabel}"
width="350px" disabled="true"/>
<textbox value="@{controller.orderLastSyncInfo.lastSyncDate}" width="130px" disabled="true"/>
<textbox id="txtImportedLabel" value="@{controller.orderLastSyncInfo.key}"
width="220px" disabled="true"/>
<button label="${i18n:_('Sync with JIRA')}" id="syncWithJiraButton" disabled="@{controller.jiraDeactivated}"
onClick="controller.syncWithJira()" />
</hbox>
@ -337,7 +338,7 @@
<popup id="jirasyncPopup" sclass="finder-popup">
<groupbox mold="3d" closable="false" width="420px">
<caption id="jiraSyncCaption" label="Select a label" />
<combobox id="comboJiraLabel" autodrop="true" width="400px"/>
<combobox id="comboJiraLabel" autodrop="true" width="400px" constraint="no empty:${i18n:_('cannot be empty')}"/>
<separator/>
<hbox>
<button id="startJiraSyncButton" />

View file

@ -45,6 +45,7 @@ import org.libreplan.business.IDataBootstrap;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.ConnectorException;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.orders.daos.IOrderDAO;
import org.libreplan.business.orders.entities.Order;
@ -220,7 +221,7 @@ public class JiraTimesheetSynchronizerTest {
@Test
@Ignore("Only working if you have a JIRA server configured")
public void testSyncJiraTimesheet() {
public void testSyncJiraTimesheet() throws ConnectorException {
Order order = givenOrderWithValidOrderLines();
jiraTimesheetSynchronizer