Source code for woob.capabilities.calendar

# Copyright(C) 2010-2013 Bezleputh
#
# This file is part of woob.
#
# woob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# woob 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with woob. If not, see <http://www.gnu.org/licenses/>.

from datetime import datetime, time

from woob.tools.date import parse_date

from .address import PostalAddress, compat_field
from .base import BaseObject, Enum, EnumField, Field, FloatField, IntField, StringField
from .collection import CapCollection, Collection, CollectionNotFound
from .date import DateField


__all__ = ["BaseCalendarEvent", "CapCalendarEvent"]


class CATEGORIES(Enum):
    CONCERT = "Concert"
    CINE = "Cinema"
    THEATRE = "Theatre"
    TELE = "Television"
    CONF = "Conference"
    AUTRE = "Autre"
    EXPO = "Exposition"
    SPECTACLE = "Spectacle"
    FEST = "Festival"
    SPORT = "Sport"


# the following elements deal with ICalendar standards
# see https://fr.wikipedia.org/wiki/ICalendar#%C3%89v%C3%A9nements_(VEVENT)
class TRANSP(Enum):
    OPAQUE = "OPAQUE"
    TRANSPARENT = "TRANSPARENT"


class STATUS(Enum):
    TENTATIVE = "TENTATIVE"
    CONFIRMED = "CONFIRMED"
    CANCELLED = "CANCELLED"


class TICKET(Enum):
    AVAILABLE = "Available"
    NOTAVAILABLE = "Not available"
    CLOSED = "Closed"


[docs]class BaseCalendarEvent(BaseObject): """ Represents a calendar event """ start_date = DateField("Start date of the event") end_date = DateField("End date of the event") timezone = StringField("Timezone of the event in order to convert to utc time", default="Etc/UCT") summary = StringField("Title of the event") address = Field("Address where event will take place", PostalAddress) category = EnumField("Category of the event", CATEGORIES) description = StringField("Description of the event") price = FloatField("Price of the event") booked_entries = IntField("Entry number") max_entries = IntField("Max entry number") event_planner = StringField("Name of the event planner") city = compat_field("address", "city") location = compat_field("address", "street") # the following elements deal with ICalendar standards # see https://fr.wikipedia.org/wiki/ICalendar#%C3%89v%C3%A9nements_(VEVENT) sequence = IntField("Number of updates, the first is number 1") # (TENTATIVE, CONFIRMED, CANCELLED) status = EnumField("Status of the event", STATUS) # (OPAQUE, TRANSPARENT) transp = EnumField("Describes if event is available", TRANSP) # (AVAILABLE, NOTAVAILABLE, CLOSED) ticket = EnumField("Describes if tickets are available", TICKET)
[docs] @classmethod def id2url(cls, _id): """Overloaded in child classes provided by backends.""" raise NotImplementedError()
@property def page_url(self): """ Get page URL of the announce. """ return self.id2url(self.id)
class Query(BaseObject): """ Query to find events """ start_date = DateField("Start date of the event") end_date = DateField("End date of the event") city = StringField("Name of the city in witch event will take place") categories = Field("List of categories of the event", list, tuple, default=list(CATEGORIES)) ticket = Field("List of status of the tickets sale", list, tuple, default=list(TICKET)) summary = StringField("Title of the event")
[docs]class CapCalendarEvent(CapCollection): """ Capability of calendar event type sites """ ASSOCIATED_CATEGORIES = "ALL"
[docs] def has_matching_categories(self, query): if self.ASSOCIATED_CATEGORIES == "ALL": return True for category in query.categories: if category in self.ASSOCIATED_CATEGORIES: return True return False
[docs] def search_events(self, query): """ Search event :param query: search query :type query: :class:`Query` :rtype: iter[:class:`BaseCalendarEvent`] """ raise NotImplementedError()
[docs] def list_events(self, date_from, date_to=None): """ list coming event. :param date_from: date of beguinning of the events list :type date_from: date :param date_to: date of ending of the events list :type date_to: date :rtype: iter[:class:`BaseCalendarEvent`] """ raise NotImplementedError()
[docs] def get_event(self, _id): """ Get an event from an ID. :param _id: id of the event :type _id: str :rtype: :class:`BaseCalendarEvent` or None is fot found. """ raise NotImplementedError()
[docs] def attends_event(self, event, is_attending=True): """ Attends or not to an event :param event : the event :type event : BaseCalendarEvent :param is_attending : is attending to the event or not :type is_attending : bool """ raise NotImplementedError()
[docs] def iter_resources(self, objs, split_path): """ Iter events by category """ if len(split_path) == 0 and self.ASSOCIATED_CATEGORIES != "ALL": for category in self.ASSOCIATED_CATEGORIES: collection = Collection([category], category) yield collection elif len(split_path) == 1 and split_path[0] in self.ASSOCIATED_CATEGORIES: query = Query() query.categories = split_path query.start_date = datetime.combine(parse_date("today"), time.min) query.end_date = parse_date("") query.city = "" yield from self.search_events(query)
[docs] def validate_collection(self, objs, collection): """ Validate Collection """ if collection.path_level == 0: return if collection.path_level == 1 and collection.split_path[0] in CATEGORIES.values: return raise CollectionNotFound(collection.split_path)