@Override
  protected int getMaxProgress() {
    LocaleService localeService = (LocaleService) Component.getInstance(LocaleServiceImpl.class);
    List<HLocale> localeList =
        localeService.getSupportedLanguageByProjectIteration(
            projectIteration.getProject().getSlug(), projectIteration.getSlug());

    return projectIteration.getDocuments().size() * localeList.size();
  }
  @Override
  @Transactional
  public HDocument saveDocument(
      String projectSlug,
      String iterationSlug,
      Resource sourceDoc,
      Set<String> extensions,
      boolean copyTrans) {
    // Only active iterations allow the addition of a document
    HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug);

    // Check permission
    identity.checkPermission(hProjectIteration, "import-template");

    String docId = sourceDoc.getName();

    HDocument document = documentDAO.getByDocIdAndIteration(hProjectIteration, docId);
    HLocale hLocale = this.localeServiceImpl.validateSourceLocale(sourceDoc.getLang());

    boolean changed = false;
    int nextDocRev;
    if (document == null) { // must be a create operation
      nextDocRev = 1;
      changed = true;
      // TODO check that entity name matches id parameter
      document = new HDocument(sourceDoc.getName(), sourceDoc.getContentType(), hLocale);
      document.setProjectIteration(hProjectIteration);
      hProjectIteration.getDocuments().put(docId, document);
      document = documentDAO.makePersistent(document);
    } else if (document.isObsolete()) { // must also be a create operation
      nextDocRev = document.getRevision() + 1;
      changed = true;
      document.setObsolete(false);
      // not sure if this is needed
      hProjectIteration.getDocuments().put(docId, document);
    } else { // must be an update operation
      nextDocRev = document.getRevision() + 1;
    }

    changed |=
        resourceUtils.transferFromResource(sourceDoc, document, extensions, hLocale, nextDocRev);
    documentDAO.flush();

    long actorId = authenticatedAccount.getPerson().getId();
    if (changed) {
      documentUploadedEvent.fireAfterSuccess(
          new DocumentUploadedEvent(actorId, document.getId(), true, hLocale.getLocaleId()));
      clearStatsCacheForUpdatedDocument(document);
    }

    if (copyTrans && nextDocRev == 1) {
      copyTranslations(document);
    }

    return document;
  }
  private void prepareTransUnitUpdatedEvent(
      int previousVersionNum, ContentState previousState, HTextFlowTarget target) {
    LocaleId localeId = target.getLocaleId();
    HTextFlow textFlow = target.getTextFlow();
    HDocument document = textFlow.getDocument();
    HProjectIteration projectIteration = document.getProjectIteration();
    String iterationSlug = projectIteration.getSlug();
    String projectSlug = projectIteration.getProject().getSlug();
    ProjectType projectType = projectIteration.getProjectType();

    WorkspaceId workspaceId =
        new WorkspaceId(new ProjectIterationId(projectSlug, iterationSlug, projectType), localeId);
    Optional<TranslationWorkspace> workspaceOptional =
        translationWorkspaceManager.tryGetWorkspace(workspaceId);
    if (!workspaceOptional.isPresent()) {
      return;
    }

    TransUnitTransformer transUnitTransformer =
        serviceLocator.getInstance(TransUnitTransformer.class);
    TransUnit transUnit = transUnitTransformer.transform(textFlow, target, target.getLocale());

    DocumentId documentId = new DocumentId(document.getId(), document.getDocId());
    int wordCount = textFlow.getWordCount().intValue();

    TransUnitUpdateInfo updateInfo =
        createTransUnitUpdateInfo(
            transUnit, documentId, wordCount, previousVersionNum, previousState);

    CacheValue context =
        updateContext.getIfPresent(new CacheKey(transUnit.getId(), transUnit.getLocaleId()));
    TransUnitUpdated updated;
    if (context != null) {
      updated = new TransUnitUpdated(updateInfo, context.editorClientId, context.updateType);
      log.debug("about to publish trans unit updated event {}", updated);
    } else if (ServletContexts.instance().getRequest() != null) {

      String sessionId = ServletContexts.instance().getRequest().getSession().getId();
      EditorClientId editorClientId = new EditorClientId(sessionId, -1);
      updated =
          new TransUnitUpdated(
              updateInfo, editorClientId, TransUnitUpdated.UpdateType.NonEditorSave);
    } else {
      updated =
          new TransUnitUpdated(
              updateInfo,
              new EditorClientId("unknown", -1),
              TransUnitUpdated.UpdateType.NonEditorSave);
    }
    if (Events.exists()) {
      Events.instance()
          .raiseTransactionSuccessEvent(
              TextFlowTargetUpdatedEvent.EVENT_NAME,
              new TextFlowTargetUpdatedEvent(workspaceOptional.get(), target.getId(), updated));
    }
  }
  @Override
  public int getTotalProgressCount(
      HProjectIteration sourceVersion, HProjectIteration targetVersion) {
    int matchCount = getTotalMatchCount(sourceVersion.getId(), targetVersion.getId());

    List<HLocale> locales =
        getSupportedLocales(targetVersion.getProject().getSlug(), targetVersion.getSlug());

    return matchCount * locales.size();
  }
  @Override
  public GetDocumentListResult execute(GetDocumentList action, ExecutionContext context)
      throws ActionException {
    identity.checkLoggedIn();

    LocaleId localeId = action.getWorkspaceId().getLocaleId();
    ProjectIterationId iterationId = action.getProjectIterationId();
    ArrayList<DocumentInfo> docs = new ArrayList<DocumentInfo>();
    HProjectIteration hProjectIteration =
        projectIterationDAO.getBySlug(iterationId.getProjectSlug(), iterationId.getIterationSlug());
    Collection<HDocument> hDocs = hProjectIteration.getDocuments().values();
    for (HDocument hDoc : hDocs) {
      if (action.getFilters() == null
          || action.getFilters().isEmpty()
          || action.getFilters().contains(hDoc.getPath() + hDoc.getName())) {
        DocumentId docId = new DocumentId(hDoc.getId(), hDoc.getDocId());
        TranslationStats stats = documentDAO.getStatistics(hDoc.getId(), localeId);
        String lastModifiedBy = "";
        HPerson person = hDoc.getLastModifiedBy();
        if (person != null) {
          lastModifiedBy = person.getAccount().getUsername();
        }

        Map<String, String> downloadExtensions = new HashMap<String, String>();
        downloadExtensions.put(".po", "po?docId=" + hDoc.getDocId());
        if (translationFileServiceImpl.hasPersistedDocument(
            iterationId.getProjectSlug(),
            iterationId.getIterationSlug(),
            hDoc.getPath(),
            hDoc.getName())) {
          String extension =
              "."
                  + translationFileServiceImpl.getFileExtension(
                      iterationId.getProjectSlug(),
                      iterationId.getIterationSlug(),
                      hDoc.getPath(),
                      hDoc.getName());
          downloadExtensions.put(extension, "baked?docId=" + hDoc.getDocId());
        }

        DocumentInfo doc =
            new DocumentInfo(
                docId,
                hDoc.getName(),
                hDoc.getPath(),
                hDoc.getLocale().getLocaleId(),
                stats,
                lastModifiedBy,
                hDoc.getLastChanged(),
                downloadExtensions);
        docs.add(doc);
      }
    }
    return new GetDocumentListResult(iterationId, docs);
  }
Exemple #6
0
  @Test
  public void traverseProjectGraph() throws Exception {
    EntityManager em = getEm();
    HIterationProject project = em.find(HIterationProject.class, 1l);
    assertThat(project, notNullValue());

    List<HProjectIteration> projectTargets = project.getProjectIterations();
    assertThat("Project should have 2 targets", projectTargets.size(), is(2));

    HProjectIteration target = projectTargets.get(0);
    assertThat("Expect target with id 1", target.getId(), is(1l));
  }
  private void processWebHookDocumentMilestoneEvent(
      DocumentStatisticUpdatedEvent event,
      Collection<ContentState> contentStates,
      String message,
      int percentMilestone) {

    HProjectIteration version = projectIterationDAO.findById(event.getProjectIterationId());
    HProject project = version.getProject();

    if (!project.getWebHooks().isEmpty()) {
      WordStatistic stats =
          translationStateCacheImpl.getDocumentStatistics(
              event.getDocumentId(), event.getLocaleId());

      WordStatistic oldStats = StatisticsUtil.copyWordStatistic(stats);
      if (oldStats != null) {
        oldStats.decrement(event.getNewState(), event.getWordCount());
        oldStats.increment(event.getPreviousState(), event.getWordCount());

        boolean shouldPublish =
            hasContentStateReachedMilestone(oldStats, stats, contentStates, percentMilestone);

        if (shouldPublish) {
          HDocument document = documentDAO.getById(event.getDocumentId());

          String editorUrl =
              urlUtil.fullEditorDocumentUrl(
                  project.getSlug(),
                  version.getSlug(),
                  event.getLocaleId(),
                  LocaleId.EN_US,
                  document.getDocId());

          DocumentMilestoneEvent milestoneEvent =
              new DocumentMilestoneEvent(
                  project.getSlug(),
                  version.getSlug(),
                  document.getDocId(),
                  event.getLocaleId(),
                  message,
                  editorUrl);
          for (WebHook webHook : project.getWebHooks()) {
            publishDocumentMilestoneEvent(webHook, milestoneEvent);
          }
        }
      }
    }
  }
  @Override
  public GetDocumentListResult execute(GetDocumentList action, ExecutionContext context)
      throws ActionException {

    ZanataIdentity.instance().checkLoggedIn();

    ProjectIterationId iterationId = action.getProjectIterationId();
    ArrayList<DocumentInfo> docs = new ArrayList<DocumentInfo>();
    HProjectIteration hProjectIteration =
        projectIterationDAO.getBySlug(iterationId.getProjectSlug(), iterationId.getIterationSlug());
    Collection<HDocument> hDocs = hProjectIteration.getDocuments().values();
    for (HDocument hDoc : hDocs) {
      DocumentId docId = new DocumentId(hDoc.getId());
      DocumentInfo doc = new DocumentInfo(docId, hDoc.getName(), hDoc.getPath());
      docs.add(doc);
    }
    return new GetDocumentListResult(iterationId, docs);
  }
 protected int mergeTranslationBatch(
     HProjectIteration sourceVersion,
     HProjectIteration targetVersion,
     List<HLocale> supportedLocales,
     boolean useNewerTranslation,
     int offset,
     int batchSize) {
   try {
     return runInTransaction(
         () ->
             this.mergeTranslations(
                 sourceVersion.getId(),
                 targetVersion.getId(),
                 offset,
                 batchSize,
                 useNewerTranslation,
                 supportedLocales));
   } catch (Exception e) {
     log.warn("exception during copy text flow target", e);
     return 0;
   }
 }
  private HProjectIteration retrieveAndCheckIteration(
      String projectSlug, String iterationSlug, boolean writeOperation) {
    HProjectIteration hProjectIteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug);
    HProject hProject = hProjectIteration == null ? null : hProjectIteration.getProject();

    if (hProjectIteration == null) {
      throw new NoSuchEntityException(
          "Project Iteration '" + projectSlug + ":" + iterationSlug + "' not found.");
    } else if (hProjectIteration.getStatus().equals(EntityStatus.OBSOLETE)
        || hProject.getStatus().equals(EntityStatus.OBSOLETE)) {
      throw new NoSuchEntityException(
          "Project Iteration '" + projectSlug + ":" + iterationSlug + "' not found.");
    } else if (writeOperation) {
      if (hProjectIteration.getStatus().equals(EntityStatus.READONLY)
          || hProject.getStatus().equals(EntityStatus.READONLY)) {
        throw new ReadOnlyEntityException(
            "Project Iteration '" + projectSlug + ":" + iterationSlug + "' is read-only.");
      } else {
        return hProjectIteration;
      }
    } else {
      return hProjectIteration;
    }
  }
 /**
  * Check if sourceVersion or targetVersion has source document.
  *
  * @param sourceVersion
  * @param targetVersion
  */
 private boolean isVersionsEmpty(
     HProjectIteration sourceVersion, HProjectIteration targetVersion) {
   if (sourceVersion.getDocuments().isEmpty()) {
     log.error(
         "No documents in source version {}:{}",
         sourceVersion.getProject().getSlug(),
         sourceVersion.getSlug());
     return true;
   }
   if (targetVersion.getDocuments().isEmpty()) {
     log.error(
         "No documents in target version {}:{}",
         targetVersion.getProject().getSlug(),
         targetVersion.getSlug());
     return true;
   }
   return false;
 }
  @Override
  @Async
  public Future<Void> startMergeTranslations(
      String sourceProjectSlug,
      String sourceVersionSlug,
      String targetProjectSlug,
      String targetVersionSlug,
      boolean useNewerTranslation,
      MergeTranslationsTaskHandle handle) {

    HProjectIteration sourceVersion =
        projectIterationDAO.getBySlug(sourceProjectSlug, sourceVersionSlug);

    if (sourceVersion == null) {
      log.error("Cannot find source version of {}:{}", sourceProjectSlug, sourceVersionSlug);
      return AsyncTaskResult.taskResult();
    }

    HProjectIteration targetVersion =
        projectIterationDAO.getBySlug(targetProjectSlug, targetVersionSlug);

    if (targetVersion == null) {
      log.error("Cannot find target version of {}:{}", targetProjectSlug, targetVersionSlug);
      return AsyncTaskResult.taskResult();
    }

    if (isVersionsEmpty(sourceVersion, targetVersion)) {
      return AsyncTaskResult.taskResult();
    }

    if (getSupportedLocales(targetProjectSlug, targetVersionSlug).isEmpty()) {
      log.error(
          "No locales enabled in target version of {} [{}]", targetProjectSlug, targetVersionSlug);
      return AsyncTaskResult.taskResult();
    }

    Optional<MergeTranslationsTaskHandle> taskHandleOpt = Optional.fromNullable(handle);

    if (taskHandleOpt.isPresent()) {
      prepareMergeTranslationsHandle(sourceVersion, targetVersion, taskHandleOpt.get());
    }

    Stopwatch overallStopwatch = Stopwatch.createStarted();
    log.info(
        "merge translations start: from {} to {}",
        sourceProjectSlug + ":" + sourceVersionSlug,
        targetProjectSlug + ":" + targetVersionSlug);

    int startCount = 0;
    int totalCount = getTotalMatchCount(sourceVersion.getId(), targetVersion.getId());

    List<HLocale> supportedLocales =
        getSupportedLocales(targetVersion.getProject().getSlug(), targetVersion.getSlug());

    while (startCount < totalCount) {
      int processedCount =
          mergeTranslationBatch(
              sourceVersion,
              targetVersion,
              supportedLocales,
              useNewerTranslation,
              startCount,
              TEXTFLOWS_PER_BATCH);
      if (taskHandleOpt.isPresent()) {
        taskHandleOpt.get().increaseProgress(processedCount);
      }

      startCount += TEXTFLOWS_PER_BATCH;
      textFlowDAO.clear();
    }
    versionStateCacheImpl.clearVersionStatsCache(targetVersion.getId());
    log.info(
        "merge translation end: from {} to {}, {}",
        sourceProjectSlug + ":" + sourceVersionSlug,
        targetProjectSlug + ":" + targetVersionSlug,
        overallStopwatch);

    return AsyncTaskResult.taskResult();
  }
 public IterationCopyTransTask(HProjectIteration projectIteration, HCopyTransOptions options) {
   super(options, "IterationCopyTransTask: " + projectIteration.getSlug());
   this.projectIteration = projectIteration;
 }
  //    @Test(enabled = true, description = "this should only be executed manually in IDE")
  @Ignore
  @Test
  @PerformanceProfiling
  public void pushTranslation() {
    EntityMaker entityMaker =
        EntityMakerBuilder.builder()
            .addFieldOrPropertyMaker(
                HProject.class, "sourceViewURL", FixedValueMaker.EMPTY_STRING_MAKER)
            .build();
    HProjectIteration iteration = entityMaker.makeAndPersist(getEm(), HProjectIteration.class);
    HLocale srcLocale = createAndPersistLocale(LocaleId.EN_US, getEm());
    HLocale transLocale = createAndPersistLocale(LocaleId.DE, getEm());

    String versionSlug = iteration.getSlug();
    String projectSlug = iteration.getProject().getSlug();

    HDocument document = new HDocument("message", ContentType.PO, srcLocale);
    document.setProjectIteration(iteration);
    getEm().persist(document);
    getEm().flush();

    // adjust this number to suit testing purpose
    int numOfTextFlows = 50;
    int numOfTextFlowsHavingTarget =
        createSourceAndSomeTargets(document, transLocale, numOfTextFlows);
    getEm().getTransaction().commit();
    getEm().getTransaction().begin();

    Long targetsCountBefore =
        getEm()
            .createQuery("select count(*) from HTextFlowTarget where locale = :locale", Long.class)
            .setParameter("locale", transLocale)
            .getSingleResult();
    Assertions.assertThat(targetsCountBefore).isEqualTo(numOfTextFlowsHavingTarget);

    // ============ add targets =========
    TranslationsResource translations = new TranslationsResource();
    translations.setRevision(1);
    for (int i = 0; i < numOfTextFlows; i++) {
      addSampleTranslation(translations, "res" + i);
    }
    Monitor mon = MonitorFactory.start("");
    log.info("==== start translateAllInDoc");
    service.translateAllInDoc(
        projectSlug,
        versionSlug,
        document.getDocId(),
        transLocale.getLocaleId(),
        translations,
        extensions,
        MergeType.AUTO,
        false,
        TranslationSourceType.API_UPLOAD);
    log.info("==== stop translateAllInDoc: {}", mon.stop());
    getEm().getTransaction().commit();
    getEm().getTransaction().begin();

    Long targetsCount =
        getEm()
            .createQuery("select count(*) from HTextFlowTarget where locale = :locale", Long.class)
            .setParameter("locale", transLocale)
            .getSingleResult();
    Assertions.assertThat(targetsCount).isEqualTo(numOfTextFlows);

    List<HTextFlowTargetHistory> histories =
        getEm()
            .createQuery("from HTextFlowTargetHistory", HTextFlowTargetHistory.class)
            .getResultList();
    Assertions.assertThat(histories).hasSize(numOfTextFlowsHavingTarget);
  }
  // TODO Need to refactor this method to get Message statistic by default.
  // This is to be consistance with UI which uses message stats, and for
  // calculating remaining hours.
  @Override
  public ContainerTranslationStatistics getStatistics(
      String projectSlug,
      String iterationSlug,
      boolean includeDetails,
      boolean includeWordStats,
      String[] locales) {
    LocaleId[] localeIds;

    // if no locales are specified, search in all locales
    if (locales.length == 0) {
      List<HLocale> iterationLocales =
          localeServiceImpl.getSupportedLangugeByProjectIteration(projectSlug, iterationSlug);
      localeIds = new LocaleId[iterationLocales.size()];
      for (int i = 0, iterationLocalesSize = iterationLocales.size();
          i < iterationLocalesSize;
          i++) {
        HLocale loc = iterationLocales.get(i);
        localeIds[i] = loc.getLocaleId();
      }
    } else {
      localeIds = new LocaleId[locales.length];
      for (int i = 0; i < locales.length; i++) {
        localeIds[i] = new LocaleId(locales[i]);
      }
    }

    HProjectIteration iteration = projectIterationDAO.getBySlug(projectSlug, iterationSlug);

    if (iteration == null) {
      throw new NoSuchEntityException(projectSlug + "/" + iterationSlug);
    }

    Map<String, TransUnitCount> transUnitIterationStats =
        projectIterationDAO.getAllStatisticsForContainer(iteration.getId());
    Map<String, TransUnitWords> wordIterationStats =
        projectIterationDAO.getAllWordStatsStatistics(iteration.getId());

    ContainerTranslationStatistics iterationStats = new ContainerTranslationStatistics();
    iterationStats.setId(iterationSlug);
    iterationStats.addRef(
        new Link(
            URI.create(zPathService.generatePathForProjectIteration(iteration)),
            "statSource",
            "PROJ_ITER"));
    long iterationTotalMssgs =
        projectIterationDAO.getTotalMessageCountForIteration(iteration.getId());
    long iterationTotalWords = projectIterationDAO.getTotalWordCountForIteration(iteration.getId());

    for (LocaleId locId : localeIds) {
      // trans unit level stats
      TransUnitCount count = transUnitIterationStats.get(locId.getId());
      // Stats might not return anything if nothing is translated
      if (count == null) {
        count = new TransUnitCount(0, 0, (int) iterationTotalMssgs);
      }

      HTextFlowTarget target =
          localeServiceImpl.getLastTranslated(projectSlug, iterationSlug, locId);

      String lastModifiedBy = "";
      Date lastModifiedDate = null;

      if (target != null) {
        lastModifiedDate = target.getLastChanged();
        if (target.getLastModifiedBy() != null) {
          lastModifiedBy = target.getLastModifiedBy().getAccount().getUsername();
        }
      }

      TransUnitWords wordCount = wordIterationStats.get(locId.getId());
      if (wordCount == null) {
        wordCount = new TransUnitWords(0, 0, (int) iterationTotalWords);
      }

      TranslationStatistics transUnitStats =
          getMessageStats(count, locId, lastModifiedDate, lastModifiedBy);
      transUnitStats.setRemainingHours(StatisticsUtil.getRemainingHours(wordCount));
      iterationStats.addStats(transUnitStats);

      // word level stats
      if (includeWordStats) {
        TranslationStatistics wordsStats =
            getWordsStats(wordCount, locId, lastModifiedDate, lastModifiedBy);
        wordsStats.setRemainingHours(StatisticsUtil.getRemainingHours(wordCount));
        iterationStats.addStats(wordsStats);
      }
    }

    // TODO Do in a single query
    if (includeDetails) {
      for (String docId : iteration.getDocuments().keySet()) {
        iterationStats.addDetailedStats(
            this.getStatistics(projectSlug, iterationSlug, docId, includeWordStats, locales));
      }
    }

    return iterationStats;
  }