/*
* LinShare is an open source filesharing software, part of the LinPKI software
* suite, developed by Linagora.
*
* Copyright (C) 2015 LINAGORA
*
* 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, provided you comply with the Additional Terms applicable for
* LinShare software by Linagora pursuant to Section 7 of the GNU Affero General
* Public License, subsections (b), (c), and (e), pursuant to which you must
* notably (i) retain the display of the “LinShare™” trademark/logo at the top
* of the interface window, the display of the “You are using the Open Source
* and free version of LinShare™, powered by Linagora © 2009–2015. Contribute to
* Linshare R&D by subscribing to an Enterprise offer!” infobox and in the
* e-mails sent with the Program, (ii) retain all hypertext links between
* LinShare and linshare.org, between linagora.com and Linagora, and (iii)
* refrain from infringing Linagora intellectual property rights over its
* trademarks and commercial brands. Other Additional Terms apply, see
* <http://www.linagora.com/licenses/> for more details.
*
* 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 and
* its applicable Additional Terms for LinShare along with this program. If not,
* see <http://www.gnu.org/licenses/> for the GNU Affero General Public License
* version 3 and <http://www.linagora.com/licenses/> for the Additional Terms
* applicable to LinShare software.
*/
package org.linagora.linshare.core.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.linagora.linshare.core.business.service.DomainBusinessService;
import org.linagora.linshare.core.business.service.DomainPermissionBusinessService;
import org.linagora.linshare.core.business.service.FunctionalityBusinessService;
import org.linagora.linshare.core.domain.constants.AuditLogEntryType;
import org.linagora.linshare.core.domain.constants.FunctionalityNames;
import org.linagora.linshare.core.domain.constants.LogAction;
import org.linagora.linshare.core.domain.entities.AbstractDomain;
import org.linagora.linshare.core.domain.entities.Account;
import org.linagora.linshare.core.domain.entities.Functionality;
import org.linagora.linshare.core.exception.BusinessErrorCode;
import org.linagora.linshare.core.exception.BusinessException;
import org.linagora.linshare.core.service.FunctionalityService;
import org.linagora.linshare.mongo.entities.logs.FunctionalityAuditLogEntry;
import org.linagora.linshare.mongo.repository.AuditAdminMongoRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class FunctionalityServiceImpl extends AbstractFunctionalityServiceImpl<Functionality> implements FunctionalityService {
protected final Logger logger = LoggerFactory.getLogger(FunctionalityServiceImpl.class);
final private FunctionalityBusinessService businessService;
protected List<String> excludesForUsers = new ArrayList<String>();
final private AuditAdminMongoRepository mongoRepository;
public FunctionalityServiceImpl(
FunctionalityBusinessService functionalityBusinessService,
DomainBusinessService domainBusinessService,
DomainPermissionBusinessService domainPermissionBusinessService,
AuditAdminMongoRepository mongoRepository) {
super(domainBusinessService, domainPermissionBusinessService);
this.businessService = functionalityBusinessService;
this.mongoRepository = mongoRepository;
// Users
excludesForUsers.add(FunctionalityNames.SHARE_NOTIFICATION_BEFORE_EXPIRATION.toString());
excludesForUsers.add(FunctionalityNames.UPLOAD_REQUEST__DELAY_BEFORE_NOTIFICATION.toString());
excludesForUsers.add(FunctionalityNames.DOMAIN__MAIL.toString());
excludesForUsers.add(FunctionalityNames.ANTIVIRUS.toString());
excludesForUsers.add(FunctionalityNames.TIME_STAMPING.toString());
}
@Override
public Iterable<Functionality> findAll(Account actor, String domainId) throws BusinessException {
return findAll(actor, domainId, null, false, false);
}
@Override
public Iterable<Functionality> findAll(Account actor, String domainId,
String parentId) throws BusinessException {
return findAll(actor, domainId, parentId, false, false);
}
@Override
public Iterable<Functionality> findAll(Account actor, String domainId,
String parentId, boolean tree, boolean withSubFunctionalities)
throws BusinessException {
Validate.notNull(actor);
Validate.isTrue(actor.hasAdminRole() || actor.hasSuperAdminRole());
Validate.notEmpty(domainId);
FunctionalityNames parentIdentifier = null;
if (parentId != null) {
// check if it is a valid parent identifier
parentIdentifier = FunctionalityNames.valueOf(parentId);
}
AbstractDomain domain = getDomain(actor, domainId);
Set<Functionality> functionalities = businessService.getAllFunctionalities(domain, excludes);
Map<String, Functionality> parents = Maps.newHashMap();
List<Functionality> subs = Lists.newArrayList();
for (Functionality f : functionalities) {
// We check if this a sub functionality (a parameter)
if (f.isParam()) {
subs.add(f);
} else {
parents.put(f.getIdentifier(), f);
}
}
Map<String, List<Functionality>> children = new HashMap<String, List<Functionality>>();
for (Functionality func : subs) {
if (parents.containsKey(func.getParentIdentifier())) {
// if parent contains at least one sub functionality to display, the parent must be display.
if (func.isDisplayable()) {
Functionality parent = parents.get(func.getParentIdentifier());
// We need to display the parent functionality to display children
// only if the parent is not forbidden.
if (!parent.getActivationPolicy().isForbidden()) {
parent.setDisplayable(true);
}
}
if (tree) {
parents.get(func.getParentIdentifier()).addChild(func);
}
// storing children in maps
List<Functionality> list = children.get(func.getParentIdentifier());
if (list == null) {
list = Lists.newArrayList();
children.put(func.getParentIdentifier(), list);
}
list.add(func);
} else {
logger.error("Sub functionality {} without a parent : {}", func.getIdentifier(), func.getParentIdentifier());
}
}
List<Functionality> result = Lists.newArrayList();
if (parentId == null) {
result.addAll(parents.values());
} else {
List<Functionality> list = children.get(parentIdentifier.toString());
if (list == null) {
logger.debug("Functionality {} has no children.", parentIdentifier.toString());
return Lists.newArrayList();
}
return list;
}
if (withSubFunctionalities) {
result.addAll(subs);
}
return Iterables.filter(result, isDisplayable());
}
@Override
public Functionality find(Account actor, String domainId, String functionalityId, boolean tree) throws BusinessException {
Validate.notEmpty(domainId);
Validate.notEmpty(functionalityId);
Validate.notNull(actor);
Validate.isTrue(actor.hasAdminRole() || actor.hasSuperAdminRole());
logger.debug("looking for functionality : " + functionalityId + " in domain "+ domainId);
AbstractDomain domain = getDomain(actor, domainId);
Functionality entity = businessService.getFunctionality(domain, functionalityId);
Set<Functionality> functionalities = businessService.getAllFunctionalities(domain, excludes);
for (Functionality f : functionalities) {
if (f.isParam()) {
if (f.getParentIdentifier().equals(functionalityId)) {
// We check if children should by display
if (f.isDisplayable()) {
entity.setDisplayable(true);
if (tree) {
entity.addChild(f);
}
}
}
}
}
if (!entity.isDisplayable()) {
throw new BusinessException(BusinessErrorCode.FUNCTIONALITY_NOT_FOUND, "Functionality not found : " + functionalityId);
}
return entity;
}
@Override
public Functionality find(Account actor, String domainId, String identifier)
throws BusinessException {
return find(actor, domainId, identifier, false);
}
@Override
public void delete(Account actor, String domainId, String functionalityId) throws IllegalArgumentException, BusinessException {
Validate.notNull(actor);
Validate.notEmpty(domainId);
Validate.notEmpty(functionalityId);
Validate.isTrue(actor.hasAdminRole() || actor.hasSuperAdminRole());
Functionality func = find(actor, domainId, functionalityId);
AbstractDomain domain = getDomain(actor, domainId);
checkDeleteRights(domain);
businessService.delete(domainId, functionalityId);
FunctionalityAuditLogEntry log = new FunctionalityAuditLogEntry(actor, LogAction.DELETE,
AuditLogEntryType.FUNCTIONALITY, func);
mongoRepository.insert(log);
}
@Override
public Functionality update(Account actor, String domainId, Functionality functionality) throws BusinessException {
Validate.notEmpty(domainId);
Validate.notNull(functionality);
Validate.notEmpty(functionality.getIdentifier());
Validate.notNull(actor);
Validate.isTrue(actor.hasAdminRole() || actor.hasSuperAdminRole());
// AKO : Some refactoring must be made here, because there actually 3 database calls made by this function
// We have to make only one call find it first, then the business must returns the functionality.
AbstractDomain domain = getDomain(actor, domainId);
if (checkUpdateRights(actor, domain, functionality)) {
businessService.update(domainId, functionality);
}
Functionality func = businessService.getFunctionality(domain, functionality.getIdentifier());
FunctionalityAuditLogEntry log = new FunctionalityAuditLogEntry(actor, LogAction.UPDATE,
AuditLogEntryType.FUNCTIONALITY, func);
mongoRepository.insert(log);
return func;
}
@Override
public Set<Functionality> findAll(Account actor) throws BusinessException {
Validate.notNull(actor);
Set<Functionality> functionalities = businessService
.getAllFunctionalities(actor.getDomain(), excludesForUsers);
return functionalities;
}
@Override
public Functionality find(Account actor, String functionalityId)
throws BusinessException {
Validate.notNull(actor);
Validate.notEmpty(functionalityId);
Validate.isTrue(actor.hasSimpleRole());
Functionality functionality = businessService.getFunctionality(
actor.getDomain(), functionalityId);
return functionality;
}
private Predicate<Functionality> isDisplayable() {
return new Predicate<Functionality>() {
@Override
public boolean apply(Functionality input) {
if(input.isDisplayable()){
return true;
}
logger.debug("Functionality filtered: " + input.getIdentifier());
return false;
}
};
}
}