def get(self, request, *args, **kwargs): self.show_recent = kwargs.pop('show_recent', False) content = kwargs.pop('content', None) if not content: return HttpResponseBadRequest('No content type supplied') self.model = SEARCH_MODEL_NAMES_REVERSE.get(content, None) if not self.model: return HttpResponseBadRequest( 'Unknown content type supplied: "%s"' % content) self.page_size = int( request.GET.get('page_size', self.default_page_size)) if not is_number(self.page_size): return HttpResponseBadRequest( 'Malformed parameter: "page_size": %s' % self.page_size) self.page_size = max(self.min_page_size, min(self.max_page_size, self.page_size)) self.offset_timestamp = request.GET.get('offset_timestamp', self.default_offset_timestamp) if self.offset_timestamp is not None and not is_number( self.offset_timestamp): return HttpResponseBadRequest( 'Malformed parameter: "offset_timestamp"') if self.offset_timestamp is not None and isinstance( self.offset_timestamp, six.string_types): self.offset_timestamp = float(self.offset_timestamp) return super(TypedContentWidgetView, self).get(request, *args, **kwargs)
def get(self, request, *args, **kwargs): """ Accepted GET-params: `page_size` int (optional): Number of items to be returned. If a value larger than `self.max_page_size` is supplied, `self.max_page_size`is used instead. Default: `self.default_page_size` `offset_timestamp` float (optional): If supplied, only items older than the given timestamp are returned. Items with the exact timestamp are excluded. Use this parameter in conjunction with the return value `last_timestamp` for pagination. `only_mine` bool (optional): if True, will only show objects that belong to groups or projects the `user` is a member of. If False, will include all visible items in this portal for the user. """ # require authenticated user self.user = request.user if not request.user.is_authenticated: return HttpResponseForbidden('Not authenticated.') content = kwargs.pop('content', None) if content: self.filter_model = SEARCH_MODEL_NAMES_REVERSE.get(content, None) if not self.filter_model: return HttpResponseBadRequest( 'Unknown content type supplied: "%s"' % content) self.page_size = int( request.GET.get('page_size', self.default_page_size)) if not is_number(self.page_size): return HttpResponseBadRequest( 'Malformed parameter: "page_size": %s' % self.page_size) self.page_size = max(self.min_page_size, min(self.max_page_size, self.page_size)) self.offset_timestamp = request.GET.get('offset_timestamp', self.default_offset_timestamp) if self.offset_timestamp is not None and not is_number( self.offset_timestamp): return HttpResponseBadRequest( 'Malformed parameter: "offset_timestamp"') if self.offset_timestamp is not None and isinstance( self.offset_timestamp, six.string_types): self.offset_timestamp = float(self.offset_timestamp) self.only_mine = request.GET.get('only_mine', self.only_mine_default) if isinstance(self.only_mine, six.string_types): self.only_mine = bool(json.loads(self.only_mine)) items = self.get_items() response = self.render_to_response(items) return response
def get(self, request, *args, **kwargs): """ Accepted GET-params: `q` str: the query to search for `page_size` int (optional): Number of items to be returned. If a value larger than `self.max_page_size` is supplied, `self.max_page_size`is used instead. Default: `self.default_page_size` """ self.user = request.user query = self.request.GET.get('q', '').strip() if not query: return HttpResponseBadRequest('Missing parameter: "q"!') self.query = query self.query_terms = self.query.lower().split(' ') self.page_size = int( request.GET.get('page_size', self.default_page_size)) if not is_number(self.page_size): return HttpResponseBadRequest( 'Malformed parameter: "page_size": %s' % self.page_size) self.page_size = max(self.min_page_size, min(self.max_page_size, self.page_size)) items = self.get_items() response = self.render_to_response(items) return response
def alerts_mark_seen(request, before_timestamp=None): """ Marks all NotificationAlerts of the current user as seen. @param before_timestamp: if kwarg is given, only marks alerts older than the given timestamp as seen. """ if request and not request.user.is_authenticated: return HttpResponseForbidden('Not authenticated') if not request.method == 'POST': return HttpResponseNotAllowed(['POST']) if before_timestamp is not None and not is_number(before_timestamp): return HttpResponseBadRequest('Malformed parameter: "before_timestamp"') if before_timestamp: before_timestamp = float(before_timestamp) before_dt = datetime_from_timestamp(before_timestamp) else: before_dt = now() unseen_alerts = NotificationAlert.objects.filter( portal=CosinnusPortal.get_current(), user=request.user, last_event_at__lte=before_dt, seen=False ) unseen_alerts.update(seen=True) return HttpResponse('ok')
def get(self, request, *args, **kwargs): self.newer_than_timestamp = kwargs.pop('newer_than_timestamp', None) if self.newer_than_timestamp is not None and not is_number(self.newer_than_timestamp): return HttpResponseBadRequest('Malformed parameter: "newer_than_timestamp"') if self.newer_than_timestamp is not None and isinstance(self.newer_than_timestamp, six.string_types): self.newer_than_timestamp = float(self.newer_than_timestamp) return super(AlertsRetrievalView, self).get(request, *args, **kwargs)
def get(self, request, *args, **kwargs): self.page_size = int( request.GET.get('page_size', self.default_page_size)) if not is_number(self.page_size): return HttpResponseBadRequest( 'Malformed parameter: "page_size": %s' % self.page_size) self.page_size = max(self.min_page_size, min(self.max_page_size, self.page_size)) self.offset_timestamp = request.GET.get('offset_timestamp', self.default_offset_timestamp) if self.offset_timestamp is not None and not is_number( self.offset_timestamp): return HttpResponseBadRequest( 'Malformed parameter: "offset_timestamp"') if self.offset_timestamp is not None and isinstance( self.offset_timestamp, six.string_types): self.offset_timestamp = float(self.offset_timestamp) self.set_options() return super(BasePagedOffsetWidgetView, self).get(request, *args, **kwargs)
def _get_validated_amount(amount): """ Validates if a given amount is valid for payment (is a number, and in limits). @return: The float amount if valid, a JsonResponse with an error otherwise. """ if not is_number(amount): return JsonResponse({'error': _('The amount submitted does not seem to be a number!')}, status=500) amount = float(amount) # check min/max payment amounts if amount > settings.PAYMENTS_MAXIMUM_ALLOWED_PAYMENT_AMOUNT: return JsonResponse({'error': _('The payment amount is higher than the allowed maximum amount!')}, status=500) if amount < settings.PAYMENTS_MINIMUM_ALLOWED_PAYMENT_AMOUNT: return JsonResponse({'error': _('The payment amount is lower than the allowed minimum amount!')}, status=500) return amount
def map_search_endpoint(request, filter_group_id=None): """ Maps API search endpoint using haystack search results. For parameters see ``MAP_SEARCH_PARAMETERS`` returns JSON with the contents of type ``HaystackMapResult`` @param filter_group_id: Will filter all items by group relation, where applicable (i.e. users are filtered by group memberships for that group, events as events in that group) """ implicit_ignore_location = not any([ loc_param in request.GET for loc_param in ['sw_lon', 'sw_lat', 'ne_lon', 'ne_lat'] ]) params = _collect_parameters(request.GET, MAP_SEARCH_PARAMETERS) query = force_text(params['q']) limit = params['limit'] page = params['page'] item_id = params['item'] prefer_own_portal = getattr(settings, 'MAP_API_HACKS_PREFER_OWN_PORTAL', False) if not is_number(limit) or limit < 0: return HttpResponseBadRequest( '``limit`` param must be a positive number or 0!') limit = min(limit, SERVER_SIDE_SEARCH_LIMIT) if not is_number(page) or page < 0: return HttpResponseBadRequest( '``page`` param must be a positive number or 0!') # filter for requested model types model_list = [ klass for klass, param_name in list(SEARCH_MODEL_NAMES.items()) if params.get(param_name, False) ] sqs = SearchQuerySet().models(*model_list) # filter for map bounds (Points are constructed ith (lon, lat)!!!) if not params['ignore_location'] and not implicit_ignore_location: sqs = sqs.within('location', Point(params['sw_lon'], params['sw_lat']), Point(params['ne_lon'], params['ne_lat'])) # filter for user's own content if params['mine'] and request.user.is_authenticated: user_id = request.user.id sqs = sqs.filter_and( Q(creator=user_id) | Q(user_id=user_id) | Q(group_members=user_id)) # filter for search terms if query: sqs = sqs.auto_query(query) # group-filtered-map view for on-group pages if filter_group_id: group = get_object_or_None(get_cosinnus_group_model(), id=filter_group_id) if group: filtered_groups = [filter_group_id] # get child projects of this group filtered_groups += [ subproject.id for subproject in group.get_children() if subproject.is_active ] sqs = sqs.filter_and( Q(membership_groups__in=filtered_groups) | Q(group__in=filtered_groups)) # filter topics topics = ensure_list_of_ints(params.get('topics', '')) if topics: sqs = sqs.filter_and(mt_topics__in=topics) # filter for portal visibility sqs = filter_searchqueryset_for_portal( sqs, restrict_multiportals_to_current=prefer_own_portal) # filter for read access by this user sqs = filter_searchqueryset_for_read_access(sqs, request.user) # filter events by upcoming status if params['events'] and Event is not None: sqs = filter_event_searchqueryset_by_upcoming(sqs) # filter all default user groups if the new dashboard is being used (they count as "on plattform" and aren't shown) if getattr(settings, 'COSINNUS_USE_V2_DASHBOARD', False): sqs = sqs.exclude(is_group_model=True, slug__in=get_default_user_group_slugs()) # if we hae no query-boosted results, use *only* our custom sorting (haystack's is very random) if not query: if prefer_own_portal: sqs = sqs.order_by('-portal', '-local_boost') else: sqs = sqs.order_by('-local_boost') # sort results into one list per model total_count = sqs.count() sqs = sqs[limit * page:limit * (page + 1)] results = [] for result in sqs: # if we hae no query-boosted results, use *only* our custom sorting (haystack's is very random) if not query: result.score = result.local_boost if prefer_own_portal and is_number(result.portal) and int( result.portal) == CosinnusPortal.get_current().id: result.score += 100.0 results.append(HaystackMapResult(result, user=request.user)) # if the requested item (direct select) is not in the queryset snippet # (might happen because of an old URL), then mix it in as first item and drop the last if item_id: item_id = str(item_id) if not any([res['id'] == item_id for res in results]): item_result = get_searchresult_by_itemid(item_id, request.user) if item_result: results = [HaystackMapResult(item_result, user=request.user) ] + results[:-1] page_obj = None if results: page_obj = { 'index': page, 'count': len(results), 'total_count': total_count, 'start': (limit * page) + 1, 'end': (limit * page) + len(results), 'has_next': total_count > (limit * (page + 1)), 'has_previous': page > 0, } data = { 'results': results, 'page': page_obj, } return JsonResponse(data)
def map_detail_endpoint(request): """ Maps API object detail endpoint using pSQL results. For parameters see ``MAP_DETAIL_PARAMETERS`` returns JSON with the contents of type ``DetailedMapResult`` """ params = _collect_parameters(request.GET, MAP_DETAIL_PARAMETERS) portal = params['portal'] slug = params['slug'] model_type = params['type'] if not is_number(portal) or portal < 0: return HttpResponseBadRequest( '``portal`` param must be a positive number!') if not slug: return HttpResponseBadRequest('``slug`` param must be supplied!') slug = force_text(slug) # stringify is necessary for number-only slugs if not model_type or not isinstance(model_type, six.string_types): return HttpResponseBadRequest( '``type`` param must be supplied and be a string!') if portal == 0: portal = CosinnusPortal.get_current().id # try to retrieve the requested object model = SEARCH_MODEL_NAMES_REVERSE.get(model_type, None) if model is None: return HttpResponseBadRequest( '``type`` param indicated an invalid data model type!') # TODO: for groups/projects we should really use the cache here. if model_type == 'people': # UserProfiles are retrieved independent of the portal obj = get_object_or_None(get_user_profile_model(), user__username=slug) elif model_type == 'events': group_slug, event_slug = slug.split('*', 1) obj = get_object_or_None(model, group__portal__id=portal, group__slug=group_slug, slug=event_slug) else: obj = get_object_or_None(model, portal__id=portal, slug=slug) if obj is None: return HttpResponseNotFound( 'No item found that matches the requested type and slug (obj: %s, %s, %s).' % (escape(force_text(model)), portal, slug)) # check read permission if not model_type in SEARCH_MODEL_TYPES_ALWAYS_READ_PERMISSIONS and not check_object_read_access( obj, request.user): return HttpResponseForbidden( 'You do not have permission to access this item.') # get the basic result data from the search index (as it is already prepared and faster to access there) haystack_result = get_searchresult_by_args(portal, model_type, slug) if not haystack_result: return HttpResponseNotFound( 'No item found that matches the requested type and slug (index: %s, %s, %s).' % (portal, model_type, slug)) # format data result_model = SEARCH_RESULT_DETAIL_TYPE_MAP[model_type] result = result_model(haystack_result, obj, request.user) data = { 'result': result, } return JsonResponse(data)
def get_context_data(self, **kwargs): forum_group = None forum_slug = getattr(settings, 'NEWW_FORUM_GROUP_SLUG', None) note_form = None if forum_slug: forum_group = get_object_or_None( get_cosinnus_group_model(), slug=forum_slug, portal=CosinnusPortal.get_current()) try: from cosinnus_note.forms import NoteForm note_form = NoteForm(group=forum_group) except: if settings.DEBUG: raise announcement = None announcement_is_preview = False # for superusers, check if we're viewing an announcement_preview if self.request.GET.get('show_announcement', None) is not None and check_user_superuser( self.request.user): announcement_id = self.request.GET.get('show_announcement') if is_number(announcement_id): announcement_is_preview = True announcement = get_object_or_None(UserDashboardAnnouncement, id=int(announcement_id)) else: announcement = UserDashboardAnnouncement.get_next_for_user( self.request.user) welcome_screen_expired = self.request.user.date_joined < (now( ) - timedelta(days=getattr( settings, 'COSINNUS_V2_DASHBOARD_WELCOME_SCREEN_EXPIRY_DAYS', 7))) welcome_screen_enabled = getattr( settings, 'COSINNUS_V2_DASHBOARD_WELCOME_SCREEN_ENABLED', True) options = { 'ui_prefs': get_ui_prefs_for_user(self.request.user), 'force_only_mine': getattr(settings, 'COSINNUS_USERDASHBOARD_FORCE_ONLY_MINE', False) or \ getattr(settings, 'COSINNUS_FORUM_DISABLED', False), } ctx = { 'user_dashboard_options_json': json.dumps(options), 'forum_group': forum_group, 'note_form': note_form, 'announcement': announcement, 'announcement_is_preview': announcement_is_preview, 'show_welcome_screen': welcome_screen_enabled and not welcome_screen_expired, } if settings.COSINNUS_CONFERENCES_ENABLED: _now = now() my_conferences = CosinnusConference.objects.get_for_user( self.request.user) my_current_conferences = [(conf, conf.get_icon()) for conf in my_conferences if conf.get_or_infer_to_date and conf.get_or_infer_to_date > _now] my_pending_conference_applications = [ (appl.conference, appl.get_icon()) for appl in self.request.user.user_applications.pending_current() ] ctx['my_upcoming_conferences_with_icons'] = my_pending_conference_applications + my_current_conferences return ctx
def start(self, name, meeting_id, welcome="Welcome to the conversation", moderator_password="", attendee_password="", max_participants=None, voice_bridge=None, parent_meeting_id=None, options=None, presentation_url=""): """ This function calls the BigBlueButton API directly to create a meeting with all available parameters available in the cosinnus-core.BBBRoom model. :param name: Human readable name for the meeting :type: str :param meeting_id: Human readable ID for the meeting :type: str :param welcome: Welcome message when joining the meeting :type: str :param moderator_password: Password for users to join with moderator privileges :type: str :param attendee_password: Password for users to join with default attendee privileges :type: str :param max_participants: Number of users allowed in the conference :type: int :param voice_bridge: Dial in PIN for telephone users :type: int :param parent_meeting_id: Breaking room for a running conference :type: str :param options: BBBRoom options according to the listed options in the BigBlueButton API :type: dict :param presentation_url: Publicly available URL of presentation file to be pre-uploaded as slides to BBB room :type: str :return: XML representation of the API result :rtype: XML """ call = 'create' # set default values voice_bridge = voice_bridge if voice_bridge and is_number( voice_bridge) else bbb_utils.random_voice_bridge() attendee_password = attendee_password if attendee_password else bbb_utils.random_password( ) moderator_password = moderator_password if moderator_password else bbb_utils.random_password( ) query = ( ("name", name), ('meetingID', meeting_id), ("welcome", welcome), ("voiceBridge", voice_bridge), ("attendeePW", attendee_password), ("moderatorPW", moderator_password), ) if max_participants and is_number(max_participants): query += (("maxParticipants", int(max_participants)), ) if parent_meeting_id: query += (("parentMeetingID", parent_meeting_id), ) if options: for key, value in options.items(): query += ((key, value), ) query = urllib.parse.urlencode(query) hashed = self.api_call(query, call) url = self.api_auth_url + call + '?' + hashed # Presentation file has to be sent via POST request with XML body if presentation_url: headers = {'Content-Type': 'application/xml'} xml = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'>" absolute_url = get_domain_for_portal( CosinnusPortal.get_current()) + presentation_url xml += f"<document url='{absolute_url}' />" xml += "</module></modules>" response = requests.post(url, data=xml, headers=headers) else: response = requests.get(url) result = bbb_utils.parse_xml(response.content.decode('utf-8')) if result: return result else: logger.error( 'BBB Room error: Server request `start` was not successful.', extra={ 'response_status_code': response.status_code, 'result': response.text }) raise Exception( 'BBB Room exception: Server request was not successful: ' + str(response.text))
def map_search_endpoint(request, filter_group_id=None): """ Maps API search endpoint using haystack search results. For parameters see ``MAP_SEARCH_PARAMETERS`` returns JSON with the contents of type ``HaystackMapResult`` @param filter_group_id: Will filter all items by group relation, where applicable (i.e. users are filtered by group memberships for that group, events as events in that group) """ implicit_ignore_location = not any([ loc_param in request.GET for loc_param in ['sw_lon', 'sw_lat', 'ne_lon', 'ne_lat'] ]) params = _collect_parameters(request.GET, MAP_SEARCH_PARAMETERS) query = force_text(params['q']) limit = params['limit'] page = params['page'] item_id = params['item'] if params.get('cloudfiles', False): return map_cloudfiles_endpoint(request, query, limit, page) # TODO: set to params['external'] after the external switch button is in frontend! external = settings.COSINNUS_EXTERNAL_CONTENT_ENABLED prefer_own_portal = getattr(settings, 'MAP_API_HACKS_PREFER_OWN_PORTAL', False) if not is_number(limit) or limit < 0: return HttpResponseBadRequest( '``limit`` param must be a positive number or 0!') limit = min(limit, SERVER_SIDE_SEARCH_LIMIT) if not is_number(page) or page < 0: return HttpResponseBadRequest( '``page`` param must be a positive number or 0!') # filter for requested model types model_list = [ klass for klass, param_name in list(SEARCH_MODEL_NAMES.items()) if params.get(param_name, False) ] sqs = SearchQuerySet().models(*model_list) # filter for map bounds (Points are constructed ith (lon, lat)!!!) if not params['ignore_location'] and not implicit_ignore_location: sqs = sqs.within('location', Point(params['sw_lon'], params['sw_lat']), Point(params['ne_lon'], params['ne_lat'])) # filter for user's own content if params['mine'] and request.user.is_authenticated: user_id = request.user.id sqs = sqs.filter_and( Q(creator=user_id) | Q(user_id=user_id) | Q(group_members=user_id)) # filter for search terms if query: sqs = sqs.auto_query(query) # group-filtered-map view for on-group pages if filter_group_id: group = get_object_or_None(get_cosinnus_group_model(), id=filter_group_id) if group: filtered_groups = [filter_group_id] # get child projects of this group filtered_groups += [ subproject.id for subproject in group.get_children() if subproject.is_active ] sqs = sqs.filter_and( Q(membership_groups__in=filtered_groups) | Q(group__in=filtered_groups)) # filter topics topics = ensure_list_of_ints(params.get('topics', '')) if topics: sqs = sqs.filter_and(mt_topics__in=topics) if settings.COSINNUS_ENABLE_SDGS: sdgs = ensure_list_of_ints(params.get('sdgs', '')) if sdgs: sqs = sqs.filter_and(sdgs__in=sdgs) if settings.COSINNUS_MANAGED_TAGS_ENABLED: managed_tags = ensure_list_of_ints(params.get('managed_tags', '')) if managed_tags: sqs = sqs.filter_and(managed_tags__in=managed_tags) # filter for portal visibility sqs = filter_searchqueryset_for_portal( sqs, restrict_multiportals_to_current=prefer_own_portal, external=external) # filter for read access by this user sqs = filter_searchqueryset_for_read_access(sqs, request.user) # filter events by upcoming status and exclude hidden proxies if params['events'] and Event is not None: sqs = filter_event_searchqueryset_by_upcoming(sqs).exclude( is_hidden_group_proxy=True) # filter all default user groups if the new dashboard is being used (they count as "on plattform" and aren't shown) if getattr(settings, 'COSINNUS_USE_V2_DASHBOARD', False): sqs = sqs.exclude(is_group_model=True, slug__in=get_default_user_group_slugs()) # kip score sorting and only rely on natural ordering? skip_score_sorting = False # if we hae no query-boosted results, use *only* our custom sorting (haystack's is very random) if not query: sort_args = ['-local_boost'] # if we only look at conferences, order them by their from_date, future first! if prefer_own_portal: sort_args = ['-portal'] + sort_args """ # this would be the way to force-sort a content type by a natural ordering instead of score if its the only type being shown if params.get('conferences', False) and sum([1 if params.get(content_key, False) else 0 for content_key in MAP_CONTENT_TYPE_SEARCH_PARAMETERS.keys()]) == 1: sort_args = ['-from_date'] + sort_args skip_score_sorting = True sqs = sqs.order_by(*sort_args) """ # sort results into one list per model total_count = sqs.count() sqs = sqs[limit * page:limit * (page + 1)] results = [] for i, result in enumerate(sqs): if skip_score_sorting: # if we skip score sorting and only rely on the natural ordering, we make up fake high scores result.score = 100000 - (limit * page) - i elif not query: # if we hae no query-boosted results, use *only* our custom sorting (haystack's is very random) result.score = result.local_boost if prefer_own_portal and is_number(result.portal) and int( result.portal) == CosinnusPortal.get_current().id: result.score += 100.0 results.append(HaystackMapResult(result, user=request.user)) # if the requested item (direct select) is not in the queryset snippet # (might happen because of an old URL), then mix it in as first item and drop the last if item_id: item_id = str(item_id) if not any([res['id'] == item_id for res in results]): item_result = get_searchresult_by_itemid(item_id, request.user) if item_result: results = [HaystackMapResult(item_result, user=request.user) ] + results[:-1] page_obj = None if results: page_obj = { 'index': page, 'count': len(results), 'total_count': total_count, 'start': (limit * page) + 1, 'end': (limit * page) + len(results), 'has_next': total_count > (limit * (page + 1)), 'has_previous': page > 0, } data = { 'results': results, 'page': page_obj, } return JsonResponse(data)