# -*- coding: utf-8 -*- # Copyright(C) 2013 Bezleputh # # This file is part of weboob. # # weboob is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # weboob is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with weboob. If not, see . import re import sys from datetime import date, timedelta, time, datetime from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter from weboob.capabilities.base import empty from weboob.capabilities.calendar import ICapCalendarEvent from weboob.tools.application.repl import ReplApplication, defaultcount __all__ = ['Boobcoming'] class ICalFormatter(IFormatter): MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary') def start_format(self, **kwargs): self.output(u'BEGIN:VCALENDAR') self.output(u'VERSION:2.0') self.output(u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN') def format_obj(self, obj, alias): result = u'BEGIN:VEVENT\n' result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ") result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ") result += u'SUMMARY:%s\n' % obj.summary if hasattr(obj, 'location') and not empty(obj.location): result += u'LOCATION:%s\n' % obj.location if hasattr(obj, 'categories') and not empty(obj.categories): result += u'CATEGORIES:%s\n' % obj.categories if hasattr(obj, 'status') and not empty(obj.status): result += u'STATUS:%s\n' % obj.status if hasattr(obj, 'description') and not empty(obj.description): result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n') if hasattr(obj, 'transp') and not empty(obj.transp): result += u'TRANSP:%s\n' % obj.transp if hasattr(obj, 'sequence') and not empty(obj.sequence): result += u'SEQUENCE:%s\n' % obj.sequence if hasattr(obj, 'url') and not empty(obj.url): result += u'URL:%s\n' % obj.url result += u'END:VEVENT' return result def flush(self, **kwargs): self.output(u'END:VCALENDAR') class UpcomingListFormatter(PrettyFormatter): MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category') def get_title(self, obj): return ' %s - %s ' % (obj.category, obj.summary) def get_description(self, obj): result = u'' result += u'\tDate: %s\n' % obj.start_date.strftime('%A %d %B %Y') result += u'\tHour: %s - %s \n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M')) return result.strip('\n\t') class UpcomingFormatter(IFormatter): MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category') def format_obj(self, obj, alias): result = u'%s%s - %s%s\n' % (self.BOLD, obj.category, obj.summary, self.NC) result += u'Date: %s\n' % obj.start_date.strftime('%A %d %B %Y') result += u'Hour: %s - %s\n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M')) if hasattr(obj, 'location') and not empty(obj.location): result += u'Location: %s\n' % obj.location if hasattr(obj, 'description') and not empty(obj.description): result += u'Description:\n %s\n\n' % obj.description if hasattr(obj, 'price') and not empty(obj.price): result += u'Price: %s\n' % obj.price if hasattr(obj, 'url') and not empty(obj.url): result += u'url: %s\n' % obj.url return result class Boobcoming(ReplApplication): APPNAME = 'boobcoming' VERSION = '0.h' COPYRIGHT = 'Copyright(C) 2012 Bezleputh' DESCRIPTION = "Console application to see upcoming events." SHORT_DESCRIPTION = "see upcoming events" CAPS = ICapCalendarEvent EXTRA_FORMATTERS = {'upcoming_list': UpcomingListFormatter, 'upcoming': UpcomingFormatter, #'ical_formatter': ICalFormatter, } COMMANDS_FORMATTERS = {'list': 'upcoming_list', 'info': 'upcoming', #'export': 'ical_formatter', } WEEK = {'MONDAY': 0, 'TUESDAY': 1, 'WEDNESDAY': 2, 'THURSDAY': 3, 'FRIDAY': 4, 'SATURDAY': 5, 'SUNDAY': 6, 'LUNDI': 0, 'MARDI': 1, 'MERCREDI': 2, 'JEUDI': 3, 'VENDREDI': 4, 'SAMEDI': 5, 'DIMANCHE': 6, } @defaultcount(10) def do_list(self, line): """ list [PATTERN] List upcoming events, pattern can be an english or french week day, 'today' or a date """ self.change_path([u'events']) if line: _date = self.parse_date(line) if not _date: print >>sys.stderr, 'Invalid argument: %s' % self.get_command_help('list', short=True) return 2 date_from = datetime.combine(_date, time.min) date_to = datetime.combine(_date, time.max) else: date_from = datetime.now() date_to = None for backend, event in self.do('list_events', date_from, date_to): self.cached_format(event) def complete_info(self, text, line, *ignored): args = line.split(' ') if len(args) == 2: return self._complete_object() def do_info(self, _id): """ info ID Get information about an event. """ if not _id: print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('info', short=True) return 2 event = self.get_object(_id, 'get_event') if not event: print >>sys.stderr, 'Upcoming event not found: %s' % _id return 3 self.start_format() self.format(event) def start_format(self, **kwargs): result = u'BEGIN:VCALENDAR\n' result += u'VERSION:2.0\n' result += u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN\n' return result def format_event(self, obj): result = u'BEGIN:VEVENT\n' result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ") result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ") result += u'SUMMARY:%s\n' % obj.summary if hasattr(obj, 'location') and not empty(obj.location): result += u'LOCATION:%s\n' % obj.location if hasattr(obj, 'categories') and not empty(obj.categories): result += u'CATEGORIES:%s\n' % obj.categories if hasattr(obj, 'status') and not empty(obj.status): result += u'STATUS:%s\n' % obj.status if hasattr(obj, 'description') and not empty(obj.description): result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n') if hasattr(obj, 'transp') and not empty(obj.transp): result += u'TRANSP:%s\n' % obj.transp if hasattr(obj, 'sequence') and not empty(obj.sequence): result += u'SEQUENCE:%s\n' % obj.sequence if hasattr(obj, 'url') and not empty(obj.url): result += u'URL:%s\n' % obj.url result += u'END:VEVENT\n' return result def end_format(self): return u'END:VCALENDAR' def do_export(self, line): """ export FILENAME ID1 [ID2 ID3 ...] id is the identifier of the event FILENAME is where to write the file. If FILENAME is '-', the file is written to stdout. Export event in ICALENDAR format """ if not line: print >>sys.stderr, 'This command takes two arguments: %s' % self.get_command_help('export') return 2 _file, args = self.parse_command_args(line, 2, req_n=1) if not args: print >>sys.stderr, 'This command takes two arguments: %s' % self.get_command_help('export') return 2 _ids = args.strip().split(' ') buff = self.start_format() for _id in _ids: event = self.get_object(_id, 'get_event') if not event: print >>sys.stderr, 'Upcoming event not found: %s' % _id return 3 buff += self.format_event(event) buff += self.end_format() if _file == "-": print buff else: try: dest = self.check_file_ext(_file) with open(dest, 'w') as f: f.write(buff.encode('ascii', 'ignore')) except IOError as e: print >>sys.stderr, 'Unable to write bill in "%s": %s' % (dest, e) return 1 def check_file_ext(self, _file): splitted_file = _file.split('.') if splitted_file[-1] != 'ics': return "%s.ics" % _file else: return _file def get_date_from_day(self, day): today = date.today() today_day_number = today.weekday() requested_day_number = self.WEEK[day.upper()] if today_day_number < requested_day_number: day_to_go = requested_day_number - today_day_number else: day_to_go = 7 - today_day_number + requested_day_number requested_date = today + timedelta(day_to_go) return date(requested_date.year, requested_date.month, requested_date.day) def parse_date(self, string): matches = re.search('\s*([012]?[0-9]|3[01])\s*/\s*(0?[1-9]|1[012])\s*/?(\d{2}|\d{4})?$', string) if matches: year = matches.group(3) if not year: year = date.today().year elif len(year) == 2: year = 2000 + int(year) return date(int(year), int(matches.group(2)), int(matches.group(1))) elif string.upper() in self.WEEK.keys(): return self.get_date_from_day(string) elif string.upper() == "TODAY": return date.today()