mirror of https://github.com/tasks/tasks
Convert CaldavSynchronizer to Kotlin
parent
2454757b24
commit
e2c897e43c
@ -1,336 +0,0 @@
|
||||
package org.tasks.caldav;
|
||||
|
||||
import static com.google.common.collect.Iterables.filter;
|
||||
import static com.google.common.collect.Iterables.partition;
|
||||
import static com.google.common.collect.Lists.newArrayList;
|
||||
import static com.google.common.collect.Lists.transform;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.collect.Sets.newHashSet;
|
||||
import static org.tasks.Strings.isNullOrEmpty;
|
||||
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.Nullable;
|
||||
import at.bitfire.dav4jvm.DavCalendar;
|
||||
import at.bitfire.dav4jvm.DavResource;
|
||||
import at.bitfire.dav4jvm.Response;
|
||||
import at.bitfire.dav4jvm.Response.HrefRelation;
|
||||
import at.bitfire.dav4jvm.exception.DavException;
|
||||
import at.bitfire.dav4jvm.exception.HttpException;
|
||||
import at.bitfire.dav4jvm.exception.ServiceUnavailableException;
|
||||
import at.bitfire.dav4jvm.exception.UnauthorizedException;
|
||||
import at.bitfire.dav4jvm.property.CalendarColor;
|
||||
import at.bitfire.dav4jvm.property.CalendarData;
|
||||
import at.bitfire.dav4jvm.property.DisplayName;
|
||||
import at.bitfire.dav4jvm.property.GetCTag;
|
||||
import at.bitfire.dav4jvm.property.GetETag;
|
||||
import at.bitfire.dav4jvm.property.SyncToken;
|
||||
import at.bitfire.ical4android.ICalendar;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.todoroo.astrid.dao.TaskDaoBlocking;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.helper.UUIDHelper;
|
||||
import com.todoroo.astrid.service.TaskDeleter;
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import javax.net.ssl.SSLException;
|
||||
import net.fortuna.ical4j.model.property.ProdId;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.RequestBody;
|
||||
import org.tasks.BuildConfig;
|
||||
import org.tasks.LocalBroadcastManager;
|
||||
import org.tasks.R;
|
||||
import org.tasks.analytics.Firebase;
|
||||
import org.tasks.billing.Inventory;
|
||||
import org.tasks.data.CaldavAccount;
|
||||
import org.tasks.data.CaldavCalendar;
|
||||
import org.tasks.data.CaldavDaoBlocking;
|
||||
import org.tasks.data.CaldavTask;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class CaldavSynchronizer {
|
||||
|
||||
static {
|
||||
ICalendar.Companion.setProdId(
|
||||
new ProdId("+//IDN tasks.org//android-" + BuildConfig.VERSION_CODE + "//EN"));
|
||||
}
|
||||
|
||||
private final CaldavDaoBlocking caldavDao;
|
||||
private final TaskDaoBlocking taskDao;
|
||||
private final LocalBroadcastManager localBroadcastManager;
|
||||
private final TaskDeleter taskDeleter;
|
||||
private final Inventory inventory;
|
||||
private final Firebase firebase;
|
||||
private final CaldavClient client;
|
||||
private final iCalendar iCal;
|
||||
private final Context context;
|
||||
|
||||
@Inject
|
||||
public CaldavSynchronizer(
|
||||
@ApplicationContext Context context,
|
||||
CaldavDaoBlocking caldavDao,
|
||||
TaskDaoBlocking taskDao,
|
||||
LocalBroadcastManager localBroadcastManager,
|
||||
TaskDeleter taskDeleter,
|
||||
Inventory inventory,
|
||||
Firebase firebase,
|
||||
CaldavClient client,
|
||||
iCalendar iCal) {
|
||||
this.context = context;
|
||||
this.caldavDao = caldavDao;
|
||||
this.taskDao = taskDao;
|
||||
this.localBroadcastManager = localBroadcastManager;
|
||||
this.taskDeleter = taskDeleter;
|
||||
this.inventory = inventory;
|
||||
this.firebase = firebase;
|
||||
this.client = client;
|
||||
this.iCal = iCal;
|
||||
}
|
||||
|
||||
public void sync(CaldavAccount account) {
|
||||
if (!inventory.hasPro()) {
|
||||
setError(account, context.getString(R.string.requires_pro_subscription));
|
||||
return;
|
||||
}
|
||||
if (isNullOrEmpty(account.getPassword())) {
|
||||
setError(account, context.getString(R.string.password_required));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
synchronize(account);
|
||||
} catch (SocketTimeoutException
|
||||
| SSLException
|
||||
| ConnectException
|
||||
| UnknownHostException
|
||||
| UnauthorizedException
|
||||
| ServiceUnavailableException
|
||||
| KeyManagementException
|
||||
| NoSuchAlgorithmException e) {
|
||||
setError(account, e.getMessage());
|
||||
} catch (IOException | DavException e) {
|
||||
setError(account, e.getMessage());
|
||||
if (!(e instanceof HttpException) || ((HttpException) e).getCode() < 500) {
|
||||
firebase.reportException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronize(CaldavAccount account)
|
||||
throws IOException, DavException, KeyManagementException, NoSuchAlgorithmException {
|
||||
CaldavClient caldavClient = client.forAccount(account);
|
||||
List<Response> resources = caldavClient.getCalendars();
|
||||
Set<String> urls = newHashSet(transform(resources, c -> c.getHref().toString()));
|
||||
Timber.d("Found calendars: %s", urls);
|
||||
for (CaldavCalendar calendar :
|
||||
caldavDao.findDeletedCalendars(account.getUuid(), new ArrayList<>(urls))) {
|
||||
taskDeleter.delete(calendar);
|
||||
}
|
||||
for (Response resource : resources) {
|
||||
String url = resource.getHref().toString();
|
||||
|
||||
CaldavCalendar calendar = caldavDao.getCalendarByUrl(account.getUuid(), url);
|
||||
String remoteName = resource.get(DisplayName.class).getDisplayName();
|
||||
CalendarColor calendarColor = resource.get(CalendarColor.class);
|
||||
int color = calendarColor == null ? 0 : calendarColor.getColor();
|
||||
if (calendar == null) {
|
||||
calendar = new CaldavCalendar();
|
||||
calendar.setName(remoteName);
|
||||
calendar.setAccount(account.getUuid());
|
||||
calendar.setUrl(url);
|
||||
calendar.setUuid(UUIDHelper.newUUID());
|
||||
calendar.setColor(color);
|
||||
caldavDao.insert(calendar);
|
||||
} else if (!calendar.getName().equals(remoteName) || calendar.getColor() != color) {
|
||||
calendar.setColor(color);
|
||||
calendar.setName(remoteName);
|
||||
caldavDao.update(calendar);
|
||||
localBroadcastManager.broadcastRefreshList();
|
||||
}
|
||||
sync(calendar, resource, caldavClient.getHttpClient());
|
||||
}
|
||||
setError(account, "");
|
||||
}
|
||||
|
||||
private void setError(CaldavAccount account, String message) {
|
||||
account.setError(message);
|
||||
caldavDao.update(account);
|
||||
localBroadcastManager.broadcastRefreshList();
|
||||
if (!isNullOrEmpty(message)) {
|
||||
Timber.e(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void sync(CaldavCalendar caldavCalendar, Response resource, OkHttpClient httpClient)
|
||||
throws DavException {
|
||||
Timber.d("sync(%s)", caldavCalendar);
|
||||
HttpUrl httpUrl = resource.getHref();
|
||||
pushLocalChanges(caldavCalendar, httpClient, httpUrl);
|
||||
|
||||
SyncToken syncToken = resource.get(SyncToken.class);
|
||||
GetCTag ctag = resource.get(GetCTag.class);
|
||||
@Nullable String remoteCtag = null;
|
||||
if (syncToken != null) {
|
||||
remoteCtag = syncToken.getToken();
|
||||
} else if (ctag != null) {
|
||||
remoteCtag = ctag.getCTag();
|
||||
}
|
||||
String localCtag = caldavCalendar.getCtag();
|
||||
|
||||
if (localCtag != null && localCtag.equals(remoteCtag)) {
|
||||
Timber.d("%s up to date", caldavCalendar.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
DavCalendar davCalendar = new DavCalendar(httpClient, httpUrl);
|
||||
|
||||
ResponseList members = new ResponseList(HrefRelation.MEMBER);
|
||||
davCalendar.calendarQuery("VTODO", null, null, members);
|
||||
|
||||
Iterable<Response> changed =
|
||||
filter(
|
||||
members,
|
||||
vCard -> {
|
||||
GetETag eTag = vCard.get(GetETag.class);
|
||||
if (eTag == null || isNullOrEmpty(eTag.getETag())) {
|
||||
return false;
|
||||
}
|
||||
CaldavTask caldavTask = caldavDao.getTask(caldavCalendar.getUuid(), vCard.hrefName());
|
||||
return caldavTask == null || !eTag.getETag().equals(caldavTask.getEtag());
|
||||
});
|
||||
|
||||
for (List<Response> items : partition(changed, 30)) {
|
||||
ArrayList<HttpUrl> urls = newArrayList(Iterables.transform(items, Response::getHref));
|
||||
ResponseList responses = new ResponseList(HrefRelation.MEMBER);
|
||||
davCalendar.multiget(urls, responses);
|
||||
|
||||
Timber.d("MULTI %s", urls);
|
||||
|
||||
for (Response vCard : responses) {
|
||||
GetETag eTag = vCard.get(GetETag.class);
|
||||
HttpUrl url = vCard.getHref();
|
||||
if (eTag == null || isNullOrEmpty(eTag.getETag())) {
|
||||
throw new DavException("Received CalDAV GET response without ETag for " + url);
|
||||
}
|
||||
CalendarData calendarData = vCard.get(CalendarData.class);
|
||||
if (calendarData == null || isNullOrEmpty(calendarData.getICalendar())) {
|
||||
throw new DavException("Received CalDAV GET response without CalendarData for " + url);
|
||||
}
|
||||
String fileName = vCard.hrefName();
|
||||
String vtodo = calendarData.getICalendar();
|
||||
at.bitfire.ical4android.Task remote = iCalendar.Companion.fromVtodo(vtodo);
|
||||
if (remote == null) {
|
||||
Timber.e("Invalid VCALENDAR: %s", fileName);
|
||||
return;
|
||||
}
|
||||
|
||||
CaldavTask caldavTask = caldavDao.getTask(caldavCalendar.getUuid(), fileName);
|
||||
iCal.fromVtodo(caldavCalendar, caldavTask, remote, vtodo, fileName, eTag.getETag());
|
||||
}
|
||||
}
|
||||
|
||||
List<String> deleted =
|
||||
new ArrayList<>(
|
||||
difference(
|
||||
newHashSet(caldavDao.getObjects(caldavCalendar.getUuid())),
|
||||
newHashSet(transform(members, Response::hrefName))));
|
||||
if (deleted.size() > 0) {
|
||||
Timber.d("DELETED %s", deleted);
|
||||
taskDeleter.delete(caldavDao.getTasks(caldavCalendar.getUuid(), deleted));
|
||||
}
|
||||
|
||||
caldavCalendar.setCtag(remoteCtag);
|
||||
Timber.d("UPDATE %s", caldavCalendar);
|
||||
caldavDao.update(caldavCalendar);
|
||||
|
||||
caldavDao.updateParents(caldavCalendar.getUuid());
|
||||
|
||||
localBroadcastManager.broadcastRefresh();
|
||||
}
|
||||
|
||||
private void pushLocalChanges(
|
||||
CaldavCalendar caldavCalendar, OkHttpClient httpClient, HttpUrl httpUrl) {
|
||||
|
||||
for (CaldavTask task : caldavDao.getDeleted(caldavCalendar.getUuid())) {
|
||||
deleteRemoteResource(httpClient, httpUrl, task);
|
||||
}
|
||||
|
||||
for (Task task : taskDao.getCaldavTasksToPush(caldavCalendar.getUuid())) {
|
||||
try {
|
||||
pushTask(task, httpClient, httpUrl);
|
||||
} catch (IOException e) {
|
||||
Timber.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean deleteRemoteResource(
|
||||
OkHttpClient httpClient, HttpUrl httpUrl, CaldavTask caldavTask) {
|
||||
try {
|
||||
if (!isNullOrEmpty(caldavTask.getObject())) {
|
||||
DavResource remote =
|
||||
new DavResource(
|
||||
httpClient, httpUrl.newBuilder().addPathSegment(caldavTask.getObject()).build());
|
||||
remote.delete(null, response -> null);
|
||||
}
|
||||
} catch (HttpException e) {
|
||||
if (e.getCode() != 404) {
|
||||
Timber.e(e);
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Timber.e(e);
|
||||
return false;
|
||||
}
|
||||
caldavDao.delete(caldavTask);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void pushTask(Task task, OkHttpClient httpClient, HttpUrl httpUrl) throws IOException {
|
||||
Timber.d("pushing %s", task);
|
||||
CaldavTask caldavTask = caldavDao.getTask(task.getId());
|
||||
|
||||
if (caldavTask == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (task.isDeleted()) {
|
||||
if (deleteRemoteResource(httpClient, httpUrl, caldavTask)) {
|
||||
taskDeleter.delete(task);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data = iCal.toVtodo(caldavTask, task);
|
||||
RequestBody requestBody = RequestBody.create(DavCalendar.Companion.getMIME_ICALENDAR(), data);
|
||||
|
||||
try {
|
||||
DavResource remote =
|
||||
new DavResource(
|
||||
httpClient, httpUrl.newBuilder().addPathSegment(caldavTask.getObject()).build());
|
||||
org.tasks.caldav.Response response = new org.tasks.caldav.Response();
|
||||
remote.put(requestBody, null, false, response);
|
||||
GetETag getETag = GetETag.Companion.fromResponse(response.get());
|
||||
if (getETag != null && !isNullOrEmpty(getETag.getETag())) {
|
||||
caldavTask.setEtag(getETag.getETag());
|
||||
caldavTask.setVtodo(new String(data));
|
||||
}
|
||||
} catch (HttpException e) {
|
||||
Timber.e(e);
|
||||
return;
|
||||
}
|
||||
|
||||
caldavTask.setLastSync(currentTimeMillis());
|
||||
caldavDao.update(caldavTask);
|
||||
Timber.d("SENT %s", caldavTask);
|
||||
}
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
package org.tasks.caldav
|
||||
|
||||
import android.content.Context
|
||||
import at.bitfire.dav4jvm.DavCalendar
|
||||
import at.bitfire.dav4jvm.DavCalendar.Companion.MIME_ICALENDAR
|
||||
import at.bitfire.dav4jvm.DavResource
|
||||
import at.bitfire.dav4jvm.Response.HrefRelation
|
||||
import at.bitfire.dav4jvm.exception.DavException
|
||||
import at.bitfire.dav4jvm.exception.HttpException
|
||||
import at.bitfire.dav4jvm.exception.ServiceUnavailableException
|
||||
import at.bitfire.dav4jvm.exception.UnauthorizedException
|
||||
import at.bitfire.dav4jvm.property.*
|
||||
import at.bitfire.dav4jvm.property.GetETag.Companion.fromResponse
|
||||
import at.bitfire.ical4android.ICalendar.Companion.prodId
|
||||
import com.todoroo.astrid.dao.TaskDaoBlocking
|
||||
import com.todoroo.astrid.data.Task
|
||||
import com.todoroo.astrid.helper.UUIDHelper
|
||||
import com.todoroo.astrid.service.TaskDeleter
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import net.fortuna.ical4j.model.property.ProdId
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.RequestBody
|
||||
import org.tasks.BuildConfig
|
||||
import org.tasks.LocalBroadcastManager
|
||||
import org.tasks.R
|
||||
import org.tasks.Strings.isNullOrEmpty
|
||||
import org.tasks.analytics.Firebase
|
||||
import org.tasks.billing.Inventory
|
||||
import org.tasks.caldav.iCalendar.Companion.fromVtodo
|
||||
import org.tasks.data.CaldavAccount
|
||||
import org.tasks.data.CaldavCalendar
|
||||
import org.tasks.data.CaldavDaoBlocking
|
||||
import org.tasks.data.CaldavTask
|
||||
import org.tasks.time.DateTimeUtils
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.net.ConnectException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.security.KeyManagementException
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.net.ssl.SSLException
|
||||
|
||||
class CaldavSynchronizer @Inject constructor(
|
||||
@param:ApplicationContext private val context: Context,
|
||||
private val caldavDao: CaldavDaoBlocking,
|
||||
private val taskDao: TaskDaoBlocking,
|
||||
private val localBroadcastManager: LocalBroadcastManager,
|
||||
private val taskDeleter: TaskDeleter,
|
||||
private val inventory: Inventory,
|
||||
private val firebase: Firebase,
|
||||
private val client: CaldavClient,
|
||||
private val iCal: iCalendar) {
|
||||
companion object {
|
||||
init {
|
||||
prodId = ProdId("+//IDN tasks.org//android-" + BuildConfig.VERSION_CODE + "//EN")
|
||||
}
|
||||
}
|
||||
|
||||
fun sync(account: CaldavAccount) {
|
||||
if (!inventory.hasPro()) {
|
||||
setError(account, context.getString(R.string.requires_pro_subscription))
|
||||
return
|
||||
}
|
||||
if (isNullOrEmpty(account.password)) {
|
||||
setError(account, context.getString(R.string.password_required))
|
||||
return
|
||||
}
|
||||
try {
|
||||
synchronize(account)
|
||||
} catch (e: SocketTimeoutException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: SSLException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: ConnectException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: UnknownHostException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: UnauthorizedException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: ServiceUnavailableException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: KeyManagementException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: IOException) {
|
||||
setError(account, e.message)
|
||||
} catch (e: DavException) {
|
||||
setError(account, e.message)
|
||||
if (e !is HttpException || e.code < 500) {
|
||||
firebase.reportException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class, DavException::class, KeyManagementException::class, NoSuchAlgorithmException::class)
|
||||
private fun synchronize(account: CaldavAccount) {
|
||||
val caldavClient = client.forAccount(account)
|
||||
val resources = caldavClient.calendars
|
||||
val urls = resources.map { it.href.toString() }.toHashSet()
|
||||
Timber.d("Found calendars: %s", urls)
|
||||
for (calendar in caldavDao.findDeletedCalendars(account.uuid!!, ArrayList(urls))) {
|
||||
taskDeleter.delete(calendar)
|
||||
}
|
||||
for (resource in resources) {
|
||||
val url = resource.href.toString()
|
||||
var calendar = caldavDao.getCalendarByUrl(account.uuid!!, url)
|
||||
val remoteName = resource[DisplayName::class.java]!!.displayName
|
||||
val calendarColor = resource[CalendarColor::class.java]
|
||||
val color = calendarColor?.color ?: 0
|
||||
if (calendar == null) {
|
||||
calendar = CaldavCalendar()
|
||||
calendar.name = remoteName
|
||||
calendar.account = account.uuid
|
||||
calendar.url = url
|
||||
calendar.uuid = UUIDHelper.newUUID()
|
||||
calendar.color = color
|
||||
caldavDao.insert(calendar)
|
||||
} else if (calendar.name != remoteName || calendar.color != color) {
|
||||
calendar.color = color
|
||||
calendar.name = remoteName
|
||||
caldavDao.update(calendar)
|
||||
localBroadcastManager.broadcastRefreshList()
|
||||
}
|
||||
sync(calendar, resource, caldavClient.httpClient)
|
||||
}
|
||||
setError(account, "")
|
||||
}
|
||||
|
||||
private fun setError(account: CaldavAccount, message: String?) {
|
||||
account.error = message
|
||||
caldavDao.update(account)
|
||||
localBroadcastManager.broadcastRefreshList()
|
||||
if (!isNullOrEmpty(message)) {
|
||||
Timber.e(message)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(DavException::class)
|
||||
private fun sync(caldavCalendar: CaldavCalendar, resource: at.bitfire.dav4jvm.Response, httpClient: OkHttpClient) {
|
||||
Timber.d("sync(%s)", caldavCalendar)
|
||||
val httpUrl = resource.href
|
||||
pushLocalChanges(caldavCalendar, httpClient, httpUrl)
|
||||
val syncToken = resource[SyncToken::class.java]
|
||||
val ctag = resource[GetCTag::class.java]
|
||||
var remoteCtag: String? = null
|
||||
if (syncToken != null) {
|
||||
remoteCtag = syncToken.token
|
||||
} else if (ctag != null) {
|
||||
remoteCtag = ctag.cTag
|
||||
}
|
||||
val localCtag = caldavCalendar.ctag
|
||||
if (localCtag != null && localCtag == remoteCtag) {
|
||||
Timber.d("%s up to date", caldavCalendar.name)
|
||||
return
|
||||
}
|
||||
val davCalendar = DavCalendar(httpClient, httpUrl)
|
||||
val members = ResponseList(HrefRelation.MEMBER)
|
||||
davCalendar.calendarQuery("VTODO", null, null, members)
|
||||
val changed = members.filter { vCard: at.bitfire.dav4jvm.Response ->
|
||||
val eTag = vCard[GetETag::class.java]
|
||||
if (eTag == null || isNullOrEmpty(eTag.eTag)) {
|
||||
return@filter false
|
||||
}
|
||||
val caldavTask = caldavDao.getTask(caldavCalendar.uuid!!, vCard.hrefName())
|
||||
caldavTask == null || eTag.eTag != caldavTask.etag
|
||||
}
|
||||
for (items in changed.chunked(30)) {
|
||||
val urls = items.map { it.href }
|
||||
val responses = ResponseList(HrefRelation.MEMBER)
|
||||
davCalendar.multiget(urls, responses)
|
||||
Timber.d("MULTI %s", urls)
|
||||
for (vCard in responses) {
|
||||
val eTag = vCard[GetETag::class.java]
|
||||
val url = vCard.href
|
||||
if (eTag == null || isNullOrEmpty(eTag.eTag)) {
|
||||
throw DavException("Received CalDAV GET response without ETag for $url")
|
||||
}
|
||||
val calendarData = vCard[CalendarData::class.java]
|
||||
if (calendarData == null || isNullOrEmpty(calendarData.iCalendar)) {
|
||||
throw DavException("Received CalDAV GET response without CalendarData for $url")
|
||||
}
|
||||
val fileName = vCard.hrefName()
|
||||
val vtodo = calendarData.iCalendar
|
||||
val remote = fromVtodo(vtodo!!)
|
||||
if (remote == null) {
|
||||
Timber.e("Invalid VCALENDAR: %s", fileName)
|
||||
return
|
||||
}
|
||||
val caldavTask = caldavDao.getTask(caldavCalendar.uuid!!, fileName)
|
||||
iCal.fromVtodo(caldavCalendar, caldavTask, remote, vtodo, fileName, eTag.eTag)
|
||||
}
|
||||
}
|
||||
val deleted = caldavDao
|
||||
.getObjects(caldavCalendar.uuid!!)
|
||||
.subtract(members.map { it.hrefName() })
|
||||
.toList()
|
||||
if (deleted.isNotEmpty()) {
|
||||
Timber.d("DELETED %s", deleted)
|
||||
taskDeleter.delete(caldavDao.getTasks(caldavCalendar.uuid!!, deleted))
|
||||
}
|
||||
caldavCalendar.ctag = remoteCtag
|
||||
Timber.d("UPDATE %s", caldavCalendar)
|
||||
caldavDao.update(caldavCalendar)
|
||||
caldavDao.updateParents(caldavCalendar.uuid!!)
|
||||
localBroadcastManager.broadcastRefresh()
|
||||
}
|
||||
|
||||
private fun pushLocalChanges(
|
||||
caldavCalendar: CaldavCalendar, httpClient: OkHttpClient, httpUrl: HttpUrl) {
|
||||
for (task in caldavDao.getDeleted(caldavCalendar.uuid!!)) {
|
||||
deleteRemoteResource(httpClient, httpUrl, task)
|
||||
}
|
||||
for (task in taskDao.getCaldavTasksToPush(caldavCalendar.uuid!!)) {
|
||||
try {
|
||||
pushTask(task, httpClient, httpUrl)
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteRemoteResource(
|
||||
httpClient: OkHttpClient, httpUrl: HttpUrl, caldavTask: CaldavTask): Boolean {
|
||||
try {
|
||||
if (!isNullOrEmpty(caldavTask.`object`)) {
|
||||
val remote = DavResource(
|
||||
httpClient, httpUrl.newBuilder().addPathSegment(caldavTask.`object`!!).build())
|
||||
remote.delete(null) {}
|
||||
}
|
||||
} catch (e: HttpException) {
|
||||
if (e.code != 404) {
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
caldavDao.delete(caldavTask)
|
||||
return true
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun pushTask(task: Task, httpClient: OkHttpClient, httpUrl: HttpUrl) {
|
||||
Timber.d("pushing %s", task)
|
||||
val caldavTask = caldavDao.getTask(task.id) ?: return
|
||||
if (task.isDeleted) {
|
||||
if (deleteRemoteResource(httpClient, httpUrl, caldavTask)) {
|
||||
taskDeleter.delete(task)
|
||||
}
|
||||
return
|
||||
}
|
||||
val data = iCal.toVtodo(caldavTask, task)
|
||||
val requestBody = RequestBody.create(MIME_ICALENDAR, data)
|
||||
try {
|
||||
val remote = DavResource(
|
||||
httpClient, httpUrl.newBuilder().addPathSegment(caldavTask.`object`!!).build())
|
||||
val response = Response()
|
||||
remote.put(requestBody, null, false, response)
|
||||
val getETag = fromResponse(response.get())
|
||||
if (getETag != null && !isNullOrEmpty(getETag.eTag)) {
|
||||
caldavTask.etag = getETag.eTag
|
||||
caldavTask.vtodo = String(data)
|
||||
}
|
||||
} catch (e: HttpException) {
|
||||
Timber.e(e)
|
||||
return
|
||||
}
|
||||
caldavTask.lastSync = DateTimeUtils.currentTimeMillis()
|
||||
caldavDao.update(caldavTask)
|
||||
Timber.d("SENT %s", caldavTask)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue