package it.niedermann.nextcloud.deck.remote.helpers.providers; import android.annotation.SuppressLint; import com.nextcloud.android.sso.api.EmptyResponse; import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import it.niedermann.nextcloud.deck.DeckLog; import it.niedermann.nextcloud.deck.database.DataBaseAdapter; 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; import it.niedermann.nextcloud.deck.model.Board; import it.niedermann.nextcloud.deck.model.Card; import it.niedermann.nextcloud.deck.model.JoinCardWithLabel; import it.niedermann.nextcloud.deck.model.JoinCardWithUser; import it.niedermann.nextcloud.deck.model.Label; import it.niedermann.nextcloud.deck.model.User; import it.niedermann.nextcloud.deck.model.enums.DBStatus; import it.niedermann.nextcloud.deck.model.full.FullCard; import it.niedermann.nextcloud.deck.model.full.FullStack; import it.niedermann.nextcloud.deck.model.propagation.CardUpdate; import it.niedermann.nextcloud.deck.remote.adapters.ServerAdapter; import it.niedermann.nextcloud.deck.remote.api.ResponseCallback; import it.niedermann.nextcloud.deck.remote.helpers.SyncHelper; public class CardDataProvider extends AbstractSyncDataProvider { private static final String ALREADY_ARCHIVED_INDICATOR = "Operation not allowed. This card is archived."; // see https://github.com/stefan-niedermann/nextcloud-deck/issues/1073 private static final Set LABEL_JOINS_IN_SYNC = Collections.synchronizedSet(new HashSet<>()); protected Board board; protected FullStack stack; public CardDataProvider(AbstractSyncDataProvider parent, Board board, FullStack stack) { super(parent); this.board = board; this.stack = stack; } @Override public void getAllFromServer(ServerAdapter serverAdapter, long accountId, ResponseCallback> responder, Instant lastSync) { if (stack.getCards() == null || stack.getCards().isEmpty()) { responder.onResponse(new ArrayList<>()); return; } List result = Collections.synchronizedList(new ArrayList<>()); for (Card card : stack.getCards()) { serverAdapter.getCard(board.getId(), stack.getId(), card.getId(), new ResponseCallback<>(responder.getAccount()) { @Override public void onResponse(FullCard response) { result.add(response); if (result.size() == stack.getCards().size()) { responder.onResponse(result); } } @SuppressLint("MissingSuperCall") @Override public void onError(Throwable throwable) { responder.onError(throwable); } }); } } @Override public FullCard getSingleFromDB(DataBaseAdapter dataBaseAdapter, long accountId, FullCard entity) { return dataBaseAdapter.getFullCardByRemoteIdDirectly(accountId, entity.getEntity().getId()); } @Override public long createInDB(DataBaseAdapter dataBaseAdapter, long accountId, FullCard entity) { fixRelations(dataBaseAdapter, accountId, entity); return dataBaseAdapter.createCardDirectly(accountId, entity.getCard()); } protected CardUpdate toCardUpdate(FullCard card) { CardUpdate c = new CardUpdate(card); // FIXME This causes an IndexOutOfBoundsException for the three "Example Tasks" on a fresh Deck server installation c.setOwner(card.getOwner().get(0)); return c; } protected void fixRelations(DataBaseAdapter dataBaseAdapter, long accountId, FullCard entity) { entity.getCard().setStackId(stack.getLocalId()); if (entity.getOwner() != null && !entity.getOwner().isEmpty()) { User user = entity.getOwner().get(0); User u = dataBaseAdapter.getUserByUidDirectly(accountId, user.getUid()); if (u == null) { dataBaseAdapter.createUser(accountId, user); } else { user.setLocalId(u.getLocalId()); dataBaseAdapter.updateUser(accountId, user, false); } u = dataBaseAdapter.getUserByUidDirectly(accountId, user.getUid()); user.setLocalId(u.getLocalId()); entity.getCard().setUserId(u.getLocalId()); } } @Override public FullCard applyUpdatesFromRemote(FullCard localEntity, FullCard remoteEntity, Long accountId) { if (localEntity.getCard().getUserId() != null) { remoteEntity.getCard().setUserId(localEntity.getCard().getUserId()); } return remoteEntity; } @Override public void updateInDB(DataBaseAdapter dataBaseAdapter, long accountId, FullCard entity, boolean setStatus) { fixRelations(dataBaseAdapter, accountId, entity); dataBaseAdapter.updateCard(entity.getCard(), setStatus); } @Override public void updateInDB(DataBaseAdapter dataBaseAdapter, long accountId, FullCard entity) { updateInDB(dataBaseAdapter, accountId, entity, false); } @Override public void goDeeper(SyncHelper syncHelper, FullCard existingEntity, FullCard entityFromServer, ResponseCallback callback) { List