From cad45ecd2c70d86662f7bf16a594a439b181649f Mon Sep 17 00:00:00 2001 From: Duarte Figueiredo Date: Wed, 19 Apr 2023 11:50:25 +0100 Subject: [PATCH] [modules/todoist] - New module that connects to https://api.todoist.com and displays number of tasks due --- bumblebee_status/modules/contrib/todoist.py | 77 ++++++++++++++++++++ screenshots/todoist.png | Bin 0 -> 744 bytes tests/modules/contrib/test_todoist.py | 58 +++++++++++++++ themes/icons/awesome-fonts.json | 3 + 4 files changed, 138 insertions(+) create mode 100644 bumblebee_status/modules/contrib/todoist.py create mode 100644 screenshots/todoist.png create mode 100644 tests/modules/contrib/test_todoist.py diff --git a/bumblebee_status/modules/contrib/todoist.py b/bumblebee_status/modules/contrib/todoist.py new file mode 100644 index 0000000..c254139 --- /dev/null +++ b/bumblebee_status/modules/contrib/todoist.py @@ -0,0 +1,77 @@ +# pylint: disable=C0111,R0903 + +""" +Displays the nº of Todoist tasks that are due: + + * https://developer.todoist.com/rest/v2/#get-active-tasks + +Uses `xdg-open` or `x-www-browser` to open web-pages. + +Requires the following library: + * requests + +Errors: + if the Todoist get active tasks query failed, the shown value is `n/a` + +Parameters: + * todoist.token: Todoist api token, you can get it in https://todoist.com/app/settings/integrations/developer. + * todoist.filter: a filter statement defined by Todoist (https://todoist.com/help/articles/introduction-to-filters), eg: "!assigned to: others & (Overdue | due: today)" +""" + +import shutil +from typing import Final + +import requests + +import core.decorators +import core.input +import core.module +import core.widget + +HOST_API: Final[str] = "https://api.todoist.com" +HOST_WEBSITE: Final[str] = "https://todoist.com/app/today" + +TASKS_URL: Final[str] = f"{HOST_API}/rest/v2/tasks" + + +class Module(core.module.Module): + @core.decorators.every(minutes=5) + def __init__(self, config, theme): + super().__init__(config, theme, core.widget.Widget(self.todoist)) + + self.__user_id = None + self.background = True + self.__label = "" + + token = self.parameter("token", "") + self.__filter = self.parameter("filter", "") + + self.__requests = requests.Session() + self.__requests.headers.update({"Authorization": f"Bearer {token}"}) + + cmd = "xdg-open" + if not shutil.which(cmd): + cmd = "x-www-browser" + + core.input.register( + self, + button=core.input.LEFT_MOUSE, + cmd=f"{cmd} {HOST_WEBSITE}", + ) + + def todoist(self, _): + return self.__label + + def update(self): + try: + self.__label = self.__get_pending_tasks() + except Exception: + self.__label = "n/a" + + def __get_pending_tasks(self) -> str: + params = {"filter": self.__filter} if self.__filter else None + + response = self.__requests.get(TASKS_URL, params=params) + data = response.json() + + return str(len(data)) diff --git a/screenshots/todoist.png b/screenshots/todoist.png new file mode 100644 index 0000000000000000000000000000000000000000..66e1bae2c0d08ab0b97d8806d3eb239751557ba4 GIT binary patch literal 744 zcmVP)* z7?waxLUA~uQ7;VzH0q_HfQa&vjGTJ^geli=+Kiw20(Gt5uo+F((<>0&==bk|f|%xDBBH!>|Neb+<8c6>N=)ro z5zsUD?%iLvZsU90URttbMNMrZ9O>zsW154Bi1HG;!%@N6bLXc{n+4}$YR8I6if3)Hk$3L@>4ELHNCtn4AHO8FfuVOpSODXD>E+9p5Ho=R7Zx6isU0gK!As}PUjTZbth@%o zy?F7mt{yaT2Zuz%t;f`k2jTLPn}`2~jay2~YSPkkyL%=8OVqb--v$LoVVZ!6Nbr)E zcMybITi0~?@)bP;3kcUgF#N@f7Z5en@)8Z~+qRvUCSW3>yo8+l@dKbr zOzl`vd_o$qDr;((9UZpQ(DDlxTVMQhfqN7szhTqrK7Jb3Uhu*LNH^&23$bmK_}0000