From f99a3fab11f37e6bff4763f7c6d0c840d333e041 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Fri, 22 Nov 2019 09:27:25 -0600 Subject: [PATCH] Truncate google task titles and descriptions Google returns HTTP 400 if limits are exceeded --- .../gtasks/GoogleTaskSynchronizerTest.java | 43 +++++++++++++++++++ .../tasks/gtasks/GoogleTaskSynchronizer.java | 29 ++++++++++--- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/app/src/androidTest/java/org/tasks/gtasks/GoogleTaskSynchronizerTest.java b/app/src/androidTest/java/org/tasks/gtasks/GoogleTaskSynchronizerTest.java index 01974e266..234b8f3e1 100644 --- a/app/src/androidTest/java/org/tasks/gtasks/GoogleTaskSynchronizerTest.java +++ b/app/src/androidTest/java/org/tasks/gtasks/GoogleTaskSynchronizerTest.java @@ -4,7 +4,10 @@ import static com.natpryce.makeiteasy.MakeItEasy.with; import static com.todoroo.astrid.data.Task.HIDE_UNTIL_DUE; import static com.todoroo.astrid.data.Task.HIDE_UNTIL_DUE_TIME; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; +import static org.tasks.gtasks.GoogleTaskSynchronizer.getTruncatedValue; import static org.tasks.gtasks.GoogleTaskSynchronizer.mergeDates; +import static org.tasks.gtasks.GoogleTaskSynchronizer.truncate; import static org.tasks.makers.TaskMaker.DUE_DATE; import static org.tasks.makers.TaskMaker.DUE_TIME; import static org.tasks.makers.TaskMaker.HIDE_TYPE; @@ -104,4 +107,44 @@ public class GoogleTaskSynchronizerTest { assertEquals(0, local.getHideUntil().longValue()); } + + @Test + public void truncateValue() { + assertEquals("1234567", truncate("12345678", 7)); + } + + @Test + public void dontTruncateMax() { + assertEquals("1234567", truncate("1234567", 7)); + } + + @Test + public void dontTruncateShortValue() { + assertEquals("12345", truncate("12345", 7)); + } + + @Test + public void dontTruncateNull() { + assertNull(truncate(null, 7)); + } + + @Test + public void dontOverwriteTruncatedValue() { + assertEquals("123456789", getTruncatedValue("123456789", "1234567", 7)); + } + + @Test + public void overwriteTruncatedValueWithShortenedValue() { + assertEquals("12345", getTruncatedValue("123456789", "12345", 7)); + } + + @Test + public void overwriteTruncatedValueWithNullValue() { + assertNull(getTruncatedValue("123456789", null, 7)); + } + + @Test + public void overwriteNullValueWithTruncatedValue() { + assertEquals("1234567", getTruncatedValue(null, "1234567", 7)); + } } diff --git a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java index 9dfffb519..c0a0cc352 100644 --- a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java +++ b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java @@ -7,6 +7,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.text.TextUtils; +import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.googleapis.json.GoogleJsonResponseException; @@ -59,6 +60,8 @@ import timber.log.Timber; public class GoogleTaskSynchronizer { private static final String DEFAULT_LIST = "@default"; // $NON-NLS-1$ + private static final int MAX_TITLE_LENGTH = 1024; + private static final int MAX_DESCRIPTION_LENGTH = 8192; private static final Comparator PARENTS_FIRST = (o1, o2) -> { @@ -287,7 +290,8 @@ public class GoogleTaskSynchronizer { return; } - com.google.api.services.tasks.model.Task remoteModel; + com.google.api.services.tasks.model.Task remoteModel = + new com.google.api.services.tasks.model.Task(); boolean newlyCreated = false; String remoteId; @@ -302,12 +306,10 @@ public class GoogleTaskSynchronizer { if (!Strings.isNullOrEmpty(selectedList)) { listId = selectedList; } - remoteModel = new com.google.api.services.tasks.model.Task(); newlyCreated = true; } else { // update case remoteId = gtasksMetadata.getRemoteId(); listId = gtasksMetadata.getListId(); - remoteModel = new com.google.api.services.tasks.model.Task(); remoteModel.setId(remoteId); } @@ -323,8 +325,8 @@ public class GoogleTaskSynchronizer { remoteModel.setDeleted(true); } - remoteModel.setTitle(task.getTitle()); - remoteModel.setNotes(task.getNotes()); + remoteModel.setTitle(truncate(task.getTitle(), MAX_TITLE_LENGTH)); + remoteModel.setNotes(truncate(task.getNotes(), MAX_DESCRIPTION_LENGTH)); if (task.hasDueDate()) { remoteModel.setDue(GtasksApiUtilities.unixTimeToGtasksDueDate(task.getDueDate())); } @@ -474,13 +476,13 @@ public class GoogleTaskSynchronizer { task = taskCreator.createWithValues(""); } - task.setTitle(gtask.getTitle()); + task.setTitle(getTruncatedValue(task.getTitle(), gtask.getTitle(), MAX_TITLE_LENGTH)); task.setCreationDate(DateUtilities.now()); task.setCompletionDate( GtasksApiUtilities.gtasksCompletedTimeToUnixTime(gtask.getCompleted())); long dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(gtask.getDue()); mergeDates(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate), task); - task.setNotes(gtask.getNotes()); + task.setNotes(getTruncatedValue(task.getNotes(), gtask.getNotes(), MAX_DESCRIPTION_LENGTH)); googleTask.setListId(listId); googleTask.setLastSync(DateUtilities.now() + 1000L); write(task, googleTask); @@ -489,6 +491,19 @@ public class GoogleTaskSynchronizer { googleTaskListDao.insertOrReplace(list); } + static String truncate(@Nullable String string, int max) { + return string == null || string.length() <= max ? string : string.substring(0, max); + } + + static String getTruncatedValue(@Nullable String currentValue, @Nullable String newValue, int maxLength) { + return Strings.isNullOrEmpty(newValue) + || newValue.length() < maxLength + || Strings.isNullOrEmpty(currentValue) + || !currentValue.startsWith(newValue) + ? newValue + : currentValue; + } + private void write(Task task, GoogleTask googleTask) { if (!(TextUtils.isEmpty(task.getTitle()) && TextUtils.isEmpty(task.getNotes()))) { task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);