From 88dd843c4281fe20dc7416dcd919178a49e5c9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=B6rist?= Date: Sun, 19 Aug 2018 16:42:06 +0200 Subject: [PATCH] [birthday] Rewrite Plugin The plugin did not work with Gajim 1.0.3, but will now with Gajim 1.1.0 --- birthday_reminder/birthday_reminder_large.png | Bin 6998 -> 0 bytes birthday_reminder/manifest.ini | 9 +- birthday_reminder/plugin.py | 180 +++++++++--------- 3 files changed, 93 insertions(+), 96 deletions(-) delete mode 100644 birthday_reminder/birthday_reminder_large.png diff --git a/birthday_reminder/birthday_reminder_large.png b/birthday_reminder/birthday_reminder_large.png deleted file mode 100644 index d150022ee35d2e383e8fd38f02546d64b984d419..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6998 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

lFe{%g0KJRJ;!LeBbsGZJzP4`#?OH%fW5VF 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 jD|>S)IeRy2Z)Z0LcPhaqyBVK -homepage: http://trac-plugins.gajim.org/wiki/BirthdayReminderPlugin -min_gajim_version: 0.16.11 + Philipp Hörist +homepage: https://dev.gajim.org/gajim/gajim-plugins/wikis/BirthdayReminderPlugin +min_gajim_version: 1.0.99 diff --git a/birthday_reminder/plugin.py b/birthday_reminder/plugin.py index 7fe2cb8..dcade36 100644 --- a/birthday_reminder/plugin.py +++ b/birthday_reminder/plugin.py @@ -1,119 +1,115 @@ import os -import glob +import json import datetime -from xml.dom.minidom import * -from gi.repository import GObject +import logging + +from gi.repository import GLib from gajim.plugins import GajimPlugin -from gajim.plugins.helpers import log_calls -from gajim.notify import popup from gajim.common import configpaths from gajim.common import app from gajim.common import ged +log = logging.getLogger('gajim.plugin_system.birthday') + +TITLE = _('%s has birthday today') +TEXT = _('Send him a message') + class BirthDayPlugin(GajimPlugin): - - @log_calls('BirthDayPlugin') def init(self): - self.config_dialog = None self.description = ('Birthday reminder plugin') self.events_handlers = { - 'roster-received': (ged.GUI2, self.roster_received)} - configpath = configpaths.ConfigPaths() - cache_path = configpath.cache_root - self.vcard_path = os.path.join(cache_path, 'vcards') + os.sep - self.timeout_id = 0 + 'vcard-received': (ged.GUI2, self._vcard_received)} + + self.timeout_id = None + self._timeout_id_start = None + self.showed_accounts = [] - def check_birthdays(self, account=None): - def show_popup(account, jid): - contact_instances = app.contacts.get_contacts(account, jid) - contact = app.contacts.get_highest_prio_contact_from_contacts( - contact_instances) - if contact: - nick = GObject.markup_escape_text(contact.get_shown_name()) - try: - image = os.path.dirname(__file__) + os.sep + \ - 'birthday_reminder_large.png' - except: - image = None + self._birthdays = {} + self._load_birthdays() - popup('Send message', contact.jid, account, type_='', - path_to_image=image, title=title, text=text + ' ' + nick) + def activate(self): + self._timeout_id_start = GLib.timeout_add_seconds( + 5, self._check_birthdays_at_start) + self._timeout_id = GLib.timeout_add_seconds( + 86400, self._check_birthdays) - accounts = app.contacts.get_accounts() - vcards = [] - date_dict = {} - for jid in glob.glob(self.vcard_path + '*@*'): - if os.path.isfile(jid): - vcards.append(jid) + def deactivate(self): + if self._timeout_id is not None: + GLib.source_remove(self.timeout_id) + if self._timeout_id_start is not None: + GLib.source_remove(self._timeout_id_start) - for xmldoc in vcards: + def _load_birthdays(self): + path = os.path.join(configpaths.get('MY_DATA'), 'birthdays.json') + if os.path.exists(path): + with open(path, 'r', encoding='utf-8') as file: + content = file.read() + if content: + self._birthdays = json.loads(content) + + def _store_birthdays(self): + path = os.path.join(configpaths.get('MY_DATA'), 'birthdays.json') + with open(path, 'w', encoding='utf-8') as file: + json.dump(self._birthdays, file) + + def _vcard_received(self, event): + birthday = event.vcard_dict.get('BDAY') + if not birthday: + if event.jid in self._birthdays: + del self._birthdays[event.jid] + log.info('Received empty birthday: %s', event.jid) + else: try: - xml = parse(xmldoc) - except: - pass + year, month, day = birthday.split('-') + year = int(year) + month = int(month) + day = int(day) + except Exception: + log.warning('Invalid date: %s', birthday) + if event.jid in self._birthdays: + del self._birthdays[event.jid] else: - name = xml.getElementsByTagName('BDAY') - for node in name: - try: - data = node.childNodes[0].nodeValue - date_dict[xmldoc[len(self.vcard_path):][:-1]] = data - except: - pass + self._birthdays[event.jid] = (year, month, day) + log.info('Received birthday: %s %s', + event.jid, (year, month, day)) + self._store_birthdays() + def _check_birthdays_at_start(self): + self._check_birthdays() + + def _check_birthdays(self): + log.info('Check birthdays...') today = datetime.date.today() + for jid, birthdate in self._birthdays.items(): + year, month, day = birthdate + if today.month == month and today.day == day: + account, contact = self._find_contact(jid) + if contact is None: + if jid in self._birthdays: + del self._birthdays[jid] + self._store_birthdays() + continue + else: + log.info('Issue notification for %s', jid) + nick = contact.get_shown_name() or jid + app.notification.popup( + 'reminder', + jid, + account, + icon_name='trophy-gold', + title=TITLE % GLib.markup_escape_text(nick), + text=TEXT) - for key, value in date_dict.items(): - try: - convert_date = datetime.datetime.strptime(value, "%Y-%m-%d") - user_bday = datetime.date(today.year, convert_date.month, - convert_date.day) - except: - continue - - if user_bday < today: - user_bday = user_bday.replace(year=today.year+1) - - time_to_bday = abs(user_bday - today) - title = "BirthDay Reminder" - text = None - - if time_to_bday.days > 5: - continue - if time_to_bday.days == 5: - text = "5 days before BDay" - elif time_to_bday.days == 3: - text = "3 days before BDay" - elif time_to_bday.days == 1: - text = "Tomorrow BDay" - elif time_to_bday.days == 0: - text = "Today BDay" - if not text: - continue - if account: - show_popup(account,key) - else: - for acct in accounts: - show_popup(account, key) return True - @log_calls('BirthDayPlugin') - def activate(self): - self.timeout_id = GObject.timeout_add_seconds(24*3600, - self.check_birthdays) - - @log_calls('BirthDayPlugin') - def deactivate(self): - if self.timeout_id > 0: - GObject.source_remove(self.timeout_id) - - - @log_calls('BirthDayPlugin') - def roster_received(self, obj): - if obj.conn.name not in self.showed_accounts: - self.check_birthdays(obj.conn.name) - self.showed_accounts.append(obj.conn.name) + def _find_contact(self, jid): + accounts = app.contacts.get_accounts() + for account in accounts: + contact = app.contacts.get_contacts(account, jid) + if contact is not None: + return account, contact[0]