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)
def _getParams(self): super(CategoryEventHook, self)._getParams() self._idList = self._pathParams['idlist'].split('-') self._wantFavorites = False if 'favorites' in self._idList: self._idList.remove('favorites') self._wantFavorites = True self._eventType = get_query_parameter(self._queryParams, ['T', 'type']) if self._eventType == 'simple_event': self._eventType = 'lecture' self._occurrences = get_query_parameter(self._queryParams, ['occ', 'occurrences'], 'no') == 'yes' self._location = get_query_parameter(self._queryParams, ['l', 'location']) self._room = get_query_parameter(self._queryParams, ['r', 'room'])
def _getParams(self): super(RoomBookingHookBase, 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 self._occurrences = _yesno( get_query_parameter(self._queryParams, ['occ', 'occurrences'], 'no'))
def _update_query(self, query): order = get_query_parameter(request.args.to_dict(), ['o', 'order']) desc = get_query_parameter(request.args.to_dict(), ['c', 'descending']) == 'yes' limit = get_query_parameter(request.args.to_dict(), ['n', 'limit']) offset = get_query_parameter(request.args.to_dict(), ['O', 'offset']) col = { 'start': Event.start_dt, 'end': Event.end_dt, 'id': Event.id, 'title': Event.title }.get(order) if col: query = query.order_by(col.desc() if desc else col) if limit: query = query.limit(limit) if offset: query = query.offset(offset) return query
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')
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)
def _get_reservation_state_filter(params): cancelled = get_query_parameter(params, ['cxl', 'cancelled']) rejected = get_query_parameter(params, ['rej', 'rejected']) confirmed = get_query_parameter(params, ['confirmed']) archived = get_query_parameter(params, ['arch', 'archived', 'archival']) repeating = get_query_parameter(params, ['rec', 'recurring', 'rep', 'repeating']) avc = get_query_parameter(params, ['avc']) avc_support = get_query_parameter(params, ['avcs', 'avcsupport']) startup_support = get_query_parameter(params, ['sts', 'startupsupport']) booked_for = get_query_parameter(params, ['bf', 'bookedfor']) filters = [] if cancelled is not None: filters.append(Reservation.is_cancelled == _yesno(cancelled)) if rejected is not None: filters.append(Reservation.is_rejected == _yesno(rejected)) if confirmed is not None: if confirmed == 'pending': filters.append(Reservation.is_pending) elif _yesno(confirmed): filters.append(Reservation.is_accepted) else: filters.append(~Reservation.is_accepted) filters.append(Reservation.is_rejected | Reservation.is_cancelled) if archived is not None: filters.append(Reservation.is_archived == _yesno(archived)) if repeating is not None: if _yesno(repeating): filters.append(Reservation.repeat_frequency != 0) else: filters.append(Reservation.repeat_frequency == 0) if avc is not None: filters.append(Reservation.uses_vc == _yesno(avc)) if avc_support is not None: filters.append(Reservation.needs_vc_assistance == _yesno(avc_support)) if startup_support is not None: filters.append(Reservation.needs_assistance == _yesno(startup_support)) if booked_for: like_str = '%{}%'.format( booked_for.replace('?', '_').replace('*', '%')) filters.append(Reservation.booked_for_name.ilike(like_str)) return filters
def _export_reservations(hook, limit_per_room, include_rooms, extra_filters=None): """Exports reservations. :param hook: The HTTPAPIHook instance :param limit_per_room: Should the limit/offset be applied per room :param include_rooms: Should reservations include room information """ filters = list(extra_filters) if extra_filters else [] if hook._fromDT and hook._toDT: filters.append(cast(Reservation.start_dt, Date) <= hook._toDT.date()) filters.append(cast(Reservation.end_dt, Date) >= hook._fromDT.date()) filters.append(cast(Reservation.start_dt, Time) <= hook._toDT.time()) filters.append(cast(Reservation.end_dt, Time) >= hook._fromDT.time()) elif hook._toDT: filters.append(cast(Reservation.end_dt, Date) <= hook._toDT.date()) filters.append(cast(Reservation.end_dt, Time) <= hook._toDT.time()) elif hook._fromDT: filters.append(cast(Reservation.start_dt, Date) >= hook._fromDT.date()) filters.append(cast(Reservation.start_dt, Time) >= hook._fromDT.time()) filters += _get_reservation_state_filter(hook._queryParams) occurs = [ datetime.strptime(x, '%Y-%m-%d').date() for x in filter( None, get_query_parameter(hook._queryParams, ['occurs'], '').split(',')) ] data = ['vc_equipment'] if hook._occurrences: data.append('occurrences') order = { 'start': Reservation.start_dt, 'end': Reservation.end_dt }.get(hook._orderBy, Reservation.start_dt) if hook._descending: order = order.desc() reservations_data = Reservation.get_with_data( *data, filters=filters, limit=hook._limit, offset=hook._offset, order=order, limit_per_room=limit_per_room, occurs_on=occurs) for result in reservations_data: yield result['reservation'].room_id, _serializable_reservation( result, include_rooms)
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