Fix CalDAV repeatUntil sync

pull/1055/head
Alex Baker 4 years ago
parent e396dbf7bf
commit 8992997a0f

@ -11,6 +11,11 @@ import java.text.ParseException
@RunWith(AndroidJUnit4::class)
class RepeatRuleToStringTest {
@Test
fun daily() {
assertEquals("Repeats daily", toString("RRULE:FREQ=DAILY"))
}
@Test
fun weekly() {
assertEquals("Repeats weekly", toString("RRULE:FREQ=WEEKLY;INTERVAL=1"))

@ -4,6 +4,7 @@ import android.content.Context
import at.bitfire.ical4android.Task.Companion.tasksFromReader
import com.todoroo.astrid.data.Task
import org.tasks.caldav.CaldavConverter
import org.tasks.data.CaldavTask
import org.tasks.preferences.Preferences
import java.io.StringReader
import java.nio.file.Files
@ -20,11 +21,22 @@ object TestUtilities {
return task
}
private fun fromResource(path: String): at.bitfire.ical4android.Task {
fun setup(path: String): Pair<Task, CaldavTask> {
val task = Task()
val vtodo = readFile(path)
CaldavConverter.apply(task, fromString(vtodo))
return Pair(task, CaldavTask().apply { this.vtodo = vtodo })
}
private fun fromResource(path: String): at.bitfire.ical4android.Task =
fromString(readFile(path))
fun readFile(path: String): String {
val url = javaClass.classLoader!!.getResource(path)
val paths = Paths.get(url!!.toURI())
return fromString(String(Files.readAllBytes(paths), Charsets.UTF_8))
return String(Files.readAllBytes(paths), Charsets.UTF_8)
}
private fun fromString(task: String) = tasksFromReader(StringReader(task))[0]
fun fromString(task: String): at.bitfire.ical4android.Task =
task.let { tasksFromReader(StringReader(it))[0] }
}

@ -234,7 +234,7 @@ class Task : Parcelable {
fun repeatAfterCompletion(): Boolean = recurrence.isRepeatAfterCompletion()
fun sanitizedRecurrence(): String? = getRecurrenceWithoutFrom()?.replace("BYDAY=;".toRegex(), "") // $NON-NLS-1$//$NON-NLS-2$
fun sanitizedRecurrence(): String? = getRecurrenceWithoutFrom()?.sanitizeRRule()
fun getRecurrenceWithoutFrom(): String? = recurrence.withoutFrom()
@ -608,6 +608,11 @@ class Task : Parcelable {
}
}
@JvmStatic
fun String?.sanitizeRRule(): String? = this
?.replace("BYDAY=;", "")
?.replace("COUNT=-1;", "")
@JvmStatic fun isUuidEmpty(uuid: String?): Boolean {
return NO_UUID == uuid || Strings.isNullOrEmpty(uuid)
}

@ -53,11 +53,10 @@ public class CaldavConverter {
local.setRecurrence("");
} else {
Recur recur = repeatRule.getRecur();
if (recur.getInterval() <= 0) {
recur.setInterval(1);
}
Date until = recur.getUntil();
local.setRepeatUntil(until == null ? 0 : org.tasks.time.DateTime.from(until).getMillis());
local.setRecurrence(
"RRULE:" + recur.toString() + (local.repeatAfterCompletion() ? ";FROM=COMPLETION" : ""));
"RRULE:" + Task.sanitizeRRule(recur.toString()) + (local.repeatAfterCompletion() ? ";FROM=COMPLETION" : ""));
}
Due due = remote.getDue();
if (due == null) {
@ -142,8 +141,14 @@ public class CaldavConverter {
}
if (task.isRecurring()) {
try {
String rrule = task.getRecurrenceWithoutFrom().replace("RRULE:", "");
remote.setRRule(new RRule(rrule));
RRule rrule = new RRule(task.getRecurrenceWithoutFrom().replace("RRULE:", ""));
long repeatUntil = task.getRepeatUntil();
rrule
.getRecur()
.setUntil(
repeatUntil > 0 ? new DateTime(newDateTime(repeatUntil).toUTC().getMillis()) : null);
String sanitized = Task.sanitizeRRule(rrule.getValue()); // ical4j adds COUNT=-1 if there is an UNTIL value
remote.setRRule(new RRule(sanitized));
if (remote.getDtStart() == null) {
Date date = remote.getDue() != null ? remote.getDue().getDate() : new Date();
remote.setDtStart(new DtStart(date));

@ -40,7 +40,7 @@ public class RepeatRuleToString {
int count = rrule.getCount();
String countString =
count > 0 ? context.getResources().getQuantityString(R.plurals.repeat_times, count) : "";
if (interval == 1) {
if (interval <= 1) {
String frequencyString = context.getString(getSingleFrequencyResource(frequency));
if ((frequency == WEEKLY || frequency == MONTHLY) && !rrule.getByDay().isEmpty()) {
String dayString = getDayString(rrule);

@ -15,14 +15,15 @@ import com.google.ical.values.DateValue;
import com.google.ical.values.DateValueImpl;
import com.google.ical.values.Weekday;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import net.fortuna.ical4j.model.Date;
import org.tasks.locale.Locale;
import java.time.LocalDate;
import java.time.LocalDateTime;
public class DateTime {
@ -95,6 +96,10 @@ public class DateTime {
return new DateTime(dateValue.year(), dateValue.month(), dateValue.day());
}
public static DateTime from(Date date) {
return new DateTime(date.getTime(), UTC);
}
private DateTime setTime(int hours, int minutes, int seconds, int milliseconds) {
Calendar calendar = getCalendar();
calendar.set(Calendar.HOUR_OF_DAY, hours);

@ -55,7 +55,7 @@ class AppleRemindersTests {
@Test
fun repeatDaily() {
assertEquals("RRULE:FREQ=DAILY;INTERVAL=1", vtodo("apple/repeat_daily.txt").recurrence)
assertEquals("RRULE:FREQ=DAILY", vtodo("apple/repeat_daily.txt").recurrence)
}
@Test

@ -5,6 +5,7 @@ import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.tasks.TestUtilities.setup
import org.tasks.TestUtilities.vtodo
import org.tasks.time.DateTime
import java.util.*
@ -56,7 +57,7 @@ class ThunderbirdTests {
@Test
fun repeatDaily() {
assertEquals(
"RRULE:FREQ=DAILY;INTERVAL=1", vtodo("thunderbird/repeat_daily.txt").recurrence)
"RRULE:FREQ=DAILY", vtodo("thunderbird/repeat_daily.txt").recurrence)
}
@Test
@ -83,4 +84,20 @@ class ThunderbirdTests {
fun highPriority() {
assertEquals(Task.Priority.HIGH, vtodo("thunderbird/priority_high.txt").priority)
}
@Test
fun getRepeatUntil() {
assertEquals(
DateTime(2020, 7, 31, 11, 0, 0, 0).millis,
vtodo("thunderbird/repeat_until_date_time.txt").repeatUntil)
}
@Test
fun dontTruncateTimeFromUntil() {
val (task, caldavTask) = setup("thunderbird/repeat_until_date_time.txt")
val remote = CaldavConverter.toCaldav(caldavTask, task)
assertEquals(
"FREQ=WEEKLY;UNTIL=20200731T160000Z;BYDAY=MO,TU,WE,TH,FR",
remote.rRule!!.value)
}
}

@ -0,0 +1,30 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
BEGIN:VTIMEZONE
TZID:America/Chicago
BEGIN:STANDARD
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZNAME:CST
TZOFFSETFROM:-0500
TZOFFSETTO:-0600
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZNAME:CDT
TZOFFSETFROM:-0600
TZOFFSETTO:-0500
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VTODO
CREATED:20200717T155259Z
DTSTAMP:20200717T155411Z
DTSTART;TZID=America/Chicago:20200717T110000
LAST-MODIFIED:20200717T155411Z
RRULE:FREQ=WEEKLY;UNTIL=20200731T160000Z;BYDAY=MO,TU,WE,TH,FR
SUMMARY:Repeat until
UID:3c6ed018-7840-404b-9182-5e2f39967a55
END:VTODO
END:VCALENDAR
Loading…
Cancel
Save