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

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

/*
 * 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.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
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 java.util.zip.ZipOutputStream;

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.FolderFormsListDTO;
import com.formkiq.server.domain.type.FolderListDTO;
import com.formkiq.server.domain.type.FolderPermission;
import com.formkiq.server.domain.type.FormDTO;
import com.formkiq.server.domain.type.SyncListDTO;
import com.formkiq.server.domain.type.UserRole;
import com.formkiq.server.service.dto.ArchiveDTO;
import com.formkiq.server.service.dto.Workflow;

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 UUID}
     * @param uuid {@link String}
     * @return {@link Pair}
     */
    private Pair checkFormSavePermissions(
            final User user, final String folder, final UUID 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 (parentuuid != null && !this.securityService
                .hasPermission(accessForm, FolderPermission.PERM_FORM_ENTRY)) {
            throw new FormAccessDeniedException();
        }

        if (parentuuid == null && !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) {

        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.hasFormChildren(folder, uuid)) {

            this.folderDao.deleteForm(folder, uuid);

        } 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;
    }

    @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) {
            throw new FormNotFoundException("Folder not found");
        }

        return dto;
    }

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

        Map map = new HashMap();

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

        FolderForm clientForm = (FolderForm) obj[1];

        if (ClientFormType.WORKFLOW.equals(clientForm.getType())) {

            Workflow workflow = this.jsonMapper.build()
                    .readValue(clientForm.getData(), Workflow.class);

            for (String formUUID : workflow.getSteps()) {

                obj = findFormDataInternal(client, formUUID);
                byte[] formdata = (byte[]) obj[0];
                map.put(formUUID, formdata);
            }
        }

        if (map.size() > 1) {
            return zipFile(map);
        }

        return map.values().iterator().next();
    }

    /**
     * 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 token) {
        return this.folderDao.findForms(folder, token);
    }

    @Override
    public FolderFormsListDTO findForms(final String folder,
            final String form, final String token) {
        return this.folderDao.findForms(folder, form, token);
    }

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

    @Override
    public SyncListDTO getSyncList(final UserDetails ud,
            final ClientFormType type, final String folder,
            final String nextToken) {

        User user = (User) ud;

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

        if (this.securityService.hasPermission(fa,
                FolderPermission.PERM_FORM_RESULTS)) {

            return this.folderDao.findFormSyncList(type, folder, nextToken);
        }

        throw new FormAccessDeniedException();
    }

    @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.setFolderid(f.getFolderid());
        fa.setUserid(user.getUserid());
        fa.setPermissions(Arrays.asList(FolderPermission.PERM_FORM_ADMIN));
        this.folderDao.saveFolderAccess(fa);

        return f.getFolderid();
    }

    /**
     * Saves Form.
     * @param archive {@link ArchiveDTO}
     * @param folderForm {@link FolderForm}
     * @param folder {@link String}
     * @param bytes byte[]
     */
    private void saveForm(final ArchiveDTO archive, final FolderForm folderForm,
            final String folder, final byte[] bytes) {

        UUID uuid = archive.getUUID();
        UUID parentuuid = archive.getParentUUID();

        ClientFormType type = archive.isFormJSON() ? ClientFormType.FORM
                : ClientFormType.WORKFLOW;

        String data = archive.getData();
        Date insertedDate = archive.getInsertedDate();
        Date updatedDate = archive.getUpdatedDate();

        folderForm.setType(type);
        folderForm.setFolderid(UUID.fromString(folder));
        folderForm.setUUID(uuid);
        folderForm.setData(data);

        folderForm.setInsertedDate(insertedDate);
        folderForm.setUpdatedDate(updatedDate);
        folderForm.setParentUUID(parentuuid);

        updateAsset(folderForm, bytes);

        this.folderDao.saveForm(folderForm);
    }

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

        User user = (User) ud;
        boolean isAdmin = UserRole.ROLE_ADMIN.equals(user.getRole());

        ArchiveDTO archive = extractJSONFromZipFile(bytes);

        String uuid = archive.getUUID().toString();
        String name = archive.getName();
        UUID parentuuid = archive.getParentUUID();

        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 (!isAdmin || StringUtils.hasText(lastSha1hash)) {

            if (!StringUtils.hasText(lastSha1hash)) {
                throw new FormNotFoundException("sha1hash parameter required");
            }

            if (!lastSha1hash.equals(folderForm.getSha1hash())) {
                throw new FormNotFoundException(name
                        + " has been modified. 'Sync' first and try again.");
            }

        }

        saveForm(archive, folderForm, folder, bytes);

        return folderForm.getSha1hash();
    }

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

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

        if (assetid != null) {

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

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

        asset.setData(this.userDao.convertToBlob(bytes));
        asset = this.assetDao.saveAsset(asset);

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

    /**
     * Create Zip file.
     * @param map {@link Map}
     * @return byte[] zip file
     * @throws IOException IOException
     */
    private byte[] zipFile(final Map map) throws IOException {

        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(bs);

        for (Map.Entry e : map.entrySet()) {

            String name = e.getKey();
            byte[] data = e.getValue();

            ZipEntry ze = new ZipEntry(name + ".zip");
            zip.putNextEntry(ze);

            zip.write(data, 0, data.length);
            zip.closeEntry();
        }

        byte[] bytes = bs.toByteArray();

        IOUtils.closeQuietly(bs);
        IOUtils.closeQuietly(zip);

        return bytes;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy