Exemple #1
0
class Calendar(object):
    def __init__(self,
                 name,
                 dbpath,
                 path,
                 readonly=False,
                 color='',
                 unicode_symbols=True,
                 default_tz=None,
                 local_tz=None):
        """
        :param name: the name of the calendar
        :type name: str
        :param dbpath: path where the local chaching db should be saved
        :type dbpath: str
        :param readonly: if True, this Calendar cannot be modified
        :type readonly: bool
        :param color: the color which this calendar's events should be
                      printed in
        :type color: str
        :param unicode_symbols: if True, unicode symbols will be used for
                                representing this calendars's events properties
        :type unicode_symbols: bool
        :param default_tz: timezone used by default
        :tpye default_tz: pytz.timezone
        :param local_tz: the timezone this calendar's event's times should be
                         shown in
        :type local_tz: pytz.timezone
        """

        self._default_tz = default_tz
        self._local_tz = default_tz if local_tz is None else local_tz
        self.name = name
        self.color = color
        self.path = os.path.expanduser(path)
        self._dbtool = backend.SQLiteDb(
            self.name,
            dbpath,
            default_tz=self._default_tz,
            local_tz=self._local_tz,
        )
        self._storage = FilesystemStorage(path, '.ics')
        self._readonly = readonly
        self._unicode_symbols = unicode_symbols

        if self._db_needs_update():
            self.db_update()

    def local_ctag(self):
        return os.path.getmtime(self.path)

    def get_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(start, end, show_deleted)

    def get_allday_by_time_range(self, start, end=None, show_deleted=False):
        return self._dbtool.get_allday_range(start, end, show_deleted)

    def get_datetime_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(start, end, show_deleted)

    def get_event(self, href):
        event = self._dbtool.get(href)
        event.color = self.color
        event.readonly = self.readonly
        event.unicode_symbols = self.unicode_symbols
        return event

    def update(self, event):
        """update an event in the database

        param event: the event that should be updated
        type event: event.Event
        """
        if self._readonly:
            raise ReadOnlyCalendarError()
        if event.etag is None:
            self.new(event)
        else:
            self._storage.update(event.href, event, event.etag)
            self._dbtool.update(event.vevent.to_ical(),
                                event.href,
                                etag=event.etag)

    def new(self, event):
        """save a new event to the database

        param event: the event that should be updated
        type event: event.Event
        """
        if self._readonly:
            raise ReadOnlyCalendarError()
        event.href, event.etag = self._storage.upload(event)
        self._dbtool.update(event.to_ical(), event.href, event.etag)
        self._dbtool.set_ctag(self.local_ctag())

    def delete(self, event):
        """delete event from this collection
        """
        if self._readonly:
            raise ReadOnlyCalendarError()
        self._storage.delete(event.href, event.etag)
        self._dbtool.delete(event.href)

    def _db_needs_update(self):
        if self.local_ctag() == self._dbtool.get_ctag():
            return False
        else:
            return True

    def db_update(self):
        """update the db from the vdir,

        should be called after every change to the vdir
        """
        storage_hrefs = list()
        for href, etag in self._storage.list():
            storage_hrefs.append(href)
            if etag != self._dbtool.get_etag(href):
                self._update_vevent(href)
        db_hrefs = [href for href, etag in self._dbtool.list()]
        for href in set(db_hrefs) - set(storage_hrefs):
            self._dbtool.delete(href)

        self._dbtool.set_ctag(self.local_ctag())

    def _update_vevent(self, href):
        """should only be called during db_update, does not check for
        readonly"""
        event, etag = self._storage.get(href)
        try:
            self._dbtool.update(event.raw, href=href, etag=etag)
            return True
        except Exception as error:
            if not isinstance(error, UnsupportedFeatureError):
                logger.exception('')
            logger.error(
                "During `update_vevent` we failed to parse vcard {}/{} with "
                "error\n\"{}\",\nthis means, that event is not available in "
                "khal.".format(self.name, href, error))
            return False

    def new_event(self, ical, local_tz, default_tz):
        """creates and returns (but does not insert) new event from ical
        string"""
        return Event(ical=ical,
                     calendar=self.name,
                     local_tz=local_tz,
                     default_tz=default_tz)
Exemple #2
0
class Calendar(object):

    def __init__(self, name, dbpath, path, readonly=False, color='',
                 unicode_symbols=True, default_tz=None,
                 local_tz=None, debug=True):
        """
        :param name: the name of the calendar
        :type name: str
        :param dbpath: path where the local chaching db should be saved
        :type dbpath: str
        :param readonly: if True, this Calendar cannot be modified
        :type readonly: bool
        :param color: the color which this calendar's events should be
                      printed in
        :type color: str
        :param unicode_symbols: if True, unicode symbols will be used for
                                representing this calendars's events properties
        :type unicode_symbols: bool
        :param default_tz: timezone used by default
        :tpye default_tz: pytz.timezone
        :param local_tz: the timezone this calendar's event's times should be
                         shown in
        :type local_tz: pytz.timezone
        :param debug: if True, some debugging information will be printed
        :type debug: bool
        """

        self._default_tz = default_tz
        self._local_tz = default_tz if local_tz is None else local_tz
        self.name = name
        self.color = color
        self.path = os.path.expanduser(path)
        self._debug = debug
        self._dbtool = backend.SQLiteDb(
            self.name,
            dbpath,
            default_tz=self._default_tz,
            local_tz=self._local_tz,
            color=self.color,
            readonly=readonly,
            debug=self._debug)
        self._storage = FilesystemStorage(path, '.ics')
        self._readonly = readonly
        self._unicode_symbols = unicode_symbols

        if self._db_needs_update():
            self.db_update()

    def local_ctag(self):
        return os.path.getmtime(self.path)

    def get_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(start, end, show_deleted)

    def get_allday_by_time_range(self, start, end=None, show_deleted=False):
        return self._dbtool.get_allday_range(start, end, show_deleted)

    def get_datetime_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(start, end, show_deleted)

    def get_event(self, href):
        return self._dbtool.get(href)

    def update(self, event):
        """update an event in the database

        param event: the event that should be updated
        type event: event.Event
        """
        if self._readonly:
            raise ReadOnlyCalendarError()
        if event.etag is None:
            self.new(event)
        else:
            try:
                self._storage.update(event.href, event, event.etag)
                self._dbtool.update(event.vevent.to_ical(),
                                    self.name,
                                    event.href,
                                    etag=event.etag)
            except Exception as error:
                logger.error('Failed to parse vcard {} from collection {} '
                             'during update'.format(event.href, self.name))
                logger.debug(traceback.format_exc(error))

    def new(self, event):
        """save a new event to the database

        param event: the event that should be updated
        type event: event.Event
        """
        if self._readonly:
            raise ReadOnlyCalendarError()
        href, etag = self._storage.upload(event)
        event.href = href
        event.etag = etag
        try:
            self._dbtool.update(event.to_ical(),
                                href=href,
                                etag=etag)
            self._dbtool.set_ctag(self.local_ctag())
        except Exception as error:
            logger.error(
                'Failed to parse vcard {} during new in collection '
                '{}'.format(event.href, self.name))
            logger.debug(traceback.format_exc(error))

    def delete(self, event):
        """delete event from this collection
        """
        if self._readonly:
            raise ReadOnlyCalendarError()
        self._storage.delete(event.href, event.etag)
        self._dbtool.delete(event.href)

    def _db_needs_update(self):
        if self.local_ctag() == self._dbtool.get_ctag():
            return False
        else:
            return True

    def db_update(self):
        """update the db from the vdir,

        should be called after every change to the vdir
        """
        storage_hrefs = list()
        for href, etag in self._storage.list():
            storage_hrefs.append(href)
            if etag != self._dbtool.get_etag(href):
                self._update_vevent(href)
        db_hrefs = [href for href, etag in self._dbtool.list()]
        for href in set(db_hrefs) - set(storage_hrefs):
            self._dbtool.delete(href)

        self._dbtool.set_ctag(self.local_ctag())

    def _update_vevent(self, href):
        """should only be called during db_update, does not check for
        readonly"""
        event, etag = self._storage.get(href)
        try:
            self._dbtool.update(event.raw, href=href, etag=etag,
                                ignore_invalid_items=True)
            return True
        except Exception as error:
            if not isinstance(error, UnsupportedFeatureError):
                logger.exception('')
            logger.error(
                "During `update_vevent` we failed to parse vcard {}/{} with "
                "error\n\"{}\",\nthis means, that event is not available in "
                "khal."
                .format(self.name, href, error))
            return False

    def new_event(self, ical, local_tz, default_tz):
        """creates and returns (but does not insert) new event from ical
        string"""
        return Event(ical=ical, calendar=self.name, local_tz=local_tz,
                     default_tz=default_tz)
Exemple #3
0
class Calendar(object):
    def __init__(self,
                 name,
                 dbpath,
                 path,
                 readonly=False,
                 color='',
                 unicode_symbols=True,
                 locale=None):
        """
        :param name: the name of the calendar
        :type name: str
        :param dbpath: path where the local chaching db should be saved
        :type dbpath: str
        :param readonly: if True, this Calendar cannot be modified
        :type readonly: bool
        :param color: the color which this calendar's events should be
                      printed in
        :type color: str
        :param unicode_symbols: if True, unicode symbols will be used for
                                representing this calendars's events properties
        :type unicode_symbols: bool
        :param locale: the locale settings
        :type locale: dict()
        """
        self._locale = locale

        self.name = name
        self.color = color
        self.path = os.path.expanduser(path)
        self._dbtool = backend.SQLiteDb(self.name, dbpath, locale=self._locale)
        create_directory(path)
        self._storage = FilesystemStorage(path, '.ics')
        self._readonly = readonly
        self._unicode_symbols = unicode_symbols

        if self._db_needs_update():
            self.db_update()

    @property
    def readonly(self):
        return self._readonly

    def _cover_event(self, event):
        event.color = self.color
        event.readonly = self._readonly
        event.unicode_symbols = self._unicode_symbols
        return event

    def local_ctag(self):
        return os.path.getmtime(self.path)

    def get_allday_by_time_range(self, start, end=None):
        return [
            self._cover_event(event)
            for event in self._dbtool.get_allday_range(start, end)
        ]

    def get_datetime_by_time_range(self, start, end):
        return [
            self._cover_event(event)
            for event in self._dbtool.get_time_range(start, end)
        ]

    def get_event(self, href):
        return self._cover_event(self._dbtool.get(href))

    def update(self, event):
        """update an event in the database

        param event: the event that should be updated
        type event: event.Event
        """
        with self._dbtool.at_once():
            if self._readonly:
                raise ReadOnlyCalendarError()
            if event.etag is None:
                self.new(event)
            else:
                etag = self._storage.update(event.href, event, event.etag)
                self._dbtool.update(event.vevent.to_ical(),
                                    event.href,
                                    etag=etag)

    def new(self, event):
        """save a new event to the database

        param event: the event that should be updated
        type event: event.Event
        """
        with self._dbtool.at_once():
            if self._readonly:
                raise ReadOnlyCalendarError()
            event.href, event.etag = self._storage.upload(event)
            self._dbtool.update(event.to_ical(), event.href, event.etag)
            self._dbtool.set_ctag(self.local_ctag())

    def delete(self, href, etag):
        """delete event from this collection
        """
        if self._readonly:
            raise ReadOnlyCalendarError()
        self._storage.delete(href, etag)
        self._dbtool.delete(href)

    def _db_needs_update(self):
        if self.local_ctag() == self._dbtool.get_ctag():
            return False
        else:
            return True

    def db_update(self):
        """update the db from the vdir,

        should be called after every change to the vdir
        """
        db_hrefs = set(href for href, etag in self._dbtool.list())
        storage_hrefs = set()

        with self._dbtool.at_once():
            for href, etag in self._storage.list():
                storage_hrefs.add(href)
                dbetag = self._dbtool.get_etag(href)
                if etag != dbetag:
                    logger.debug('Updating {} because {} != {}'.format(
                        href, etag, dbetag))
                    self._update_vevent(href)
            for href in db_hrefs - storage_hrefs:
                self._dbtool.delete(href)

            self._dbtool.set_ctag(self.local_ctag())

    def _update_vevent(self, href):
        """should only be called during db_update, does not check for
        readonly"""
        event, etag = self._storage.get(href)
        try:
            self._dbtool.update(event.raw, href=href, etag=etag)
            return True
        except Exception as e:
            if not isinstance(e, (UpdateFailed, UnsupportedFeatureError)):
                logger.exception('Unknown exception happened.')
            logger.warning('Skipping {}/{}: {}\n'
                           'This event will not be available in khal.'.format(
                               self.name, href, str(e)))
            return False

    def new_event(self, ical):
        """creates and returns (but does not insert) new event from ical
        string"""
        return Event(ical=ical, calendar=self.name, locale=self._locale)

    def search(self, search_string):
        return [
            self._cover_event(event)
            for event in self._dbtool.search(search_string)
        ]
Exemple #4
0
class Calendar(object):

    def __init__(self, name, dbpath, path, readonly=False, color='',
                 unicode_symbols=True, default_tz=None,
                 local_tz=None, debug=True):

        self._default_tz = default_tz
        self._local_tz = default_tz if local_tz is None else local_tz
        self.name = name
        self.color = color
        self.path = path
        self._debug = debug
        self._dbtool = backend.SQLiteDb(
            dbpath,
            default_tz=self._default_tz,
            local_tz=self._local_tz,
            debug=self._debug)
        self._storage = FilesystemStorage(path, '.ics')
        self._readonly = readonly
        self._unicode_symbols = unicode_symbols

        if self._db_needs_update():
            self.db_update()

    def local_ctag(self):
        return os.path.getmtime(self.path)

    def get_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(start,
                                           end,
                                           self.name,
                                           self.color,
                                           self._readonly,
                                           self._unicode_symbols,
                                           show_deleted)

    def get_allday_by_time_range(self, start, end=None, show_deleted=False):
        return self._dbtool.get_allday_range(
            start, end, self.name, self.color, self._readonly,
            self._unicode_symbols, show_deleted)

    def get_datetime_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(
            start, end, self.name, self.color, self._readonly,
            self._unicode_symbols, show_deleted)

    def get_event(self, href):
        return self._dbtool.get_vevent_from_db(
            href, self.name, color=self.color, readonly=self._readonly,
            unicode_symbols=self._unicode_symbols)

    def update(self, event):
        """update an event in the database

        param event: the event that should be updated
        type event: event.Event
        """
        if event.etag is None:
            self.new(event)
        else:
            try:
                self._storage.update(event.href, event, event.etag)
                self._dbtool.update(event.vevent.to_ical(),
                                    self.name,
                                    event.href,
                                    etag=event.etag)
            except Exception as error:
                logging.error('Failed to parse vcard {} from collection {} '
                              'during update'.format(event.href, self.name))
                logging.debug(traceback.format_exc(error))

    def new(self, event):
        """save a new event to the database

        param event: the event that should be updated
        type event: event.Event
        """
        href, etag = self._storage.upload(event)
        event.href = href
        event.etag = etag
        try:
            self._dbtool.update(event.to_ical(),
                                self.name,
                                href=href,
                                etag=etag)
            self._dbtool.set_ctag(self.name, self.local_ctag())
        except Exception as error:
            logging.error(
                'Failed to parse vcard {} during new in collection '
                '{}'.format(event.href, self.name))
            logging.debug(traceback.format_exc(error))

    def delete(self, event):
        """delete event from this collection
        """
        self._storage.delete(event.href, event.etag)
        self._dbtool.delete(event.href, event.account)

    def _db_needs_update(self):
        if self.local_ctag() == self._dbtool.get_ctag(self.name):
            return False
        else:
            return True

    def db_update(self):
        """update the db from the vdir,

        should be called after every change to the vdir
        """
        # This compares folder-content against db-content
        status = True
        fs_hrefs = []
        for href, etag in self._storage.list():
            fs_hrefs.append(href)
            if etag != self._dbtool.get_etag(href, self.name):
                status = status and self.update_vevent(href)
        if status:
            self._dbtool.set_ctag(self.name, self.local_ctag())

        # this compares db-content against folder-content
        # if an item is removed from the vdir, we also delete it in the db
        # in this case we asume, that the vdir content is the place to trust
        for href,account in self._dbtool.get_all_href_from_db([self.name]):
            if href not in fs_hrefs:
                self._dbtool.delete(href,self.name)


    def update_vevent(self, href):
        event, etag = self._storage.get(href)
        try:
            self._dbtool.update(event.raw, self.name, href=href, etag=etag,
                                ignore_invalid_items=True)
            return True
        except Exception as error:
            logging.error(
                'Failed to parse vcard {} during '
                'update_vevent in collection ''{}'.format(href, self.name))
            logging.debug(traceback.format_exc(error))
            return False

    def new_event(self, ical):
        """creates new event form ical string"""
        return Event(ical=ical, account=self.name)
Exemple #5
0
class Calendar(object):

    def __init__(self, name, dbpath, path, readonly=False, color='',
                 unicode_symbols=True, default_tz=None,
                 local_tz=None, debug=True):

        self._default_tz = default_tz
        self._local_tz = default_tz if local_tz is None else local_tz
        self.name = name
        self.color = color
        self.path = path
        self._debug = debug
        self._dbtool = backend.SQLiteDb(
            dbpath,
            default_tz=self._default_tz,
            local_tz=self._local_tz,
            debug=self._debug)
        self._storage = FilesystemStorage(path, '.ics')
        self._readonly = readonly
        self._unicode_symbols = unicode_symbols

        if self._db_needs_update():
            self.db_update()

    def local_ctag(self):
        return os.path.getmtime(self.path)

    def get_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(start,
                                           end,
                                           self.name,
                                           self.color,
                                           self._readonly,
                                           self._unicode_symbols,
                                           show_deleted)

    def get_allday_by_time_range(self, start, end=None, show_deleted=False):
        return self._dbtool.get_allday_range(
            start, end, self.name, self.color, self._readonly,
            self._unicode_symbols, show_deleted)

    def get_datetime_by_time_range(self, start, end, show_deleted=False):
        return self._dbtool.get_time_range(
            start, end, self.name, self.color, self._readonly,
            self._unicode_symbols, show_deleted)

    def get_event(self, href):
        return self._dbtool.get_vevent_from_db(
            href, self.name, color=self.color, readonly=self._readonly,
            unicode_symbols=self._unicode_symbols)

    def update(self, event):
        """update an event in the database

        param event: the event that should be updated
        type event: event.Event
        """
        if event.etag is None:
            self.new(event)
        else:
            try:
                self._storage.update(event.href, event, event.etag)
                self._dbtool.update(event.vevent.to_ical(),
                                    self.name,
                                    event.href,
                                    etag=event.etag)
            except Exception as error:
                logger.error('Failed to parse vcard {} from collection {} '
                             'during update'.format(event.href, self.name))
                logger.debug(traceback.format_exc(error))

    def new(self, event):
        """save a new event to the database

        param event: the event that should be updated
        type event: event.Event
        """
        href, etag = self._storage.upload(event)
        event.href = href
        event.etag = etag
        try:
            self._dbtool.update(event.to_ical(),
                                self.name,
                                href=href,
                                etag=etag)
            self._dbtool.set_ctag(self.name, self.local_ctag())
        except Exception as error:
            logger.error(
                'Failed to parse vcard {} during new in collection '
                '{}'.format(event.href, self.name))
            logger.debug(traceback.format_exc(error))

    def delete(self, event):
        """delete event from this collection
        """
        self._storage.delete(event.href, event.etag)
        self._dbtool.delete(event.href, event.account)

    def _db_needs_update(self):
        if self.local_ctag() == self._dbtool.get_ctag(self.name):
            return False
        else:
            return True

    def db_update(self):
        """update the db from the vdir,

        should be called after every change to the vdir
        """
        status = True
        for href, etag in self._storage.list():
            if etag != self._dbtool.get_etag(href, self.name):
                status = status and self.update_vevent(href)
        if status:
            self._dbtool.set_ctag(self.name, self.local_ctag())

    def update_vevent(self, href):
        event, etag = self._storage.get(href)
        try:
            self._dbtool.update(event.raw, self.name, href=href, etag=etag,
                                ignore_invalid_items=True)
            return True
        except Exception as error:
            logger.error(
                'Failed to parse vcard {} during '
                'update_vevent in collection ''{}'.format(href, self.name))
            logger.debug(traceback.format_exc(error))
            return False

    def new_event(self, ical, local_tz, default_tz):
        """creates new event form ical string"""
        return Event(ical=ical, account=self.name, local_tz=local_tz,
                     default_tz=default_tz)