Example #1
0
 @Override
 public int onStartCommand(Intent intent, int flags, int startid) {
   SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplication());
   int backupIntervalMinutes =
       Integer.parseInt(
           pref.getString(
               SettingsActivity.KEY_PREF_BACKUP_INTERVAL,
               getResources().getString(R.string.pref_default_backup_interval)));
   if (backupIntervalMinutes > 0) {
     int backupInterval = backupIntervalMinutes * 60 * 1000;
     Logger.i(
         this.getClass().getName(),
         "Backups running every " + backupIntervalMinutes + " minute/s");
     sRunning = true;
     sTimer.scheduleAtFixedRate(
         new TimerTask() {
           @Override
           public void run() {
             if (!mFirstRun) {
               runBackup();
             }
             mFirstRun = false;
           }
         },
         0,
         backupInterval);
     return START_STICKY;
   } else {
     Logger.i(this.getClass().getName(), "Backups are disabled");
     sRunning = true;
     return START_STICKY;
   }
 }
  @Override
  public void start() {
    File logFile = Logger.getLogFile();

    // TRICKY: make sure the github_oauth2 token has been set
    int githubTokenIdentifier =
        AppContext.context()
            .getResources()
            .getIdentifier("github_oauth2", "string", AppContext.context().getPackageName());
    String githubUrl =
        AppContext.context().getResources().getString(R.string.github_bug_report_repo);

    if (githubTokenIdentifier != 0) {
      GithubReporter reporter =
          new GithubReporter(
              AppContext.context(),
              githubUrl,
              AppContext.context().getResources().getString(githubTokenIdentifier));
      reporter.reportBug(mNotes, logFile);

      // empty the log
      try {
        FileUtils.write(logFile, "");
      } catch (IOException e) {
        e.printStackTrace();
      }

      Logger.i(this.getClass().getName(), "Submitted bug report");
    } else if (githubTokenIdentifier == 0) {
      Logger.w(this.getClass().getName(), "the github oauth2 token is missing");
    }
  }
Example #3
0
 /** Stops the service */
 private void stopService() {
   if (sTimer != null) {
     sTimer.cancel();
   }
   sRunning = false;
   Logger.i(this.getClass().getName(), "stopping backup service");
 }
 /**
  * Merges chunks found in a target translation Project that do not exist in the source translation
  * to a sibling chunk so that no data is lost.
  *
  * @param library
  * @param targetTranslation target translation to merge
  * @return
  */
 public static boolean migrateChunkChanges(
     final Library library, final TargetTranslation targetTranslation) {
   try {
     Logger.i(
         TargetTranslationMigrator.class.getName(),
         "Migrating chunks in target translation " + targetTranslation.getProjectId());
     final SourceTranslation sourceTranslation =
         library.getDefaultSourceTranslation(targetTranslation.getProjectId(), "en");
     if (sourceTranslation == null) {
       Logger.w(
           TargetTranslationMigrator.class.getName(),
           "Could not find a source translation for the target translation "
               + targetTranslation.getId());
       return false;
     }
     if (targetTranslation.getPath().exists()) {
       boolean migrationSuccess = true;
       // perform the chunk migration on each chapter of the target translation
       for (ChapterTranslation chapterTranslation : targetTranslation.getChapterTranslations()) {
         Chapter chapter = library.getChapter(sourceTranslation, chapterTranslation.getId());
         if (chapter != null) {
           boolean success =
               mergeInvalidChunksInChapter(library, sourceTranslation, targetTranslation, chapter);
           migrationSuccess = migrationSuccess && success;
         }
       }
       return migrationSuccess;
     }
   } catch (Exception e) {
     Logger.e(
         TargetTranslationMigrator.class.getName(),
         "Failed to merge the chunks in the target translation "
             + targetTranslation.getProjectId());
   }
   return false;
 }
  /**
   * Detects the format of the file and imports it
   *
   * @param file
   */
  public void importTranslation(final File file) {
    try {
      if (file.exists() && file.isFile()) {
        String[] name = file.getName().split("\\.");
        if (name[name.length - 1].toLowerCase().equals(Project.PROJECT_EXTENSION)) {
          // import translationStudio project
          final ProgressDialog dialog = new ProgressDialog(this);
          dialog.setMessage(getResources().getString(R.string.import_project));
          dialog.setCancelable(false);
          dialog.setCanceledOnTouchOutside(false);
          dialog.show();

          final Handler handle = new Handler(Looper.getMainLooper());
          new ThreadableUI(this) {

            @Override
            public void onStop() {}

            @Override
            public void run() {
              ProjectImport[] importRequests = Sharing.prepareArchiveImport(file);
              if (importRequests.length > 0) {
                boolean importWarnings = false;
                for (ProjectImport s : importRequests) {
                  if (!s.isApproved()) {
                    importWarnings = true;
                  }
                }
                if (importWarnings) {
                  // review the import status in a dialog
                  FragmentTransaction ft = getFragmentManager().beginTransaction();
                  Fragment prev = getFragmentManager().findFragmentByTag("dialog");
                  if (prev != null) {
                    ft.remove(prev);
                  }
                  ft.addToBackStack(null);
                  app().closeToastMessage();
                  ProjectTranslationImportApprovalDialog newFragment =
                      new ProjectTranslationImportApprovalDialog();
                  newFragment.setImportRequests(importRequests);
                  newFragment.setOnClickListener(
                      new ProjectTranslationImportApprovalDialog.OnClickListener() {
                        @Override
                        public void onOk(ProjectImport[] requests) {
                          handle.post(
                              new Runnable() {
                                @Override
                                public void run() {
                                  dialog.setMessage(getResources().getString(R.string.loading));
                                  dialog.show();
                                }
                              });

                          for (ProjectImport r : requests) {
                            Sharing.importProject(r);
                          }
                          Sharing.cleanImport(requests);
                          AppContext.context().showToastMessage(R.string.success);
                          handle.post(
                              new Runnable() {
                                @Override
                                public void run() {
                                  dialog.dismiss();
                                }
                              });
                        }

                        @Override
                        public void onCancel(ProjectImport[] requests) {}
                      });
                  newFragment.show(ft, "dialog");
                } else {
                  // TODO: we should update the status with the results of the import and let the
                  // user see an overview of the import process.
                  for (ProjectImport r : importRequests) {
                    Sharing.importProject(r);
                  }
                  Sharing.cleanImport(importRequests);
                  app().showToastMessage(R.string.success);
                }
              } else {
                Sharing.cleanImport(importRequests);
                app().showToastMessage(R.string.translation_import_failed);
              }
            }

            @Override
            public void onPostExecute() {
              dialog.dismiss();
            }
          }.start();
        } else if (name[name.length - 1].toLowerCase().equals("zip")) {
          // import DokuWiki files
          final ProgressDialog dialog = new ProgressDialog(SharingActivity.this);
          dialog.setMessage(getResources().getString(R.string.import_project));
          dialog.setCanceledOnTouchOutside(false);
          dialog.setCancelable(false);
          dialog.show();
          new ThreadableUI(this) {

            @Override
            public void onStop() {}

            @Override
            public void run() {
              if (Sharing.importDokuWikiArchive(file)) {
                app().showToastMessage(R.string.success);
              } else {
                app().showToastMessage(R.string.translation_import_failed);
              }
            }

            @Override
            public void onPostExecute() {
              dialog.dismiss();
            }
          }.start();
        } else if (name[name.length - 1].toLowerCase().equals("txt")) {
          // import legacy 1.x DokuWiki files

          final ProgressDialog dialog = new ProgressDialog(SharingActivity.this);
          dialog.setMessage(getResources().getString(R.string.import_project));
          dialog.setCanceledOnTouchOutside(false);
          dialog.setCancelable(false);
          dialog.show();
          new ThreadableUI(this) {

            @Override
            public void onStop() {}

            @Override
            public void run() {
              if (Sharing.importDokuWiki(file)) {
                app().showToastMessage(R.string.success);
              } else {
                app().showToastMessage(R.string.translation_import_failed);
              }
            }

            @Override
            public void onPostExecute() {
              dialog.dismiss();
            }
          }.start();
        }
      } else {
        app().showToastMessage(R.string.missing_file);
      }
    } catch (Exception e) {
      Logger.e(this.getClass().getName(), "Failed to read file", e);
    }
  }
  /**
   * Merges invalid chunks found in the target translation with a valid sibling chunk in order to
   * preserve translation data. Merged chunks are marked as not finished to force translators to
   * review the changes.
   *
   * @param library
   * @param sourceTranslation
   * @param targetTranslation
   * @param chapter
   * @return
   */
  private static boolean mergeInvalidChunksInChapter(
      final Library library,
      final SourceTranslation sourceTranslation,
      final TargetTranslation targetTranslation,
      final Chapter chapter) {
    boolean success = true;
    Logger.i(
        TargetTranslationMigrator.class.getName(),
        "Searching chapter " + chapter.getId() + " for invalid chunks ");
    // TRICKY: the translation format doesn't matter for migrating
    FrameTranslation[] frameTranslations =
        targetTranslation.getFrameTranslations(chapter.getId(), TranslationFormat.DEFAULT);
    String invalidChunks = "";
    Frame lastValidFrame = null;
    for (FrameTranslation frameTranslation : frameTranslations) {
      Frame frame = library.getFrame(sourceTranslation, chapter.getId(), frameTranslation.getId());
      if (frame != null) {
        lastValidFrame = frame;
        // merge invalid frames into the existing frame
        if (!invalidChunks.isEmpty()) {
          targetTranslation.applyFrameTranslation(
              frameTranslation, invalidChunks + frameTranslation.body);
          invalidChunks = "";
          targetTranslation.reopenFrame(frame);
        }
      } else if (!frameTranslation.body.trim().isEmpty()) {
        if (lastValidFrame == null) {
          // collect invalid frame
          invalidChunks += frameTranslation.body + CHUNK_MERGE_MARKER;
        } else { // if last frame is not null, then append invalid chunk to it
          FrameTranslation lastFrameTranslation =
              targetTranslation.getFrameTranslation(lastValidFrame);
          targetTranslation.applyFrameTranslation(
              lastFrameTranslation,
              lastFrameTranslation.body + CHUNK_MERGE_MARKER + frameTranslation.body);
          targetTranslation.reopenFrame(lastValidFrame);
        }
        targetTranslation.applyFrameTranslation(frameTranslation, ""); // clear out old data
      }
    }
    // clean up remaining invalid chunks
    if (!invalidChunks.isEmpty()) {
      if (lastValidFrame == null) {
        // push remaining invalid chunks onto the first available frame
        String[] frameslugs = library.getFrameSlugs(sourceTranslation, chapter.getId());
        if (frameslugs.length > 0) {
          lastValidFrame = library.getFrame(sourceTranslation, chapter.getId(), frameslugs[0]);
        } else {
          Logger.w(
              TargetTranslationMigrator.class.getName(),
              "No frames were found for chapter " + chapter.getId());
        }
      }

      if (lastValidFrame != null) {
        FrameTranslation frameTranslation = targetTranslation.getFrameTranslation(lastValidFrame);
        targetTranslation.applyFrameTranslation(
            frameTranslation, invalidChunks + CHUNK_MERGE_MARKER + frameTranslation.body);
        targetTranslation.reopenFrame(lastValidFrame);
      }
    }

    return success;
  }
Example #7
0
 @Override
 public void onCreate() {
   Logger.i(this.getClass().getName(), "starting backup service");
 }
Example #8
0
  /** Performs the backup if nessesary */
  private void runBackup() {
    boolean backupPerformed = false;
    Translator translator = AppContext.getTranslator();
    TargetTranslation[] targetTranslations = translator.getTargetTranslations();
    for (TargetTranslation t : targetTranslations) {

      // commit pending changes
      try {
        t.commit();
      } catch (Exception e) {
        Logger.e(this.getClass().getName(), "Failed to commit changes before backing up", e);
        continue;
      }

      // run backup if there are translations
      if (t.numTranslated() > 0) {

        // retreive commit hash
        String tag;
        try {
          tag = t.getCommitHash();
        } catch (Exception e) {
          Logger.w(this.getClass().getName(), "Failed to read commit hash", e);
          continue;
        }

        // check if backup is required
        if (tag != null) {
          File primaryBackupDir =
              new File(AppContext.getPublicDirectory(), "backups/" + t.getId() + "/");
          File primaryBackupFile =
              new File(primaryBackupDir, tag + "." + Translator.ARCHIVE_EXTENSION);
          File downloadBackupDir =
              new File(AppContext.getPublicDownloadsDirectory(), "backups/" + t.getId() + "/");
          File downloadBackupFile =
              new File(downloadBackupDir, tag + "." + Translator.ARCHIVE_EXTENSION);
          // e.g. ../../backups/uw-obs-de/[commit hash].tstudio
          if (!downloadBackupFile.exists()) {

            // peform backup
            File archive =
                new File(
                    AppContext.getPublicDownloadsDirectory(),
                    t.getId() + ".temp." + Translator.ARCHIVE_EXTENSION);
            try {
              translator.exportArchive(t, archive);
            } catch (Exception e) {
              Logger.e(
                  this.getClass().getName(),
                  "Failed to export the target translation " + t.getId(),
                  e);
              continue;
            }
            if (archive.exists() && archive.isFile()) {
              // move into backup
              FileUtils.deleteQuietly(downloadBackupDir);
              FileUtils.deleteQuietly(primaryBackupDir);
              downloadBackupDir.mkdirs();
              primaryBackupDir.mkdirs();
              try {
                // backup to downloads directory
                FileUtils.copyFile(archive, downloadBackupFile);
                // backup to a slightly less public area (used for auto restore)
                FileUtils.copyFile(archive, primaryBackupFile);
                backupPerformed = true;
              } catch (IOException e) {
                Logger.e(
                    this.getClass().getName(),
                    "Failed to copy the backup archive for target translation: " + t.getId(),
                    e);
              }
              archive.delete();
            } else {
              Logger.w(
                  this.getClass().getName(),
                  "Failed to export the target translation: " + t.getId());
            }
          }
        } else {
          Logger.w(this.getClass().getName(), "Could not find the commit hash");
        }
      }
    }

    if (backupPerformed) {
      onBackupComplete();
    }
  }