def _getAnswer(self): event_persons = [] criteria = { 'surName': self._surName, 'name': self._name, 'organisation': self._organisation, 'email': self._email } users = search_avatars(criteria, self._exactMatch, self._searchExt) if self._event: fields = { EventPerson.first_name: self._name, EventPerson.last_name: self._surName, EventPerson.email: self._email, EventPerson.affiliation: self._organisation } criteria = [ unaccent_match(col, val, exact=self._exactMatch) for col, val in fields.iteritems() ] event_persons = self._event.persons.filter(*criteria).all() fossilized_users = fossilize( sorted(users, key=lambda av: (av.getStraightFullName(), av.getEmail()))) fossilized_event_persons = map(serialize_event_person, event_persons) unique_users = { to_unicode(user['email']): user for user in chain(fossilized_users, fossilized_event_persons) } return sorted(unique_users.values(), key=lambda x: (to_unicode(x['name']).lower(), to_unicode(x['email'])))
def _makeFossil(self, obj, iface): return fossilize(obj, iface, tz=self._tz, naiveTZ=self._serverTZ, filters={'access': self._userAccessFilter}, mapClassType={'AcceptedContribution': 'Contribution'})
def _postprocess(self, obj, fossil, iface): if iface is IRoomMetadataWithReservationsFossil: (startDT, endDT) = (self._fromDT or MIN_DATETIME, self._toDT or MAX_DATETIME) if self._fromDT or self._toDT: toDate = self._toDT.date() if self._toDT else None fromDate = self._fromDT.date() if self._fromDT else None resvEx = ReservationBase() resvEx.startDT = startDT resvEx.endDT = endDT resvEx.room = obj resvEx.isRejected = False resvEx.isCancelled = False if fromDate != toDate: resvEx.repeatability = RepeatabilityEnum.daily resvs = set(c.withReservation for c in resvEx.getCollisions()) else: resvs = obj.getReservations() iresvs1, iresvs2 = itertools.tee(itertools.ifilter(self._resvFilter, resvs), 2) fresvs = fossilize(iresvs1, IRoomReservationMetadataFossil, tz=self._tz, naiveTZ=self._serverTZ) for fresv, resv in itertools.izip(iter(fresvs), iresvs2): self._addOccurrences(fresv, resv, startDT, endDT) fossil['reservations'] = fresvs return fossil
def _build_event_api_data(self, event): can_manage = self.user is not None and event.can_manage(self.user) data = self._build_event_api_data_base(event) data.update({ '_fossil': self.fossils_mapping['event'].get(self._detail_level), 'categoryId': event.category_id, 'category': event.category.title, 'note': build_note_api_data(event.note), 'roomFullname': event.room_name, 'url': url_for('event.conferenceDisplay', confId=event.id, _external=True), 'modificationDate': self._serialize_date(event.as_legacy.getModificationDate()), 'creationDate': self._serialize_date(event.created_dt), 'creator': self._serialize_person(event.creator, person_type='Avatar', can_manage=can_manage), 'hasAnyProtection': event.effective_protection_mode != ProtectionMode.public, 'roomMapURL': event.room.map_url if event.room else None, 'folders': build_folders_api_data(event), 'chairs': self._serialize_persons(event.person_links, person_type='ConferenceChair', can_manage=can_manage), 'material': build_material_legacy_api_data(event) + filter(None, [build_note_legacy_api_data(event.note)]) }) event_category_path = event.category.chain visibility = {'id': '', 'name': 'Everywhere'} if event.visibility is None: pass # keep default elif event.visibility == 0: visibility['name'] = 'Nowhere' elif event.visibility: try: path_segment = event_category_path[-event.visibility] except IndexError: pass else: visibility['id'] = path_segment['id'] visibility['name'] = path_segment['title'] data['visibility'] = visibility if can_manage: data['allowed'] = self._serialize_access_list(event) if self._detail_level in {'contributions', 'subcontributions'}: data['contributions'] = [] for contribution in event.contributions: include_subcontribs = self._detail_level == 'subcontributions' serialized_contrib = self._serialize_contribution(contribution, include_subcontribs) data['contributions'].append(serialized_contrib) elif self._detail_level == 'sessions': # Contributions without a session data['contributions'] = [] for contribution in event.contributions: if not contribution.session: serialized_contrib = self._serialize_contribution(contribution) data['contributions'].append(serialized_contrib) data['sessions'] = [] for session_ in event.sessions: data['sessions'].extend(self._build_session_api_data(session_)) if self._occurrences: data['occurrences'] = fossilize(self._calculate_occurrences(event, self._fromDT, self._toDT, pytz.timezone(self._serverTZ)), {Period: IPeriodFossil}, tz=self._tz, naiveTZ=self._serverTZ) return data
def _process(self, iterator, filter=None, iface=None): if iface is None: iface = self.DETAIL_INTERFACES.get(self._detail) if iface is None: raise HTTPAPIError('Invalid detail level: %s' % self._detail, apache.HTTP_BAD_REQUEST) for obj in self._iterateOver(iterator, self._offset, self._limit, self._orderBy, self._descending, filter): yield self._postprocess(obj, fossilize(obj, iface, tz=self._tz, naiveTZ=self._serverTZ, filters={'access': self._userAccessFilter}, mapClassType={'AcceptedContribution':'Contribution'}), iface)
def _addOccurrences(self, fossil, obj, startDT, endDT): if self._occurrences: (startDT, endDT) = (startDT or MIN_DATETIME, endDT or MAX_DATETIME) # get occurrences in the date interval fossil['occurrences'] = fossilize(itertools.ifilter( lambda x: x.startDT >= startDT and x.endDT <= endDT, self._eventDaysIterator(obj)), {Period: IPeriodFossil}, tz=self._tz, naiveTZ=self._serverTZ) return fossil
def _makeFossil(self, obj, iface): return fossilize( obj, iface, tz=self._tz, naiveTZ=self._serverTZ, filters={"access": self._userAccessFilter}, mapClassType={"AcceptedContribution": "Contribution"}, )
def _getAnswer(self): results = [ g.as_legacy_group for g in GroupProxy.search(self._group, exact=self._exactMatch) ] fossilized_results = fossilize(results, IGroupFossil) for fossilizedGroup in fossilized_results: fossilizedGroup["isGroup"] = True return fossilized_results
def getVars(self): wvars = wcomponents.WTemplated.getVars(self) regForm = self._conf.getRegistrationForm() wvars["body_title"] = self._getTitle() wvars["title_regform"] = regForm.getTitle() wvars["currency"] = self._conf.getRegistrationForm().getCurrency() wvars["postURL"] = quoteattr(str(urlHandlers.UHConfRegistrationFormCreation.getURL(self._conf))) wvars["conf"] = self._conf wvars['sections'] = fossilize(section for section in self.getSections() if section.isEnabled()) return wvars
def _getAnswer(self): idx = self.schedModule.getFinishedIndex() if len(idx) > 0: # 1 day ts = idx.maxKey() - 24 * 60 * 60 return fossilize.fossilize(idx.itervalues(ts)) else: return {}
def _getAnswer(self): idx = self.schedModule.getFinishedIndex() if len(idx) > 0: # 1 day ts = idx.maxKey() - 24*60*60 return fossilize.fossilize(x for x in idx.itervalues(ts) if not hasattr(getattr(x, '_task', None), '__Broken_state__')) else: return {}
def getVars(self): wvars = wcomponents.WTemplated.getVars(self) regForm = self._conf.getRegistrationForm() wvars["body_title"] = self._getTitle() wvars["title_regform"] = regForm.getTitle() wvars["currency"] = payment_event_settings.get(self._conf, 'currency') if wvars.get('manager'): wvars['postURL'] = quoteattr(url_for('event_mgmt.confModifRegistrants-newRegistrant-save', self._conf)) else: wvars["postURL"] = quoteattr(str(urlHandlers.UHConfRegistrationFormCreation.getURL(self._conf))) wvars["conf"] = self._conf wvars['sections'] = fossilize(section for section in self.getSections() if section.isEnabled()) return wvars
def _getAnswer(self): idx = self.schedModule.getFinishedIndex() if len(idx) > 0: # 1 day ts = idx.maxKey() - 24 * 60 * 60 return fossilize.fossilize( x for x in idx.itervalues(ts) if not hasattr(getattr(x, '_task', None), '__Broken_state__')) else: return {}
def getVars(self): wvars = wcomponents.WTemplated.getVars(self) regForm = self._conf.getRegistrationForm() wvars["body_title"] = self._getTitle() wvars["title_regform"] = regForm.getTitle() wvars["currency"] = payment_event_settings.get(self._conf, 'currency') wvars["postURL"] = quoteattr( str(urlHandlers.UHConfRegistrationFormCreation.getURL(self._conf))) wvars["conf"] = self._conf wvars['sections'] = fossilize(section for section in self.getSections() if section.isEnabled()) return wvars
def _process(self, iterator, filter=None, iface=None): if iface is None: iface = self.DETAIL_INTERFACES.get(self._detail) if iface is None: raise HTTPAPIError('Invalid detail level: %s' % self._detail, apache.HTTP_BAD_REQUEST) for obj in self._iterateOver(iterator, self._offset, self._limit, self._orderBy, self._descending, filter): yield self._postprocess( obj, fossilize( obj, iface, tz=self._tz, naiveTZ=self._serverTZ, filters={'access': self._userAccessFilter}, mapClassType={'AcceptedContribution': 'Contribution'}), iface)
def _build_event_api_data(self, event): can_manage = self.user is not None and event.can_manage(self.user) data = self._build_event_api_data_base(event) data.update({ '_fossil': self.fossils_mapping['event'].get(self._detail_level), 'categoryId': unicode(event.category_id), 'category': event.category.getTitle(), 'note': build_note_api_data(event.note), 'roomFullname': event.room_name, 'url': url_for('event.conferenceDisplay', confId=event.id, _external=True), 'modificationDate': self._serialize_date(event.as_legacy.getModificationDate()), 'creationDate': self._serialize_date(event.as_legacy.getCreationDate()), 'creator': self._serialize_person(event.creator, person_type='Avatar', can_manage=can_manage), 'hasAnyProtection': event.as_legacy.hasAnyProtection(), 'roomMapURL': event.room.map_url if event.room else None, 'visibility': Conversion.visibility(event.as_legacy), 'folders': build_folders_api_data(event), 'chairs': self._serialize_persons(event.person_links, person_type='ConferenceChair', can_manage=can_manage), 'material': build_material_legacy_api_data(event) + [build_note_legacy_api_data(event.note)] }) if can_manage: data['allowed'] = self._serialize_access_list(event) if self._detail_level in {'contributions', 'subcontributions'}: data['contributions'] = [] for contribution in event.contributions: include_subcontribs = self._detail_level == 'subcontributions' serialized_contrib = self._serialize_contribution(contribution, include_subcontribs) data['contributions'].append(serialized_contrib) elif self._detail_level == 'sessions': # Contributions without a session data['contributions'] = [] for contribution in event.contributions: if not contribution.session: serialized_contrib = self._serialize_contribution(contribution) data['contributions'].append(serialized_contrib) data['sessions'] = [] for session_ in event.sessions: data['sessions'].extend(self._build_session_api_data(session_)) if self._occurrences: data['occurrences'] = fossilize(self._calculate_occurrences(event, self._fromDT, self._toDT, pytz.timezone(self._serverTZ)), {Period: IPeriodFossil}, tz=self._tz, naiveTZ=self._serverTZ) return data
def _getCategoryPath(id, aw): path = [] firstCat = cat = CategoryManager().getById(id) visibility = cat.getVisibility() while cat: # the first category (containing the event) is always shown, others only with access iface = ICategoryMetadataFossil if firstCat or cat.canAccess(aw) else ICategoryProtectedMetadataFossil path.append(fossilize(cat, iface)) cat = cat.getOwner() if visibility > len(path): visibilityName= "Everywhere" elif visibility == 0: visibilityName = "Nowhere" else: categId = path[visibility-1]["id"] visibilityName = CategoryManager().getById(categId).getName() path.reverse() path.append({"visibility": {"name": visibilityName}}) return path
def _getCategoryPath(id, aw): path = [] firstCat = cat = CategoryManager().getById(id) visibility = cat.getVisibility() while cat: # the first category (containing the event) is always shown, others only with access iface = ICategoryMetadataFossil if firstCat or cat.canAccess(aw) else ICategoryProtectedMetadataFossil path.append(fossilize(cat, iface)) cat = cat.getOwner() if visibility > len(path): visibilityName = "Everywhere" elif visibility == 0: visibilityName = "Nowhere" else: categId = path[visibility-1]["id"] visibilityName = CategoryManager().getById(categId).getName() path.reverse() path.append({"visibility": {"name": visibilityName}}) return path
def _getAnswer(self): return fossilize.fossilize(self.schedModule.getStatus())
def getSectionsFossil(self): return fossilize(self._conf.getRegistrationForm().getSortedForms())
def _operation(self): return fossilize(self._booking._disconnect(), timezone=self._conf.getTimezone())
def getVars(self): wvars = WConfRegistrationFormDisplay.getVars(self) wvars["sections"] = fossilize(WConfRegistrationFormDisplay.getSections(self)) return wvars
def _getAnswer(self): return fossilize.fossilize(self.schedModule.getFailedIndex().values())
def _build_event_api_data(self, event): can_manage = self.user is not None and event.can_manage(self.user) data = self._build_event_api_data_base(event) data.update( { "_fossil": self.fossils_mapping["event"].get(self._detail_level), "categoryId": event.category_id, "category": event.category.title, "note": build_note_api_data(event.note), "roomFullname": event.room_name, "url": url_for("event.conferenceDisplay", confId=event.id, _external=True), "modificationDate": self._serialize_date(event.as_legacy.getModificationDate()), "creationDate": self._serialize_date(event.created_dt), "creator": self._serialize_person(event.creator, person_type="Avatar", can_manage=can_manage), "hasAnyProtection": event.effective_protection_mode != ProtectionMode.public, "roomMapURL": event.room.map_url if event.room else None, "folders": build_folders_api_data(event), "chairs": self._serialize_persons( event.person_links, person_type="ConferenceChair", can_manage=can_manage ), "material": build_material_legacy_api_data(event) + filter(None, [build_note_legacy_api_data(event.note)]), } ) event_category_path = event.category.chain visibility = {"id": "", "name": "Everywhere"} if event.visibility is None: pass # keep default elif event.visibility == 0: visibility["name"] = "Nowhere" elif event.visibility: try: path_segment = event_category_path[-event.visibility] except IndexError: pass else: visibility["id"] = path_segment["id"] visibility["name"] = path_segment["title"] data["visibility"] = visibility if can_manage: data["allowed"] = self._serialize_access_list(event) if self._detail_level in {"contributions", "subcontributions"}: data["contributions"] = [] for contribution in event.contributions: include_subcontribs = self._detail_level == "subcontributions" serialized_contrib = self._serialize_contribution(contribution, include_subcontribs) data["contributions"].append(serialized_contrib) elif self._detail_level == "sessions": # Contributions without a session data["contributions"] = [] for contribution in event.contributions: if not contribution.session: serialized_contrib = self._serialize_contribution(contribution) data["contributions"].append(serialized_contrib) data["sessions"] = [] for session_ in event.sessions: data["sessions"].extend(self._build_session_api_data(session_)) if self._occurrences: data["occurrences"] = fossilize( self._calculate_occurrences(event, self._fromDT, self._toDT, pytz.timezone(self._serverTZ)), {Period: IPeriodFossil}, tz=self._tz, naiveTZ=self._serverTZ, ) return data
def _build_event_api_data(self, event): can_manage = self.user is not None and event.can_manage(self.user) data = self._build_event_api_data_base(event) data.update({ '_fossil': self.fossils_mapping['event'].get(self._detail_level), 'categoryId': unicode(event.category_id), 'category': event.category.getTitle(), 'note': build_note_api_data(event.note), 'roomFullname': event.room_name, 'url': url_for('event.conferenceDisplay', confId=event.id, _external=True), 'modificationDate': self._serialize_date(event.as_legacy.getModificationDate()), 'creationDate': self._serialize_date(event.as_legacy.getCreationDate()), 'creator': self._serialize_person(event.creator, person_type='Avatar', can_manage=can_manage), 'hasAnyProtection': event.as_legacy.hasAnyProtection(), 'roomMapURL': event.room.map_url if event.room else None, 'visibility': Conversion.visibility(event.as_legacy), 'folders': build_folders_api_data(event), 'chairs': self._serialize_persons(event.person_links, person_type='ConferenceChair', can_manage=can_manage), 'material': build_material_legacy_api_data(event) + [build_note_legacy_api_data(event.note)] }) if can_manage: data['allowed'] = self._serialize_access_list(event) if self._detail_level in {'contributions', 'subcontributions'}: data['contributions'] = [] for contribution in event.contributions: include_subcontribs = self._detail_level == 'subcontributions' serialized_contrib = self._serialize_contribution( contribution, include_subcontribs) data['contributions'].append(serialized_contrib) elif self._detail_level == 'sessions': # Contributions without a session data['contributions'] = [] for contribution in event.contributions: if not contribution.session: serialized_contrib = self._serialize_contribution( contribution) data['contributions'].append(serialized_contrib) data['sessions'] = [] for session_ in event.sessions: data['sessions'].extend(self._build_session_api_data(session_)) if self._occurrences: data['occurrences'] = fossilize(self._calculate_occurrences( event, self._fromDT, self._toDT, pytz.timezone(self._serverTZ)), {Period: IPeriodFossil}, tz=self._tz, naiveTZ=self._serverTZ) return data
def _operation(self): return fossilize(self._booking.connectionStatus(), timezone=self._conf.getTimezone())
def _operation(self): self._force = self._pm.extract("force", pType=bool, allowEmpty=True) return fossilize(self._booking._connect(force=self._force), timezone=self._conf.getTimezone())
def _makeFossil(self, obj, iface): return fossilize(obj, iface, tz=self._tz, naiveTZ=self._serverTZ, filters={'access': self._userAccessFilter}, canModify=obj.canModify(self._aw), mapClassType={'AcceptedContribution': 'Contribution'})
def _getAnswer(self): return fossilize.fossilize(list(v for (k,v) in self.schedModule.getWaitingQueue()))
def _getAnswer(self): return fossilize(self._conf.getRegistrarsLimits())
def _getAnswer(self): return fossilize.fossilize(self.schedModule.getRunningList())
def getVars(self): wvars = WConfRegistrationFormDisplay.getVars(self) wvars["sections"] = fossilize( WConfRegistrationFormDisplay.getSections(self)) return wvars
def _getAnswer(self): return fossilize.fossilize( x for x in reversed(self.schedModule.getFailedIndex().values()) if not hasattr(x, '__Broken_state__') and not hasattr(getattr(x, '_task', None), '__Broken_state__'))
def _getAnswer(self): return fossilize.fossilize([v for k, v in self.schedModule.getWaitingQueue()])
def _getAnswer(self): return fossilize.fossilize(x for x in reversed(self.schedModule.getFailedIndex().values()) if not hasattr(x, '__Broken_state__') and not hasattr(getattr(x, '_task', None), '__Broken_state__'))
def _getAnswer(self): return fossilize.fossilize( [v for k, v in self.schedModule.getWaitingQueue()])
def _makeFossil(self): iface = self.DETAIL_INTERFACES.get(self._detail) if iface is None: raise HTTPAPIError('Invalid detail level: %s' % self._detail, 400) return fossilize(self._registrant, iface)
def _build_event_api_data(self, event): can_manage = self.user is not None and event.can_manage(self.user) data = self._build_event_api_data_base(event) data.update({ '_fossil': self.fossils_mapping['event'].get(self._detail_level), 'categoryId': event.category_id, 'category': event.category.title, 'note': build_note_api_data(event.note), 'roomFullname': event.room_name, 'url': event.external_url, 'creationDate': self._serialize_date(event.created_dt), 'creator': self._serialize_person(event.creator, person_type='Avatar', can_manage=can_manage), 'hasAnyProtection': event.effective_protection_mode != ProtectionMode.public, 'roomMapURL': event.room.map_url if event.room else None, 'folders': build_folders_api_data(event), 'chairs': self._serialize_persons(event.person_links, person_type='ConferenceChair', can_manage=can_manage), 'material': build_material_legacy_api_data(event) + filter(None, [build_note_legacy_api_data(event.note)]), 'keywords': event.keywords, }) event_category_path = event.category.chain visibility = {'id': '', 'name': 'Everywhere'} if event.visibility is None: pass # keep default elif event.visibility == 0: visibility['name'] = 'Nowhere' elif event.visibility: try: path_segment = event_category_path[-event.visibility] except IndexError: pass else: visibility['id'] = path_segment['id'] visibility['name'] = path_segment['title'] data['visibility'] = visibility if can_manage: data['allowed'] = self._serialize_access_list(event) allow_details = contribution_settings.get(event, 'published') or can_manage if self._detail_level in {'contributions', 'subcontributions' } and allow_details: data['contributions'] = [] for contribution in event.contributions: include_subcontribs = self._detail_level == 'subcontributions' serialized_contrib = self._serialize_contribution( contribution, include_subcontribs) data['contributions'].append(serialized_contrib) elif self._detail_level == 'sessions' and allow_details: # Contributions without a session data['contributions'] = [] for contribution in event.contributions: if not contribution.session: serialized_contrib = self._serialize_contribution( contribution) data['contributions'].append(serialized_contrib) data['sessions'] = [] for session_ in event.sessions: data['sessions'].extend(self._build_session_api_data(session_)) if self._occurrences: data['occurrences'] = fossilize(self._calculate_occurrences( event, self._fromDT, self._toDT, pytz.timezone(config.DEFAULT_TIMEZONE)), {Period: IPeriodFossil}, tz=self._tz, naiveTZ=config.DEFAULT_TIMEZONE) # check whether the plugins want to add/override any data for update in values_from_signal( signals.event.metadata_postprocess.send('http-api', event=event, data=data), as_list=True): data.update(update) return data
def _makeFossil(self, obj, iface): return fossilize(obj, iface, tz=self._tz, naiveTZ=self._serverTZ, filters={'access': self._userAccessFilter})
def handler(prefix, path): path = posixpath.join('/', prefix, path) clearCache() # init fossil cache logger = Logger.get('httpapi') if request.method == 'POST': # Convert POST data to a query string queryParams = [(key, [x.encode('utf-8') for x in values]) for key, values in request.form.iterlists()] query = urllib.urlencode(queryParams, doseq=1) # we only need/keep multiple values so we can properly validate the signature. # the legacy code below expects a dict with just the first value. # if you write a new api endpoint that needs multiple values get them from # ``request.values.getlist()`` directly queryParams = {key: values[0] for key, values in queryParams} else: # Parse the actual query string queryParams = dict((key, value.encode('utf-8')) for key, value in request.args.iteritems()) query = request.query_string apiKey = get_query_parameter(queryParams, ['ak', 'apikey'], None) cookieAuth = get_query_parameter(queryParams, ['ca', 'cookieauth'], 'no') == 'yes' signature = get_query_parameter(queryParams, ['signature']) timestamp = get_query_parameter(queryParams, ['timestamp'], 0, integer=True) noCache = get_query_parameter(queryParams, ['nc', 'nocache'], 'no') == 'yes' pretty = get_query_parameter(queryParams, ['p', 'pretty'], 'no') == 'yes' onlyPublic = get_query_parameter(queryParams, ['op', 'onlypublic'], 'no') == 'yes' onlyAuthed = get_query_parameter(queryParams, ['oa', 'onlyauthed'], 'no') == 'yes' scope = 'read:legacy_api' if request.method == 'GET' else 'write:legacy_api' if not request.headers.get('Authorization', '').lower().startswith('basic '): try: oauth_valid, oauth_request = oauth.verify_request([scope]) if not oauth_valid and oauth_request and oauth_request.error_message != 'Bearer token not found.': raise BadRequest('OAuth error: {}'.format( oauth_request.error_message)) elif g.get( 'received_oauth_token' ) and oauth_request.error_message == 'Bearer token not found.': raise BadRequest('OAuth error: Invalid token') except ValueError: # XXX: Dirty hack to workaround a bug in flask-oauthlib that causes it # not to properly urlencode request query strings # Related issue (https://github.com/lepture/flask-oauthlib/issues/213) oauth_valid = False else: oauth_valid = False # Get our handler function and its argument and response type hook, dformat = HTTPAPIHook.parseRequest(path, queryParams) if hook is None or dformat is None: raise NotFound # Disable caching if we are not just retrieving data (or the hook requires it) if request.method == 'POST' or hook.NO_CACHE: noCache = True ak = error = result = None ts = int(time.time()) typeMap = {} status_code = None is_response = False try: used_session = None if cookieAuth: used_session = session if not used_session.user: # ignore guest sessions used_session = None if apiKey or oauth_valid or not used_session: if not oauth_valid: # Validate the API key (and its signature) ak, enforceOnlyPublic = checkAK(apiKey, signature, timestamp, path, query) if enforceOnlyPublic: onlyPublic = True # Create an access wrapper for the API key's user user = ak.user if ak and not onlyPublic else None else: # Access Token (OAuth) at = load_token(oauth_request.access_token.access_token) user = at.user if at and not onlyPublic else None # Get rid of API key in cache key if we did not impersonate a user if ak and user is None: cacheKey = normalizeQuery( path, query, remove=('_', 'ak', 'apiKey', 'signature', 'timestamp', 'nc', 'nocache', 'oa', 'onlyauthed')) else: cacheKey = normalizeQuery(path, query, remove=('_', 'signature', 'timestamp', 'nc', 'nocache', 'oa', 'onlyauthed')) if signature: # in case the request was signed, store the result under a different key cacheKey = 'signed_' + cacheKey else: # We authenticated using a session cookie. token = request.headers.get( 'X-CSRF-Token', get_query_parameter(queryParams, ['csrftoken'])) if used_session.csrf_protected and used_session.csrf_token != token: raise HTTPAPIError('Invalid CSRF token', 403) user = used_session.user if not onlyPublic else None userPrefix = 'user-{}_'.format(used_session.user.id) cacheKey = userPrefix + normalizeQuery( path, query, remove=('_', 'nc', 'nocache', 'ca', 'cookieauth', 'oa', 'onlyauthed', 'csrftoken')) # Bail out if the user requires authentication but is not authenticated if onlyAuthed and not user: raise HTTPAPIError('Not authenticated', 403) addToCache = not hook.NO_CACHE cache = GenericCache('HTTPAPI') cacheKey = RE_REMOVE_EXTENSION.sub('', cacheKey) if not noCache: obj = cache.get(cacheKey) if obj is not None: result, extra, ts, complete, typeMap = obj addToCache = False if result is None: g.current_api_user = user # Perform the actual exporting res = hook(user) if isinstance(res, current_app.response_class): addToCache = False is_response = True result, extra, complete, typeMap = res, {}, True, {} elif isinstance(res, tuple) and len(res) == 4: result, extra, complete, typeMap = res else: result, extra, complete, typeMap = res, {}, True, {} if result is not None and addToCache: ttl = api_settings.get('cache_ttl') if ttl > 0: cache.set(cacheKey, (result, extra, ts, complete, typeMap), ttl) except HTTPAPIError as e: error = e if e.getCode(): status_code = e.getCode() if result is None and error is None: # TODO: usage page raise NotFound else: if ak and error is None: # Commit only if there was an API key and no error norm_path, norm_query = normalizeQuery(path, query, remove=('signature', 'timestamp'), separate=True) uri = to_unicode('?'.join(filter(None, (norm_path, norm_query)))) ak.register_used(request.remote_addr, uri, not onlyPublic) db.session.commit() else: # No need to commit stuff if we didn't use an API key (nothing was written) # XXX do we even need this? db.session.rollback() # Log successful POST api requests if error is None and request.method == 'POST': logger.info('API request: %s?%s', path, query) if is_response: return result serializer = Serializer.create(dformat, query_params=queryParams, pretty=pretty, typeMap=typeMap, **hook.serializer_args) if error: if not serializer.schemaless: # if our serializer has a specific schema (HTML, ICAL, etc...) # use JSON, since it is universal serializer = Serializer.create('json') result = fossilize(error) else: if serializer.encapsulate: result = fossilize( HTTPAPIResult(result, path, query, ts, complete, extra), IHTTPAPIExportResultFossil) del result['_fossil'] try: data = serializer(result) response = current_app.make_response(data) content_type = serializer.get_response_content_type() if content_type: response.content_type = content_type if status_code: response.status_code = status_code return response except Exception: logger.exception('Serialization error in request %s?%s', path, query) raise
class CategoryEventFetcher(IteratedDataFetcher, SerializerBase): def __init__(self, user, hook): super().__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(f'Invalid detail level: {self._detail_level}', 400) def _calculate_occurrences(self, event, from_dt, to_dt, tz): start_dt = max(from_dt, event.start_dt) if from_dt else event.start_dt end_dt = min(to_dt, event.end_dt) if to_dt else event.end_dt for day in iterdays(start_dt, end_dt): first_start, last_end = find_event_day_bounds(event, day.date()) if first_start is not None: yield Period(first_start, last_end) def _get_query_options(self, detail_level): acl_user_strategy = joinedload('acl_entries').joinedload('user') # remote group membership checks will trigger a load on _all_emails # but not all events use this so there's no need to eager-load them # acl_user_strategy.noload('_primary_email') # acl_user_strategy.noload('_affiliation') creator_strategy = joinedload('creator') contributions_strategy = subqueryload('contributions') contributions_strategy.subqueryload('references') if detail_level in {'subcontributions', 'sessions'}: contributions_strategy.subqueryload('subcontributions').subqueryload('references') sessions_strategy = subqueryload('sessions') options = [acl_user_strategy, creator_strategy] if detail_level in {'contributions', 'subcontributions', 'sessions'}: options.append(contributions_strategy) if detail_level == 'sessions': options.append(sessions_strategy) options.append(undefer('effective_protection_mode')) return options def category(self, idlist, format): try: idlist = list(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)) def category_extra(self, ids): if self._toDT is None: has_future_events = False else: query = Event.find(Event.category_id.in_(ids), ~Event.is_deleted, Event.start_dt > self._toDT) has_future_events = query.has_rows() return { 'eventCategories': self._build_category_path_data(ids), 'moreFutureEvents': has_future_events } def event(self, idlist): query = (Event.find(Event.id.in_(idlist), ~Event.is_deleted, 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)) def _filter_event(self, event): if self._room or self._location or self._eventType: if self._eventType and event.type_.name != self._eventType: return False if self._location: name = event.venue_name if not name or not fnmatch.fnmatch(name.lower(), self._location.lower()): return False if self._room: name = event.room_name if not name or not fnmatch.fnmatch(name.lower(), self._room.lower()): return False return True 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 serialize_events(self, events): return list(map(self._build_event_api_data, events)) def _serialize_category_path(self, category): visibility = {'id': None, 'name': 'Everywhere'} path = [self._serialize_path_entry(category_data) for category_data in category.chain] if category.visibility is not None: try: path_segment = path[-category.visibility] except IndexError: pass else: visibility['id'] = path_segment['id'] visibility['name'] = path_segment['name'] path.append({'visibility': visibility}) return path def _serialize_path_entry(self, category_data): return { '_fossil': 'categoryMetadata', 'type': 'Category', 'name': category_data['title'], 'id': category_data['id'], 'url': url_for('categories.display', category_id=category_data['id'], _external=True) } def _build_category_path_data(self, ids): return [{'_type': 'CategoryPath', 'categoryId': category.id, 'path': self._serialize_category_path(category)} for category in Category.query.filter(Category.id.in_(ids)).options(undefer('chain'))] def _build_event_api_data(self, event): can_manage = self.user is not None and event.can_manage(self.user) data = self._build_event_api_data_base(event) material_data = build_material_legacy_api_data(event) if legacy_note_material := build_note_legacy_api_data(event.note): material_data.append(legacy_note_material) data.update({ '_fossil': self.fossils_mapping['event'].get(self._detail_level), 'categoryId': event.category_id, 'category': event.category.title, 'note': build_note_api_data(event.note), 'roomFullname': event.room_name, 'url': event.external_url, 'creationDate': self._serialize_date(event.created_dt), 'creator': self._serialize_person(event.creator, person_type='Avatar', can_manage=can_manage), 'hasAnyProtection': event.effective_protection_mode != ProtectionMode.public, 'roomMapURL': event.room.map_url if event.room else None, 'folders': build_folders_api_data(event), 'chairs': self._serialize_persons(event.person_links, person_type='ConferenceChair', can_manage=can_manage), 'material': material_data, 'keywords': event.keywords, }) event_category_path = event.category.chain visibility = {'id': '', 'name': 'Everywhere'} if event.visibility is None: pass # keep default elif event.visibility == 0: visibility['name'] = 'Nowhere' elif event.visibility: try: path_segment = event_category_path[-event.visibility] except IndexError: pass else: visibility['id'] = path_segment['id'] visibility['name'] = path_segment['title'] data['visibility'] = visibility if can_manage: data['allowed'] = self._serialize_access_list(event) allow_details = contribution_settings.get(event, 'published') or can_manage if self._detail_level in {'contributions', 'subcontributions'}: data['contributions'] = [] if allow_details: for contribution in event.contributions: include_subcontribs = self._detail_level == 'subcontributions' serialized_contrib = self._serialize_contribution(contribution, include_subcontribs) data['contributions'].append(serialized_contrib) elif self._detail_level == 'sessions': data['contributions'] = [] data['sessions'] = [] if allow_details: # Contributions without a session for contribution in event.contributions: if not contribution.session: serialized_contrib = self._serialize_contribution(contribution) data['contributions'].append(serialized_contrib) for session_ in event.sessions: data['sessions'].extend(self._build_session_api_data(session_)) if self._occurrences: data['occurrences'] = fossilize(self._calculate_occurrences(event, self._fromDT, self._toDT, pytz.timezone(config.DEFAULT_TIMEZONE)), {Period: IPeriodFossil}, tz=self._tz, naiveTZ=config.DEFAULT_TIMEZONE) # check whether the plugins want to add/override any data for update in values_from_signal( signals.event.metadata_postprocess.send('http-api', event=event, data=data), as_list=True): data.update(update) return data
def _value(self): if self.serializable: return map(fossilize, retrieve_principals(self._get_data())) else: data = sorted(self._get_data(), key=lambda x: (x.last_name if isinstance(x, User) else x.name).lower()) return fossilize(x.as_avatar if isinstance(x, User) else x.as_legacy_group for x in data)