com.axelor.dms.db.repo.DMSFileRepository.java Source code

Java tutorial

Introduction

Here is the source code for com.axelor.dms.db.repo.DMSFileRepository.java

Source

/**
 * Axelor Business Solutions
 *
 * Copyright (C) 2005-2016 Axelor (<http://axelor.com>).
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * 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 com.axelor.dms.db.repo;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.persistence.PersistenceException;

import org.apache.shiro.authz.UnauthorizedException;
import org.joda.time.LocalDateTime;

import com.axelor.auth.AuthUtils;
import com.axelor.auth.db.Group;
import com.axelor.auth.db.User;
import com.axelor.common.ClassUtils;
import com.axelor.common.Inflector;
import com.axelor.db.EntityHelper;
import com.axelor.db.JpaRepository;
import com.axelor.db.JpaSecurity;
import com.axelor.db.JpaSecurity.AccessType;
import com.axelor.db.Model;
import com.axelor.db.mapper.Mapper;
import com.axelor.dms.db.DMSFile;
import com.axelor.dms.db.DMSFileTag;
import com.axelor.dms.db.DMSPermission;
import com.axelor.i18n.I18n;
import com.axelor.meta.MetaFiles;
import com.axelor.meta.db.MetaAttachment;
import com.axelor.meta.db.MetaFile;
import com.axelor.meta.db.repo.MetaAttachmentRepository;
import com.axelor.rpc.Resource;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.primitives.Longs;
import com.google.inject.persist.Transactional;

public class DMSFileRepository extends JpaRepository<DMSFile> {

    @Inject
    private MetaFiles metaFiles;

    @Inject
    private JpaSecurity security;

    @Inject
    private DMSPermissionRepository dmsPermissions;

    @Inject
    private MetaAttachmentRepository attachments;

    public DMSFileRepository() {
        super(DMSFile.class);
    }

    @SuppressWarnings("all")
    private Model findRelated(DMSFile file) {
        if (file.getRelatedId() == null || file.getRelatedModel() == null) {
            return null;
        }
        Class<? extends Model> klass = null;
        try {
            klass = (Class) ClassUtils.findClass(file.getRelatedModel());
        } catch (Exception e) {
            return null;
        }
        final Model entity = JpaRepository.of(klass).find(file.getRelatedId());
        return EntityHelper.getEntity(entity);
    }

    @Override
    public DMSFile save(DMSFile entity) {

        final DMSFile parent = entity.getParent();
        final Model related = findRelated(entity);
        final boolean isAttachment = related != null && entity.getMetaFile() != null;

        // if new attachment, save attachment reference
        if (isAttachment) {
            // remove old attachment if file is moved
            MetaAttachment attachmentOld = attachments.all()
                    .filter("self.metaFile.id = ? AND self.objectId != ? AND self.objectName != ?",
                            entity.getMetaFile().getId(), related.getId(), related.getClass().getName())
                    .fetchOne();
            if (attachmentOld != null) {
                System.err.println("OLD: " + attachmentOld);
                attachments.remove(attachmentOld);
            }

            MetaAttachment attachment = attachments.all()
                    .filter("self.metaFile.id = ? AND self.objectId = ? AND self.objectName = ?",
                            entity.getMetaFile().getId(), related.getId(), related.getClass().getName())
                    .fetchOne();
            if (attachment == null) {
                attachment = metaFiles.attach(entity.getMetaFile(), related);
                attachments.save(attachment);
            }
        }

        // if not an attachment or has parent, do nothing
        if (parent != null || related == null) {
            return super.save(entity);
        }

        // create parent folders

        Mapper mapper = Mapper.of(related.getClass());
        String homeName = null;
        try {
            homeName = mapper.getNameField().get(related).toString();
        } catch (Exception e) {
        }
        if (homeName == null) {
            homeName = Strings.padStart("" + related.getId(), 5, '0');
        }

        DMSFile dmsRoot = all().filter(
                "(self.relatedId is null OR self.relatedId = 0) AND self.relatedModel = ? and self.isDirectory = true",
                entity.getRelatedModel()).fetchOne();

        final Inflector inflector = Inflector.getInstance();

        if (dmsRoot == null) {
            dmsRoot = new DMSFile();
            dmsRoot.setFileName(inflector.pluralize(inflector.humanize(related.getClass().getSimpleName())));
            dmsRoot.setRelatedModel(entity.getRelatedModel());
            dmsRoot.setIsDirectory(true);
            dmsRoot = super.save(dmsRoot); // should get id before it's child
        }

        DMSFile dmsHome = new DMSFile();
        dmsHome.setFileName(homeName);
        dmsHome.setRelatedId(entity.getRelatedId());
        dmsHome.setRelatedModel(entity.getRelatedModel());
        dmsHome.setParent(dmsRoot);
        dmsHome.setIsDirectory(true);
        dmsHome = super.save(dmsHome); // should get id before it's child

        entity.setParent(dmsHome);

        return super.save(entity);
    }

    @Override
    public void remove(DMSFile entity) {
        // remove all children
        if (entity.getIsDirectory() == Boolean.TRUE) {
            final List<DMSFile> children = all().filter("self.parent.id = ?", entity.getId()).fetch();
            for (DMSFile child : children) {
                if (child != entity) {
                    remove(child);
                    ;
                }
            }
        }

        // remove attached file
        if (entity.getMetaFile() != null) {
            final MetaFile metaFile = entity.getMetaFile();
            long count = attachments.all().filter("self.metaFile = ?", metaFile).count();
            if (count == 1) {
                final MetaAttachment attachment = attachments.all().filter("self.metaFile = ?", metaFile)
                        .fetchOne();
                attachments.remove(attachment);
            }
            count = all().filter("self.metaFile = ?", metaFile).count();
            if (count == 1) {
                entity.setMetaFile(null);
                try {
                    metaFiles.delete(metaFile);
                } catch (IOException e) {
                    throw new PersistenceException(e);
                }
            }
        }

        super.remove(entity);
    }

    private DMSFile findFrom(Map<String, Object> json) {
        if (json == null || json.get("id") == null) {
            return null;
        }
        final Long id = Longs.tryParse(json.get("id").toString());
        return find(id);
    }

    private boolean canCreate(DMSFile parent) {
        final User user = AuthUtils.getUser();
        final Group group = user.getGroup();
        if (parent.getCreatedBy() == user || security.hasRole("role.super") || security.hasRole("role.admin")) {
            return true;
        }
        return dmsPermissions.all()
                .filter("self.file = :file AND self.permission.canWrite = true AND "
                        + "(self.user = :user OR self.group = :group)")
                .bind("file", parent).bind("user", user).bind("group", group).autoFlush(false).count() > 0;
    }

    private boolean canOffline(DMSFile file, User user) {
        return file.getIsDirectory() != Boolean.TRUE && file.getMetaFile() != null && dmsPermissions.all()
                .filter("self.file = ? AND self.value = 'OFFLINE' AND self.user = ?", file, user).count() > 0;
    }

    @Transactional
    public DMSFile setOffline(DMSFile file, boolean offline) {
        Preconditions.checkNotNull(file, "file can't be null");

        // directory can't be marked as offline
        if (file.getIsDirectory() == Boolean.TRUE) {
            return file;
        }

        final User user = AuthUtils.getUser();
        boolean canOffline = canOffline(file, user);

        if (offline == canOffline) {
            return file;
        }

        DMSPermission permission;

        if (offline) {
            permission = new DMSPermission();
            permission.setValue("OFFLINE");
            permission.setFile(file);
            permission.setUser(user);
            file.addPermission(permission);
        } else {
            permission = dmsPermissions.all()
                    .filter("self.file = ? AND self.value = 'OFFLINE' AND self.user = ?", file, user).fetchOne();
            file.removePermission(permission);
            dmsPermissions.remove(permission);
        }

        return this.save(file);
    }

    public List<DMSFile> findOffline(int limit, int offset) {
        return all().filter("self.permissions[].value = 'OFFLINE' AND self.permissions[].user = :user")
                .bind("user", AuthUtils.getUser()).fetch(limit, offset);
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> validate(Map<String, Object> json, Map<String, Object> context) {
        final DMSFile file = findFrom(json);
        final DMSFile parent = findFrom((Map<String, Object>) json.get("parent"));
        if (parent == null) {
            return json;
        }
        if (file != null && file.getParent() == parent) {
            return json;
        }

        // check whether user can create/move document here
        if (file == null && !canCreate(parent)) {
            throw new UnauthorizedException(I18n.get("You can't create document here."));
        }
        if (file != null && file.getParent() != parent && !canCreate(parent)) {
            throw new UnauthorizedException(I18n.get("You can't move document here."));
        }

        return json;
    }

    @Override
    public Map<String, Object> populate(Map<String, Object> json, Map<String, Object> context) {
        final DMSFile file = findFrom(json);
        if (file == null) {
            return json;
        }

        boolean isFile = file.getIsDirectory() != Boolean.TRUE;
        LocalDateTime dt = file.getUpdatedOn();
        if (dt == null) {
            dt = file.getCreatedOn();
        }

        final User user = AuthUtils.getUser();
        final MetaFile metaFile = file.getMetaFile();

        boolean canShare = file.getCreatedBy() == user
                || security.isPermitted(AccessType.CREATE, DMSFile.class, file.getId())
                || dmsPermissions.all()
                        .filter("self.file = ? AND self.value = 'FULL' AND (self.user = ? OR self.group = ?)", file,
                                user, user.getGroup())
                        .count() > 0;

        json.put("typeIcon", isFile ? "fa fa-file" : "fa fa-folder");
        json.put("downloadIcon", "fa fa-download");
        json.put("detailsIcon", "fa fa-info-circle");

        json.put("canShare", canShare);
        json.put("canWrite", canCreate(file));

        if (canOffline(file, user)) {
            json.put("offline", true);
        }

        json.put("lastModified", dt);
        json.put("createdOn", file.getCreatedOn());
        json.put("createdBy", file.getCreatedBy());
        json.put("updatedBy", file.getUpdatedBy());
        json.put("updatedOn", file.getUpdatedOn());

        if ("html".equals(file.getContentType())) {
            json.put("fileType", "text/html");
            json.put("contentType", "html");
            json.put("typeIcon", "fa fa-file-text-o");
            json.remove("downloadIcon");
        }
        if ("spreadsheet".equals(file.getContentType())) {
            json.put("fileType", "text/json");
            json.put("contentType", "spreadsheet");
            json.put("typeIcon", "fa fa-file-excel-o");
            json.remove("downloadIcon");
        }

        if (metaFile != null) {

            String fileType = metaFile.getFileType();
            String fileIcon = "fa-file-o";

            switch (fileType) {
            case "application/msword":
            case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
            case "application/vnd.oasis.opendocument.text":
                fileIcon = "fa-file-word-o";
                break;
            case "application/vnd.ms-excel":
            case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
            case "application/vnd.oasis.opendocument.spreadsheet":
                fileIcon = "fa-file-excel-o";
                break;
            case "application/pdf":
                fileIcon = "fa-file-pdf-o";
                break;
            case "application/zip":
            case "application/gzip":
                fileIcon = "fa-file-archive-o";
                break;
            default:
                String type = metaFile.getFileType();
                if (type != null) {
                    if (type.startsWith("text"))
                        fileIcon = "fa-file-text-o";
                    if (type.startsWith("image"))
                        fileIcon = "fa-file-image-o";
                    if (type.startsWith("video"))
                        fileIcon = "fa-file-video-o";
                }
                break;
            }

            json.put("fileType", fileType);
            json.put("typeIcon", "fa " + fileIcon);
        }

        if (file.getTags() != null) {
            final List<Object> tags = new ArrayList<>();
            for (DMSFileTag tag : file.getTags()) {
                tags.add(Resource.toMap(tag, "id", "code", "name", "style"));
            }
            json.put("tags", tags);
        }

        return json;
    }
}