diff options
Diffstat (limited to 'app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers')
13 files changed, 463 insertions, 110 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AbstractSyncDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AbstractSyncDataProvider.java index 166d6c519..11fb38a66 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AbstractSyncDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AbstractSyncDataProvider.java @@ -1,9 +1,10 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; +import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.List; +import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.model.interfaces.IRemoteEntity; import it.niedermann.nextcloud.deck.persistence.sync.adapters.ServerAdapter; @@ -26,28 +27,37 @@ public abstract class AbstractSyncDataProvider<T extends IRemoteEntity> { } } - public void handleDeletes(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, List<T> entitiesFromServer){ + public void handleDeletes(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, List<T> entitiesFromServer) { // do nothing as a default. } /** * Searches each entry of <code>listB</code> in list <code>listA</code> and returns the missing ones + * * @param listA List * @param listB List * @return all entries of <code>listB</code> missing in <code>listA</code> */ - public static <T extends IRemoteEntity> List<T> findDelta(List<T> listA, List<T> listB){ + public static <T extends IRemoteEntity> List<T> findDelta(List<T> listA, List<T> listB) { List<T> delta = new ArrayList<>(); for (T b : listB) { + if (b == null) { + DeckLog.error("Entry in listB is null! skipping..."); + continue; + } boolean found = false; for (T a : listA) { - if ((a.getLocalId()!= null && b.getLocalId()!= null ? (a.getLocalId().equals(b.getLocalId())) + if (a == null) { + DeckLog.error("Entry in listA is null! skipping..."); + continue; + } + if ((a.getLocalId() != null && b.getLocalId() != null ? (a.getLocalId().equals(b.getLocalId())) : a.getId().equals(b.getId())) && b.getAccountId() == a.getAccountId()) { found = true; break; } } - if (!found){ + if (!found) { delta.add(b); } } @@ -58,7 +68,14 @@ public abstract class AbstractSyncDataProvider<T extends IRemoteEntity> { children.add(child); } - public abstract void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<T>> responder, Date lastSync); + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<T>> responder, Instant lastSync) { + return; + } + + public void getAllFromServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<List<T>> responder, Instant lastSync) { + // Overridden, because we also need the DB-Adapter at some points here (see ACL data provider) + getAllFromServer(serverAdapter, accountId, responder, lastSync); + } public abstract T getSingleFromDB(DataBaseAdapter dataBaseAdapter, long accountId, T entity); @@ -72,7 +89,7 @@ public abstract class AbstractSyncDataProvider<T extends IRemoteEntity> { public abstract void deleteInDB(DataBaseAdapter dataBaseAdapter, long accountId, T t); - public void deletePhysicallyInDB(DataBaseAdapter dataBaseAdapter, long accountId, T t){ + public void deletePhysicallyInDB(DataBaseAdapter dataBaseAdapter, long accountId, T t) { deleteInDB(dataBaseAdapter, accountId, t); } @@ -106,7 +123,7 @@ public abstract class AbstractSyncDataProvider<T extends IRemoteEntity> { stillGoingDeeper = true; } - public abstract List<T> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync); + public abstract List<T> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync); public void goDeeperForUpSync(SyncHelper syncHelper, ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, IResponseCallback<Boolean> callback) { //do nothing diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AccessControlDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AccessControlDataProvider.java index 3242ab7c1..6dde6b45c 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AccessControlDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AccessControlDataProvider.java @@ -1,17 +1,24 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; -import java.util.Date; +import java.time.Instant; import java.util.List; +import java.util.concurrent.CountDownLatch; +import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.model.AccessControl; +import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.User; import it.niedermann.nextcloud.deck.model.full.FullBoard; +import it.niedermann.nextcloud.deck.model.ocs.user.GroupMemberUIDs; +import it.niedermann.nextcloud.deck.model.ocs.user.OcsUser; import it.niedermann.nextcloud.deck.persistence.sync.adapters.ServerAdapter; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DataBaseAdapter; +import it.niedermann.nextcloud.deck.persistence.sync.helpers.util.AsyncUtil; public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessControl> { + private static final Long TYPE_GROUP = 1L; private List<AccessControl> acl; private FullBoard board; @@ -22,10 +29,66 @@ public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessCo } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<AccessControl>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<List<AccessControl>> responder, Instant lastSync) { + AsyncUtil.awaitAsyncWork(acl.size(), latch -> { + for (AccessControl accessControl : acl) { + if (accessControl.getType() == TYPE_GROUP) { + serverAdapter.searchGroupMembers(accessControl.getUser().getUid(), new IResponseCallback<GroupMemberUIDs>(responder.getAccount()) { + @Override + public void onResponse(GroupMemberUIDs response) { + accessControl.setGroupMemberUIDs(response); + if (response.getUids().size() > 0) { + ensureGroupMembersInDB(getAccount(), dataBaseAdapter, serverAdapter, response); + } + latch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + super.onError(throwable); + latch.countDown(); + } + }); + } else latch.countDown(); + } + }); + responder.onResponse(acl); } + private void ensureGroupMembersInDB(Account account, DataBaseAdapter dataBaseAdapter, ServerAdapter serverAdapter, GroupMemberUIDs response) { + CountDownLatch memberLatch = new CountDownLatch(response.getUids().size()); + for (String uid : response.getUids()) { + User user = dataBaseAdapter.getUserByUidDirectly(account.getId(), uid); + if (user == null) { + // unknown user. fetch! + serverAdapter.getSingleUserData(uid, new IResponseCallback<OcsUser>(account) { + @Override + public void onResponse(OcsUser response) { + DeckLog.log(response.toString()); + User user = new User(); + user.setUid(response.getId()); + user.setPrimaryKey(response.getId()); + user.setDisplayname(response.getDisplayName()); + dataBaseAdapter.createUser(account.getId(), user); + memberLatch.countDown(); + } + + @Override + public void onError(Throwable throwable) { + super.onError(throwable); + memberLatch.countDown(); + } + }); + } else memberLatch.countDown(); + } + try { + memberLatch.await(); + } catch (InterruptedException e) { + DeckLog.logError(e); + } + } + @Override public AccessControl getSingleFromDB(DataBaseAdapter dataBaseAdapter, long accountId, AccessControl entity) { return dataBaseAdapter.getAccessControlByRemoteIdDirectly(accountId, entity.getEntity().getId()); @@ -34,7 +97,26 @@ public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessCo @Override public long createInDB(DataBaseAdapter dataBaseAdapter, long accountId, AccessControl entity) { prepareUser(dataBaseAdapter, accountId, entity); - return dataBaseAdapter.createAccessControl(accountId, entity); + long newId = dataBaseAdapter.createAccessControl(accountId, entity); + entity.setLocalId(newId); + handleGroupMemberships(dataBaseAdapter, entity); + return newId; + } + + private void handleGroupMemberships(DataBaseAdapter dataBaseAdapter, AccessControl entity) { + if (entity.getType() != TYPE_GROUP) { + return; + } + dataBaseAdapter.deleteGroupMembershipsOfGroup(entity.getUser().getLocalId()); + if (entity.getGroupMemberUIDs() == null) { + return; + } + for (String groupMemberUID : entity.getGroupMemberUIDs().getUids()) { + User member = dataBaseAdapter.getUserByUidDirectly(entity.getAccountId(), groupMemberUID); + if (member != null) { + dataBaseAdapter.addUserToGroup(entity.getUserId(), member.getLocalId()); + } + } } private void prepareUser(DataBaseAdapter dataBaseAdapter, long accountId, AccessControl entity) { @@ -42,6 +124,7 @@ public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessCo if (user == null) { long userId = dataBaseAdapter.createUser(accountId, entity.getUser()); entity.setUserId(userId); + entity.getUser().setLocalId(userId); } else { entity.setUserId(user.getLocalId()); entity.getUser().setLocalId(user.getLocalId()); @@ -52,7 +135,9 @@ public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessCo @Override public void updateInDB(DataBaseAdapter dataBaseAdapter, long accountId, AccessControl entity, boolean setStatus) { prepareUser(dataBaseAdapter, accountId, entity); + entity.setBoardId(board.getLocalId()); dataBaseAdapter.updateAccessControl(entity, setStatus); + handleGroupMemberships(dataBaseAdapter, entity); } @Override @@ -64,6 +149,9 @@ public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessCo public void createOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<AccessControl> responder, AccessControl entity) { AccessControl acl = new AccessControl(entity); acl.setBoardId(board.getBoard().getId()); + if (acl.getUser() == null && acl.getUserId() != null) { + acl.setUser(dataBaseAdapter.getUserByLocalIdDirectly(acl.getUserId())); + } serverAdapter.createAccessControl(board.getBoard().getId(), acl, responder); } @@ -79,6 +167,7 @@ public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessCo @Override public void deletePhysicallyInDB(DataBaseAdapter dataBaseAdapter, long accountId, AccessControl accessControl) { + dataBaseAdapter.deleteGroupMembershipsOfGroup(accessControl.getUser().getLocalId()); dataBaseAdapter.deleteAccessControl(accessControl, false); } @@ -88,7 +177,7 @@ public class AccessControlDataProvider extends AbstractSyncDataProvider<AccessCo } @Override - public List<AccessControl> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { + public List<AccessControl> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { return dataBaseAdapter.getLocallyChangedAccessControl(accountId, board.getLocalId()); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/ActivityDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/ActivityDataProvider.java index a3785ca78..5a7abf732 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/ActivityDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/ActivityDataProvider.java @@ -1,7 +1,9 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; -import java.util.ArrayList; -import java.util.Date; +import androidx.annotation.NonNull; + +import java.time.Instant; +import java.util.Collections; import java.util.List; import it.niedermann.nextcloud.deck.api.IResponseCallback; @@ -12,15 +14,16 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DataBaseAdapter public class ActivityDataProvider extends AbstractSyncDataProvider<Activity> { - protected Card card; + @NonNull + private final Card card; - public ActivityDataProvider(AbstractSyncDataProvider<?> parent, Card card) { + public ActivityDataProvider(AbstractSyncDataProvider<?> parent, @NonNull Card card) { super(parent); this.card = card; } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<Activity>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<Activity>> responder, Instant lastSync) { serverAdapter.getActivitiesForCard(card.getId(), responder); } @@ -65,7 +68,7 @@ public class ActivityDataProvider extends AbstractSyncDataProvider<Activity> { } @Override - public List<Activity> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { - return new ArrayList<>(); + public List<Activity> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { + return Collections.emptyList(); } } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java index 37e00dada..781f7b1f4 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java @@ -4,7 +4,7 @@ import android.net.Uri; import java.io.File; import java.io.IOException; -import java.util.Date; +import java.time.Instant; import java.util.List; import it.niedermann.nextcloud.deck.DeckLog; @@ -32,7 +32,7 @@ public class AttachmentDataProvider extends AbstractSyncDataProvider<Attachment> } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<Attachment>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<Attachment>> responder, Instant lastSync) { responder.onResponse(attachments); } @@ -104,7 +104,7 @@ public class AttachmentDataProvider extends AbstractSyncDataProvider<Attachment> } @Override - public List<Attachment> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { + public List<Attachment> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { return dataBaseAdapter.getLocallyChangedAttachmentsByLocalCardIdDirectly(accountId, card.getLocalId()); } @@ -120,7 +120,7 @@ public class AttachmentDataProvider extends AbstractSyncDataProvider<Attachment> dataBaseAdapter.deleteAttachment(accountId, attachment, false); } for (Attachment attachment : entitiesFromServer) { - if (attachment.getDeletedAt() != null && attachment.getDeletedAt().getTime() != 0) { + if (attachment.getDeletedAt() != null && attachment.getDeletedAt().toEpochMilli() != 0) { Attachment toDelete = dataBaseAdapter.getAttachmentByRemoteIdDirectly(accountId, attachment.getId()); if (toDelete != null) { dataBaseAdapter.deleteAttachment(accountId, toDelete, false); 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 98163029f..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,14 +1,16 @@ 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; -import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.CountDownLatch; -import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.model.AccessControl; import it.niedermann.nextcloud.deck.model.Board; @@ -19,16 +21,33 @@ import it.niedermann.nextcloud.deck.model.full.FullStack; import it.niedermann.nextcloud.deck.persistence.sync.adapters.ServerAdapter; import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DataBaseAdapter; import it.niedermann.nextcloud.deck.persistence.sync.helpers.SyncHelper; +import it.niedermann.nextcloud.deck.persistence.sync.helpers.util.AsyncUtil; public class BoardDataProvider extends AbstractSyncDataProvider<FullBoard> { - public BoardDataProvider(){ + public BoardDataProvider() { super(null); } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<FullBoard>> responder, Date 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 @@ -39,27 +58,65 @@ public class BoardDataProvider extends AbstractSyncDataProvider<FullBoard> { @Override public long createInDB(DataBaseAdapter dataBaseAdapter, long accountId, FullBoard entity) { handleOwner(dataBaseAdapter, accountId, entity); - return dataBaseAdapter.createBoardDirectly(accountId, entity.getBoard()); + Long localId = dataBaseAdapter.createBoardDirectly(accountId, entity.getBoard()); + entity.getBoard().setLocalId(localId); + handleUsers(dataBaseAdapter, accountId, entity); + return localId; } private void handleOwner(DataBaseAdapter dataBaseAdapter, long accountId, FullBoard entity) { - if (entity.getOwner()!=null) { - User remoteOwner = entity.getOwner(); - User owner = dataBaseAdapter.getUserByUidDirectly(accountId, remoteOwner.getUid()); - if (owner == null){ - dataBaseAdapter.createUser(accountId, remoteOwner); - } else { - dataBaseAdapter.updateUser(accountId, remoteOwner, false); - } - owner = dataBaseAdapter.getUserByUidDirectly(accountId, remoteOwner.getUid()); + if (entity.getOwner() != null) { + User owner = createOrUpdateUser(dataBaseAdapter, accountId, entity.getOwner()); entity.getBoard().setOwnerId(owner.getLocalId()); } } + private void handleUsers(DataBaseAdapter dataBaseAdapter, long accountId, FullBoard entity) { + dataBaseAdapter.deleteBoardMembershipsOfBoard(entity.getLocalId()); + if (entity.getUsers() != null && !entity.getUsers().isEmpty()) { + for (User user : entity.getUsers()) { + if (user == null) { + continue; + } + User existing = createOrUpdateUser(dataBaseAdapter, accountId, user); + dataBaseAdapter.addUserToBoard(existing.getLocalId(), entity.getLocalId()); + } + } + } + + private User createOrUpdateUser(DataBaseAdapter dataBaseAdapter, long accountId, User remoteUser) { + User owner = dataBaseAdapter.getUserByUidDirectly(accountId, remoteUser.getUid()); + if (owner == null) { + dataBaseAdapter.createUser(accountId, remoteUser); + } else { + dataBaseAdapter.updateUser(accountId, remoteUser, false); + } + return dataBaseAdapter.getUserByUidDirectly(accountId, remoteUser.getUid()); + } + @Override public void updateInDB(DataBaseAdapter dataBaseAdapter, long accountId, FullBoard entity, boolean setStatus) { + handleDefaultLabels(dataBaseAdapter, entity); handleOwner(dataBaseAdapter, accountId, entity); dataBaseAdapter.updateBoard(entity.getBoard(), setStatus); + handleUsers(dataBaseAdapter, accountId, entity); + } + + private void handleDefaultLabels(DataBaseAdapter dataBaseAdapter, FullBoard entity) { + // ## merge labels (created at board creation): + // the server creates four default labels. if a board is copied, they will also be copied. At sync, after creating the board, the labels are already there. + // this merges the created default ones with the ones i already have. + if (entity != null && entity.getLabels() != null) { + for (Label label : entity.getLabels()) { + // does this label exist and unknown to server yet? + Label existing = dataBaseAdapter.getLabelByBoardIdAndTitleDirectly(entity.getLocalId(), label.getTitle()); + if (existing != null && existing.getId() == null) { + // take our label and lets say it IS the same as on server (but use the local color, no matter what the server says) + existing.setId(label.getId()); + dataBaseAdapter.updateLabel(existing, false); + } + } + } } @Override @@ -71,19 +128,19 @@ public class BoardDataProvider extends AbstractSyncDataProvider<FullBoard> { @Override public void goDeeper(SyncHelper syncHelper, FullBoard existingEntity, FullBoard entityFromServer, IResponseCallback<Boolean> callback) { List<Label> labels = entityFromServer.getLabels(); - if (labels != null && !labels.isEmpty()){ + if (labels != null && !labels.isEmpty()) { syncHelper.doSyncFor(new LabelDataProvider(this, existingEntity.getBoard(), labels)); } List<AccessControl> acl = entityFromServer.getParticipants(); - if (acl != null && !acl.isEmpty()){ - for (AccessControl ac : acl){ + if (acl != null && !acl.isEmpty()) { + for (AccessControl ac : acl) { ac.setBoardId(existingEntity.getLocalId()); } syncHelper.doSyncFor(new AccessControlDataProvider(this, existingEntity, acl)); } - if (entityFromServer.getStacks() != null && !entityFromServer.getStacks().isEmpty()){ + if (entityFromServer.getStacks() != null && !entityFromServer.getStacks().isEmpty()) { syncHelper.doSyncFor(new StackDataProvider(this, existingEntity)); } } @@ -94,7 +151,7 @@ public class BoardDataProvider extends AbstractSyncDataProvider<FullBoard> { } @Override - public List<FullBoard> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { + public List<FullBoard> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { return dataBaseAdapter.getLocallyChangedBoards(accountId); } @@ -102,21 +159,17 @@ public class BoardDataProvider extends AbstractSyncDataProvider<FullBoard> { public void goDeeperForUpSync(SyncHelper syncHelper, ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, IResponseCallback<Boolean> callback) { Long accountId = callback.getAccount().getId(); List<Label> locallyChangedLabels = dataBaseAdapter.getLocallyChangedLabels(accountId); - CountDownLatch countDownLatch = new CountDownLatch(locallyChangedLabels.size()); - for (Label label : locallyChangedLabels) { - Board board = dataBaseAdapter.getBoardByLocalIdDirectly(label.getBoardId()); - label.setBoardId(board.getId()); - syncHelper.doUpSyncFor(new LabelDataProvider(this, board, Collections.singletonList(label)), countDownLatch); - } - try { - countDownLatch.await(); - } catch (InterruptedException e) { - DeckLog.logError(e); - } + AsyncUtil.awaitAsyncWork(locallyChangedLabels.size(), (countDownLatch) -> { + for (Label label : locallyChangedLabels) { + Board board = dataBaseAdapter.getBoardByLocalIdDirectly(label.getBoardId()); + label.setBoardId(board.getId()); + syncHelper.doUpSyncFor(new LabelDataProvider(this, board, Collections.singletonList(label)), countDownLatch); + } + }); List<Long> localBoardIDsWithChangedACL = dataBaseAdapter.getBoardIDsOfLocallyChangedAccessControl(accountId); for (Long boardId : localBoardIDsWithChangedACL) { - syncHelper.doUpSyncFor(new AccessControlDataProvider(this, dataBaseAdapter.getFullBoardByLocalIdDirectly(accountId, boardId) ,new ArrayList<>())); + syncHelper.doUpSyncFor(new AccessControlDataProvider(this, dataBaseAdapter.getFullBoardByLocalIdDirectly(accountId, boardId), new ArrayList<>())); } Set<Long> syncedBoards = new HashSet<>(); diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java index 03e02bd70..0ceac2cd8 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/CardDataProvider.java @@ -1,12 +1,15 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; +import android.annotation.SuppressLint; + +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.List; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.api.IResponseCallback; +import it.niedermann.nextcloud.deck.exceptions.DeckException; import it.niedermann.nextcloud.deck.exceptions.OfflineException; import it.niedermann.nextcloud.deck.model.Account; import it.niedermann.nextcloud.deck.model.Attachment; @@ -37,7 +40,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<FullCard>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<FullCard>> responder, Instant lastSync) { List<FullCard> result = new ArrayList<>(); if (stack.getCards() == null || stack.getCards().isEmpty()) { @@ -54,6 +57,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { } } + @SuppressLint("MissingSuperCall") @Override public void onError(Throwable throwable) { responder.onError(throwable); @@ -70,7 +74,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { @Override public long createInDB(DataBaseAdapter dataBaseAdapter, long accountId, FullCard entity) { fixRelations(dataBaseAdapter, accountId, entity); - return dataBaseAdapter.createCard(accountId, entity.getCard()); + return dataBaseAdapter.createCardDirectly(accountId, entity.getCard()); } protected CardUpdate toCardUpdate(FullCard card) { @@ -144,10 +148,17 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { } else { DeckLog.verbose("Comments - Version is too low, DONT SYNC"); } + syncHelper.doSyncFor(new OcsProjectDataProvider(this, existingEntity.getCard())); } @Override public void createOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<FullCard> responder, FullCard entity) { + if (stack.getId() == null) { + responder.onError(new DeckException(DeckException.Hint.DEPENDENCY_NOT_SYNCED_YET, "Stack \"" + + stack.getStack().getTitle() + "\" for Card \"" + entity.getCard().getTitle() + + "\" is not synced yet. Perform a full sync (pull to refresh) as soon as you are online again.")); + return; + } entity.getCard().setStackId(stack.getId()); serverAdapter.createCard(board.getId(), stack.getId(), entity.getCard(), responder); } @@ -170,7 +181,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { } @Override - public List<FullCard> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { + public List<FullCard> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { if (board == null || stack == null) { // no cards changed! // (see call from StackDataProvider: goDeeperForUpSync called with null for board.) @@ -184,8 +195,13 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { public void goDeeperForUpSync(SyncHelper syncHelper, ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, IResponseCallback<Boolean> callback) { FullStack stack; Board board; + List<JoinCardWithLabel> changedLabels; + if (this.stack == null) { + changedLabels = dataBaseAdapter.getAllChangedLabelJoins(); + } else { + changedLabels = dataBaseAdapter.getAllChangedLabelJoinsForStack(this.stack.getLocalId()); + } - List<JoinCardWithLabel> changedLabels = dataBaseAdapter.getAllChangedJoins(); Account account = callback.getAccount(); for (JoinCardWithLabel changedLabelLocal : changedLabels) { Card card = dataBaseAdapter.getCardByLocalIdDirectly(account.getId(), changedLabelLocal.getCardId()); @@ -201,7 +217,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { board = this.board; } - JoinCardWithLabel changedLabel = dataBaseAdapter.getRemoteIdsForJoin(changedLabelLocal.getCardId(), changedLabelLocal.getLabelId()); + JoinCardWithLabel changedLabel = dataBaseAdapter.getAllChangedLabelJoinsWithRemoteIDs(changedLabelLocal.getCardId(), changedLabelLocal.getLabelId()); if (changedLabel.getStatusEnum() == DBStatus.LOCAL_DELETED) { if (changedLabel.getLabelId() == null || changedLabel.getCardId() == null) { dataBaseAdapter.deleteJoinedLabelForCardPhysicallyByRemoteIDs(account.getId(), changedLabel.getCardId(), changedLabel.getLabelId()); @@ -229,11 +245,22 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { } } - List<JoinCardWithUser> deletedUsers = dataBaseAdapter.getAllDeletedUserJoinsWithRemoteIDs(); - for (JoinCardWithUser deletedUser : deletedUsers) { - Card card = dataBaseAdapter.getCardByRemoteIdDirectly(account.getId(), deletedUser.getCardId()); + + List<JoinCardWithUser> changedUsers; + if (this.stack == null) { + changedUsers = dataBaseAdapter.getAllChangedUserJoinsWithRemoteIDs(); + } else { + changedUsers = dataBaseAdapter.getAllChangedUserJoinsWithRemoteIDsForStack(this.stack.getLocalId()); + } + for (JoinCardWithUser changedUser : changedUsers) { + // not already known to server? + if (changedUser.getCardId() == null) { + //skip for now + continue; + } + Card card = dataBaseAdapter.getCardByRemoteIdDirectly(account.getId(), changedUser.getCardId()); if (this.stack == null) { - stack = dataBaseAdapter.getFullStackByLocalIdDirectly(card.getLocalId()); + stack = dataBaseAdapter.getFullStackByLocalIdDirectly(card.getStackId()); } else { stack = this.stack; } @@ -243,16 +270,16 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { } else { board = this.board; } - User user = dataBaseAdapter.getUserByLocalIdDirectly(deletedUser.getUserId()); - if (deletedUser.getStatusEnum() == DBStatus.LOCAL_DELETED) { - serverAdapter.unassignUserFromCard(board.getId(), stack.getId(), deletedUser.getCardId(), user.getUid(), new IResponseCallback<Void>(account) { + User user = dataBaseAdapter.getUserByLocalIdDirectly(changedUser.getUserId()); + if (changedUser.getStatusEnum() == DBStatus.LOCAL_DELETED) { + serverAdapter.unassignUserFromCard(board.getId(), stack.getId(), changedUser.getCardId(), user.getUid(), new IResponseCallback<Void>(account) { @Override public void onResponse(Void response) { - dataBaseAdapter.deleteJoinedUserForCardPhysicallyByRemoteIDs(account.getId(), deletedUser.getCardId(), user.getUid()); + dataBaseAdapter.deleteJoinedUserForCardPhysicallyByRemoteIDs(account.getId(), changedUser.getCardId(), user.getUid()); } }); - } else if (deletedUser.getStatusEnum() == DBStatus.LOCAL_EDITED) { - serverAdapter.assignUserToCard(board.getId(), stack.getId(), deletedUser.getCardId(), user.getUid(), new IResponseCallback<Void>(account) { + } else if (changedUser.getStatusEnum() == DBStatus.LOCAL_EDITED) { + serverAdapter.assignUserToCard(board.getId(), stack.getId(), changedUser.getCardId(), user.getUid(), new IResponseCallback<Void>(account) { @Override public void onResponse(Void response) { dataBaseAdapter.setStatusForJoinCardWithUser(card.getLocalId(), user.getLocalId(), DBStatus.UP_TO_DATE.getId()); @@ -261,7 +288,12 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { } } - List<Attachment> attachments = dataBaseAdapter.getLocallyChangedAttachmentsDirectly(account.getId()); + List<Attachment> attachments; + if (this.stack == null) { + attachments = dataBaseAdapter.getLocallyChangedAttachmentsDirectly(account.getId()); + } else { + attachments = dataBaseAdapter.getLocallyChangedAttachmentsForStackDirectly(this.stack.getLocalId()); + } for (Attachment attachment : attachments) { FullCard card = dataBaseAdapter.getFullCardByLocalIdDirectly(account.getId(), attachment.getCardId()); stack = dataBaseAdapter.getFullStackByLocalIdDirectly(card.getCard().getStackId()); @@ -269,7 +301,12 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { syncHelper.doUpSyncFor(new AttachmentDataProvider(this, board, stack.getStack(), card, Collections.singletonList(attachment))); } - List<Card> cardsWithChangedComments = dataBaseAdapter.getCardsWithLocallyChangedCommentsDirectly(account.getId()); + List<Card> cardsWithChangedComments; + if (this.stack == null) { + cardsWithChangedComments = dataBaseAdapter.getCardsWithLocallyChangedCommentsDirectly(account.getId()); + } else { + cardsWithChangedComments = dataBaseAdapter.getCardsWithLocallyChangedCommentsForStackDirectly(this.stack.getLocalId()); + } for (Card card : cardsWithChangedComments) { syncHelper.doUpSyncFor(new DeckCommentsDataProvider(this, card)); } @@ -279,7 +316,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { @Override public void handleDeletes(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, List<FullCard> entitiesFromServer) { - List<FullCard> localCards = dataBaseAdapter.getFullCardsForStackDirectly(accountId, stack.getLocalId()); + List<FullCard> localCards = dataBaseAdapter.getFullCardsForStackDirectly(accountId, stack.getLocalId(), null); List<FullCard> delta = findDelta(entitiesFromServer, localCards); for (FullCard cardToDelete : delta) { if (cardToDelete.getId() == null) { @@ -294,6 +331,7 @@ public class CardDataProvider extends AbstractSyncDataProvider<FullCard> { // do not delete, it's still there and was just moved! } + @SuppressLint("MissingSuperCall") @Override public void onError(Throwable throwable) { if (!(throwable instanceof OfflineException)) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/DeckCommentsDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/DeckCommentsDataProvider.java index 5b9be120f..06ef3030d 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/DeckCommentsDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/DeckCommentsDataProvider.java @@ -1,8 +1,8 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.List; import it.niedermann.nextcloud.deck.DeckLog; @@ -24,10 +24,13 @@ public class DeckCommentsDataProvider extends AbstractSyncDataProvider<OcsCommen } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<OcsComment>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<OcsComment>> responder, Instant lastSync) { serverAdapter.getCommentsForRemoteCardId(card.getId(), new IResponseCallback<OcsComment>(responder.getAccount()) { @Override public void onResponse(OcsComment response) { + if (response == null) { + response = new OcsComment(); + } List<OcsComment> comments = response.split(); Collections.sort(comments, (o1, o2) -> o1.getSingle().getCreationDateTime().compareTo(o2.getSingle().getCreationDateTime())); verifyCommentListIntegrity(comments); @@ -131,7 +134,7 @@ public class DeckCommentsDataProvider extends AbstractSyncDataProvider<OcsCommen } @Override - public List<OcsComment> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { + public List<OcsComment> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { return new OcsComment(dataBaseAdapter.getLocallyChangedCommentsByLocalCardIdDirectly(accountId, card.getLocalId())).split(); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/LabelDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/LabelDataProvider.java index 403d71f87..caa7c68e6 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/LabelDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/LabelDataProvider.java @@ -1,8 +1,9 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; -import java.util.Date; +import java.time.Instant; import java.util.List; +import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.api.IResponseCallback; import it.niedermann.nextcloud.deck.exceptions.HandledServerErrors; import it.niedermann.nextcloud.deck.model.Board; @@ -12,14 +13,14 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DataBaseAdapter public class LabelDataProvider extends AbstractSyncDataProvider<Label> { - private List<Label> labels; - private Board board; + private final List<Label> labels; + private final Board board; public LabelDataProvider(AbstractSyncDataProvider<?> parent, Board board, List<Label> labels) { super(parent); this.board = board; this.labels = labels; - if (this.labels!= null && board != null){ + if (this.labels != null && board != null) { for (Label label : labels) { label.setBoardId(board.getLocalId()); } @@ -27,7 +28,7 @@ public class LabelDataProvider extends AbstractSyncDataProvider<Label> { } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<Label>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<Label>> responder, Instant lastSync) { responder.onResponse(labels); } @@ -44,7 +45,7 @@ public class LabelDataProvider extends AbstractSyncDataProvider<Label> { updateInDB(dataBaseAdapter, accountId, entity, false); return entity.getLocalId(); } else { - return dataBaseAdapter.createLabel(accountId, entity); + return dataBaseAdapter.createLabelDirectly(accountId, entity); } } @@ -53,7 +54,7 @@ public class LabelDataProvider extends AbstractSyncDataProvider<Label> { dataBaseAdapter.updateLabel(entity, setStatus); } - private IResponseCallback<Label> getLabelUniqueHandler(DataBaseAdapter dataBaseAdapter, Label entitiy, IResponseCallback<Label> responder){ + private IResponseCallback<Label> getLabelUniqueHandler(DataBaseAdapter dataBaseAdapter, Label entitiy, IResponseCallback<Label> responder) { return new IResponseCallback<Label>(responder.getAccount()) { @Override public void onResponse(Label response) { @@ -62,10 +63,13 @@ public class LabelDataProvider extends AbstractSyncDataProvider<Label> { @Override public void onError(Throwable throwable) { - if (HandledServerErrors.LABELS_TITLE_MUST_BE_UNIQUE == HandledServerErrors.fromThrowable(throwable)){ + if (HandledServerErrors.LABELS_TITLE_MUST_BE_UNIQUE == HandledServerErrors.fromThrowable(throwable)) { + DeckLog.log(throwable.getCause().getMessage() + ": " + entitiy.toString()); dataBaseAdapter.deleteLabelPhysically(entitiy); + responder.onResponse(entitiy); + } else { + responder.onError(throwable); } - responder.onError(throwable); } }; } @@ -92,7 +96,7 @@ public class LabelDataProvider extends AbstractSyncDataProvider<Label> { } @Override - public List<Label> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { + public List<Label> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { return labels; } @@ -105,7 +109,7 @@ public class LabelDataProvider extends AbstractSyncDataProvider<Label> { public void handleDeletes(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, List<Label> entitiesFromServer) { List<Label> deletedLabels = findDelta(labels, dataBaseAdapter.getFullBoardByLocalIdDirectly(accountId, board.getLocalId()).getLabels()); for (Label deletedLabel : deletedLabels) { - if (deletedLabel.getId()!=null){ + if (deletedLabel.getId() != null) { // preserve new, unsynced card. dataBaseAdapter.deleteLabelPhysically(deletedLabel); } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/OcsProjectDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/OcsProjectDataProvider.java new file mode 100644 index 000000000..b9bfb8b31 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/OcsProjectDataProvider.java @@ -0,0 +1,100 @@ +package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; + +import java.time.Instant; +import java.util.Collections; +import java.util.List; + +import it.niedermann.nextcloud.deck.DeckLog; +import it.niedermann.nextcloud.deck.api.IResponseCallback; +import it.niedermann.nextcloud.deck.model.Card; +import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProject; +import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProjectList; +import it.niedermann.nextcloud.deck.model.ocs.projects.OcsProjectResource; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.ServerAdapter; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DataBaseAdapter; + +public class OcsProjectDataProvider extends AbstractSyncDataProvider<OcsProject> { + private Card card; + + public OcsProjectDataProvider(AbstractSyncDataProvider<?> parent, Card card) { + super(parent); + this.card = card; + } + + @Override + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<OcsProject>> responder, Instant lastSync) { + serverAdapter.getProjectsForCard(card.getId(), new IResponseCallback<OcsProjectList>(responder.getAccount()) { + @Override + public void onResponse(OcsProjectList response) { + responder.onResponse(response.getProjects()); + } + + @Override + public void onError(Throwable throwable) { + super.onError(throwable); + // dont break the sync! + DeckLog.logError(throwable); + responder.onResponse(Collections.emptyList()); + } + }); + } + + @Override + public OcsProject getSingleFromDB(DataBaseAdapter dataBaseAdapter, long accountId, OcsProject entity) { + return dataBaseAdapter.getProjectByRemoteIdDirectly(accountId, entity.getId()); + } + + @Override + public long createInDB(DataBaseAdapter dataBaseAdapter, long accountId, OcsProject entity) { + Long newId = dataBaseAdapter.createProjectDirectly(accountId, entity); + entity.setLocalId(newId); + updateResources(dataBaseAdapter, accountId, entity); + return newId; + } + + @Override + public void updateInDB(DataBaseAdapter dataBaseAdapter, long accountId, OcsProject entity, boolean setStatus) { + dataBaseAdapter.updateProjectDirectly(accountId, entity); + dataBaseAdapter.deleteProjectResourcesForProjectIdDirectly(entity.getLocalId()); + updateResources(dataBaseAdapter, accountId, entity); + } + + @Override + public void deleteInDB(DataBaseAdapter dataBaseAdapter, long accountId, OcsProject ocsProject) { + if (ocsProject != null && ocsProject.getLocalId() != null) { + dataBaseAdapter.deleteProjectDirectly(ocsProject); + } + } + + private void updateResources(DataBaseAdapter dataBaseAdapter, Long accountId, OcsProject entity) { + if (entity.getResources() != null) { + for (OcsProjectResource resource : entity.getResources()) { + resource.setProjectId(entity.getLocalId()); + resource.setLocalId(dataBaseAdapter.createProjectResourceDirectly(accountId, resource)); + if ("deck-card".equals(resource.getType())) { + dataBaseAdapter.assignCardToProjectIfMissng(accountId, entity.getLocalId(), resource.getId()); + } + } + } + } + + @Override + public void createOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<OcsProject> responder, OcsProject entity) { + // Do Nothing + } + + @Override + public void updateOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<OcsProject> callback, OcsProject entity) { + // Do Nothing + } + + @Override + public void deleteOnServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<Void> callback, OcsProject entity, DataBaseAdapter dataBaseAdapter) { + // Do Nothing + } + + @Override + public List<OcsProject> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { + return Collections.emptyList(); + } +} diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java index a3c123afd..93761d616 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/StackDataProvider.java @@ -1,12 +1,13 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; +import java.time.Instant; import java.util.Collections; -import java.util.Date; -import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; import it.niedermann.nextcloud.deck.api.IResponseCallback; +import it.niedermann.nextcloud.deck.exceptions.DeckException; import it.niedermann.nextcloud.deck.model.Board; import it.niedermann.nextcloud.deck.model.Card; import it.niedermann.nextcloud.deck.model.full.FullBoard; @@ -19,13 +20,15 @@ import it.niedermann.nextcloud.deck.persistence.sync.helpers.SyncHelper; public class StackDataProvider extends AbstractSyncDataProvider<FullStack> { private FullBoard board; + private Set<Long> syncedStacks = new ConcurrentSkipListSet<>(); + public StackDataProvider(AbstractSyncDataProvider<?> parent, FullBoard board) { super(parent); this.board = board; } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<FullStack>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<FullStack>> responder, Instant lastSync) { serverAdapter.getStacks(board.getId(), responder); } @@ -54,12 +57,12 @@ public class StackDataProvider extends AbstractSyncDataProvider<FullStack> { @Override public void goDeeper(SyncHelper syncHelper, FullStack existingEntity, FullStack entityFromServer, IResponseCallback<Boolean> callback) { - boolean serverHasCards = entityFromServer.getCards() != null && !entityFromServer.getCards().isEmpty(); - boolean weHaveCards = existingEntity.getCards() != null && !existingEntity.getCards().isEmpty(); - if (serverHasCards || weHaveCards){ + boolean serverHasCards = entityFromServer.getCards() != null && !entityFromServer.getCards().isEmpty(); + boolean weHaveCards = existingEntity.getCards() != null && !existingEntity.getCards().isEmpty(); + if (serverHasCards || weHaveCards) { existingEntity.setCards(entityFromServer.getCards()); List<Card> cards = existingEntity.getCards(); - if (cards != null ){ + if (cards != null) { for (Card card : cards) { card.setStackId(existingEntity.getLocalId()); } @@ -72,6 +75,9 @@ public class StackDataProvider extends AbstractSyncDataProvider<FullStack> { @Override public void createOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<FullStack> responder, FullStack entity) { + if (board.getId() == null) { + throw new DeckException(DeckException.Hint.DEPENDENCY_NOT_SYNCED_YET, "Board for this stack is not synced yet. Perform a full sync (pull to referesh) as soon as you are online again."); + } entity.getStack().setBoardId(board.getId()); serverAdapter.createStack(board.getBoard(), entity.getStack(), responder); } @@ -89,8 +95,8 @@ public class StackDataProvider extends AbstractSyncDataProvider<FullStack> { } @Override - public List<FullStack> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { - if (board == null){ + public List<FullStack> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { + if (board == null) { // no stacks changed! // (see call from BoardDataProvider: goDeeperForUpSync called with null for board.) // so we can just skip this one and proceed with cards. @@ -103,16 +109,19 @@ public class StackDataProvider extends AbstractSyncDataProvider<FullStack> { @Override public void goDeeperForUpSync(SyncHelper syncHelper, ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, IResponseCallback<Boolean> callback) { List<FullCard> changedCards = dataBaseAdapter.getLocallyChangedCardsDirectly(callback.getAccount().getId()); - Set<Long> syncedStacks = new HashSet<>(); - if (changedCards != null && changedCards.size() > 0){ + if (changedCards != null && !changedCards.isEmpty()) { for (FullCard changedCard : changedCards) { long stackId = changedCard.getCard().getStackId(); - boolean added = syncedStacks.add(stackId); - if (added) { + boolean alreadySynced = syncedStacks.contains(stackId); + if (!alreadySynced) { FullStack stack = dataBaseAdapter.getFullStackByLocalIdDirectly(stackId); - Board board = dataBaseAdapter.getBoardByLocalIdDirectly(stack.getStack().getBoardId()); - changedCard.getCard().setStackId(stack.getId()); - syncHelper.doUpSyncFor(new CardDataProvider(this, board, stack)); + // already synced and known to server? + if (stack.getStack().getId() != null) { + syncedStacks.add(stackId); + Board board = dataBaseAdapter.getBoardByLocalIdDirectly(stack.getStack().getBoardId()); + changedCard.getCard().setStackId(stack.getId()); + syncHelper.doUpSyncFor(new CardDataProvider(this, board, stack)); + } } } } else { @@ -132,7 +141,7 @@ public class StackDataProvider extends AbstractSyncDataProvider<FullStack> { List<FullStack> localStacks = dataBaseAdapter.getFullStacksForBoardDirectly(accountId, board.getLocalId()); List<FullStack> delta = findDelta(entitiesFromServer, localStacks); for (FullStack stackToDelete : delta) { - if (stackToDelete.getId() == null){ + if (stackToDelete.getId() == null) { // not pushed up yet so: continue; } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/UserDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/UserDataProvider.java index 60c906bda..279ce9e55 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/UserDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/UserDataProvider.java @@ -1,6 +1,6 @@ package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers; -import java.util.Date; +import java.time.Instant; import java.util.List; import it.niedermann.nextcloud.deck.api.IResponseCallback; @@ -27,7 +27,7 @@ public class UserDataProvider extends AbstractSyncDataProvider<User> { } @Override - public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<User>> responder, Date lastSync) { + public void getAllFromServer(ServerAdapter serverAdapter, long accountId, IResponseCallback<List<User>> responder, Instant lastSync) { responder.onResponse(users); } @@ -67,7 +67,7 @@ public class UserDataProvider extends AbstractSyncDataProvider<User> { } @Override - public List<User> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Date lastSync) { + public List<User> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { return null; } diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/partial/BoardWitAclDownSyncDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/partial/BoardWithAclDownSyncDataProvider.java index 326d257ab..8516f0fc0 100644 --- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/partial/BoardWitAclDownSyncDataProvider.java +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/partial/BoardWithAclDownSyncDataProvider.java @@ -11,7 +11,7 @@ import it.niedermann.nextcloud.deck.persistence.sync.helpers.SyncHelper; import it.niedermann.nextcloud.deck.persistence.sync.helpers.providers.AccessControlDataProvider; import it.niedermann.nextcloud.deck.persistence.sync.helpers.providers.BoardDataProvider; -public class BoardWitAclDownSyncDataProvider extends BoardDataProvider { +public class BoardWithAclDownSyncDataProvider extends BoardDataProvider { @Override public void goDeeper(SyncHelper syncHelper, FullBoard existingEntity, FullBoard entityFromServer, IResponseCallback<Boolean> callback) { diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/partial/BoardWithStacksAndLabelsUpSyncDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/partial/BoardWithStacksAndLabelsUpSyncDataProvider.java new file mode 100644 index 000000000..5f2c79ad3 --- /dev/null +++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/partial/BoardWithStacksAndLabelsUpSyncDataProvider.java @@ -0,0 +1,37 @@ +package it.niedermann.nextcloud.deck.persistence.sync.helpers.providers.partial; + +import java.time.Instant; +import java.util.Collections; +import java.util.List; + +import it.niedermann.nextcloud.deck.api.IResponseCallback; +import it.niedermann.nextcloud.deck.model.full.FullBoard; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.ServerAdapter; +import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.DataBaseAdapter; +import it.niedermann.nextcloud.deck.persistence.sync.helpers.SyncHelper; +import it.niedermann.nextcloud.deck.persistence.sync.helpers.providers.BoardDataProvider; + +public class BoardWithStacksAndLabelsUpSyncDataProvider extends BoardDataProvider { + + private FullBoard board; + + public BoardWithStacksAndLabelsUpSyncDataProvider(FullBoard boardToSync) { + board = boardToSync; + } + + @Override + public List<FullBoard> getAllChangedFromDB(DataBaseAdapter dataBaseAdapter, long accountId, Instant lastSync) { + return Collections.singletonList(board); + } + + @Override + public void goDeeper(SyncHelper syncHelper, FullBoard existingEntity, FullBoard entityFromServer, IResponseCallback<Boolean> callback) { + // do nothing! + + } + + @Override + public void handleDeletes(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, List<FullBoard> entitiesFromServer) { + // do nothing! + } +} |