Store remote vtodo and preserve unsupported fields

pull/645/head
Alex Baker 6 years ago
parent 37bd715475
commit bcc5deba18

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 56,
"identityHash": "dcac47adc6c2df5755061388ec3a1248",
"identityHash": "cc409e42965995fd353910a20daf49cf",
"entities": [
{
"tableName": "notification",
@ -746,7 +746,7 @@
},
{
"tableName": "caldav_tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `account` TEXT, `object` TEXT, `remote_id` TEXT, `etag` TEXT, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `account` TEXT, `object` TEXT, `remote_id` TEXT, `etag` TEXT, `last_sync` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `vtodo` TEXT)",
"fields": [
{
"fieldPath": "id",
@ -795,6 +795,12 @@
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "vtodo",
"columnName": "vtodo",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
@ -809,7 +815,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"dcac47adc6c2df5755061388ec3a1248\")"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"cc409e42965995fd353910a20daf49cf\")"
]
}
}

@ -7,7 +7,7 @@ import android.content.SyncResult;
import android.os.Bundle;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.common.io.CharStreams;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.SyncFlags;
@ -31,6 +31,7 @@ import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@ -155,17 +156,22 @@ public class CalDAVSyncAdapter extends InjectingAbstractThreadedSyncAdapter {
if (eTag == null || isNullOrEmpty(eTag.getETag())) {
throw new DavException("Received CalDAV GET response without ETag for " + vCard.getLocation());
}
Timber.d("SINGLE %s", vCard.getLocation());
ResponseBody responseBody = vCard.get("text/calendar");
Reader reader = responseBody.charStream();
Reader reader = null;
try {
processVTodo(vCard.fileName(), caldavAccount, eTag.getETag(), reader);
reader = responseBody.charStream();
processVTodo(vCard.fileName(), caldavAccount, eTag.getETag(), CharStreams.toString(reader));
} finally {
if (reader != null) {
reader.close();
}
}
} else {
davCalendar.multiget(newArrayList(transform(changed, DavResource::getLocation)));
ArrayList<HttpUrl> urls = newArrayList(transform(changed, DavResource::getLocation));
davCalendar.multiget(urls);
Timber.d("MULTI %s", urls);
for (DavResource vCard : davCalendar.getMembers()) {
PropertyCollection vcardProperties = vCard.getProperties();
@ -179,20 +185,22 @@ public class CalDAVSyncAdapter extends InjectingAbstractThreadedSyncAdapter {
throw new DavException("Received CalDAV GET response without CalendarData for " + vCard.getLocation());
}
String vtodo = calendarData.getICalendar();
processVTodo(vCard.fileName(), caldavAccount, eTag.getETag(), new StringReader(vtodo));
processVTodo(vCard.fileName(), caldavAccount, eTag.getETag(), calendarData.getICalendar());
}
}
}
Sets.SetView<String> deleted = difference(
List<String> deleted = newArrayList(difference(
newHashSet(caldavDao.getObjects(caldavAccount.getUuid())),
newHashSet(remoteObjects));
List<String> toDelete = newArrayList(deleted);
taskDeleter.markDeleted(caldavDao.getTasks(caldavAccount.getUuid(), toDelete));
caldavDao.deleteObjects(caldavAccount.getUuid(), toDelete);
newHashSet(remoteObjects)));
if (deleted.size() > 0) {
Timber.d("DELETED %s", deleted);
taskDeleter.markDeleted(caldavDao.getTasks(caldavAccount.getUuid(), deleted));
caldavDao.deleteObjects(caldavAccount.getUuid(), deleted);
}
caldavAccount.setCtag(remoteCtag);
Timber.d("UPDATE %s", caldavAccount);
caldavDao.update(caldavAccount);
} catch (IOException | HttpException | DavException | CalendarStorageException e) {
Timber.e(e, e.getMessage());
@ -243,58 +251,60 @@ public class CalDAVSyncAdapter extends InjectingAbstractThreadedSyncAdapter {
return;
}
CaldavTask caldavMetadata = caldavDao.getTask(task.getId());
CaldavTask caldavTask = caldavDao.getTask(task.getId());
if (caldavMetadata == null) {
if (caldavTask == null) {
return;
}
if (task.isDeleted()) {
if (deleteRemoteResource(httpClient, httpUrl, caldavMetadata)) {
caldavDao.delete(caldavMetadata);
if (deleteRemoteResource(httpClient, httpUrl, caldavTask)) {
caldavDao.delete(caldavTask);
}
return;
}
at.bitfire.ical4android.Task remoteModel = TaskConverter.toCaldav(task);
at.bitfire.ical4android.Task remoteModel = TaskConverter.toCaldav(caldavTask, task);
if (Strings.isNullOrEmpty(caldavMetadata.getRemoteId())) {
if (Strings.isNullOrEmpty(caldavTask.getRemoteId())) {
String caldavUid = UUIDHelper.newUUID();
caldavMetadata.setRemoteId(caldavUid);
caldavTask.setRemoteId(caldavUid);
remoteModel.setUid(caldavUid);
} else {
remoteModel.setUid(caldavMetadata.getRemoteId());
remoteModel.setUid(caldavTask.getRemoteId());
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
remoteModel.write(os);
RequestBody requestBody = RequestBody.create(
DavCalendar.MIME_ICALENDAR,
os.toByteArray());
byte[] data = os.toByteArray();
RequestBody requestBody = RequestBody.create(DavCalendar.MIME_ICALENDAR, data);
try {
DavResource remote = new DavResource(httpClient, httpUrl.newBuilder().addPathSegment(caldavMetadata.getObject()).build());
DavResource remote = new DavResource(httpClient, httpUrl.newBuilder().addPathSegment(caldavTask.getObject()).build());
remote.put(requestBody, null, false);
GetETag getETag = remote.getProperties().get(GetETag.class);
if (getETag != null && !isNullOrEmpty(getETag.getETag())) {
caldavTask.setEtag(getETag.getETag());
caldavTask.setVtodo(new String(data));
}
} catch (HttpException e) {
Timber.e(e.getMessage(), e);
return;
}
long modified = currentTimeMillis();
task.setModificationDate(modified);
task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
taskDao.save(task);
caldavMetadata.setLastSync(modified);
caldavDao.update(caldavMetadata);
caldavTask.setLastSync(currentTimeMillis());
caldavDao.update(caldavTask);
Timber.d("SENT %s", caldavTask);
}
private List<CaldavTask> getDeleted(long taskId, CaldavAccount caldavAccount) {
return caldavDao.getDeleted(taskId, caldavAccount.getUuid());
}
private void processVTodo(String fileName, CaldavAccount caldavAccount, String eTag, Reader reader) throws IOException, CalendarStorageException {
private void processVTodo(String fileName, CaldavAccount caldavAccount, String eTag, String vtodo) throws IOException, CalendarStorageException {
List<at.bitfire.ical4android.Task> tasks;
try {
tasks = at.bitfire.ical4android.Task.fromReader(reader);
tasks = at.bitfire.ical4android.Task.fromReader(new StringReader(vtodo));
} catch (InvalidCalendarException e) {
Timber.e(e, e.getMessage());
return;
@ -308,20 +318,21 @@ public class CalDAVSyncAdapter extends InjectingAbstractThreadedSyncAdapter {
task = taskCreator.createWithValues(null, "");
taskDao.createNew(task);
caldavTask = new CaldavTask(task.getId(), caldavAccount.getUuid(), remote.getUid(), fileName);
Timber.d("NEW %s", remote);
} else {
task = taskDao.fetch(caldavTask.getTask());
Timber.d("UPDATE %s", remote);
}
TaskConverter.apply(task, remote);
task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
taskDao.save(task);
caldavTask.setVtodo(vtodo);
caldavTask.setEtag(eTag);
caldavTask.setLastSync(DateUtilities.now() + 1000L);
if (caldavTask.getId() == Task.NO_ID) {
caldavDao.insert(caldavTask);
caldavTask.setId(caldavDao.insert(caldavTask));
Timber.d("NEW %s", caldavTask);
} else {
caldavDao.update(caldavTask);
Timber.d("UPDATE %s", caldavTask);
}
} else {
Timber.e("Received VCALENDAR with %s VTODOs; ignoring %s", tasks.size(), fileName);

@ -1,5 +1,6 @@
package org.tasks.caldav;
import com.google.common.base.Strings;
import com.todoroo.astrid.data.Task;
import net.fortuna.ical4j.model.Date;
@ -9,14 +10,18 @@ import net.fortuna.ical4j.model.property.Completed;
import net.fortuna.ical4j.model.property.Due;
import net.fortuna.ical4j.model.property.RRule;
import org.tasks.data.CaldavTask;
import java.io.IOException;
import java.io.StringReader;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import at.bitfire.ical4android.InvalidCalendarException;
import timber.log.Timber;
import static com.todoroo.astrid.data.Task.DUE_DATE;
import static com.todoroo.astrid.data.Task.URGENCY_SPECIFIC_DAY;
import static com.todoroo.astrid.data.Task.URGENCY_SPECIFIC_DAY_TIME;
import static org.tasks.date.DateTimeUtils.newDateTime;
@ -68,21 +73,31 @@ public class TaskConverter {
}
}
static int toRemote(int tasksPriority) {
switch (tasksPriority) {
static int toRemote(int remotePriority, int localPriority) {
switch (localPriority) {
case Task.IMPORTANCE_DO_OR_DIE:
return 1;
case Task.IMPORTANCE_MUST_DO:
return 2;
case Task.IMPORTANCE_SHOULD_DO:
return 3;
return remotePriority > 2 ? remotePriority : 3;
default:
return 0;
}
}
public static at.bitfire.ical4android.Task toCaldav(Task task) {
at.bitfire.ical4android.Task remote = new at.bitfire.ical4android.Task();
public static at.bitfire.ical4android.Task toCaldav(CaldavTask caldavTask, Task task) {
at.bitfire.ical4android.Task remote = null;
try {
if (!Strings.isNullOrEmpty(caldavTask.getVtodo())) {
remote = at.bitfire.ical4android.Task.fromReader(new StringReader(caldavTask.getVtodo())).get(0);
}
} catch (IOException | InvalidCalendarException e) {
Timber.e(e, e.getMessage());
}
if (remote == null) {
remote = new at.bitfire.ical4android.Task();
}
remote.setSummary(task.getTitle());
remote.setDescription(task.getNotes());
if (task.hasDueDate()) {
@ -112,7 +127,8 @@ public class TaskConverter {
Timber.e(e, e.getMessage());
}
}
remote.setPriority(toRemote(task.getImportance()));
remote.setLastModified(newDateTime(task.getModificationDate()).toUTC().getMillis());
remote.setPriority(toRemote(remote.getPriority(), task.getImportance()));
return remote;
}
}

@ -25,7 +25,7 @@ public interface CaldavDao {
void update(CaldavAccount caldavAccount);
@Insert
void insert(CaldavTask caldavTask);
long insert(CaldavTask caldavTask);
@Update
void update(CaldavTask caldavTask);

@ -40,6 +40,9 @@ public class CaldavTask {
@ColumnInfo(name = "deleted")
private long deleted;
@ColumnInfo(name = "vtodo")
private String vtodo;
public CaldavTask() {
}
@ -121,6 +124,14 @@ public class CaldavTask {
this.deleted = deleted;
}
public String getVtodo() {
return vtodo;
}
public void setVtodo(String vtodo) {
this.vtodo = vtodo;
}
@Override
public String toString() {
return "CaldavTask{" +
@ -132,6 +143,7 @@ public class CaldavTask {
", etag='" + etag + '\'' +
", lastSync=" + lastSync +
", deleted=" + deleted +
", vtodo='" + vtodo + '\'' +
'}';
}
}

@ -155,6 +155,7 @@ public class Migrations {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `object` TEXT");
database.execSQL("ALTER TABLE `caldav_tasks` ADD COLUMN `vtodo` TEXT");
}
};

Loading…
Cancel
Save