From 9434d2ffa3829a4f7a74d20b41e7af38b645f682 Mon Sep 17 00:00:00 2001 From: Milton Barrera Date: Tue, 11 Feb 2025 19:39:21 -0600 Subject: [PATCH 1/5] New GitHubUtils class to interact with GitHub API --- .../java/net/osmtracker/util/Callback.java | 17 +++++ .../java/net/osmtracker/util/GitHubUtils.java | 75 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 app/src/main/java/net/osmtracker/util/Callback.java create mode 100644 app/src/main/java/net/osmtracker/util/GitHubUtils.java diff --git a/app/src/main/java/net/osmtracker/util/Callback.java b/app/src/main/java/net/osmtracker/util/Callback.java new file mode 100644 index 00000000..78df7286 --- /dev/null +++ b/app/src/main/java/net/osmtracker/util/Callback.java @@ -0,0 +1,17 @@ +package net.osmtracker.util; + +/** + * A generic callback interface used for asynchronous operations. + * Implementations of this interface should define how to handle the result + * of an asynchronous task. + */ +public interface Callback { + /** + * Called when the asynchronous operation is completed. + * Implementations should handle the provided result accordingly. + * + * @param result The result of the operation, which may be {@code null} if an error occurs. + * @return A string value that may be used by the calling function, if applicable. + */ + String onResult(String result); +} diff --git a/app/src/main/java/net/osmtracker/util/GitHubUtils.java b/app/src/main/java/net/osmtracker/util/GitHubUtils.java new file mode 100644 index 00000000..27d5421a --- /dev/null +++ b/app/src/main/java/net/osmtracker/util/GitHubUtils.java @@ -0,0 +1,75 @@ +package net.osmtracker.util; + +import android.os.AsyncTask; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * Utility class for interacting with the GitHub API. + * Provides methods to retrieve file information and manage file uploads. + * + *

This class includes methods to: + *

+ *

+ * + *

It requires a valid GitHub authentication token for API requests.

+ */ +public class GitHubUtils { + /** + * Retrieves the SHA hash of a file in a GitHub repository. + * If the file does not exist, it returns {@code null}. + * + * @param repoOwner The owner of the repository (user or organization). + * @param repoName The name of the GitHub repository. + * @param repoFilePath The file path in the repository. + * @param token The GitHub authentication token with appropriate permissions. + * @return The SHA hash of the file if it exists, or {@code null} if the file is not found. + * @throws IOException If an I/O error occurs while making the request. + * @throws JSONException If an error occurs while parsing the JSON response. + */ + public static void getFileSHAAsync(String repoOwner, String repoName, String repoFilePath, String token, Callback callback) { + new AsyncTask() { + @Override + protected String doInBackground(Void... voids) { + try { + String apiUrl = "https://api.github.com/repos/" + repoOwner + "/" + repoName + "/contents/" + repoFilePath; + System.out.println("Fetching SHA: " + apiUrl); + HttpURLConnection connection = (HttpURLConnection) new URL(apiUrl).openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Authorization", "Bearer " + token); + connection.setRequestProperty("Accept", "application/vnd.github.v3+json"); + + if (connection.getResponseCode() == 200) { + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + JSONObject jsonResponse = new JSONObject(response.toString()); + return jsonResponse.getString("sha"); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + protected void onPostExecute(String sha) { + callback.onResult(sha); // Return result via callback + } + }.execute(); + } +} From 4cd91ad674c9490e9dd4eb45e7f4c11bd7f0f89d Mon Sep 17 00:00:00 2001 From: Milton Barrera Date: Tue, 11 Feb 2025 19:41:53 -0600 Subject: [PATCH 2/5] methods to get a unique name for a file in a GitHub repository --- .../java/net/osmtracker/util/GitHubUtils.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/app/src/main/java/net/osmtracker/util/GitHubUtils.java b/app/src/main/java/net/osmtracker/util/GitHubUtils.java index 27d5421a..460a3144 100644 --- a/app/src/main/java/net/osmtracker/util/GitHubUtils.java +++ b/app/src/main/java/net/osmtracker/util/GitHubUtils.java @@ -72,4 +72,54 @@ protected void onPostExecute(String sha) { } }.execute(); } + + /** + * Asynchronously generates a unique filename in a GitHub repository. + * If the file already exists, a number is appended before the extension. + * + * @param repoOwner The owner of the repository. + * @param repoName The name of the GitHub repository. + * @param repoFilePath The initial file path in the repository. + * @param token The GitHub authentication token. + * @param callback Callback to return the generated filename. + */ + public static void getGHFilenameAsync(String repoOwner, String repoName, final String repoFilePath, String token, Callback callback) { + String filename = repoFilePath.substring(0, repoFilePath.lastIndexOf(".")); + String extension = repoFilePath.substring(repoFilePath.lastIndexOf(".")); + checkFileExists(repoOwner, repoName, filename, extension, 0, token, callback); + } + + /** + * Recursively checks if a file exists and generates a unique filename. + * + * @param repoOwner The owner of the repository. + * @param repoName The GitHub repository name. + * @param filename The base filename (without extension). + * @param extension The file extension. + * @param count The current attempt number for uniqueness. + * @param token The GitHub authentication token. + * @param callback Callback to return the final unique filename. + */ + private static void checkFileExists(String repoOwner, String repoName, String filename, String extension, int count, String token, Callback callback) { + String newFilename;// (count == 0) ? filename + extension : filename + "(" + count + ")" + extension; + if (count == 0) { + newFilename = filename + extension; + } else { + newFilename = filename + "(" + count + ")" + extension; + } + + getFileSHAAsync(repoOwner, repoName, newFilename, token, new Callback() { + @Override + public String onResult(String sha) { + if (sha == null) { + // File does not exist, return the new unique filename + callback.onResult(newFilename); + } else { + // File exists, recursively try with the next count + checkFileExists(repoOwner, repoName, filename, extension, count + 1, token, callback); + } + return null; + } + }); + } } From 28cc6c7fe660f575a5d74d8159e02640097cf178 Mon Sep 17 00:00:00 2001 From: Milton Barrera Date: Tue, 11 Feb 2025 19:45:25 -0600 Subject: [PATCH 3/5] Using unique name for the file on commit --- .../net/osmtracker/activity/GitHubUpload.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/net/osmtracker/activity/GitHubUpload.java b/app/src/main/java/net/osmtracker/activity/GitHubUpload.java index d2265cf3..7b1a2ae9 100644 --- a/app/src/main/java/net/osmtracker/activity/GitHubUpload.java +++ b/app/src/main/java/net/osmtracker/activity/GitHubUpload.java @@ -31,7 +31,9 @@ import net.osmtracker.GitHubUser; import net.osmtracker.R; import net.osmtracker.db.DbGitHubUser; +import net.osmtracker.util.Callback; import net.osmtracker.util.DialogUtils; +import net.osmtracker.util.GitHubUtils; import org.json.JSONArray; import org.json.JSONException; @@ -102,7 +104,22 @@ private void uploadCommit() { } } - startUploadGitHub(encondedFile.toString(), file.getName(), commitMsj); + String repoOwner = getRepoName().substring(0, getRepoName().indexOf("/")).replace(".base64", ""); + String repoName = getRepoName().substring(getRepoName().indexOf("/") + 1); + String repoFilePath = file.getName().replace(".base64", ""); + GitHubUtils.getGHFilenameAsync(repoOwner, repoName, repoFilePath, gitHubUser.getToken(), + new Callback() { + @Override + public String onResult(String result) { + if (result != null) { + System.out.println("uploading to GitHub: " + result); + startUploadGitHub(encondedFile.toString(), result, commitMsj); + } else { + System.out.println("Error while getting filename."); + } + return result; + } + }); } catch (IOException e) { Toast.makeText(GitHubUpload.this, R.string.gpx_file_read_error, Toast.LENGTH_SHORT).show(); e.printStackTrace(); @@ -147,7 +164,6 @@ private void openActivityOnClick(int btnId, Class destinatio * Either starts uploading directly if we are authenticated against GitHub */ private void startUploadGitHub(final String fileInBase64, String filename, String commitMsj){ - filename = filename.substring(0, filename.lastIndexOf(".")); String fullURL = getBaseURL()+"/repos/"+getRepoName()+"/contents/"+filename; ProgressDialog progressDialog = new ProgressDialog(this); From 832d812d79f60de0e91ac95ba8bc2840c910923d Mon Sep 17 00:00:00 2001 From: Milton Barrera Date: Tue, 11 Feb 2025 19:53:42 -0600 Subject: [PATCH 4/5] Using R.string for progress dialog --- app/src/main/java/net/osmtracker/activity/GitHubUpload.java | 2 +- app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/osmtracker/activity/GitHubUpload.java b/app/src/main/java/net/osmtracker/activity/GitHubUpload.java index 7b1a2ae9..d815bdad 100644 --- a/app/src/main/java/net/osmtracker/activity/GitHubUpload.java +++ b/app/src/main/java/net/osmtracker/activity/GitHubUpload.java @@ -167,7 +167,7 @@ private void startUploadGitHub(final String fileInBase64, String filename, Strin String fullURL = getBaseURL()+"/repos/"+getRepoName()+"/contents/"+filename; ProgressDialog progressDialog = new ProgressDialog(this); - progressDialog.setMessage("Subiendo el archivo " + filename + "..."); + progressDialog.setMessage(R.string.uploading_file + filename); progressDialog.setCancelable(true); progressDialog.show(); diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 05f78ac1..49294af6 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -185,6 +185,7 @@ Error al obtener información del repositorio Subido exitosamente" Error al subir + Subiendo: Error al leer el archivo GPX No se encontró el archivo GPX Selecciono el elemento: diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fa17520a..c4534692 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -211,6 +211,7 @@ Error with repository information Successfully uploaded" Error uploading + Uploading file: Error reading the GPX file GPX file not found Item Selected: From 4fbab9c6126573a8e3d2172a95a43a8c9f525bcf Mon Sep 17 00:00:00 2001 From: Milton Barrera Date: Wed, 7 May 2025 00:18:01 -0600 Subject: [PATCH 5/5] Manually performed translations are deleted --- app/src/main/res/values-es/strings.xml | 50 +------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 49294af6..6baa11ac 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -40,7 +40,6 @@ Exportar como GPX Compartir GPX Subir a OpenStreetMap - Subir a GitHub Visualizar Detalles Traza #{0} @@ -175,53 +174,6 @@ Repositorio de GitHub válido Repositorio de GitHub inválido - - Creado exitosamente - Error al crear - Error en base de datos - Guardado exitosamente - Error al guardar - Estado del pull request: - Error al obtener información del repositorio - Subido exitosamente" - Error al subir - Subiendo: - Error al leer el archivo GPX - No se encontró el archivo GPX - Selecciono el elemento: - Privado: - Indique el nombre del repositorio - Campo requerido - - Configurar - Token de GitHub: - Obtener token - Cómo obtener un token de GitHub: - 1. Haga clic en el botón para abrir el sitio web de GitHub y crear un token. Inicie sesión con su cuenta de GitHub si es necesario. - 2. Seleccione \"Tokens (Clásicos)\" y haga clic en el botón \"Generar nuevo token\". - 3. Asigne un nombre descriptivo a su token. - 4. Seleccione una fecha de expiración. Recomendamos \"Sin expiración\" para evitar repetir este paso. - 5. Seleccione los permisos que desee otorgar al token (OSMTracker solo necesita el permiso de repositorio). - 6. Haga clic en el botón \"Generar token\". - 7. Copie el token generado y péguelo en el campo \"Token de GitHub\". - ⚠️ Puede guardar en blanco para borrar sus credenciales. - - Mensaje del commit: - Crear\nfork - Abrir pull request - Seleccione un repositorio - Crear repositorio - Hacer commit - Configurar - - Usuario del repositorio original - Nombre del repositorio original - Crear - - Título del Pull Request - Descripción del Pull Request - - Introducción a OSMTracker para Android ™ @@ -231,4 +183,4 @@ Feliz trazado 🗺 😎 OSMTracker para Android usará su ubicación GPS para registrar puntos de traza y puntos, incluso cuando la aplicación se está ejecutando en segundo plano. Tus datos no se utilizan para respaldar anuncios. - + \ No newline at end of file