@michaelmhoffman
Latest commit 34c355c Jul 24, 2021 History
Implement #550. Includes BREAKING CHANGES. Perhaps next release should increase major version number.

* feat!: add header row for `gcalcli agenda --tsv`

BREAKING CHANGE: having a header row will break any software that
assumes that the output of `gcalcli agenda --tsv` doesn't have one.

Also slightly refactored the output printing to use print() like in
most parts of the code.

* feat!: gcal agenda --tsv prints empty time fields for all-day events

BREAKING CHANGE: this changes the previous behavior which was to
depict all-day events as starting and ending at midnight.

* feat: add `--detail id` for `gcalcli agenda --tsv`
* feat: add agendaupdate for title, id, location, description

argparsers.py, cli.py: add `agendaupdate` subcommand
gcal.py: add `AgendaUpdate()`
details.py:
- `Title`, `SimpleSingleFieldHandler`: add `patch()`
- add `FIELD_HANDLERS`

* feat: add agendaupdate for time

Round trips don't work for all day events. The current output format
is to present them as events starting and ending at midnight of the
same day. But this keeps us from having events starting and ending at
midnight of the same day.

In the next commit I plan to change the output for all day events so
the time fields are blank.

Also:

- change signature of `Handler.patch()` to include `cal`, which is necessary to extract the timezone
- change default of `Handler.fieldnames` from `None` to `[]` to silence a mypy warning.

* feat: add detail for `action` for `gcalcli agenda`.

Column is ignored by `gcalcli agendaupdate`.

* feat: add agendaupdate action dispatch and `patch` action

Refactor most of existing agendaupdate into new module
`gcalcli.actions` in `patch()`.

* feat: add agendaupdate for calendar

This treats calendar as a readonly field. Actually moving calendar
would be a bit more involved, and would necessitate:
- changing agendaupdate from its current one-calendar-only restriction
- using the events().move() method to do the move. It's not done by events().patch()

That can be a future feature.

* feat: add agendaupdate `ignore` action
* feat: add agendaupdate `delete` action
* feat: add agendaupdate `insert` action
* feat: `agendaupdate` patch action uses insert if no id supplied
* feat: error when unsupported agendaupdate action used

Also limits actions to a defined set. Before one could have specified
action to be name of some other object in `gcalcli.actions` with
unpredictable results.

* feat: add agendaupdate for url

Both these fields are read-only.

If html_link is in the input, always fail.
If hangout_link is in the input, check against the current value. If they don't match, fail.

* feat: add agendaupdate for conference

Partially implements #522.

* fix: change SimpleSingleColumnHandler.header to a simple list

Can't use a property on a classmethod without making a custom
metaclass. Without that, the property is only enacted upon class
instantiation, which we aren't doing here.

A custom metaclass is too magic, and thus far we have avoided
instantiating what would be singleton objects.

Also changed `SimpleSingleColumnHandler._get()` to use `cls.header[0]`
instead of `cls._key` which is removed.

* fix: gcalcli agenda to work with refactor 72710b4

* refactor: move _tsv() implementation to gcalcli.details

Refactor `gcalcli.gcal.GoogleCalendarInterface._tsv()`, replacing the
long list of if statements with a modular design using a series of
`gcalcli.details.Handler` classes.

Each `Handler` represents the set of event properties that are
captured by each item of `gcalcli.argparsers.DETAILS`. So far only the
`header` class attribute and the `get()` methods are implemented. This
is what is necessary for TSV output.

* refactor: derive `argparsers.DETAILS` from `details.HANDLERS`

Set `gcalcli.argparsers.DETAILS` to a superset of
`gcalcli.details.HANDLERS.keys()` to avoid duplication.

* refactor: change `header` to `fieldnames` and `column` to `field`

* refactor: change `Handler.patch()` to include `fieldname` argument

This will enable `Handler`s with multiple fields to work for patching.
Necessary for `Time.patch()` and `Conference.patch()`

Also introduce `SingleFieldHandler.patch(cls,` ...`)` which dispatches to
`cls._patch()`.

* refactor: move gcal.GoogleCalendarInterface._isallday() to utils.is_all_day()

This enables its use by details.py.

* refactor: `details.Url` uses `details.URL_PROPS` to identify properties to get

The new `details.URL_PROPS` constant `OrderedDict` will also work for
use in `Url.patch()`, which should be implemented in the next commit.
This will allow automated handling of two property/fieldname pairs for
this `Handler`.

* refactor: add `exceptions.ReadonlyError`, `exceptions.ReadonlyCheckError`
* refactor: add `gcal.GoogleCalendarInterface.get_events()`

change previous uses of
`get_cal_service().events()` to `get_events()`

* refactor: add `gcal.GoogleCalendarInterface.delete()`
* refactor: add gcalcli.actions._iter_field_handlers()

* style: add extra line of whitespace

* ci: eliminate flake8-docstrings method docstring checks for details.py

These are mostly overriding pure virtual classes and adding a
docstring to each one would be superfluous and make the code harder to
read.
1 contributor

Users who have contributed to this file