/* * 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.io.File; import java.io.InputStream; import java.util.Calendar; import java.util.List; import org.apache.commons.lang.Validate; import org.linagora.linshare.core.business.service.DocumentEntryBusinessService; import org.linagora.linshare.core.business.service.OperationHistoryBusinessService; import org.linagora.linshare.core.dao.MimeTypeMagicNumberDao; import org.linagora.linshare.core.domain.constants.AuditLogEntryType; import org.linagora.linshare.core.domain.constants.ContainerQuotaType; import org.linagora.linshare.core.domain.constants.LogAction; import org.linagora.linshare.core.domain.constants.LogActionCause; import org.linagora.linshare.core.domain.constants.OperationHistoryTypeEnum; import org.linagora.linshare.core.domain.entities.AbstractDomain; import org.linagora.linshare.core.domain.entities.Account; import org.linagora.linshare.core.domain.entities.AnonymousShareEntry; import org.linagora.linshare.core.domain.entities.AntivirusLogEntry; import org.linagora.linshare.core.domain.entities.BooleanValueFunctionality; import org.linagora.linshare.core.domain.entities.DocumentEntry; import org.linagora.linshare.core.domain.entities.Functionality; import org.linagora.linshare.core.domain.entities.LogEntry; import org.linagora.linshare.core.domain.entities.OperationHistory; import org.linagora.linshare.core.domain.entities.ShareEntry; import org.linagora.linshare.core.domain.entities.StringValueFunctionality; import org.linagora.linshare.core.domain.entities.SystemAccount; import org.linagora.linshare.core.domain.objects.MailContainerWithRecipient; import org.linagora.linshare.core.domain.objects.TimeUnitValueFunctionality; import org.linagora.linshare.core.exception.BusinessErrorCode; import org.linagora.linshare.core.exception.BusinessException; import org.linagora.linshare.core.exception.TechnicalErrorCode; import org.linagora.linshare.core.exception.TechnicalException; import org.linagora.linshare.core.rac.DocumentEntryResourceAccessControl; import org.linagora.linshare.core.service.AbstractDomainService; import org.linagora.linshare.core.service.AntiSamyService; import org.linagora.linshare.core.service.DocumentEntryService; import org.linagora.linshare.core.service.FunctionalityReadOnlyService; import org.linagora.linshare.core.service.LogEntryService; import org.linagora.linshare.core.service.MailBuildingService; import org.linagora.linshare.core.service.MimeTypeService; import org.linagora.linshare.core.service.NotifierService; import org.linagora.linshare.core.service.QuotaService; import org.linagora.linshare.core.service.VirusScannerService; import org.linagora.linshare.mongo.entities.EventNotification; import org.linagora.linshare.mongo.entities.logs.AuditLogEntryUser; import org.linagora.linshare.mongo.entities.logs.DocumentEntryAuditLogEntry; import org.linagora.linshare.mongo.entities.logs.ShareEntryAuditLogEntry; import org.linagora.linshare.mongo.entities.mto.DocumentMto; import com.google.common.collect.Lists; public class DocumentEntryServiceImpl extends GenericEntryServiceImpl<Account, DocumentEntry> implements DocumentEntryService { private final DocumentEntryBusinessService documentEntryBusinessService; private final OperationHistoryBusinessService operationHistoryBusinessService; private final LogEntryService logEntryService; private final AbstractDomainService abstractDomainService; private final FunctionalityReadOnlyService functionalityReadOnlyService; private final MimeTypeService mimeTypeService; private final VirusScannerService virusScannerService; private final MimeTypeMagicNumberDao mimeTypeIdentifier; private final AntiSamyService antiSamyService; private final MailBuildingService mailBuildingService; private final NotifierService notifierService; private final Long virusscannerLimitFilesize; private final QuotaService quotaService; public DocumentEntryServiceImpl( DocumentEntryBusinessService documentEntryBusinessService, LogEntryService logEntryService, AbstractDomainService abstractDomainService, FunctionalityReadOnlyService functionalityReadOnlyService, MimeTypeService mimeTypeService, VirusScannerService virusScannerService, MimeTypeMagicNumberDao mimeTypeIdentifier, AntiSamyService antiSamyService, DocumentEntryResourceAccessControl rac, MailBuildingService mailBuildingService, NotifierService notifierService, Long virusscannerLimitFilesize, OperationHistoryBusinessService operationHistoryBusinessService, QuotaService quotaService) { super(rac); this.documentEntryBusinessService = documentEntryBusinessService; this.operationHistoryBusinessService = operationHistoryBusinessService; this.logEntryService = logEntryService; this.abstractDomainService = abstractDomainService; this.functionalityReadOnlyService = functionalityReadOnlyService; this.mimeTypeService = mimeTypeService; this.virusScannerService = virusScannerService; this.mimeTypeIdentifier = mimeTypeIdentifier; this.antiSamyService = antiSamyService; this.mailBuildingService = mailBuildingService; this.notifierService = notifierService; this.virusscannerLimitFilesize = virusscannerLimitFilesize; this.quotaService = quotaService; } @Override public DocumentEntry find(Account actor, Account owner, String uuid) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(uuid, "Missing document entry uuid"); DocumentEntry entry = documentEntryBusinessService.find(uuid); if (entry == null) { logger.error("Current actor " + actor.getAccountRepresentation() + " is looking for a misssing document entry (" + uuid + ") owned by : " + owner.getAccountRepresentation()); String message = "Can not find document entry with uuid : " + uuid; throw new BusinessException( BusinessErrorCode.DOCUMENT_ENTRY_NOT_FOUND, message); } checkReadPermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, entry); return entry; } @Override public List<DocumentEntry> findAll(Account actor, Account owner) throws BusinessException { preChecks(actor, owner); checkListPermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, null); return documentEntryBusinessService.findAllMyDocumentEntries(owner); } @Override public List<DocumentEntry> findAllMySyncEntries(Account actor, Account owner) throws BusinessException { preChecks(actor, owner); checkListPermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, null); return documentEntryBusinessService.findAllMySyncEntries(owner); } @Override public DocumentEntry create(Account actor, Account owner, File tempFile, String fileName, String comment, boolean isFromCmis, String metadata) throws BusinessException { return create(actor, owner, tempFile, fileName, comment, false, isFromCmis, metadata); } @Override public DocumentEntry create(Account actor, Account owner, File tempFile, String fileName, String comment, boolean forceAntivirusOff, boolean isFromCmis, String metadata) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(fileName, "fileName is required."); checkCreatePermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, null); DocumentEntry docEntry = null; try { fileName = sanitizeFileName(fileName); Long size = tempFile.length(); checkSpace(owner, size); // detect file's mime type. String mimeType = mimeTypeIdentifier.getMimeType(tempFile); // check if the file MimeType is allowed if (mimeTypeFilteringStatus(owner)) { mimeTypeService.checkFileMimeType(owner, fileName, mimeType); } if (!forceAntivirusOff) { Functionality antivirusFunctionality = functionalityReadOnlyService .getAntivirusFunctionality(owner.getDomain()); if (antivirusFunctionality.getActivationPolicy().getStatus()) { checkVirus(fileName, owner, tempFile, size); } } // want a timestamp on doc ? String timeStampingUrl = null; StringValueFunctionality timeStampingFunctionality = functionalityReadOnlyService .getTimeStampingFunctionality(owner.getDomain()); if (timeStampingFunctionality.getActivationPolicy().getStatus()) { timeStampingUrl = timeStampingFunctionality.getValue(); } Functionality enciphermentFunctionality = functionalityReadOnlyService .getEnciphermentFunctionality(owner.getDomain()); Boolean checkIfIsCiphered = enciphermentFunctionality .getActivationPolicy().getStatus(); // We need to set an expiration date in case of file cleaner // activation. docEntry = documentEntryBusinessService.createDocumentEntry(owner, tempFile, size, fileName, comment, checkIfIsCiphered, timeStampingUrl, mimeType, getDocumentExpirationDate(owner.getDomain()), isFromCmis, metadata); addToQuota(owner, size); } finally { try { logger.debug("deleting temp file : " + tempFile.getName()); if (tempFile.exists()) { tempFile.delete(); // remove the temporary file } } catch (Exception e) { logger.error("can not delete temp file : " + e.getMessage()); } } DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, docEntry, LogAction.CREATE); logEntryService.insert(log); return docEntry; } @Override public boolean mimeTypeFilteringStatus(Account actor) throws BusinessException { AbstractDomain domain = abstractDomainService.retrieveDomain(actor.getDomain().getUuid()); Functionality mimeFunctionality = functionalityReadOnlyService.getMimeTypeFunctionality(domain); return mimeFunctionality.getActivationPolicy().getStatus(); } @Override public DocumentEntry update(Account actor, Account owner, String docEntryUuid, File tempFile, String fileName) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(docEntryUuid, "document entry uuid is required."); DocumentEntry originalEntry = find(actor, owner, docEntryUuid); long newDocSize = tempFile.length(); long oldDocSize = originalEntry.getSize(); // new size minus old size to compute delta. long delta = newDocSize -oldDocSize; checkSpace(owner, delta); DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, originalEntry, LogAction.UPDATE); String originalFileName = originalEntry.getName(); if (fileName == null || fileName.isEmpty()) { fileName = originalFileName; } checkUpdatePermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, originalEntry); fileName = sanitizeFileName(fileName); // throws DocumentEntry documentEntry = null; try { String mimeType = mimeTypeIdentifier.getMimeType(tempFile); // check if the file MimeType is allowed Functionality mimeFunctionality = functionalityReadOnlyService .getMimeTypeFunctionality(owner.getDomain()); if (mimeFunctionality.getActivationPolicy().getStatus()) { mimeTypeService.checkFileMimeType(owner, fileName, mimeType); } Functionality antivirusFunctionality = functionalityReadOnlyService .getAntivirusFunctionality(owner.getDomain()); if (antivirusFunctionality.getActivationPolicy().getStatus()) { checkVirus(fileName, owner, tempFile, newDocSize); } // want a timestamp on doc ? String timeStampingUrl = null; StringValueFunctionality timeStampingFunctionality = functionalityReadOnlyService .getTimeStampingFunctionality(owner.getDomain()); if (timeStampingFunctionality.getActivationPolicy().getStatus()) { timeStampingUrl = timeStampingFunctionality.getValue(); } Functionality enciphermentFunctionality = functionalityReadOnlyService .getEnciphermentFunctionality(owner.getDomain()); Boolean checkIfIsCiphered = enciphermentFunctionality .getActivationPolicy().getStatus(); // We need to set an expiration date in case of file cleaner // activation. documentEntry = documentEntryBusinessService.updateDocumentEntry( owner, originalEntry, tempFile, newDocSize, fileName, checkIfIsCiphered, timeStampingUrl, mimeType, getDocumentExpirationDate(owner.getDomain())); // add new resource to the log entry log.setResourceUpdated(new DocumentMto(documentEntry)); logEntryService.insert(log); addToQuota(owner, newDocSize, oldDocSize); if(documentEntry.getShared() > 0) { // send email, file has been replaced .... // When a shared file is updated, we need to log and notify recipients. List<AuditLogEntryUser> logs = Lists.newArrayList(); List<EventNotification> events = Lists.newArrayList(); List<MailContainerWithRecipient> mails = Lists.newArrayList(); for (AnonymousShareEntry anonymousShareEntry : documentEntry .getAnonymousShareEntries()) { mails.add(mailBuildingService.buildSharedDocUpdated( anonymousShareEntry, originalFileName, documentEntry.getSize())); ShareEntryAuditLogEntry shareLog = new ShareEntryAuditLogEntry(actor, owner, LogAction.UPDATE, anonymousShareEntry, AuditLogEntryType.SHARE_ENTRY); shareLog.setTechnicalComment("update of the underlying document"); logs.add(shareLog); } for (ShareEntry shareEntry : documentEntry.getShareEntries()) { mails.add(mailBuildingService.buildSharedDocUpdated( shareEntry, originalFileName, documentEntry.getSize())); ShareEntryAuditLogEntry shareLog = new ShareEntryAuditLogEntry(actor, owner, LogAction.UPDATE, shareEntry, AuditLogEntryType.SHARE_ENTRY); shareLog.setTechnicalComment("update of the underlying document"); // The recipient must be notified (events) and aware (logs) of this modification. String recipientUuid = shareEntry.getRecipient().getLsUuid(); shareLog.addRelatedAccounts(recipientUuid); logs.add(shareLog); events.add(new EventNotification(shareLog, recipientUuid)); } logEntryService.insert(logs, events); notifierService.sendNotification(mails); } } finally { try { logger.debug("deleting temp file : " + tempFile.getName()); tempFile.delete(); // remove the temporary file } catch (Exception e) { logger.error("can not delete temp file : " + e.getMessage()); } } return documentEntry; } protected Calendar getDocumentExpirationDate(AbstractDomain domain) { return functionalityReadOnlyService.getDefaultFileExpiryTime(domain); } @Override public void deleteInconsistentDocumentEntry(SystemAccount actor, DocumentEntry documentEntry) throws BusinessException { checkDeletePermission(actor, null, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, documentEntry); Account owner = documentEntry.getEntryOwner(); try { if (documentEntryBusinessService .getRelatedEntriesCount(documentEntry) > 0) { throw new BusinessException(BusinessErrorCode.FORBIDDEN, "You are not authorized to delete this document. It still exists shares."); } documentEntryBusinessService.deleteDocumentEntry(documentEntry); DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, documentEntry, LogAction.DELETE); log.setCause(LogActionCause.INCONSISTENCY); log.setTechnicalComment("File removed because of inconsistence. Please contact your administrator."); logEntryService.insert(LogEntryService.WARN, log); // update quota manager. delFromQuota(owner, documentEntry.getSize()); } catch (IllegalArgumentException e) { logger.error( "Could not delete file " + documentEntry.getName() + " of user " + owner.getLsUuid() + ", reason : ", e); throw new TechnicalException( TechnicalErrorCode.COULD_NOT_DELETE_DOCUMENT, "Could not delete document"); } } @Override public void deleteExpiredDocumentEntry(SystemAccount actor, DocumentEntry documentEntry) throws BusinessException { checkDeletePermission(actor, null, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, documentEntry); Account owner = documentEntry.getEntryOwner(); try { if (documentEntryBusinessService .getRelatedEntriesCount(documentEntry) > 0) { throw new BusinessException(BusinessErrorCode.FORBIDDEN, "You are not authorized to delete this document. It still exists shares."); } documentEntryBusinessService.deleteDocumentEntry(documentEntry); // LogAction.FILE_EXPIRE DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, documentEntry, LogAction.DELETE); log.setTechnicalComment("Expiration of a file"); log.setCause(LogActionCause.EXPIRATION); logEntryService.insert(log); // update quota manager. delFromQuota(owner, documentEntry.getSize()); } catch (IllegalArgumentException e) { logger.error( "Could not delete file " + documentEntry.getName() + " of user " + owner.getLsUuid() + ", reason : ", e); throw new TechnicalException( TechnicalErrorCode.COULD_NOT_DELETE_DOCUMENT, "Could not delete document"); } } @Override public DocumentEntry delete(Account actor, Account owner, String documentUuid) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(documentUuid, "documentUuid is required."); logger.debug("Actor: " + actor.getAccountRepresentation() + " is trying to delete document entry: " + documentUuid); DocumentEntry documentEntry = find(actor, owner, documentUuid); checkDeletePermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, documentEntry); if (documentEntryBusinessService .getRelatedEntriesCount(documentEntry) > 0) { throw new BusinessException(BusinessErrorCode.FORBIDDEN, "You are not authorized to delete this document. There's still existing shares."); } documentEntryBusinessService.deleteDocumentEntry(documentEntry); DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, documentEntry, LogAction.DELETE); logEntryService.insert(log); // update quota manager. delFromQuota(owner, documentEntry.getSize()); return documentEntry; } @Override public InputStream getDocumentThumbnailStream(Account actor, Account owner, String uuid) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(uuid, "document entry uuid is required."); DocumentEntry entry = find(actor, owner, uuid); checkThumbNailDownloadPermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, entry); return documentEntryBusinessService.getDocumentThumbnailStream(entry); } @Override public InputStream getDocumentStream(Account actor, Account owner, String uuid) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(uuid, "document entry uuid is required."); DocumentEntry entry = find(actor, owner, uuid); checkDownloadPermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, entry); if (!actor.equals(owner)) { // If it is not the current owner, it could be useful to warn the owner. DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, entry, LogAction.DOWNLOAD); EventNotification event = new EventNotification(log, owner.getLsUuid()); logEntryService.insert(log, event); } try { return documentEntryBusinessService.getDocumentStream(entry); } catch (Exception e) { logger.error(e.getMessage(), e); throw new BusinessException(BusinessErrorCode.FILE_UNREACHABLE, "no stream available."); } } @Override public void checkDownloadPermission(Account actor, Account owner, String uuid) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(uuid, "document entry uuid is required."); DocumentEntry entry = find(actor, owner, uuid); checkDownloadPermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, entry); } @Override public void renameDocumentEntry(Account actor, Account owner, String uuid, String newName) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(uuid, "document entry uuid is required."); Validate.notEmpty(newName, "new name is required."); DocumentEntry entry = find(actor, owner, uuid); checkUpdatePermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, entry); DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, entry, LogAction.UPDATE); DocumentEntry res = documentEntryBusinessService.renameDocumentEntry(entry, newName); log.setResourceUpdated(new DocumentMto(res)); logEntryService.insert(log); } @Override public DocumentEntry updateFileProperties(Account actor, Account owner, String uuid, String newName, String fileComment, String meta) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(uuid, "document entry uuid is required."); Validate.notEmpty(newName, "new name is required."); DocumentEntry entry = find(actor, owner, uuid); // on Tapestry interface update event, we have to check the value // of the metadata field to avoid overwriting the database value to null if (meta == null) { meta = entry.getMetaData(); } if (fileComment == null) { fileComment = entry.getComment(); } checkUpdatePermission(actor, owner, DocumentEntry.class, BusinessErrorCode.DOCUMENT_ENTRY_FORBIDDEN, entry); DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, owner, entry, LogAction.UPDATE); DocumentEntry res = documentEntryBusinessService.updateFileProperties(entry, newName, fileComment, meta); log.setResourceUpdated(new DocumentMto(res)); logEntryService.insert(log); return res; } @Override public void updateFileProperties(Account actor, String docEntryUuid, String newName, String fileComment, boolean isFromCmisSync) throws BusinessException { DocumentEntry entry = documentEntryBusinessService .find(docEntryUuid); if (!actor.hasSuperAdminRole() && !actor.hasSystemAccountRole()) { if (!entry.getEntryOwner().equals(actor)) { throw new BusinessException(BusinessErrorCode.FORBIDDEN, "You are not authorized to update this document."); } } DocumentEntryAuditLogEntry log = new DocumentEntryAuditLogEntry(actor, actor, entry, LogAction.UPDATE); if (!isFromCmisSync) entry.setCmisSync(false); else { documentEntryBusinessService.syncUniqueDocument(actor, newName); entry.setCmisSync(true); } DocumentEntry res = documentEntryBusinessService.updateFileProperties(entry, newName, fileComment, null); log.setResourceUpdated(new DocumentMto(res)); logEntryService.insert(log); } private String sanitizeFileName(String fileName) throws BusinessException { fileName = fileName.replace("\\", "_"); fileName = fileName.replace(":", "_"); fileName = antiSamyService.clean(fileName); if (fileName.isEmpty()) { throw new BusinessException(BusinessErrorCode.INVALID_FILENAME, "fileName is empty after the xss filter"); } return fileName; } private Boolean checkVirus(String fileName, Account owner, File file, Long size) throws BusinessException { if (logger.isDebugEnabled()) { logger.debug("antivirus activation:" + !virusScannerService.isDisabled()); } if (virusscannerLimitFilesize != null && size > virusscannerLimitFilesize) { if (logger.isDebugEnabled()) { logger.debug("antivirus skipped."); } return true; } boolean checkStatus = false; try { checkStatus = virusScannerService.check(file); } catch (TechnicalException e) { LogEntry logEntry = new AntivirusLogEntry(owner, LogAction.ANTIVIRUS_SCAN_FAILED, e.getMessage()); logger.error( "File scan failed: antivirus enabled but not available ?"); logEntryService.create(LogEntryService.ERROR, logEntry); throw new BusinessException(BusinessErrorCode.FILE_SCAN_FAILED, "File scan failed", e); } if (logger.isDebugEnabled()) { logger.debug("antivirus scan result : " + checkStatus); } // check if the file contains virus if (!checkStatus) { LogEntry logEntry = new AntivirusLogEntry(owner, LogAction.FILE_WITH_VIRUS, fileName); logEntryService.create(LogEntryService.WARN, logEntry); logger.warn(owner.getLsUuid() + " tried to upload a file containing virus:" + fileName); String[] extras = { fileName }; throw new BusinessException(BusinessErrorCode.FILE_CONTAINS_VIRUS, "File contains virus", extras); } return checkStatus; } @Override public DocumentEntry findMoreRecentByName(Account actor, Account owner, String fileName) throws BusinessException { preChecks(actor, owner); Validate.notEmpty(fileName, "document entry name is required."); return documentEntryBusinessService.findMoreRecentByName(owner, fileName); } @Override public long getRelatedEntriesCount(Account actor, Account owner, DocumentEntry documentEntry) { preChecks(actor, owner); return documentEntryBusinessService.getRelatedEntriesCount(documentEntry); } @Override public void deleteOrComputeExpiryDate(SystemAccount actor, AbstractDomain domain, DocumentEntry documentEntry) { if (documentEntry.getShared() <= 0 ) { BooleanValueFunctionality deleteShareFunc= functionalityReadOnlyService.getDefaultShareExpiryTimeDeletionFunctionality(domain); // Test if we have to remove the document now. if (deleteShareFunc.getValue()) { logger.debug("Current document entry " + documentEntry.getRepresentation() + " need to be deleted."); deleteExpiredDocumentEntry(actor, documentEntry); } else { TimeUnitValueFunctionality fileExpirationFunc = functionalityReadOnlyService.getDefaultFileExpiryTimeFunctionality(domain); Calendar deletionDate = Calendar.getInstance(); deletionDate.add(fileExpirationFunc.toCalendarValue(), fileExpirationFunc.getValue()); documentEntry.setExpirationDate(deletionDate); documentEntryBusinessService.update(documentEntry); } } } @Override public List<String> findAllExpiredEntries(Account actor, Account owner) { preChecks(actor, owner); if (!actor.hasAllRights()) { throw new BusinessException(BusinessErrorCode.FORBIDDEN, "You do not have the right to use this method."); } return documentEntryBusinessService.findAllExpiredEntries(); } protected void checkSpace(Account owner, long size) throws BusinessException { quotaService.checkIfUserCanAddFile(owner, size, ContainerQuotaType.USER); } protected void addToQuota(Account owner, Long size) { OperationHistory oh = new OperationHistory(owner, owner.getDomain(), size, OperationHistoryTypeEnum.CREATE, ContainerQuotaType.USER); operationHistoryBusinessService.create(oh); } protected void delFromQuota(Account owner, Long size) { OperationHistory oh = new OperationHistory(owner, owner.getDomain(), - size, OperationHistoryTypeEnum.DELETE, ContainerQuotaType.USER); operationHistoryBusinessService.create(oh); } protected void addToQuota(Account owner, long newDocSize, long oldDocSize) { delFromQuota(owner, oldDocSize); addToQuota(owner, newDocSize); } }