package com.door43.translationstudio.newui.home; import android.app.DialogFragment; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.design.widget.Snackbar; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import com.door43.tools.reporting.Logger; import com.door43.translationstudio.AppContext; import com.door43.translationstudio.R; import com.door43.translationstudio.core.TargetTranslation; import com.door43.translationstudio.core.TargetTranslationMigrator; import com.door43.translationstudio.core.Translator; import com.door43.translationstudio.dialogs.CustomAlertDialog; import com.door43.translationstudio.tasks.CloneRepositoryTask; import com.door43.translationstudio.tasks.GetUserRepositoriesTask; import com.door43.translationstudio.tasks.RegisterSSHKeysTask; import com.door43.util.tasks.GenericTaskWatcher; import com.door43.util.tasks.ManagedTask; import com.door43.util.tasks.TaskManager; import com.door43.widget.ViewUtil; import org.apache.commons.io.FileUtils; import org.json.JSONException; import org.json.JSONObject; import org.unfoldingword.gogsclient.Repository; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Created by joel on 11/6/2015. */ public class RestoreFromDoor43Dialog extends DialogFragment implements GenericTaskWatcher.OnFinishedListener { private static final String STATE_REPOSITORIES = "state_repositories"; private GenericTaskWatcher taskWatcher; private RestoreFromCloudAdapter adapter; private Translator translator; private List<Repository> repositories = new ArrayList<>(); private String cloneSSHUrl; private File cloneDestDir; public View onCreateView(LayoutInflater inflater, ViewGroup container, final Bundle savedInstanceState) { getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE); View v = inflater.inflate(R.layout.dialog_restore_from_door43, container, false); this.taskWatcher = new GenericTaskWatcher(getActivity(), R.string.loading); this.taskWatcher.setOnFinishedListener(this); this.translator = AppContext.getTranslator(); Button dismissButton = (Button) v.findViewById(R.id.dismiss_button); dismissButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { taskWatcher.stop(); GetUserRepositoriesTask task = (GetUserRepositoriesTask) TaskManager.getTask(GetUserRepositoriesTask.TASK_ID); if (task != null) { task.stop(); TaskManager.cancelTask(task); TaskManager.clearTask(task); } dismiss(); } }); ListView list = (ListView) v.findViewById(R.id.list); adapter = new RestoreFromCloudAdapter(); list.setAdapter(adapter); list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Repository repo = adapter.getItem(position); String repoName = repo.getFullName().replace("/", "-"); cloneDestDir = new File(AppContext.context().getCacheDir(), repoName + System.currentTimeMillis() + "/"); cloneSSHUrl = repo.getSshUrl(); CloneRepositoryTask task = new CloneRepositoryTask(cloneSSHUrl, cloneDestDir); taskWatcher.watch(task); TaskManager.addTask(task, CloneRepositoryTask.TASK_ID); } }); // restore state if(savedInstanceState != null) { String[] repoJsonArray = savedInstanceState.getStringArray(STATE_REPOSITORIES); if(repoJsonArray != null) { for (String json : repoJsonArray) { try { Repository repo = Repository.fromJSON(new JSONObject(json)); if (json != null) { repositories.add(repo); } } catch (JSONException e) { e.printStackTrace(); } } adapter.setRepositories(repositories); } } // connect to existing task GetUserRepositoriesTask reposTask = (GetUserRepositoriesTask) TaskManager.getTask(GetUserRepositoriesTask.TASK_ID); CloneRepositoryTask cloneTask = (CloneRepositoryTask) TaskManager.getTask(CloneRepositoryTask.TASK_ID); if (reposTask != null) { taskWatcher.watch(reposTask); } else if (cloneTask != null) { taskWatcher.watch(cloneTask); } else if(repositories.size() == 0) { // start task reposTask = new GetUserRepositoriesTask(); taskWatcher.watch(reposTask); TaskManager.addTask(reposTask, GetUserRepositoriesTask.TASK_ID); } return v; } @Override public void onFinished(ManagedTask task) { taskWatcher.stop(); TaskManager.clearTask(task); if (task instanceof GetUserRepositoriesTask) { this.repositories = ((GetUserRepositoriesTask) task).getRepositories(); adapter.setRepositories(repositories); } else if (task instanceof CloneRepositoryTask) { if (!task.isCanceled()) { CloneRepositoryTask.Status status = ((CloneRepositoryTask)task).getStatus(); File tempPath = ((CloneRepositoryTask) task).getDestDir(); String cloneUrl = ((CloneRepositoryTask) task).getCloneUrl(); if(status == CloneRepositoryTask.Status.SUCCESS) { Logger.i(this.getClass().getName(), "Repository cloned from " + cloneUrl); tempPath = TargetTranslationMigrator.migrate(tempPath); TargetTranslation tempTargetTranslation = TargetTranslation.open(tempPath); boolean restoreFailed = false; if (tempTargetTranslation != null) { TargetTranslation existingTargetTranslation = translator.getTargetTranslation(tempTargetTranslation.getId()); // create orphaned backup of existing target translation if (existingTargetTranslation != null) { try { AppContext.backupTargetTranslation(existingTargetTranslation, true); } catch (Exception e) { Logger.e(this.getClass().getName(), "Failed to backup the target translation", e); } } // restore the new target translation try { translator.restoreTargetTranslation(tempTargetTranslation); } catch (IOException e) { Logger.e(this.getClass().getName(), "Failed to import the target translation " + tempTargetTranslation.getId(), e); notifyRestoreFailed(); restoreFailed = true; } } else { Logger.e(this.getClass().getName(), "Failed to open the online backup"); notifyRestoreFailed(); restoreFailed = true; } FileUtils.deleteQuietly(tempPath); if(!restoreFailed) { Handler hand = new Handler(Looper.getMainLooper()); hand.post(new Runnable() { @Override public void run() { // todo: terrible hack. We should instead register a listener with the dialog ((HomeActivity) getActivity()).notifyDatasetChanged(); Snackbar snack = Snackbar.make(RestoreFromDoor43Dialog.this.getView(), R.string.success, Snackbar.LENGTH_SHORT); ViewUtil.setSnackBarTextColor(snack, getResources().getColor(R.color.light_primary_text)); snack.show(); } }); } } else if(status == CloneRepositoryTask.Status.AUTH_FAILURE) { Logger.i(this.getClass().getName(), "Authentication failed"); // if we have already tried ask the user if they would like to try again if(AppContext.context().hasSSHKeys()) { showAuthFailure(); return; } RegisterSSHKeysTask keyTask = new RegisterSSHKeysTask(false); taskWatcher.watch(keyTask); TaskManager.addTask(keyTask, RegisterSSHKeysTask.TASK_ID); } else { notifyRestoreFailed(); } } } else if(task instanceof RegisterSSHKeysTask) { if(((RegisterSSHKeysTask)task).isSuccess()) { Logger.i(this.getClass().getName(), "SSH keys were registered with the server"); // try to clone again CloneRepositoryTask pullTask = new CloneRepositoryTask(cloneSSHUrl, cloneDestDir); taskWatcher.watch(pullTask); TaskManager.addTask(pullTask, CloneRepositoryTask.TASK_ID); } else { notifyRestoreFailed(); } } } public void showAuthFailure() { CustomAlertDialog.Create(getActivity()) .setTitle(R.string.error).setMessage(R.string.auth_failure_retry) .setPositiveButton(R.string.yes, new View.OnClickListener() { @Override public void onClick(View v) { RegisterSSHKeysTask keyTask = new RegisterSSHKeysTask(true); taskWatcher.watch(keyTask); TaskManager.addTask(keyTask, RegisterSSHKeysTask.TASK_ID); } }) .setNegativeButton(R.string.no, new View.OnClickListener() { @Override public void onClick(View v) { notifyRestoreFailed(); } }) .show("auth-failed"); } public void notifyRestoreFailed() { CustomAlertDialog.Create(getActivity()) .setTitle(R.string.error) .setMessage(R.string.restore_failed) .setPositiveButton(R.string.dismiss, null) .show("publish-failed"); } @Override public void onSaveInstanceState(Bundle out) { List<String> repoJsonList = new ArrayList<>(); for (Repository r : repositories) { repoJsonList.add(r.toJSON().toString()); } out.putStringArray(STATE_REPOSITORIES, repoJsonList.toArray(new String[repoJsonList.size()])); super.onSaveInstanceState(out); } @Override public void onDestroy() { taskWatcher.stop(); super.onDestroy(); } }