Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordesperateCoder <echotodevnull@gmail.com>2020-11-22 18:38:56 +0300
committerNiedermann IT-Dienstleistungen <stefan-niedermann@users.noreply.github.com>2020-11-22 21:02:36 +0300
commit0a92d7e1f4215528ae33103ca3081b72c3a69407 (patch)
tree4c8b56c66a897be78c4b9a683bc041221d0fe7c0
parent4f461a13a4dfd941ecb8ec8337bf1410103c85f9 (diff)
#359 etags: first steps - board list and board
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java5
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java62
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java9
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java11
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java8
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java4
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java22
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java21
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java24
9 files changed, 128 insertions, 38 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java b/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
index a303a8a33..1f0148b91 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/api/DeckAPI.java
@@ -1,6 +1,8 @@
package it.niedermann.nextcloud.deck.api;
+import com.nextcloud.android.sso.api.ParsedResponse;
+
import java.util.List;
import io.reactivex.Observable;
@@ -33,6 +35,7 @@ import retrofit2.http.Query;
public interface DeckAPI {
String MODIFIED_SINCE_HEADER = "If-Modified-Since";
+ String IF_NONE_MATCH = "If-None-Match";
// ### BOARDS
@POST("boards")
@@ -51,7 +54,7 @@ public interface DeckAPI {
Observable<FullBoard> restoreBoard(@Path("id") long id);
@GET("boards")
- Observable<List<FullBoard>> getBoards(@Query ("details") boolean verbose, @Header(MODIFIED_SINCE_HEADER) String lastSync );
+ Observable<ParsedResponse<List<FullBoard>>> getBoards(@Query ("details") boolean verbose, @Header(MODIFIED_SINCE_HEADER) String lastSync, @Header(IF_NONE_MATCH) String eTag);
// ### Stacks
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java b/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
index 8601cab41..22d84850e 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/api/JsonToEntityParser.java
@@ -284,6 +284,7 @@ public class JsonToEntityParser {
makeTraceableIfFails(() -> {
board.setTitle(getNullAsEmptyString(e.get("title")));
board.setColor(getNullAsEmptyString(e.get("color")));
+ board.setEtag(getNullAsEmptyString(e.get("ETag")));
board.setArchived(e.get("archived").getAsBoolean());
board.setLastModified(getTimestampFromLong(e.get("lastModified")));
@@ -396,6 +397,7 @@ public class JsonToEntityParser {
card.setDescription(getNullAsEmptyString(e.get("description")));
card.setStackId(e.get("stackId").getAsLong());
card.setType(getNullAsEmptyString(e.get("type")));
+ card.setEtag(getNullAsEmptyString(e.get("ETag")));
card.setLastModified(getTimestampFromLong(e.get("lastModified")));
card.setCreatedAt(getTimestampFromLong(e.get("createdAt")));
card.setDeletedAt(getTimestampFromLong(e.get("deletedAt")));
@@ -456,6 +458,7 @@ public class JsonToEntityParser {
a.setId(e.get("id").getAsLong());
a.setCardId(e.get("cardId").getAsLong());
a.setType(e.get("type").getAsString());
+ a.setEtag(getNullAsEmptyString(e.get("ETag")));
a.setData(e.get("data").getAsString());
a.setLastModified(getTimestampFromLong(e.get("lastModified")));
a.setCreatedAt(getTimestampFromLong(e.get("createdAt")));
@@ -571,33 +574,6 @@ public class JsonToEntityParser {
return Color.GRAY;
}
- protected static List<Activity> parseActivity(JsonObject e) {
- DeckLog.verbose(e.toString());
- List<Activity> activityList = new ArrayList<>();
-
- makeTraceableIfFails(() -> {
- if (e.has("ocs")) {
- JsonObject ocs = e.getAsJsonObject("ocs");
- if (ocs.has("data")) {
- JsonArray data = ocs.getAsJsonArray("data");
- for (JsonElement activityJson : data) {
- Activity activity = new Activity();
- JsonObject activityObject = activityJson.getAsJsonObject();
-
- activity.setId(activityObject.get("activity_id").getAsLong());
- activity.setType(ActivityType.findByPath(getNullAsEmptyString(activityObject.get("icon"))).getId());
- activity.setSubject(getNullAsEmptyString(activityObject.get("subject")));
- activity.setCardId(activityObject.get("object_id").getAsLong());
- activity.setLastModified(getTimestampFromString(activityObject.get("datetime")));
-
- activityList.add(activity);
- }
- }
- }
- }, e);
- return activityList;
- }
-
protected static FullStack parseStack(JsonObject e) {
DeckLog.verbose(e.toString());
FullStack fullStack = new FullStack();
@@ -607,6 +583,7 @@ public class JsonToEntityParser {
stack.setTitle(getNullAsEmptyString(e.get("title")));
stack.setBoardId(e.get("boardId").getAsLong());
stack.setId(e.get("id").getAsLong());
+ stack.setEtag(getNullAsEmptyString(e.get("ETag")));
stack.setLastModified(getTimestampFromLong(e.get("lastModified")));
stack.setDeletedAt(getTimestampFromLong(e.get("deletedAt")));
if (e.has("order") && !e.get("order").isJsonNull()) {
@@ -627,6 +604,34 @@ public class JsonToEntityParser {
return fullStack;
}
+ protected static List<Activity> parseActivity(JsonObject e) {
+ DeckLog.verbose(e.toString());
+ List<Activity> activityList = new ArrayList<>();
+
+ makeTraceableIfFails(() -> {
+ if (e.has("ocs")) {
+ JsonObject ocs = e.getAsJsonObject("ocs");
+ if (ocs.has("data")) {
+ JsonArray data = ocs.getAsJsonArray("data");
+ for (JsonElement activityJson : data) {
+ Activity activity = new Activity();
+ JsonObject activityObject = activityJson.getAsJsonObject();
+
+ activity.setId(activityObject.get("activity_id").getAsLong());
+ activity.setType(ActivityType.findByPath(getNullAsEmptyString(activityObject.get("icon"))).getId());
+ activity.setSubject(getNullAsEmptyString(activityObject.get("subject")));
+ activity.setCardId(activityObject.get("object_id").getAsLong());
+ activity.setEtag(getNullAsEmptyString(e.get("ETag")));
+ activity.setLastModified(getTimestampFromString(activityObject.get("datetime")));
+
+ activityList.add(activity);
+ }
+ }
+ }
+ }, e);
+ return activityList;
+ }
+
protected static Label parseLabel(JsonObject e) {
DeckLog.verbose(e.toString());
Label label = new Label();
@@ -635,13 +640,14 @@ public class JsonToEntityParser {
//todo: last modified!
// label.setLastModified(get);
label.setTitle(getNullAsEmptyString(e.get("title")));
+ label.setEtag(getNullAsEmptyString(e.get("ETag")));
label.setColor(getColorAsInt(e, "color"));
}, e);
return label;
}
private static String getNullAsEmptyString(JsonElement jsonElement) {
- return jsonElement.isJsonNull() ? "" : jsonElement.getAsString();
+ return jsonElement == null || jsonElement.isJsonNull() ? "" : jsonElement.getAsString();
}
private static Instant getTimestampFromString(JsonElement jsonElement) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
index 1c189d162..8abcbced7 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Account.java
@@ -54,6 +54,7 @@ public class Account implements Serializable {
private boolean maintenanceEnabled = false;
private String etag;
+ private String boardsEtag;
@Ignore
public Account(Long id, @NonNull String name, @NonNull String userName, @NonNull String url) {
@@ -190,6 +191,14 @@ public class Account implements Serializable {
this.etag = etag;
}
+ public String getBoardsEtag() {
+ return boardsEtag;
+ }
+
+ public void setBoardsEtag(String boardsEtag) {
+ this.boardsEtag = boardsEtag;
+ }
+
/**
* A cache buster parameter is added for duplicate account names on different hosts which shall be fetched from the same {@link SingleSignOnAccount} (e. g. {@link AccountSwitcherDialog})
*
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java
index 54cd0fc31..2f7771383 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/AbstractRemoteEntity.java
@@ -39,6 +39,8 @@ public abstract class AbstractRemoteEntity implements IRemoteEntity {
protected Instant lastModified;
protected Instant lastModifiedLocal;
+ protected String etag;
+
public AbstractRemoteEntity() {
}
@@ -137,6 +139,15 @@ public abstract class AbstractRemoteEntity implements IRemoteEntity {
this.status = status.getId();
}
+ @Override
+ public String getEtag() {
+ return etag;
+ }
+
+ @Override
+ public void setEtag(String etag) {
+ this.etag = etag;
+ }
@Override
public boolean equals(Object o) {
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java
index f50bf0b90..f197c0d30 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/interfaces/IRemoteEntity.java
@@ -68,6 +68,14 @@ public interface IRemoteEntity {
getEntity().setStatusEnum(status);
}
+ default String getEtag() {
+ return getEntity().getEtag();
+ }
+
+ default void setEtag(String etag) {
+ getEntity().setEtag(etag);
+ }
+
default <T> List<T> copyList(List<T> listToCopy) {
if (listToCopy == null) {
return null;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
index a0b9fd8aa..bff8ddfdb 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/ServerAdapter.java
@@ -125,9 +125,9 @@ public class ServerAdapter {
// return lastSyncHeader;
}
- public void getBoards(IResponseCallback<List<FullBoard>> responseCallback) {
+ public void getBoards(IResponseCallback<ParsedResponse<List<FullBoard>>> responseCallback) {
RequestHelper.request(provider, () ->
- provider.getDeckAPI().getBoards(true, getLastSyncDateFormatted(responseCallback.getAccount().getId())),
+ provider.getDeckAPI().getBoards(true, getLastSyncDateFormatted(responseCallback.getAccount().getId()), responseCallback.getAccount().getBoardsEtag()),
responseCallback);
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java
index 0ac0f786b..a491946ed 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/adapters/db/DeckDatabase.java
@@ -97,7 +97,7 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.dao.widgets.Sta
UserInBoard.class,
},
exportSchema = false,
- version = 22
+ version = 23
)
@TypeConverters({DateTypeConverter.class})
public abstract class DeckDatabase extends RoomDatabase {
@@ -375,6 +375,25 @@ public abstract class DeckDatabase extends RoomDatabase {
}
};
+ private static final Migration MIGRATION_22_23 = new Migration(22, 23) {
+ @Override
+ public void migrate(SupportSQLiteDatabase database) {
+ // https://github.com/stefan-niedermann/nextcloud-deck/issues/359
+ database.execSQL("ALTER TABLE `Account` ADD `boardsEtag` TEXT");
+ database.execSQL("ALTER TABLE `Board` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Stack` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Card` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Label` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `AccessControl` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Attachment` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `User` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `DeckComment` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `Activity` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `OcsProject` ADD `etag` TEXT");
+ database.execSQL("ALTER TABLE `OcsProjectResource` ADD `etag` TEXT");
+ }
+ };
+
public static final RoomDatabase.Callback ON_CREATE_CALLBACK = new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
@@ -434,6 +453,7 @@ public abstract class DeckDatabase extends RoomDatabase {
lastSyncPref.apply();
}
})
+ .addMigrations(MIGRATION_22_23)
.fallbackToDestructiveMigration()
.addCallback(ON_CREATE_CALLBACK)
.build();
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java
index 032c3594a..69e3833cf 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/SyncHelper.java
@@ -1,5 +1,8 @@
package it.niedermann.nextcloud.deck.persistence.sync.helpers;
+import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
+
+import java.net.HttpURLConnection;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -53,9 +56,10 @@ public class SyncHelper {
DeckLog.log("Conflicting changes on entity: " + existingEntity);
// TODO: what to do?
} else {
-// if (existingEntity.getLastModified().getTime() == entityFromServer.getLastModified().getTime()) {
-// continue; // TODO: is this is ok for sure? -> isn`t! NPE
-// }
+ if (entityFromServer.getEtag() != null && entityFromServer.getEtag().equals(existingEntity.getEtag())) {
+ DeckLog.info("ETags do match! skipping this one.");
+ continue;
+ }
provider.updateInDB(dataBaseAdapter, accountId, applyUpdatesFromRemote(provider, existingEntity, entityFromServer, accountId), false);
}
}
@@ -73,8 +77,17 @@ public class SyncHelper {
@Override
public void onError(Throwable throwable) {
+ super.onError(throwable);
+ if (throwable.getClass() == NextcloudHttpRequestFailedException.class) {
+ NextcloudHttpRequestFailedException requestFailedException = (NextcloudHttpRequestFailedException) throwable;
+ if (HttpURLConnection.HTTP_NOT_MODIFIED == requestFailedException.getStatusCode()){
+ DeckLog.info("ETags do match! skipping this one.");
+ // well, etags say we're fine here. no need to go deeper.
+ provider.childDone(provider, responseCallback, false);
+ return;
+ }
+ }
provider.onError(throwable, responseCallback);
- DeckLog.logError(throwable);
responseCallback.onError(throwable);
}
}, lastSync);
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java
index 5b458471f..f5e071adb 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/BoardDataProvider.java
@@ -1,5 +1,9 @@
package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers;
+import android.annotation.SuppressLint;
+
+import com.nextcloud.android.sso.api.ParsedResponse;
+
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
@@ -26,8 +30,24 @@ public class BoardDataProvider extends AbstractSyncDataProvider<FullBoard> {
}
@Override
- public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<FullBoard>> responder, Instant lastSync) {
- serverAdapter.getBoards(responder);
+ public void getAllFromServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<List<FullBoard>> responder, Instant lastSync) {
+ serverAdapter.getBoards(new IResponseCallback<ParsedResponse<List<FullBoard>>>(responder.getAccount()) {
+ @Override
+ public void onResponse(ParsedResponse<List<FullBoard>> response) {
+ String etag = response.getHeaders().get("ETag");
+ if (etag != null && !etag.equals(account.getBoardsEtag())) {
+ account.setBoardsEtag(etag);
+ dataBaseAdapter.updateAccount(account);
+ }
+ responder.onResponse(response.getResponse());
+ }
+
+ @SuppressLint("MissingSuperCall")
+ @Override
+ public void onError(Throwable throwable) {
+ responder.onError(throwable);
+ }
+ });
}
@Override