Skip to content

Commit

Permalink
show partstat status for calendar's address
Browse files Browse the repository at this point in the history
  • Loading branch information
geier committed Nov 15, 2023
1 parent f94551d commit e0bd70b
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ not released yet
* NEW event format option `status-symbol` which represents the status of an
event with a symbol (e.g. `` for confirmed, `` for cancelled, `?` for
tentative)
* NEW event format option `partstat-symbol` which represents the participation
status of an event with a symbol (e.g. `` for accepted, `` for declined,
`?` for tentative); partication status is shown for the email address
configured for the event's calendar

0.11.2
======
Expand Down
3 changes: 3 additions & 0 deletions doc/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ Several options are common to almost all of :program:`khal`'s commands
status-symbol
The status of the event as a symbol, `` or `` or `?`.

partstat-symbol
The participation status of the event as a symbol, `` or `` or `?`.

cancelled
The string `CANCELLED` (plus one blank) if the event's status is
cancelled, otherwise nothing.
Expand Down
1 change: 1 addition & 0 deletions khal/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ def build_collection(conf, selection):
'color': cal['color'],
'priority': cal['priority'],
'ctype': cal['type'],
'address': cal['address'],
}
collection = khalendar.CalendarCollection(
calendars=props,
Expand Down
1 change: 1 addition & 0 deletions khal/custom_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class CalendarConfiguration(TypedDict):
color: str
priority: int
ctype: str
address: str


class LocaleConfiguration(TypedDict):
Expand Down
35 changes: 31 additions & 4 deletions khal/khalendar/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ def __init__(self,
color: Optional[str] = None,
start: Optional[dt.datetime] = None,
end: Optional[dt.datetime] = None,
) -> None:
address: str = '',
):
"""
:param start: start datetime of this event instance
:param end: end datetime of this event instance
Expand All @@ -87,6 +88,7 @@ def __init__(self,
self.color = color
self._start: dt.datetime
self._end: dt.datetime
self.address = address

if start is None:
self._start = self._vevents[self.ref]['DTSTART'].dt
Expand Down Expand Up @@ -290,6 +292,8 @@ def symbol_strings(self) -> Dict[str, str]:
'cancelled': '\N{Cross mark}',
'confirmed': '\N{Heavy check mark}',
'tentative': '\N{White question mark ornament}',
'declined': '\N{Cross mark}',
'accepted': '\N{Heavy check mark}',
}
else:
return {
Expand All @@ -302,6 +306,8 @@ def symbol_strings(self) -> Dict[str, str]:
'cancelled': 'X',
'confirmed': 'V',
'tentative': '?',
'declined': 'X',
'accepted': 'V',
}

@property
Expand Down Expand Up @@ -563,15 +569,28 @@ def _alarm_str(self) -> str:
@property
def _status_str(self) -> str:
if self.status == 'CANCELLED':
statusstr = ' ' + self.symbol_strings['cancelled']
statusstr = self.symbol_strings['cancelled']
elif self.status == 'TENTATIVE':
statusstr = ' ' + self.symbol_strings['tentative']
statusstr = self.symbol_strings['tentative']
elif self.status == 'CONFIRMED':
statusstr = ' ' + self.symbol_strings['confirmed']
statusstr = self.symbol_strings['confirmed']
else:
statusstr = ''
return statusstr

@property
def _partstat_str(self) -> str:
partstat = self.partstat
if partstat == 'ACCEPTED':
partstatstr = self.symbol_strings['accepted']
elif partstat == 'TENTATIVE':
partstatstr = self.symbol_strings['tentative']
elif partstat == 'DECLINED':
partstatstr = self.symbol_strings['declined']
else:
partstatstr = ''
return partstatstr

def attributes(
self,
relative_to: Union[Tuple[dt.date, dt.date], dt.date],
Expand Down Expand Up @@ -703,6 +722,7 @@ def attributes(
attributes["repeat-pattern"] = self.recurpattern
attributes["alarm-symbol"] = self._alarm_str
attributes["status-symbol"] = self._status_str
attributes["partstat-symbol"] = self._partstat_str
attributes["title"] = self.summary
attributes["organizer"] = self.organizer.strip()
attributes["description"] = self.description.strip()
Expand Down Expand Up @@ -785,6 +805,13 @@ def delete_instance(self, instance: dt.datetime) -> None:
def status(self) -> str:
return self._vevents[self.ref].get('STATUS', '')

@property
def partstat(self) -> Optional[str]:
for attendee in self._vevents[self.ref].get('ATTENDEE', []):
print(attendee)
if attendee == 'mailto:' + self.address:
return attendee.params.get('PARTSTAT', '')


class DatetimeEvent(Event):
pass
Expand Down
1 change: 1 addition & 0 deletions khal/khalendar/khalendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ def _construct_event(self,
ref=ref,
color=self._calendars[calendar]['color'],
readonly=self._calendars[calendar]['readonly'],
address=self._calendars[calendar]['address'],
)
return event

Expand Down
4 changes: 3 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def coll_vdirs(tmpdir) -> CollVdirType:
color='dark blue',
priority=10,
ctype='calendar',
address='[email protected]',
)
vdirs[name] = Vdir(path, '.ics')
coll = CalendarCollection(calendars=calendars, dbpath=':memory:', locale=LOCALE_BERLIN)
Expand All @@ -71,7 +72,8 @@ def coll_vdirs_birthday(tmpdir):
os.makedirs(path, mode=0o770)
readonly = True if name == 'a_calendar' else False
calendars[name] = {'name': name, 'path': path, 'color': 'dark blue',
'readonly': readonly, 'unicode_symbols': True, 'ctype': 'birthdays'}
'readonly': readonly, 'unicode_symbols': True, 'ctype': 'birthdays',
'address': '[email protected]'}
vdirs[name] = Vdir(path, '.vcf')
coll = CalendarCollection(calendars=calendars, dbpath=':memory:', locale=LOCALE_BERLIN)
coll.default_calendar_name = cal1
Expand Down
34 changes: 34 additions & 0 deletions tests/event_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -695,3 +695,37 @@ def test_parameters_description():
assert event.description == (
'Hey, \n\nJust setting aside some dedicated time to talk about redacted.'
)

def test_partstat():
FORMAT_CALENDAR = (
'{calendar-color}{partstat-symbol}{status-symbol}{start-end-time-style} ({calendar}) '
'{title} [{location}]{repeat-symbol}'
)

event = Event.fromString(
_get_text('event_dt_partstat'), address='[email protected]', **EVENT_KWARGS)
assert event.partstat == 'ACCEPTED'
assert human_formatter(FORMAT_CALENDAR)(event.attributes(dt.date(2014, 4, 9))) == \
'✔09:30-10:30 (foobar) An Event []\x1b[0m'

event = Event.fromString(
_get_text('event_dt_partstat'), address='[email protected]', **EVENT_KWARGS)
assert event.partstat == 'DECLINED'
assert human_formatter(FORMAT_CALENDAR)(event.attributes(dt.date(2014, 4, 9))) == \
'❌09:30-10:30 (foobar) An Event []\x1b[0m'

event = Event.fromString(
_get_text('event_dt_partstat'), address='[email protected]', **EVENT_KWARGS)
assert event.partstat == 'ACCEPTED'
assert human_formatter(FORMAT_CALENDAR)(event.attributes(dt.date(2014, 4, 9))) == \
'✔09:30-10:30 (foobar) An Event []\x1b[0m'

@pytest.mark.xfail
def test_partstat_deligated():
event = Event.fromString(
_get_text('event_dt_partstat'), address='[email protected]', **EVENT_KWARGS)
assert event.partstat == 'ACCEPTED'

event = Event.fromString(
_get_text('event_dt_partstat'), address='[email protected]', **EVENT_KWARGS)
assert event.partstat == 'ACCEPTED'
22 changes: 22 additions & 0 deletions tests/ics/event_dt_partstat.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PIMUTILS.ORG//NONSGML khal / icalendar //EN
BEGIN:VEVENT
SUMMARY:An Event
DTSTART;TZID=Europe/Berlin:20140409T093000
DTEND;TZID=Europe/Berlin:20140409T103000
DTSTAMP:20140401T234817Z
UID:V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU
ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=TENTATIVE;DELEGATED-FROM=
"mailto:[email protected]";CN=Henry Cabot:mailto:hcabot@
example.com
ATTENDEE;ROLE=NON-PARTICIPANT;PARTSTAT=DELEGATED;DELEGATED-TO=
"mailto:[email protected]";CN=The Big Cheese:mailto:iamboss
@example.com
ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Jane Doe
:mailto:[email protected]
ATTENDEE;PARTSTAT=ACCEPTED:mailto:[email protected]
ATTENDEE;PARTSTAT=DECLINED:mailto:[email protected]
ATTENDEE;PARTSTAT=TENTATIVE:mailto:[email protected]
END:VEVENT
END:VCALENDAR
12 changes: 12 additions & 0 deletions tests/ics/event_dt_status_confirmed.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PIMUTILS.ORG//NONSGML khal / icalendar //EN
BEGIN:VEVENT
SUMMARY:An Event
DTSTART;TZID=Europe/Berlin:20140409T093000
DTEND;TZID=Europe/Berlin:20140409T103000
DTSTAMP:20140401T234817Z
UID:V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU
STATUS:CONFIRMED
END:VEVENT
END:VCALENDAR
12 changes: 8 additions & 4 deletions tests/settings_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,14 @@ def test_simple_config(self):
)
comp_config = {
'calendars': {
'home': {'path': os.path.expanduser('~/.calendars/home/'),
'readonly': False, 'color': None, 'priority': 10, 'type': 'calendar', 'address': ''},
'work': {'path': os.path.expanduser('~/.calendars/work/'),
'readonly': False, 'color': None, 'priority': 10, 'type': 'calendar', 'address': ''},
'home': {
'path': os.path.expanduser('~/.calendars/home/'), 'readonly': False,
'color': None, 'priority': 10, 'type': 'calendar', 'address': '',
},
'work': {
'path': os.path.expanduser('~/.calendars/work/'), 'readonly': False,
'color': None, 'priority': 10, 'type': 'calendar', 'address': '',
},
},
'sqlite': {'path': os.path.expanduser('~/.local/share/khal/khal.db')},
'locale': LOCALE_BERLIN,
Expand Down

0 comments on commit e0bd70b

Please sign in to comment.