Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Vova Perebykivskyi 2016-11-29 10:38:00 +02:00
commit 22d3601a6c
21 changed files with 317 additions and 79 deletions

View file

@ -33,7 +33,6 @@ public interface ILimitsDAO extends IGenericDAO<Limits, Long> {
List<Limits> getAll();
Limits getUsersType();
Limits getLimitsByType(String type);
Limits getResourcesType();
}

View file

@ -19,6 +19,7 @@
package org.libreplan.business.common.daos;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.entities.Limits;
import org.springframework.stereotype.Repository;
@ -38,25 +39,14 @@ public class LimitsDAO extends GenericDAOHibernate<Limits, Long> implements ILim
return list(Limits.class);
}
@Override
public Limits getUsersType() {
List<Limits> list = list(Limits.class);
for (Limits item : list) {
if ("users".equals(item.getType())) {
return item;
}
}
return null;
}
@Override
public Limits getResourcesType() {
List<Limits> list = list(Limits.class);
for (Limits item : list) {
if ("workers+machines".equals(item.getType())) {
return item;
}
}
return null;
public Limits getLimitsByType(String type) {
return (Limits) getSession()
.createCriteria(Limits.class)
.add(Restrictions.eq("type", type))
.uniqueResult();
}
}

View file

@ -23,6 +23,7 @@ import java.util.List;
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
import org.libreplan.business.logs.entities.IssueLog;
import org.libreplan.business.orders.entities.Order;
/**
* Contract for {@link IssueLogDAO}
@ -37,4 +38,11 @@ public interface IIssueLogDAO extends IIntegrationEntityDAO<IssueLog> {
* @return a list of {@link IssueLog} objects
*/
List<IssueLog> getIssueLogs();
/**
* Returns a list of {@link IssueLog} for a specified {@link Order}
*
* @param order parent element for IssueLogs
*/
List<IssueLog> getByParent(Order order);
}

View file

@ -23,6 +23,7 @@ import java.util.List;
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
import org.libreplan.business.logs.entities.RiskLog;
import org.libreplan.business.orders.entities.Order;
public interface IRiskLogDAO extends IIntegrationEntityDAO<RiskLog> {
@ -33,4 +34,11 @@ public interface IRiskLogDAO extends IIntegrationEntityDAO<RiskLog> {
*/
List<RiskLog> getRiskLogs();
/**
* Returns a list of {@link RiskLog} for a specified {@link Order}
*
* @param order parent element for RiskLogs
*/
List<RiskLog> getByParent(Order order);
}

View file

@ -21,8 +21,10 @@ package org.libreplan.business.logs.daos;
import java.util.List;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.daos.IntegrationEntityDAO;
import org.libreplan.business.logs.entities.IssueLog;
import org.libreplan.business.orders.entities.Order;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
@ -42,5 +44,12 @@ public class IssueLogDAO extends IntegrationEntityDAO<IssueLog> implements
return list(IssueLog.class);
}
@Override
public List<IssueLog> getByParent(Order order) {
return getSession()
.createCriteria(IssueLog.class)
.add(Restrictions.eq("project", order))
.list();
}
}

View file

@ -21,8 +21,10 @@ package org.libreplan.business.logs.daos;
import java.util.List;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.daos.IntegrationEntityDAO;
import org.libreplan.business.logs.entities.RiskLog;
import org.libreplan.business.orders.entities.Order;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
@ -43,4 +45,12 @@ public class RiskLogDAO extends IntegrationEntityDAO<RiskLog> implements
return list(RiskLog.class);
}
@Override
public List<RiskLog> getByParent(Order order) {
return getSession()
.createCriteria(RiskLog.class)
.add(Restrictions.eq("project", order))
.list();
}
}

View file

@ -224,6 +224,10 @@ public class Order extends OrderLineGroup implements Comparable {
return getCurrentVersionInfo().isUsingTheOwnerScenario();
}
/**
* Should be public!
* Used in orders/_edition.zul
*/
public BigDecimal getWorkBudget() {
if (workBudget == null) {
return BigDecimal.ZERO;
@ -238,6 +242,10 @@ public class Order extends OrderLineGroup implements Comparable {
this.workBudget = workBudget;
}
/**
* Should be public!
* Used in orders/_edition.zul
*/
public BigDecimal getMaterialsBudget() {
if (materialsBudget == null) {
return BigDecimal.ZERO;
@ -252,6 +260,10 @@ public class Order extends OrderLineGroup implements Comparable {
this.materialsBudget = materialsBudget;
}
/**
* Should be public!
* Used in orders/_edition.zul
*/
public BigDecimal getTotalManualBudget() {
return getWorkBudget().add(getMaterialsBudget());
}

View file

@ -19,6 +19,8 @@
package org.libreplan.importers.notifications;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.common.entities.ConnectorProperty;
import org.libreplan.business.email.entities.EmailNotification;
import org.libreplan.business.email.entities.EmailTemplate;
@ -83,6 +85,8 @@ public class ComposeMessage {
private Properties properties;
private static final Log LOG = LogFactory.getLog(ComposeMessage.class);
public boolean composeMessageForUser(EmailNotification notification) {
// Gather data about EmailTemplate needs to be used
@ -102,6 +106,11 @@ public class ComposeMessage {
EmailTemplate currentEmailTemplate = findCurrentEmailTemplate(type, locale);
if (currentEmailTemplate == null) {
LOG.error("Email template is null");
return false;
}
// Modify text that will be composed
String text = currentEmailTemplate.getContent();
text = replaceKeywords(text, currentWorker, notification);

View file

@ -20,6 +20,7 @@
package org.libreplan.web.common;
import org.libreplan.business.common.daos.ILimitsDAO;
import org.libreplan.business.common.daos.LimitsDAO;
import org.libreplan.business.common.entities.Limits;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
@ -39,6 +40,10 @@ import java.util.List;
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class LimitsModel implements ILimitsModel {
public static final String USER_LIMITS_TYPE = "users";
public static final String RESOURCES_LIMITS_TYPE = "workers+machines";
@Autowired
private ILimitsDAO limitsDAO;
@ -51,12 +56,13 @@ public class LimitsModel implements ILimitsModel {
@Override
@Transactional(readOnly = true)
public Limits getUsersType() {
return limitsDAO.getUsersType();
return limitsDAO.getLimitsByType(USER_LIMITS_TYPE);
}
@Override
@Transactional(readOnly = true)
public Limits getResourcesType() {
return limitsDAO.getResourcesType();
return limitsDAO.getLimitsByType(RESOURCES_LIMITS_TYPE);
}
}

View file

@ -115,5 +115,12 @@ public interface IIssueLogModel {
*/
void remove(IssueLog issueLog);
/**
* Returns a list of {@link IssueLog} for a specified {@link Order}
*
* @param order parent element for IssueLogs
*/
List<IssueLog> getByParent(Order order);
}

View file

@ -115,5 +115,12 @@ public interface IRiskLogModel {
*/
void remove(RiskLog riskLog);
/**
* Returns a list of {@link RiskLog} for a specified {@link Order}
*
* @param order parent element for RiskLogs
*/
List<RiskLog> getByParent(Order order);
}

View file

@ -139,6 +139,11 @@ public class IssueLogModel extends IntegrationEntityModel implements IIssueLogMo
}
}
@Override
public List<IssueLog> getByParent(Order order) {
return issueLogDAO.getByParent(order);
}
@Override
public EntityNameEnum getEntityName() {
return EntityNameEnum.ISSUE_LOG;

View file

@ -140,6 +140,11 @@ public class RiskLogModel extends IntegrationEntityModel implements IRiskLogMode
}
}
@Override
public List<RiskLog> getByParent(Order order) {
return riskLogDAO.getByParent(order);
}
@Override
public EntityNameEnum getEntityName() {
return EntityNameEnum.RISK_LOG;

View file

@ -84,6 +84,9 @@ import org.libreplan.business.users.entities.UserRole;
import org.libreplan.web.calendars.BaseCalendarModel;
import org.libreplan.web.common.IntegrationEntityModel;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.libreplan.web.logs.IIssueLogModel;
import org.libreplan.web.logs.IRiskLogModel;
import org.libreplan.web.orders.files.IOrderFileModel;
import org.libreplan.web.orders.labels.LabelsOnConversation;
import org.libreplan.web.planner.order.ISaveCommand.IBeforeSaveActions;
import org.libreplan.web.planner.order.PlanningStateCreator;
@ -169,6 +172,15 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Autowired
private IOrderVersionDAO orderVersionDAO;
@Autowired
private IOrderFileModel orderFileModel;
@Autowired
private IRiskLogModel riskLogModel;
@Autowired
private IIssueLogModel issueLogModel;
private List<Order> orderList = new ArrayList<>();
@Override
@ -508,6 +520,11 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
@Transactional
public void remove(Order detachedOrder) {
Order order = orderDAO.findExistingEntity(detachedOrder.getId());
removeFiles(order);
removeLogs(order);
removeVersions(order);
if ( order.hasNoVersions() ) {
@ -515,6 +532,15 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
}
}
private void removeLogs(Order order) {
riskLogModel.getByParent(order).forEach(riskLog -> riskLogModel.remove(riskLog));
issueLogModel.getByParent(order).forEach(issueLog -> issueLogModel.remove(issueLog));
}
private void removeFiles(Order order) {
orderFileModel.findByParent(order).forEach(orderFile -> orderFileModel.delete(orderFile));
}
private void removeVersions(Order order) {
Map<Long, OrderVersion> versionsRemovedById = new HashMap<>();
List<Scenario> currentAndDerived = currentAndDerivedScenarios();

View file

@ -30,7 +30,14 @@ public interface IOrderFileModel {
List<OrderFile> getAll();
void delete(OrderFile file);
/**
* This method is used to delete OrderFile and physical file asociated with it
*
* @param file {@link OrderFile} that need to be deleted
* @return true if file was deleted successfully.
* @return false if file was not deleted successfully.
*/
boolean delete(OrderFile file);
List<OrderFile> findByParent(OrderElement parent);

View file

@ -4,12 +4,15 @@ import org.libreplan.business.orders.daos.IOrderFileDAO;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderFile;
import org.libreplan.business.users.entities.User;
import org.libreplan.web.common.IConfigurationModel;
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 org.zkoss.zkplus.spring.SpringUtil;
import java.io.File;
import java.util.Date;
import java.util.List;
@ -21,11 +24,15 @@ import java.util.List;
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class OrderFileModel implements IOrderFileModel {
public static final String UNKNOWN_FILE_EXTENSION = "Unknown type";
@Autowired
private IOrderFileDAO fileDAO;
private OrderFile orderFile;
private IConfigurationModel configurationModel;
@Override
@Transactional
public void confirmSave() {
@ -68,10 +75,23 @@ public class OrderFileModel implements IOrderFileModel {
return fileDAO.getAll();
}
/**
* This method is used to delete OrderFile and physical file asociated with it.
* Also different cases can occur:
* - First case: there is no troubles and OrderFile is deleted from database
* and physical file is deleted from disc.
* - Second case: there is some troubles with deleting physical file from disc, but
* OrderFile is deleted from database.
*
* @param file {@link OrderFile} that needs to be deleted.
* @return true if file was deleted successfully.
* @return false if file was not successfully deleted .
*/
@Override
@Transactional
public void delete(OrderFile file){
public boolean delete(OrderFile file) {
fileDAO.delete(file);
return deletePhysicalFile(file);
}
@Override
@ -84,4 +104,33 @@ public class OrderFileModel implements IOrderFileModel {
public OrderFile getOrderFile() {
return orderFile;
}
private boolean deletePhysicalFile (OrderFile file) {
try {
configurationModel = (IConfigurationModel) SpringUtil.getBean("configurationModel");
configurationModel.init();
String projectCode = file.getParent().getCode();
String directory = configurationModel.getRepositoryLocation() + "orders" + "/" + projectCode;
File fileToDelete;
if (UNKNOWN_FILE_EXTENSION.equals(file.getType())) {
fileToDelete = new File(directory + "/" + file.getName());
}
else {
fileToDelete = new File(directory + "/" + file.getName() + "." + file.getType());
}
return fileToDelete.delete();
} catch (Exception ignored) {
/*
* org.zkoss.zk.ui.Execution("SpringUtil can be called only under ZK environment!") can occur if
* ZK environment is not raised, this can occur in JUnit tests
*/
return false;
}
}
}

View file

@ -187,19 +187,13 @@ public class OrderFilesController extends GenericForwardComposer {
return;
}
if ( isRepositoryExists() ) {
String projectCode = orderElementModel.getOrderElement().getCode();
configurationModel.init();
String directory = configurationModel.getRepositoryLocation() + "orders" + "/" + projectCode;
File fileToDelete = new File(directory + "/" + file.getName() + "." + file.getType());
boolean deleted = orderFileModel.delete(file);
boolean deleted = fileToDelete.delete();
if ( deleted ) {
orderFileModel.delete(file);
if ( deleted ){
messages.clearMessages();
messages.showMessage(Level.INFO, "File successfully deleted");
@ -266,7 +260,11 @@ public class OrderFilesController extends GenericForwardComposer {
orderFileModel.createNewFileObject();
orderFileModel.setFileName(FilenameUtils.getBaseName(media.getName()));
orderFileModel.setFileType(FilenameUtils.getExtension(media.getName()));
orderFileModel.setFileType(FilenameUtils.getExtension(media.getName()).isEmpty()
? OrderFileModel.UNKNOWN_FILE_EXTENSION
: FilenameUtils.getExtension(media.getName()));
orderFileModel.setUploadDate(new Date());
orderFileModel.setUploader(userDAO.findByLoginName(SecurityUtils.getSessionUserLoginName()));
orderFileModel.setParent(orderElementModel.getOrderElement());

View file

@ -584,26 +584,43 @@ public class MachineCRUDController extends BaseCRUDController<Machine> {
return machineModel.getMachine();
}
public boolean isCreateButtonDisabled(){
/**
* Should be public!
* Used in _listMachines.zul
*/
public boolean isCreateButtonDisabled() {
Limits resourcesTypeLimit = limitsModel.getResourcesType();
Integer resourcesCount = resourceDAO.getRowCount().intValue();
if ( resourcesTypeLimit != null )
if ( resourcesCount >= resourcesTypeLimit.getValue() )
return true;
return false;
if (isNullOrZeroValue(resourcesTypeLimit)) {
return false;
} else {
Integer resources = resourceDAO.getRowCount().intValue();
return resources >= resourcesTypeLimit.getValue();
}
}
/**
* Should be public!
* Used in _listMachines.zul
*/
public String getShowCreateFormLabel(){
Limits resourcesTypeLimit = limitsModel.getResourcesType();
Integer resourcesCount = resourceDAO.getRowCount().intValue();
int resourcesLeft = resourcesTypeLimit.getValue() - resourcesCount;
if ( resourcesCount >= resourcesTypeLimit.getValue() )
return _("Machines limit reached");
if (isNullOrZeroValue(resourcesTypeLimit)) {
return _("Create");
}
return _("Create") + " ( " + resourcesLeft + " " + _("left") + " )";
Integer resources = resourceDAO.getRowCount().intValue();
int resourcesLeft = resourcesTypeLimit.getValue() - resources;
return resources >= resourcesTypeLimit.getValue()
? _("Machines limit reached")
: _("Create") + " ( " + resourcesLeft + " " + _("left") + " )";
}
private boolean isNullOrZeroValue (Limits resourcesTypeLimit) {
return resourcesTypeLimit == null ||
resourcesTypeLimit.getValue() == null ||
resourcesTypeLimit.getValue().equals(0);
}
}

View file

@ -1114,22 +1114,43 @@ public class WorkerCRUDController extends GenericForwardComposer implements IWor
: "";
}
/**
* Should be public!
* Used in resources/worker/_list.zul
*/
public boolean isCreateButtonDisabled() {
Limits resourcesTypeLimit = limitsModel.getResourcesType();
Integer resourcesCount = resourceDAO.getRowCount().intValue();
return resourcesTypeLimit != null && resourcesCount >= resourcesTypeLimit.getValue();
if (isNullOrZeroValue(resourcesTypeLimit)) {
return false;
} else {
Integer resources = resourceDAO.getRowCount().intValue();
return resources >= resourcesTypeLimit.getValue();
}
}
/**
* Should be public!
* Used in resources/worker/_list.zul
*/
public String getShowCreateFormLabel() {
Limits resourcesTypeLimit = limitsModel.getResourcesType();
Integer resourcesCount = resourceDAO.getRowCount().intValue();
int resourcesLeft = resourcesTypeLimit.getValue() - resourcesCount;
if (resourcesCount >= resourcesTypeLimit.getValue())
return _("Workers limit reached");
if (isNullOrZeroValue(resourcesTypeLimit)) {
return _("Create");
}
return _("Create") + " ( " + resourcesLeft + " " + _("left") + " )";
Integer resources = resourceDAO.getRowCount().intValue();
int resourcesLeft = resourcesTypeLimit.getValue() - resources;
return resources >= resourcesTypeLimit.getValue()
? _("Workers limit reached")
: _("Create") + " ( " + resourcesLeft + " " + _("left") + " )";
}
private boolean isNullOrZeroValue (Limits resourcesTypeLimit) {
return resourcesTypeLimit == null ||
resourcesTypeLimit.getValue() == null ||
resourcesTypeLimit.getValue().equals(0);
}
}

View file

@ -440,10 +440,18 @@ public class UserCRUDController extends BaseCRUDController<User> implements IUse
}
}
/**
* Should be public!
* Used in _listUsers.zul
*/
public boolean isCreateButtonDisabled() {
Limits usersTypeLimit = limitsModel.getUsersType();
Integer usersCount = userModel.getRowCount().intValue();
return usersTypeLimit != null && usersCount >= usersTypeLimit.getValue();
if (isNullOrZeroValue(usersTypeLimit)) {
return false;
} else {
Integer users = userModel.getRowCount().intValue();
return users >= usersTypeLimit.getValue();
}
}
/**
@ -452,11 +460,23 @@ public class UserCRUDController extends BaseCRUDController<User> implements IUse
*/
public String getShowCreateFormLabel() {
Limits usersTypeLimit = limitsModel.getUsersType();
Integer usersCount = userModel.getRowCount().intValue();
int usersLeft = usersTypeLimit.getValue() - usersCount;
return usersCount >= usersTypeLimit.getValue()
if (isNullOrZeroValue(usersTypeLimit)) {
return _("Create");
}
Integer users = userModel.getRowCount().intValue();
int usersLeft = usersTypeLimit.getValue() - users;
return users >= usersTypeLimit.getValue()
? _("User limit reached")
: _("Create") + " ( " + usersLeft + " " + _("left") + " )";
}
private boolean isNullOrZeroValue (Limits usersTypeLimit) {
return usersTypeLimit == null ||
usersTypeLimit.getValue() == null ||
usersTypeLimit.getValue().equals(0);
}
}

View file

@ -65,6 +65,17 @@ import java.util.Date;
WEBAPP_SPRING_SECURITY_CONFIG_FILE,
WEBAPP_SPRING_SECURITY_CONFIG_TEST_FILE })
/**
* CRUD test
* 1. Add row to files table
* 2. Read it
* 3. Update it
* 4. Delete it
*
* Negative test
* 1. Create row with null field value and try to save it
*/
public class OrderFilesTest {
@Autowired
@ -82,30 +93,27 @@ public class OrderFilesTest {
@Autowired
private IHoursGroupDAO hoursGroupDAO;
/**
* CRUD test
* 1. Add row to files table
* 2. Read it
* 3. Update it
* 4. Delete it
*
* Negative test
* 1. Create row with null field value and try to save it
*/
@Test
@Transactional
public void testCRUD() {
public void testCreate() {
// Create
int sizeBefore = orderFileModel.getAll().size();
createEntities();
int sizeWithNewRow = orderFileModel.getAll().size();
assertEquals(sizeBefore + 1, sizeWithNewRow);
OrderFile orderFile = null;
// Read
removeEntities();
}
@Test
@Transactional
public void testRead() {
createEntities();
OrderFile orderFile = null;
try {
orderFile = orderFileModel.findByParent(orderElementDAO.findUniqueByCode("1a1k1k1k")).get(0);
assertEquals(orderFile.getName(), "Index");
@ -113,21 +121,38 @@ public class OrderFilesTest {
e.printStackTrace();
}
// Update
orderFile.setName("yii2");
orderFileModel.confirmSave();
removeEntities();
}
@Test
@Transactional
public void testUpdate() {
createEntities();
OrderFile orderFile = null;
try {
orderFile = orderFileModel.findByParent(orderElementDAO.findUniqueByCode("1a1k1k1k")).get(0);
orderFile.setName("yii2");
orderFileModel.confirmSave();
assertTrue(orderFile.getName().equals("yii2"));
} catch (InstanceNotFoundException e) {
e.printStackTrace();
}
// Delete
removeEntities();
}
@Test
@Transactional
public void testDelete() {
createEntities();
int sizeBefore = orderFileModel.getAll().size();
removeEntities();
int sizeAfter = orderFileModel.getAll().size();
assertEquals(sizeBefore, sizeAfter);
assertEquals(sizeBefore - 1, sizeAfter);
}
@Transactional