Package org.zanata.file

Source Code of org.zanata.file.TranslationDocumentUpload

/*
* Copyright 2013, Red Hat, Inc. and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.zanata.file;

import static org.zanata.file.DocumentUploadUtil.getInputStream;
import static org.zanata.file.DocumentUploadUtil.isSinglePart;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import lombok.extern.slf4j.Slf4j;

import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.zanata.common.DocumentType;
import org.zanata.common.EntityStatus;
import org.zanata.common.LocaleId;
import org.zanata.common.MergeType;
import org.zanata.dao.DocumentUploadDAO;
import org.zanata.dao.LocaleDAO;
import org.zanata.dao.ProjectIterationDAO;
import org.zanata.exception.ChunkUploadException;
import org.zanata.model.HDocumentUpload;
import org.zanata.model.HLocale;
import org.zanata.model.HProjectIteration;
import org.zanata.rest.DocumentFileUploadForm;
import org.zanata.rest.StringSet;
import org.zanata.rest.dto.ChunkUploadResponse;
import org.zanata.rest.dto.extensions.ExtensionType;
import org.zanata.rest.dto.resource.TranslationsResource;
import org.zanata.security.ZanataIdentity;
import org.zanata.service.TranslationFileService;
import org.zanata.service.TranslationService;

import com.google.common.base.Joiner;
import com.google.common.base.Optional;

//TODO damason: add thorough unit testing
@Slf4j
@Name("translationDocumentUploader")
public class TranslationDocumentUpload {

    @In(create = true, value = "documentUploadUtil")
    private DocumentUploadUtil util;
    @In
    private ZanataIdentity identity;
    @In
    private LocaleDAO localeDAO;
    @In
    private ProjectIterationDAO projectIterationDAO;
    @In
    private TranslationService translationServiceImpl;
    @In
    private TranslationFileService translationFileServiceImpl;
    @In
    private DocumentUploadDAO documentUploadDAO;

    public Response
            tryUploadTranslationFile(GlobalDocumentId id, String localeId,
                    String mergeType, DocumentFileUploadForm uploadForm) {
        try {
            failIfTranslationUploadNotValid(id, localeId, uploadForm);

            HLocale locale = findHLocale(localeId);
            Optional<File> tempFile;
            int totalChunks;

            if (isSinglePart(uploadForm)) {
                totalChunks = 1;
                tempFile = Optional.<File> absent();
            } else {
                if (!uploadForm.getLast()) {
                    HDocumentUpload upload =
                            util.saveUploadPart(id, locale, uploadForm);
                    totalChunks = upload.getParts().size();
                    return Response
                            .status(Status.ACCEPTED)
                            .entity(new ChunkUploadResponse(upload.getId(),
                                    totalChunks, true,
                                    "Chunk accepted, awaiting remaining chunks."))
                            .build();
                } else {
                    HDocumentUpload previousParts =
                            documentUploadDAO
                                    .findById(uploadForm.getUploadId());
                    totalChunks = previousParts.getParts().size();
                    totalChunks++; // add final part
                    tempFile =
                            Optional.of(util
                                    .combineToTempFileAndDeleteUploadRecord(
                                            previousParts,
                                            uploadForm));
                }
            }

            TranslationsResource transRes;
            if (uploadForm.getFileType().equals(".po")) {
                InputStream poStream = getInputStream(tempFile, uploadForm);
                transRes =
                        translationFileServiceImpl.parsePoFile(poStream,
                                id.getProjectSlug(), id.getVersionSlug(),
                                id.getDocId());
            } else {
                if (!tempFile.isPresent()) {
                    tempFile =
                            Optional.of(util
                                    .persistTempFileFromUpload(uploadForm));
                }
                // FIXME this is misusing the 'filename' field. the method
                // should probably take a
                // type anyway
                transRes =
                        translationFileServiceImpl.parseAdapterTranslationFile(
                                tempFile.get(), id.getProjectSlug(),
                                id.getVersionSlug(), id.getDocId(), localeId,
                                uploadForm.getFileType());
            }
            if (tempFile.isPresent()) {
                tempFile.get().delete();
            }

            Set<String> extensions =
                    newExtensions(uploadForm.getFileType().equals(".po"));
            // TODO useful error message for failed saving?
            List<String> warnings =
                    translationServiceImpl.translateAllInDoc(
                            id.getProjectSlug(), id.getVersionSlug(),
                            id.getDocId(), locale.getLocaleId(), transRes,
                            extensions, mergeTypeFromString(mergeType));

            return transUploadResponse(totalChunks, warnings);
        } catch (FileNotFoundException e) {
            log.error("failed to create input stream from temp file", e);
            return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e)
                    .build();
        } catch (ChunkUploadException e) {
            return Response.status(e.getStatusCode())
                    .entity(new ChunkUploadResponse(e.getMessage())).build();
        }
    }

    private void failIfTranslationUploadNotValid(GlobalDocumentId id,
            String localeId, DocumentFileUploadForm uploadForm)
            throws ChunkUploadException {
        util.failIfUploadNotValid(id, uploadForm);
        util.failIfHashNotPresent(uploadForm);
        failIfDocumentDoesNotExist(id);
        failIfFileTypeNotValid(uploadForm);
        failIfTranslationUploadNotAllowed(id, localeId);
    }

    private void failIfDocumentDoesNotExist(GlobalDocumentId id)
            throws ChunkUploadException {
        if (util.isNewDocument(id)) {
            throw new ChunkUploadException(Status.NOT_FOUND,
                    "No document with id \"" + id.getDocId()
                            + "\" exists in project-version \""
                            + id.getProjectSlug() + ":" + id.getVersionSlug()
                            + "\".");
        }
    }

    private void failIfFileTypeNotValid(DocumentFileUploadForm uploadForm)
            throws ChunkUploadException {
        String fileType = uploadForm.getFileType();
        if (!fileType.equals(".po")
                && !translationFileServiceImpl.hasAdapterFor(DocumentType
                        .typeFor(fileType))) {
            throw new ChunkUploadException(Status.BAD_REQUEST, "The type \""
                    + fileType + "\" specified in form parameter 'type' "
                    + "is not valid for a translation file on this server.");
        }
    }

    private void failIfTranslationUploadNotAllowed(GlobalDocumentId id,
            String localeId) throws ChunkUploadException {
        HLocale locale = findHLocale(localeId);
        if (!isTranslationUploadAllowed(id, locale)) {
            throw new ChunkUploadException(Status.FORBIDDEN,
                    "You do not have permission to upload translations for locale \""
                            + localeId + "\" to project-version \""
                            + id.getProjectSlug() + ":" + id.getVersionSlug()
                            + "\".");
        }
    }

    private HLocale findHLocale(String localeString) {
        LocaleId localeId;
        try {
            localeId = new LocaleId(localeString);
        } catch (IllegalArgumentException e) {
            throw new ChunkUploadException(Status.BAD_REQUEST,
                    "Invalid value for locale", e);
        }

        HLocale locale = localeDAO.findByLocaleId(localeId);
        if (locale == null) {
            throw new ChunkUploadException(Status.NOT_FOUND,
                    "The specified locale \"" + localeString
                            + "\" does not exist on this server.");
        }
        return locale;
    }

    private boolean isTranslationUploadAllowed(GlobalDocumentId id,
            HLocale locale) {
        HProjectIteration projectIteration =
                projectIterationDAO.getBySlug(id.getProjectSlug(),
                        id.getVersionSlug());
        // TODO should this check be "add-translation" or "modify-translation"?
        // They appear to be granted identically at the moment.
        return projectIteration.getStatus() == EntityStatus.ACTIVE
                && projectIteration.getProject().getStatus() == EntityStatus.ACTIVE
                && identity != null
                && identity.hasPermission("add-translation",
                        projectIteration.getProject(), locale);
    }

    private static Set<String> newExtensions(boolean gettextExtensions) {
        Set<String> extensions;
        if (gettextExtensions) {
            extensions = new StringSet(ExtensionType.GetText.toString());
        } else {
            extensions = Collections.<String> emptySet();
        }
        return extensions;
    }

    private static Response transUploadResponse(int totalChunks,
            List<String> warnings) {
        ChunkUploadResponse response = new ChunkUploadResponse();
        response.setExpectingMore(false);
        response.setAcceptedChunks(totalChunks);
        if (warnings != null && !warnings.isEmpty()) {
            response.setSuccessMessage(buildWarningString(warnings));
        } else {
            response.setSuccessMessage("Translations uploaded successfully");
        }
        return Response.status(Status.OK).entity(response).build();
    }

    private static String buildWarningString(List<String> warnings) {
        return Joiner.on("\n\t").join(
                "Upload succeeded but had the following warnings:", warnings)
                + "\n";
    }

    private static MergeType mergeTypeFromString(String type) {
        if ("import".equals(type)) {
            return MergeType.IMPORT;
        } else {
            return MergeType.AUTO;
        }
    }

}
TOP

Related Classes of org.zanata.file.TranslationDocumentUpload

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.