Skip to content

Commit e49fdb6

Browse files
committed
Don't generate exception VEVENTs when there are only invalid/filtered recurrence properties, so that the generated event is non-recurring
1 parent 5f5a9fe commit e49fdb6

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

lib/src/main/kotlin/at/bitfire/synctools/mapping/calendar/LegacyAndroidEventProcessor.kt

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,25 +83,27 @@ class LegacyAndroidEventProcessor(
8383
to = to
8484
)
8585

86-
// exceptions of recurring main event
87-
for (exception in eventAndExceptions.exceptions) {
88-
val exceptionEvent = Event()
86+
// Add exceptions of recurring main event
87+
if (to.rRules.isNotEmpty() || to.rDates.isNotEmpty()) {
88+
for (exception in eventAndExceptions.exceptions) {
89+
val exceptionEvent = Event()
8990

90-
// convert exception to Event
91-
populateEvent(
92-
entity = exception,
93-
main = eventAndExceptions.main,
94-
to = exceptionEvent
95-
)
91+
// convert exception to Event
92+
populateEvent(
93+
entity = exception,
94+
main = eventAndExceptions.main,
95+
to = exceptionEvent
96+
)
9697

97-
// make sure that exception has a RECURRENCE-ID
98-
val recurrenceId = exceptionEvent.recurrenceId ?: continue
98+
// make sure that exception has a RECURRENCE-ID
99+
val recurrenceId = exceptionEvent.recurrenceId ?: continue
99100

100-
// generate EXDATE instead of VEVENT with RECURRENCE-ID for cancelled instances
101-
if (exception.entityValues.getAsInteger(Events.STATUS) == Events.STATUS_CANCELED)
102-
addAsExDate(exception, recurrenceId, to = to)
103-
else
104-
to.exceptions += exceptionEvent
101+
// generate EXDATE instead of VEVENT with RECURRENCE-ID for cancelled instances
102+
if (exception.entityValues.getAsInteger(Events.STATUS) == Events.STATUS_CANCELED)
103+
addAsExDate(exception, recurrenceId, to = to)
104+
else
105+
to.exceptions += exceptionEvent
106+
}
105107
}
106108
}
107109

lib/src/test/kotlin/at/bitfire/synctools/mapping/calendar/LegacyAndroidEventProcessorTest.kt

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class LegacyAndroidEventProcessorTest {
3131
private val tzVienna = tzRegistry.getTimeZone("Europe/Vienna")!!
3232

3333
@Test
34-
fun `Populate regular exception`() {
34+
fun `Exception is processed`() {
3535
val result = Event()
3636
processor.populate(
3737
eventAndExceptions = EventAndExceptions(
@@ -65,7 +65,38 @@ class LegacyAndroidEventProcessorTest {
6565
}
6666

6767
@Test
68-
fun `Populate cancelled exception as EXDATE`() {
68+
fun `Exception is ignored when there's only one invalid RRULE`() {
69+
val result = Event()
70+
processor.populate(
71+
eventAndExceptions = EventAndExceptions(
72+
main = Entity(contentValuesOf(
73+
Events.TITLE to "Factically non-recurring non-all-day event with exception",
74+
Events.DTSTART to 1594056600000L,
75+
Events.EVENT_TIMEZONE to tzVienna.id,
76+
Events.ALL_DAY to 0,
77+
Events.RRULE to "FREQ=DAILY;UNTIL=20200706T173000Z"
78+
)),
79+
exceptions = listOf(
80+
Entity(contentValuesOf(
81+
Events.ORIGINAL_INSTANCE_TIME to 1594143000000L,
82+
Events.ORIGINAL_ALL_DAY to 0,
83+
Events.DTSTART to 1594038600000L,
84+
Events.EVENT_TIMEZONE to tzShanghai.id,
85+
Events.ALL_DAY to 0,
86+
Events.TITLE to "Event moved to one hour later"
87+
))
88+
)
89+
),
90+
to = result
91+
)
92+
assertEquals("Factically non-recurring non-all-day event with exception", result.summary)
93+
assertEquals(DtStart("20200706T193000", tzVienna), result.dtStart)
94+
assertTrue(result.rRules.isEmpty())
95+
assertTrue(result.exceptions.isEmpty())
96+
}
97+
98+
@Test
99+
fun `Cancelled exception becomes EXDATE`() {
69100
val result = Event()
70101
processor.populate(
71102
eventAndExceptions = EventAndExceptions(
@@ -97,7 +128,7 @@ class LegacyAndroidEventProcessorTest {
97128
}
98129

99130
@Test
100-
fun `Populate cancelled exception without RECURRENCE-ID`() {
131+
fun `Cancelled exception without RECURRENCE-ID is ignored`() {
101132
val result = Event()
102133
processor.populate(
103134
eventAndExceptions = EventAndExceptions(

0 commit comments

Comments
 (0)