All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.formkiq.server.service.FolderServiceImpl Maven / Gradle / Ivy

There is a newer version: 0.6.1
Show newest version
/*
 * Copyright (C) 2016 FormKiQ Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.formkiq.server.service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.formkiq.server.dao.AssetDao;
import com.formkiq.server.dao.FolderDao;
import com.formkiq.server.dao.UserDao;
import com.formkiq.server.domain.Asset;
import com.formkiq.server.domain.Folder;
import com.formkiq.server.domain.FolderAccess;
import com.formkiq.server.domain.FolderForm;
import com.formkiq.server.domain.User;
import com.formkiq.server.domain.type.ClientFormType;
import com.formkiq.server.domain.type.FolderDTO;
import com.formkiq.server.domain.type.FolderFormStatus;
import com.formkiq.server.domain.type.FolderFormsListDTO;
import com.formkiq.server.domain.type.FolderListDTO;
import com.formkiq.server.domain.type.FolderPermission;
import com.formkiq.server.domain.type.FolderStatus;
import com.formkiq.server.domain.type.FormDTO;
import com.formkiq.server.domain.type.FormOrderByField;
import com.formkiq.server.domain.type.SortDirection;
import com.formkiq.server.service.dto.ArchiveDTO;
import com.formkiq.server.service.dto.Form;
import com.formkiq.server.service.dto.Workflow;
import com.formkiq.server.util.Zips;

import javassist.bytecode.stackmap.TypeData.ClassName;

/**
 * FormService implementation.
 *
 */
@Service
public class FolderServiceImpl implements FolderService {

    /** Logger. */
    protected static final Logger LOG = Logger.getLogger(ClassName.class
            .getName());

    /** AssetDao. */
    @Autowired
    private AssetDao assetDao;

    /** FolderDao. */
    @Autowired
    private FolderDao folderDao;

    /** JSON Object Mapper. */
    @Autowired
    private Jackson2ObjectMapperBuilder jsonMapper;

    /** SpringSecurityService. */
    @Autowired
    private SpringSecurityService securityService;

    /** UserDao. */
    @Autowired
    private UserDao userDao;

    /**
     * Checks Form Save Permissions.
     * @param user {@link User}
     * @param folder {@link String}
     * @param parentuuid {@link String}
     * @param uuid {@link String}
     * @return {@link Pair}
     */
    private Pair checkFormSavePermissions(
            final User user, final String folder, final String parentuuid,
            final String uuid) {

        Pair pair = this.folderDao.findForm(user,
                folder, uuid);

        FolderForm folderForm = pair.getLeft();
        FolderAccess accessForm = pair.getRight();

        if (accessForm == null && this.securityService.isAdmin()) {

            accessForm = new FolderAccess();
            accessForm.setPermissions(
                    Arrays.asList(FolderPermission.PERM_FORM_ADMIN));

            folderForm = this.folderDao.findForm(folder, uuid);
            pair = Pair.of(folderForm, accessForm);
        }

        if (!StringUtils.isEmpty(parentuuid) && !this.securityService
                .hasPermission(accessForm, FolderPermission.PERM_FORM_ENTRY)) {
            throw new FormAccessDeniedException();
        }

        if (StringUtils.isEmpty(parentuuid) && !this.securityService
                .hasPermission(accessForm, FolderPermission.PERM_FORM_DESIGN)) {
            throw new FormAccessDeniedException();
        }
        return pair;
    }

    @Override
    public void deleteFolder(final UserDetails ud, final String folder) {

        User user = (User) ud;
        FolderAccess access = this.folderDao.findFolderAccess(user, folder);

        if (!this.securityService.hasPermission(access,
                FolderPermission.PERM_FORM_ADMIN)) {
            throw new FormAccessDeniedException();
        }

        if (!this.folderDao.hasFiles(folder)) {

            this.folderDao.deleteFolder(folder);

        } else {

            throw new PreconditionFailedException(
                    "Forms need to be deleted first");
        }
    }

    @Override
    public void deleteFolderFile(final UserDetails ud, final String folder,
            final String uuid, final boolean isparentuuid) {

        User user = (User) ud;
        FolderAccess access = this.folderDao.findFolderAccess(user, folder);

        if (!this.securityService.hasPermission(access,
                FolderPermission.PERM_FORM_ADMIN)) {
            throw new FormAccessDeniedException();
        }

        if (isparentuuid) {

            this.folderDao.deleteForm(folder, uuid, isparentuuid);

        } else if (!this.folderDao.hasFormChildren(folder, uuid)) {

            this.folderDao.deleteForm(folder, uuid, isparentuuid);

        } else {
            throw new PreconditionFailedException(
                    "Sub records need to be deleted first");
        }
    }

    /**
     * Extracts data from a byte[] zip file.
     * @param bytes bytes[]
     * @return {@link ArchiveDTO}
     */
    private ArchiveDTO extractJSONFromZipFile(final byte[] bytes) {

        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
        ZipInputStream zipStream = new ZipInputStream(is);

        ArchiveDTO archive = new ArchiveDTO(this.jsonMapper);

        try {

            ZipEntry entry = null;
            while ((entry = zipStream.getNextEntry()) != null) {

                String filename = entry.getName();
                String data = IOUtils.toString(zipStream);

                if (filename.endsWith(".form")) {

                    archive.addForm(data);

                } else if (filename.endsWith(".workflow")) {

                    archive.addWorkflow(data);
                }
            }

        } catch (IOException e) {
            LOG.log(Level.WARNING, e.getMessage(), e);
            throw new InvalidRequestBodyException();

        } finally {

            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(zipStream);
        }

        return archive;
    }

    @Override
    public FolderDTO findFolder(final UserDetails ud, final String folder) {
        User user = (User) ud;
        FolderDTO dto = this.folderDao.findFolderDTO(user, folder);

        if (dto == null) {
            throw new FormNotFoundException("Folder not found");
        }

        return dto;
    }

    /**
     * Finds a Folder File, and checks permissions.
     * @param folder {@link String}
     * @param uuid {@link String}
     * @param name {@link String}
     * @param parentuuid {@link String}
     * @param lastSha1hash {@link String}
     * @return {@link FolderForm}
     */
    private FolderForm findFolderFile(final String folder, final String uuid,
            final String name, final String parentuuid,
            final String lastSha1hash) {

        User user = (User) this.securityService.getUserDetails();

        Pair pair = checkFormSavePermissions(user,
                folder, parentuuid, uuid);

        FolderForm folderForm = pair.getLeft();

        if (folderForm == null) {

            if (this.folderDao.findFolder(folder) == null) {
                throw new FormAccessDeniedException();
            }

            if (!StringUtils.isEmpty(parentuuid)) {

                pair = checkFormSavePermissions(user, folder, null,
                        parentuuid.toString());

                if (pair.getLeft() == null) {
                    throw new FormNotFoundException(
                            "form " + parentuuid + " not found");
                }
            }

            folderForm = new FolderForm();

        } else if (!StringUtils.hasText(lastSha1hash)) {

            throw new FormNotFoundException("sha1hash parameter required");

        } else if (!lastSha1hash.equals(folderForm.getSha1hash())) {

            throw new FormNotFoundException(name
                    + " has been modified. 'Sync' first and try again.");
        }

        return folderForm;
    }

    @Override
    public FormDTO findForm(final UserDetails ud, final String folder,
            final String uuid) {

        FormDTO dto = null;
        User user = (User) ud;

        FolderAccess access = this.folderDao.findFolderAccess(user, folder);

        if (access != null) {
            dto = this.folderDao.findFormDTO(folder, uuid);
        }

        if (dto == null
                || FolderFormStatus.DELETED.name().equals(dto.getStatus())) {
            throw new FormNotFoundException("Folder not found");
        }

        return dto;
    }

    @Override
    public byte[] findFormData(final String client, final String uuid)
            throws IOException {

        Object[] obj = findFormDataInternal(client, uuid);
        byte[] data = (byte[]) obj[0];

        return data;
    }

    /**
     * Finds Form Data.
     * @param folder {@link String}
     * @param uuid {@link String}
     * @return Object[]
     * @throws IOException IOException
     */
    private Object[] findFormDataInternal(final String folder,
            final String uuid) throws IOException {

        FolderForm clientForm = this.folderDao.findForm(folder, uuid);

        if (clientForm != null) {
            byte[] data = this.assetDao.findAssetData(clientForm.getAssetid());
            return new Object[] { data, clientForm };
        }

        throw new FormNotFoundException("form " + uuid + " not found");
    }

    @Override
    public FolderFormsListDTO findForms(final String folder,
            final String parentUUID, final String text,
            final FormOrderByField orderby, final SortDirection direction,
            final List status, final String token) {

        User user = (User) this.securityService.getUserDetails();
        FolderAccess access = this.folderDao.findFolderAccess(user, folder);

        if (access != null) {
            return this.folderDao.findForms(folder, parentUUID, text, orderby,
                    direction, status, token);
        }

        throw new FormNotFoundException("Folder not found");
    }

    /**
     * Get Folder Form Status.
     * @param draft boolean
     * @return {@link FolderFormStatus}
     */
    private FolderFormStatus getFolderFormStatus(final boolean draft) {
        return draft ? FolderFormStatus.DRAFT : FolderFormStatus.ACTIVE;
    }

    @Override
    public FolderListDTO getFolderList(final UserDetails ud,
            final String token) {
        User user = (User) ud;
        return this.folderDao.findFolderList(user, token);
    }

    @Override
    public UUID saveFolder(final UserDetails ud, final String folder,
            final String foldername) {

        User user = (User) ud;

        if (StringUtils.hasText(folder)) {

            FolderAccess fa = this.folderDao.findFolderAccess(user, folder);

            if (fa != null) {

                if (!this.securityService.hasPermission(fa,
                        FolderPermission.PERM_FORM_ADMIN)) {
                    throw new FormAccessDeniedException();
                }

                Folder f = this.folderDao.findFolder(folder);
                f.setName(foldername);
                this.folderDao.saveFolder(f);
                return f.getFolderid();

            }

            throw new FormNotFoundException(foldername);
        }

        Folder f = new Folder();
        f.setName(foldername);
        this.folderDao.saveFolder(f);

        FolderAccess fa = new FolderAccess();
        fa.setStatus(FolderStatus.ACTIVE);
        fa.setFolderid(f.getFolderid());
        fa.setUserid(user.getUserid());
        fa.setPermissions(Arrays.asList(FolderPermission.PERM_FORM_ADMIN));
        this.folderDao.saveFolderAccess(fa);

        return f.getFolderid();
    }

    @Override
    public String saveForm(final String folder, final byte[] bytes,
            final String lastSha1hash) throws IOException {

        String sha1hash = null;
        ArchiveDTO archive = extractJSONFromZipFile(bytes);

        Workflow wf = archive.getWorkflow();
        List forms = new ArrayList<>();

        if (wf != null) {

            String name = wf.getName();
            String uuid = wf.getUUID();
            String parentuuid = wf.getParentUUID();

            FolderForm form = findFolderFile(folder, uuid, name,
                    parentuuid, lastSha1hash);

            form.setType(ClientFormType.WORKFLOW);
            form.setFolderid(UUID.fromString(folder));
            form.setUUID(UUID.fromString(uuid));
            form.setData(archive.getWorkflowJSON());

            form.setInsertedDate(wf.getInsertedDate());
            form.setUpdatedDate(wf.getUpdatedDate());
            form.setStatus(getFolderFormStatus(wf.isDraft()));

            if (StringUtils.hasText(parentuuid)) {
                form.setParentUUID(UUID.fromString(parentuuid));
            }

            forms.add(form);

            if (StringUtils.isEmpty(parentuuid)) {

                byte[] zipfile = Zips.zipFile(name + ".workflow",
                        archive.getWorkflowJSON());

                updateAsset(form, zipfile, sha1hash);

            } else {

                updateAsset(form, bytes, null);
            }

            sha1hash = form.getSha1hash();

            this.folderDao.saveForm(form);
        }

        for (Map.Entry e : archive.getForms().entrySet()) {

            Form form = e.getValue();
            String name = form.getName();
            String uuid = form.getUUID();
            String parentuuid = form.getParentUUID();
            String data = archive.getFormJSON(uuid);

            FolderForm folderForm = findFolderFile(folder, uuid, name,
                    parentuuid, lastSha1hash);

            folderForm.setType(ClientFormType.FORM);
            folderForm.setFolderid(UUID.fromString(folder));
            folderForm.setUUID(UUID.fromString(uuid));
            folderForm.setData(data);
            folderForm.setStatus(getFolderFormStatus(form.isDraft()));

            folderForm.setInsertedDate(form.getInsertedDate());
            folderForm.setUpdatedDate(form.getUpdatedDate());

            if (StringUtils.hasText(parentuuid)) {
                folderForm.setParentUUID(UUID.fromString(parentuuid));
            }

            forms.add(folderForm);

            if (StringUtils.isEmpty(parentuuid)) {

                byte[] zipfile = Zips.zipFile(form.getName() + ".form", data);

                updateAsset(folderForm, zipfile, sha1hash);
                this.folderDao.saveForm(folderForm);

            } else if (archive.getWorkflow() == null) {

                updateAsset(folderForm, bytes, null);
                this.folderDao.saveForm(folderForm);

            } else {

                folderForm.setSha1hash(sha1hash);
                folderForm.setType(ClientFormType.WORKFLOW_FORM);
                this.folderDao.saveForm(folderForm);
            }
        }

        return forms.get(0).getSha1hash();
    }

    /**
     * Update Asset on FolderForm.
     * @param form {@link FolderForm}
     * @param bytes byte[]
     * @param sha1hash {@link String}
     */
    private void updateAsset(final FolderForm form, final byte[] bytes,
            final String sha1hash) {

        Asset asset = null;
        UUID assetid = form.getAssetid();

        if (assetid != null) {

            asset = this.assetDao.findAsset(assetid);
        }

        if (asset == null) {
            asset = new Asset();
        }

        if (bytes != null) {
            asset.setData(this.userDao.convertToBlob(bytes));
            asset = this.assetDao.saveAsset(asset);

            form.setAssetid(asset.getAssetId());
            form.setSha1hash(DigestUtils.sha1Hex(bytes));
        }

        if (StringUtils.hasText(sha1hash)) {
            form.setSha1hash(sha1hash);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy