Skip to content

Commit 3b59e5a

Browse files
authored
Merge pull request #138 from cloud-atlas-ai:muness/issue19
Skip declined event for recurring events
2 parents 2e02f2c + b413e9c commit 3b59e5a

File tree

5 files changed

+75
-13
lines changed

5 files changed

+75
-13
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/icalUtils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ function processRecurringRules(event: any, dayToMatch: string, excludedDates: mo
9090

9191
if (moment(clonedEvent.start).isSame(dayToMatch, 'day')) {
9292
console.debug(`Adding recurring event: ${clonedEvent.summary} ${clonedEvent.start} - ${clonedEvent.end}`);
93+
console.debug(clonedEvent);
9394
matchingEvents.push(clonedEvent);
9495
}
9596
});

src/main.ts

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default class ICSPlugin extends Plugin {
6767
].filter(Boolean).join(' ').trim();
6868
}
6969

70+
7071
async getEvents(date: string): Promise<IEvent[]> {
7172
let events: IEvent[] = [];
7273
let errorMessages: string[] = []; // To store error messages
@@ -96,16 +97,9 @@ export default class ICSPlugin extends Plugin {
9697

9798
// Exception handling for parsing and filtering
9899
try {
99-
dateEvents = filterMatchingEvents(icsArray, date, calendarSetting.format.showOngoing);
100-
101-
// Exclude transparent events
102-
dateEvents = dateEvents.filter(event => {
103-
if (event.transparency && event.transparency.toUpperCase() === "TRANSPARENT") {
104-
console.debug(`Excluding transparent event: ${event.summary}`);
105-
return false;
106-
}
107-
return true;
108-
});
100+
dateEvents = dateEvents = filterMatchingEvents(icsArray, date, calendarSetting.format.showOngoing)
101+
.filter(e => this.excludeTransparentEvents(e, calendarSetting))
102+
.filter(e => this.excludeDeclinedEvents(e, calendarSetting));
109103

110104
} catch (filterError) {
111105
console.error(`Error filtering events for calendar ${calendarSetting.icsName}: ${filterError}`);
@@ -186,6 +180,51 @@ export default class ICSPlugin extends Plugin {
186180
return;
187181
}
188182

183+
excludeTransparentEvents(event: any, calendarSetting: Calendar): boolean {
184+
// 1. Exclude transparent events
185+
if (
186+
event.transparency &&
187+
event.transparency.toUpperCase() === "TRANSPARENT"
188+
) {
189+
console.debug(`Excluding transparent event: ${event.summary}`);
190+
return false;
191+
}
192+
193+
return true;
194+
195+
}
196+
197+
excludeDeclinedEvents(event: any, calendarSetting: Calendar): boolean {
198+
if (!event.attendees) {
199+
event.attendees = Array.isArray(event.attendee)
200+
? event.attendee
201+
: event.attendee
202+
? [event.attendee]
203+
: [];
204+
}
205+
206+
// 3. Check if the user (calendar owner) declined
207+
const ownerEmail = calendarSetting.ownerEmail?.toLowerCase().trim();
208+
if (ownerEmail) {
209+
const myAttendee = event.attendees.find((att: any) => {
210+
const attEmail = att.val.replace("mailto:", "").toLowerCase().trim();
211+
return attEmail === ownerEmail;
212+
});
213+
214+
if (myAttendee) {
215+
const partStat = myAttendee.params?.PARTSTAT?.toUpperCase();
216+
if (partStat === "DECLINED") {
217+
// The owner of this calendar has declined the event
218+
console.debug(
219+
`Skipping event (“${event.summary}”) for ${ownerEmail} due to DECLINED`
220+
);
221+
return false;
222+
}
223+
}
224+
}
225+
return true;
226+
}
227+
189228
async loadSettings() {
190229
this.data = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
191230
}

src/settings/ICSSettings.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ export interface ICSSettings {
99
export interface Calendar {
1010
icsUrl: string;
1111
icsName: string;
12+
13+
/**
14+
* Optional field for storing the owner email of this calendar.
15+
* Used when checking PARTSTAT=DECLINED for that email.
16+
*/
17+
ownerEmail?: string;
18+
1219
calendarType: 'remote' | 'vdir'; // Add this line
1320
format: {
1421
checkbox: boolean;

src/settings/ICSSettingsTab.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export default class ICSSettingsTab extends PluginSettingTab {
103103
this.plugin.addCalendar({
104104
icsName: modal.icsName,
105105
icsUrl: modal.icsUrl,
106+
ownerEmail: modal.ownerEmail,
106107
format: modal.format,
107108
calendarType: modal.calendarType as 'remote' | 'vdir',
108109
});
@@ -140,6 +141,7 @@ export default class ICSSettingsTab extends PluginSettingTab {
140141
this.plugin.addCalendar({
141142
icsName: modal.icsName,
142143
icsUrl: modal.icsUrl,
144+
ownerEmail: modal.ownerEmail,
143145
format: modal.format,
144146
calendarType: modal.calendarType as 'remote' | 'vdir',
145147
});
@@ -204,6 +206,7 @@ class SettingsModal extends Modal {
204206
urlSetting: Setting;
205207
urlText: TextComponent;
206208
urlDropdown: DropdownComponent;
209+
ownerEmail: string = "";
207210

208211
saved: boolean = false;
209212
error: boolean = false;
@@ -217,7 +220,7 @@ class SettingsModal extends Modal {
217220
location: boolean,
218221
description: boolean,
219222
showAttendees: boolean,
220-
showOngoing: boolean
223+
showOngoing: boolean,
221224
} = DEFAULT_CALENDAR_FORMAT;
222225
calendarType: string;
223226
constructor(app: App, plugin: ICSPlugin, setting?: Calendar) {
@@ -226,6 +229,7 @@ class SettingsModal extends Modal {
226229
if (setting) {
227230
this.icsName = setting.icsName;
228231
this.icsUrl = setting.icsUrl;
232+
this.ownerEmail = setting.ownerEmail;
229233
this.format = setting.format;
230234
this.calendarType = setting.calendarType || 'remote';
231235
}
@@ -254,6 +258,17 @@ class SettingsModal extends Modal {
254258
nameText = text;
255259
nameText.setValue(this.icsName).onChange(async (v) => {
256260
this.icsName = v;
261+
this.hasChanges = true;
262+
});
263+
});
264+
265+
const ownerEmailSetting = new Setting(settingDiv)
266+
.setName('Calendar Owner Email (Optional)')
267+
.setDesc('Used to skip declined events')
268+
.addText(text => {
269+
text.setValue(this.ownerEmail).onChange(value => {
270+
this.ownerEmail = value;
271+
this.hasChanges = true;
257272
});
258273
});
259274

0 commit comments

Comments
 (0)