コード例 #1
0
 def _getParams(self):
     super(NoteExportHook, self)._getParams()
     event = self._obj = Event.get(self._pathParams['event_id'],
                                   is_deleted=False)
     if event is None:
         raise HTTPAPIError('No such event', 404)
     session_id = self._pathParams.get('session_id')
     if session_id:
         self._obj = Session.query.with_parent(event).filter_by(
             id=session_id).first()
         if self._obj is None:
             raise HTTPAPIError("No such session", 404)
     contribution_id = self._pathParams.get('contribution_id')
     if contribution_id:
         contribution = self._obj = (
             Contribution.query.with_parent(event).filter_by(
                 id=contribution_id, is_deleted=False).first())
         if contribution is None:
             raise HTTPAPIError("No such contribution", 404)
         subcontribution_id = self._pathParams.get('subcontribution_id')
         if subcontribution_id:
             self._obj = SubContribution.query.with_parent(
                 contribution).filter_by(id=subcontribution_id,
                                         is_deleted=False).first()
             if self._obj is None:
                 raise HTTPAPIError("No such subcontribution", 404)
     self._note = EventNote.get_for_linked_object(self._obj,
                                                  preload_event=False)
     if self._note is None or self._note.is_deleted:
         raise HTTPAPIError("No such note", 404)
コード例 #2
0
    def __call__(self, user):
        """Perform the actual exporting"""
        if self.HTTP_POST != (request.method == 'POST'):
            raise HTTPAPIError('This action requires %s' % ('POST' if self.HTTP_POST else 'GET'), 405)
        if not self.GUEST_ALLOWED and not user:
            raise HTTPAPIError('Guest access to this resource is forbidden.', 403)

        method_name = self._getMethodName()
        func = getattr(self, method_name, None)
        extra_func = getattr(self, method_name + '_extra', None)
        if not func:
            raise NotImplementedError(method_name)

        if not self.COMMIT:
            is_response, resultList, complete, extra = self._perform(user, func, extra_func)
            db.session.rollback()
        else:
            try:
                init_email_queue()
                is_response, resultList, complete, extra = self._perform(user, func, extra_func)
                db.session.commit()
                flush_email_queue()
            except Exception:
                db.session.rollback()
                raise
        if is_response:
            return resultList
        return resultList, extra, complete, self.SERIALIZER_TYPE_MAP
コード例 #3
0
 def export_user(self, user):
     if not user:
         raise HTTPAPIError('You need to be logged in', 403)
     user = User.get(self._user_id, is_deleted=False)
     if not user:
         raise HTTPAPIError('Requested user not found', 404)
     if not user.can_be_modified(user):
         raise HTTPAPIError('You do not have access to that info', 403)
     return [user.as_avatar.fossilize()]
コード例 #4
0
 def _getParams(self):
     super(AgreementExportHook, self)._getParams()
     type_ = self._pathParams['agreement_type']
     try:
         self._definition = get_agreement_definitions()[type_]
     except KeyError:
         raise HTTPAPIError('No such agreement type', 404)
     self.event = Event.get(self._pathParams['event_id'], is_deleted=False)
     if self.event is None:
         raise HTTPAPIError('No such event', 404)
コード例 #5
0
    def _getParams(self):
        self._offset = get_query_parameter(self._queryParams, ['O', 'offset'], 0, integer=True)
        if self._offset < 0:
            raise HTTPAPIError('Offset must be a positive number', 400)
        self._orderBy = get_query_parameter(self._queryParams, ['o', 'order'])
        self._descending = get_query_parameter(self._queryParams, ['c', 'descending'], 'no') == 'yes'
        self._detail = get_query_parameter(self._queryParams, ['d', 'detail'], self.DEFAULT_DETAIL)
        tzName = get_query_parameter(self._queryParams, ['tz'], None)

        if tzName is None:
            tzName = config.DEFAULT_TIMEZONE
        try:
            self._tz = pytz.timezone(tzName)
        except pytz.UnknownTimeZoneError, e:
            raise HTTPAPIError("Bad timezone: '%s'" % e.message, 400)
コード例 #6
0
    def _getParams(self):
        super(FileHook, self)._getParams()

        self._attachment = Attachment.get(int(self._pathParams['res']))

        if not self._attachment:
            raise HTTPAPIError("File not found", 404)
コード例 #7
0
 def _perform(self, user, func, extra_func):
     self._getParams()
     if not self._has_access(user):
         raise HTTPAPIError('Access to this resource is restricted.', 403)
     resultList, complete = self._performCall(func, user)
     if isinstance(resultList, current_app.response_class):
         return True, resultList, None, None
     extra = extra_func(user, resultList) if extra_func else None
     return False, resultList, complete, extra
コード例 #8
0
 def _has_access(self, user):
     if not config.ENABLE_ROOMBOOKING or not rb_check_user_access(user):
         return False
     if self._room.can_be_booked(user):
         return True
     elif self._room.can_be_prebooked(user):
         raise HTTPAPIError(
             'The API only supports direct bookings but this room only allows pre-bookings.'
         )
     return False
コード例 #9
0
 def __init__(self, user, hook):
     super(CategoryEventFetcher, self).__init__(user, hook)
     self._eventType = hook._eventType
     self._occurrences = hook._occurrences
     self._location = hook._location
     self._room = hook._room
     self.user = user
     self._detail_level = get_query_parameter(request.args.to_dict(),
                                              ['d', 'detail'], 'events')
     if self._detail_level not in ('events', 'contributions',
                                   'subcontributions', 'sessions'):
         raise HTTPAPIError(
             'Invalid detail level: {}'.format(self._detail_level), 400)
コード例 #10
0
 def api_roomBooking(self, user):
     data = MultiDict({
         'start_dt': self._params['from'],
         'end_dt': self._params['to'],
         'repeat_frequency': RepeatFrequency.NEVER,
         'repeat_interval': 0,
         'room_id': self._room.id,
         'booked_for_user': self._params['booked_for'],
         'contact_email': self._params['booked_for'].email,
         'contact_phone': self._params['booked_for'].phone,
         'booking_reason': self._params['reason']
     })
     try:
         reservation = Reservation.create_from_data(self._room, data, user)
     except ConflictingOccurrences:
         raise HTTPAPIError(
             'Failed to create the booking due to conflicts with other bookings'
         )
     except fossirError as e:
         raise HTTPAPIError('Failed to create the booking: {}'.format(e))
     db.session.add(reservation)
     db.session.flush()
     return {'reservationID': reservation.id}
コード例 #11
0
 def _getParams(self):
     super(AttachmentsExportHook, self)._getParams()
     event = self._obj = Event.get(self._pathParams['event_id'],
                                   is_deleted=False)
     if event is None:
         raise HTTPAPIError('No such event', 404)
     session_id = self._pathParams.get('session_id')
     if session_id:
         self._obj = Session.query.with_parent(event).filter_by(
             id=session_id).first()
         if self._obj is None:
             raise HTTPAPIError("No such session", 404)
     contribution_id = self._pathParams.get('contribution_id')
     if contribution_id:
         contribution = self._obj = Contribution.query.with_parent(
             event).filter_by(id=contribution_id).first()
         if contribution is None:
             raise HTTPAPIError("No such contribution", 404)
         subcontribution_id = self._pathParams.get('subcontribution_id')
         if subcontribution_id:
             self._obj = SubContribution.query.with_parent(
                 contribution).filter_by(id=subcontribution_id).first()
             if self._obj is None:
                 raise HTTPAPIError("No such subcontribution", 404)
コード例 #12
0
    def _getParams(self):
        super(BookRoomHook, self)._getParams()
        self._fromDT = utc_to_server(self._fromDT.astimezone(
            pytz.utc)).replace(tzinfo=None) if self._fromDT else None
        self._toDT = utc_to_server(self._toDT.astimezone(pytz.utc)).replace(
            tzinfo=None) if self._toDT else None
        if not self._fromDT or not self._toDT or self._fromDT.date(
        ) != self._toDT.date():
            raise HTTPAPIError('from/to must be on the same day')
        elif self._fromDT >= self._toDT:
            raise HTTPAPIError('to must be after from')
        elif self._fromDT < datetime.now():
            raise HTTPAPIError('You cannot make bookings in the past')

        username = get_query_parameter(self._queryParams, 'username')
        if not username:
            raise HTTPAPIError('No username provided')
        users = User.find_all(~User.is_deleted,
                              Identity.identifier == username)
        if not users:
            raise HTTPAPIError('Username does not exist')
        elif len(users) != 1:
            raise HTTPAPIError('Ambiguous username ({} users found)'.format(
                len(users)))
        user = users[0]

        self._params = {
            'room_id': get_query_parameter(self._queryParams, 'roomid'),
            'reason': get_query_parameter(self._queryParams, 'reason'),
            'booked_for': user,
            'from': self._fromDT,
            'to': self._toDT
        }
        missing = [key for key, val in self._params.iteritems() if not val]
        if missing:
            raise HTTPAPIError('Required params missing: {}'.format(
                ', '.join(missing)))
        self._room = Room.get(self._params['room_id'])
        if not self._room:
            raise HTTPAPIError('A room with this ID does not exist')
コード例 #13
0
 def category(self, idlist, format):
     try:
         idlist = map(int, idlist)
     except ValueError:
         raise HTTPAPIError('Category IDs must be numeric', 400)
     if format == 'ics':
         buf = serialize_categories_ical(idlist,
                                         self.user,
                                         event_filter=Event.happens_between(
                                             self._fromDT, self._toDT),
                                         event_filter_fn=self._filter_event,
                                         update_query=self._update_query)
         return send_file('events.ics', buf, 'text/calendar')
     else:
         query = (Event.query.filter(
             ~Event.is_deleted, Event.category_chain_overlaps(idlist),
             Event.happens_between(self._fromDT, self._toDT)).options(
                 *self._get_query_options(self._detail_level)))
     query = self._update_query(query)
     return self.serialize_events(
         x for x in query
         if self._filter_event(x) and x.can_access(self.user))
コード例 #14
0
class HTTPAPIHook(object):
    """This class is the hook between the query (path+params) and the generator of the results (fossil).
       It is also in charge of checking the parameters and the access rights.
    """

    HOOK_LIST = []
    TYPES = None  # abstract
    PREFIX = 'export'  # url prefix. must exist in fossir.web.flask.blueprints.api, too! also used as function prefix
    RE = None  # abstract
    METHOD_NAME = None  # overrides method name derived from prefix+type
    DEFAULT_DETAIL = None  # abstract
    MAX_RECORDS = {}
    SERIALIZER_TYPE_MAP = {}  # maps fossil type names to friendly names (useful for plugins e.g. RoomCERN --> Room)
    VALID_FORMATS = None  # None = all formats
    GUEST_ALLOWED = True  # When False, it forces authentication
    COMMIT = False  # commit database changes
    HTTP_POST = False  # require (and allow) HTTP POST
    NO_CACHE = False

    @classmethod
    def parseRequest(cls, path, queryParams):
        """Parse a request path and return a hook and the requested data type."""
        path = urllib.unquote(path)
        hooks = cls.HOOK_LIST
        for expCls in hooks:
            Logger.get('HTTPAPIHook.parseRequest').debug(expCls)
            m = expCls._matchPath(path)
            if m:
                gd = m.groupdict()
                g = m.groups()
                type = g[0]
                format = g[-1]
                if format not in DataFetcher.getAllowedFormats():
                    return None, None
                elif expCls.VALID_FORMATS and format not in expCls.VALID_FORMATS:
                    return None, None
                return expCls(queryParams, type, gd, format), format
        return None, None

    @staticmethod
    def register(cls):
        """Register a hook.

        To use it, simply decorate the hook class with this method."""
        assert cls.RE is not None
        HTTPAPIHook.HOOK_LIST.append(cls)
        return cls

    @classmethod
    def _matchPath(cls, path):
        if not hasattr(cls, '_RE'):
            types = '|'.join(cls.TYPES)
            cls._RE = re.compile(r'/' + cls.PREFIX + '/(' + types + r')' + ('/' + cls.RE).rstrip('/') + r'\.(\w+)$')
        return cls._RE.match(path)

    def __init__(self, queryParams, type, pathParams, format):
        self._format = format
        self._queryParams = queryParams
        self._type = type
        self._pathParams = pathParams

    def _getParams(self):
        self._offset = get_query_parameter(self._queryParams, ['O', 'offset'], 0, integer=True)
        if self._offset < 0:
            raise HTTPAPIError('Offset must be a positive number', 400)
        self._orderBy = get_query_parameter(self._queryParams, ['o', 'order'])
        self._descending = get_query_parameter(self._queryParams, ['c', 'descending'], 'no') == 'yes'
        self._detail = get_query_parameter(self._queryParams, ['d', 'detail'], self.DEFAULT_DETAIL)
        tzName = get_query_parameter(self._queryParams, ['tz'], None)

        if tzName is None:
            tzName = config.DEFAULT_TIMEZONE
        try:
            self._tz = pytz.timezone(tzName)
        except pytz.UnknownTimeZoneError, e:
            raise HTTPAPIError("Bad timezone: '%s'" % e.message, 400)
        max = self.MAX_RECORDS.get(self._detail, 1000)
        self._userLimit = get_query_parameter(self._queryParams, ['n', 'limit'], 0, integer=True)
        if self._userLimit > max:
            raise HTTPAPIError("You can only request up to %d records per request with the detail level '%s'" %
                               (max, self._detail), 400)
        self._limit = self._userLimit if self._userLimit > 0 else max

        fromDT = get_query_parameter(self._queryParams, ['f', 'from'])
        toDT = get_query_parameter(self._queryParams, ['t', 'to'])
        dayDT = get_query_parameter(self._queryParams, ['day'])

        if (fromDT or toDT) and dayDT:
            raise HTTPAPIError("'day' can only be used without 'from' and 'to'", 400)
        elif dayDT:
            fromDT = toDT = dayDT

        self._fromDT = DataFetcher._getDateTime('from', fromDT, self._tz) if fromDT else None
        self._toDT = DataFetcher._getDateTime('to', toDT, self._tz, aux=self._fromDT) if toDT else None
コード例 #15
0
    def _getDateTime(cls, ctx, dateTime, tz, aux=None):

        try:
            rel, value = cls._parseDateTime(dateTime, ctx == 'from')
        except ArgumentParseError, e:
            raise HTTPAPIError(e.message, 400)
コード例 #16
0
 def _getParams(self):
     super(RoomHook, self)._getParams()
     self._location = self._pathParams['location']
     self._ids = map(int, self._pathParams['idlist'].split('-'))
     if self._detail not in {'rooms', 'reservations'}:
         raise HTTPAPIError('Invalid detail level: %s' % self._detail, 400)
コード例 #17
0
    def export_file(self, user):
        if self._attachment.type != AttachmentType.file:
            raise HTTPAPIError("Resource is not a file", 404)

        return self._attachment.file.send()