def get_results(self, request, term, page, context): term = term.lower() start = (page - 1) * 10 end = page * 10 q = Q(name__icontains=term) # add all extra lookup fields defined by swapped out group models for lookup_field in get_cosinnus_group_model().NAME_LOOKUP_FIELDS: if lookup_field != 'name': q = q | Q(**{lookup_field + '__icontains': term}) qs = get_cosinnus_group_model().objects.filter(q).filter( portal_id=CosinnusPortal.get_current().id) if request.GET.get('except', None): qs = qs.exclude(id=int(request.GET.get('except'))) # TODO: also search russian/other extension fields of name, make a good interface to generically grab those count = qs.count() if count < start: raise Http404 has_more = count > end groups = [] for group in qs[start:end]: # access group.name by its dict lookup to support translation magic groups.append((group.id, group['name'])) return (NO_ERR_RESP, has_more, groups)
def check_user_can_see_user(user, target_user): """ Checks if ``user`` is in any relation with ``target_user`` so that he can see them and their profile, and can send him messages, etc. This depends on the privacy settings of ``target_user`` and on whether they are members of a same group/project. """ visibility = target_user.cosinnus_profile.media_tag.visibility if visibility == BaseTagObject.VISIBILITY_ALL: return True if visibility == BaseTagObject.VISIBILITY_GROUP and user.is_authenticated: return True if check_user_superuser(user): return True if user == target_user: return True # in any case, group members of the same project/group can always see each other # but filter the default groups for this! exclude_pks = get_default_user_group_ids() user_groups = [ ug_pk for ug_pk in get_cosinnus_group_model().objects.get_for_user_pks(user) if not ug_pk in exclude_pks ] target_user_groups = [ tug_pk for tug_pk in get_cosinnus_group_model().objects.get_for_user_pks(target_user) if not tug_pk in exclude_pks ] if any([(user_group_pk in target_user_groups) for user_group_pk in user_groups]): return True return False
def convert_to_society(self, request, queryset): """ Converts this CosinnusGroup's type """ converted_names = [] refused_portal_names = [] for group in queryset: if group.portal_id != CosinnusPortal.get_current().id: refused_portal_names.append(group.name) continue group.type = CosinnusGroup.TYPE_SOCIETY # clear parent group if the project had one (societies cannot have parents!) group.parent = None group.save(allow_type_change=True) if group.type == CosinnusGroup.TYPE_SOCIETY: converted_names.append(group.name) CosinnusPermanentRedirect.create_for_pattern(group.portal, CosinnusGroup.TYPE_PROJECT, group.slug, group) # we beat the cache with a hammer on all class models, to be sure CosinnusProject._clear_cache(group=group) CosinnusSociety._clear_cache(group=group) get_cosinnus_group_model()._clear_cache(group=group) CosinnusGroupMembership.clear_member_cache_for_group(group) # delete and recreate all group widgets (there might be different ones for group than for project) WidgetConfig.objects.filter(group_id=group.pk).delete() create_initial_group_widgets(group, group) if converted_names: message = _('The following Projects were converted to Groups:') + '\n' + ", ".join(converted_names) self.message_user(request, message, messages.SUCCESS) if refused_portal_names: message_error = 'These Projects could not be converted because they do not belong to this portal:' + '\n' + ", ".join(refused_portal_names) self.message_user(request, message_error, messages.ERROR)
def check_object_read_access(obj, user): """ Checks read permissions for a CosinnusGroup or BaseTaggableObject or any object with a creator attribute. Returns ``True`` if the user is either admin, staff member, group admin, group member, or the group is public. """ # check what kind of object was supplied (CosinnusGroup or BaseTaggableObject) if type(obj) is get_cosinnus_group_model() or issubclass( obj.__class__, get_cosinnus_group_model()): group = obj is_member = check_ug_membership(user, group) is_admin = check_ug_admin(user, group) return (group.public and user.is_authenticated() ) or check_user_superuser(user) or is_member or is_admin elif issubclass(obj.__class__, BaseTaggableObjectModel): group = obj.group is_member = check_ug_membership(user, group) is_admin = check_ug_admin(user, group) # items are readable only if their visibility tag is public, or it is set to group and a group member # is accessing the item, or the item's creator is accessing it if obj.media_tag: obj_is_visible = obj.creator == user or \ obj.media_tag.visibility == BaseTagObject.VISIBILITY_ALL or \ (obj.media_tag.visibility == BaseTagObject.VISIBILITY_GROUP and (is_member or is_admin)) elif issubclass( obj.__class__, BaseHierarchicalTaggableObjectModel) and obj.is_container: # folders do not have a media tag and inherit visibility from the group obj_is_visible = group.public or is_member or is_admin else: # catch error cases where no media_tag was created. that case should break, but not here. obj_is_visible = is_member or is_admin return check_user_superuser( user) or obj_is_visible or obj.grant_extra_read_permissions(user) elif type(obj) is CosinnusIdea: # ideas are only either public or visible by any logged in user, no private setting return obj.public or user.is_authenticated() elif issubclass(obj.__class__, BaseUserProfile): return check_user_can_see_user(user, obj.user) else: met_proper_object_conditions = False extra_conditions = False if hasattr(obj, 'grant_extra_read_permissions'): extra_conditions = extra_conditions or obj.grant_extra_read_permissions( user) met_proper_object_conditions = True if hasattr(obj, 'creator'): extra_conditions = extra_conditions or (obj.creator == user or check_user_superuser(user)) met_proper_object_conditions = True if not met_proper_object_conditions: raise Exception("cosinnus.core.permissions: You must either supply a CosinnusGroup " +\ "or a BaseTaggableObject or an object with a ``creator`` property " +\ "or an object with a ``grant_extra_read_permissions(self, user)`` function " +\ "to check_object_read_access(). The supplied object " +\ "type was: %s" % (str(obj.__class__) if obj else "None")) else: return extra_conditions
def check_object_likefollow_access(obj, user): """ Checks permissions of a user to like/follow an object. This permission may behave differently depending on the object model. """ # liking this object must be enabled and user logged in if not (getattr(obj, 'IS_LIKEABLE_OBJECT', False) or user.is_authenticated()): return False # groups can always be followed, and all other visible objects is_group = type(obj) is get_cosinnus_group_model() or issubclass(obj.__class__, get_cosinnus_group_model()) return is_group or check_object_read_access(obj, user)
def __init__(self, obj=None, is_emphasized=False, user=None): if obj: from cosinnus.templatetags.cosinnus_tags import full_name if is_emphasized: self['is_emphasized'] = is_emphasized # smart conversion by known models if type(obj) is get_cosinnus_group_model() or issubclass(obj.__class__, get_cosinnus_group_model()): self['icon'] = obj.get_icon() self['text'] = escape(obj.name) self['url'] = obj.get_absolute_url() elif type(obj) is CosinnusIdea: self['icon'] = obj.get_icon() self['text'] = escape(obj.title) self['url'] = obj.get_absolute_url() elif type(obj) is CosinnusOrganization: self['icon'] = 'fa-building' self['text'] = escape(obj.name) self['url'] = obj.get_absolute_url() elif isinstance(obj, NextcloudFileProxy): self['icon'] = 'fa-cloud' self['text'] = obj.name self['url'] = obj.url self['subtext'] = obj.excerpt elif obj._meta.model.__name__ == 'Message' and not settings.COSINNUS_ROCKET_ENABLED and not 'cosinnus_message' in settings.COSINNUS_DISABLED_COSINNUS_APPS: self['icon'] = 'fa-envelope' self['text'] = escape(obj.subject) self['url'] = reverse('postman:view_conversation', kwargs={'thread_id': obj.thread_id}) if obj.thread_id else obj.get_absolute_url() self['subtext'] = escape(', '.join([full_name(participant) for participant in obj.other_participants(user)])) elif issubclass(obj.__class__, BaseUserProfile): self['icon'] = obj.get_icon() self['text'] = escape(full_name(obj.user)) self['url'] = obj.get_absolute_url() elif BaseTaggableObjectModel in inspect.getmro(obj.__class__): self['icon'] = 'fa-question' self['text'] = escape(obj.get_readable_title()) self['url'] = obj.get_absolute_url() self['subtext'] = escape(obj.group.name) if hasattr(obj, 'get_icon'): self['icon'] = obj.get_icon() if obj.group.slug in get_default_user_group_slugs(): self['group'] = escape(CosinnusPortal.get_current().name) else: self['group'] = escape(obj.group.name) self['group_icon'] = obj.group.get_icon() if obj.__class__.__name__ == 'Event': if obj.state != 2: self['subtext'] = {'is_date': True, 'date': django_date_filter(obj.from_date, 'Y-m-d')}
def __init__(self, instance, *args, **kwargs): super(_CosinnusProjectForm, self).__init__(instance=instance, *args, **kwargs) # choosable groups are only the ones the user is a member of, and never the forum user_group_ids = list(CosinnusSociety.objects.get_for_user_pks(self.request.user)) # choosable are also conferences the user is an admin of user_conference_ids = list(CosinnusConference.objects.get_for_user_group_admin_pks(self.request.user)) conference_and_group_types = [get_cosinnus_group_model().TYPE_SOCIETY, get_cosinnus_group_model().TYPE_CONFERENCE] groups_and_conferences = get_cosinnus_group_model().objects.filter(type__in=conference_and_group_types) qs = groups_and_conferences.filter(portal=CosinnusPortal.get_current(), is_active=True, id__in=user_group_ids+user_conference_ids) forum_slug = getattr(settings, 'NEWW_FORUM_GROUP_SLUG', None) if forum_slug: qs = qs.exclude(slug=forum_slug) self.fields['parent'].queryset = qs
def _get_current_bbb_server_auth_pair(self, source_object=None): """ Central helper function to retrieve the currently selected BBB-server API URL and Secret. @return: tuple of (str: BBB_API_URL, str: BBB_SECRET_KEY) if a server is set, or (None, None) if no server is set """ current_portal = CosinnusPortal.get_current() if source_object is None: source_object = current_portal conference_settings = CosinnusConferenceSettings.get_for_object( source_object) if conference_settings: try: # find if the srouce object belongs to or is a group with premium status active bbb_server_choice = conference_settings.bbb_server_choice # if no object or portal is given, we always use the non-premium choice if not source_object is current_portal: # check if we can find a group in the source object's hierarchy chain checked_parent = source_object found_group = None for i in range(5): # max loop number if type(checked_parent) is get_cosinnus_group_model( ) or issubclass(checked_parent.__class__, get_cosinnus_group_model()): found_group = checked_parent break checked_parent = get_parent_object_in_conference_setting_chain( checked_parent) if checked_parent is None: break # if we have found a group, and that group has a premium status, we use # the premium server choice of the bbb server settings object if found_group and (found_group.is_premium): bbb_server_choice = conference_settings.bbb_server_choice_premium auth_pair = dict( settings.COSINNUS_BBB_SERVER_AUTH_AND_SECRET_PAIRS).get( bbb_server_choice) return (auth_pair[0], auth_pair[1] ) # force fail on improper tuple except Exception as e: logger.error( 'Misconfigured: Either COSINNUS_BBB_SERVER_CHOICES or COSINNUS_BBB_SERVER_AUTH_AND_SECRET_PAIRS are not properly set up!', extra={'exception': e}) return (None, None)
def get_context_data(self, **kwargs): forum_group = None forum_slug = getattr(settings, 'NEWW_FORUM_GROUP_SLUG', None) if forum_slug: forum_group = get_object_or_None( get_cosinnus_group_model(), slug=forum_slug, portal=CosinnusPortal.get_current()) note_form = None try: from cosinnus_note.forms import NoteForm note_form = NoteForm(group=forum_group) except: if settings.DEBUG: raise options = { 'ui_prefs': get_ui_prefs_for_user(self.request.user), } ctx = { 'user_dashboard_options_json': json.dumps(options), 'forum_group': forum_group, 'note_form': note_form, } return ctx
def get_queryset(self): include_uids = CosinnusPortal.get_current().groups.values_list('id', flat=True) queryset = get_cosinnus_group_model().objects.filter(id__in=include_uids) if hasattr(self, 'organization') and self.organization: exclude_uids = self.organization.groups.values_list('id', flat=True) queryset = queryset.exclude(id__in=exclude_uids) return queryset
def get_reflect_data(self, request, group, obj=None): # if this is a group or the Forum, we can select this event to be reflected into other groups reflect_is_forum = group.slug == getattr(settings, 'NEWW_FORUM_GROUP_SLUG', None) reflectable_groups = {} reflecting_group_ids = [] may_reflect = request.user.is_authenticated and \ ((group.type == group.TYPE_SOCIETY) or reflect_is_forum) if obj is None: return { 'may_reflect': may_reflect, } if may_reflect: # find all groups the user can reflect into (for the forum: all of theirs, for other groups, the subprojects) if reflect_is_forum: target_groups = get_cosinnus_group_model().objects.get_for_user(request.user) else: target_groups = group.get_children() target_groups = sorted(target_groups, key=lambda sortgroup: sortgroup.name.lower()) # find already-reflecting groups for this user reflecting_group_ids = BaseTaggableObjectReflection.get_group_ids_for_object(obj) reflectable_groups = [(target_group, target_group.id in reflecting_group_ids) for target_group in target_groups if target_group != group] ct = ContentType.objects.get_for_model(obj._meta.model) return { 'may_reflect': may_reflect, 'reflectable_groups': reflectable_groups, 'reflecting_group_ids': reflecting_group_ids, 'reflect_is_forum': reflect_is_forum, 'reflecting_object_id': obj.id, 'reflecting_object_content_type': '%s.%s' % (ct.app_label, ct.model), }
def confirm_page_admin(request, group_id): """ GET to this view to try to obtain a user access token for a facebook fan-page linked to the group_id supplied. Will always redirect to the group form's facebook tab. """ if not request.user.is_authenticated(): raise PermissionDenied group = get_object_or_404(get_cosinnus_group_model(), id=group_id) if not group.facebook_page_id: messages.error( request, _('This group does not have a Facebook Fan-Page associated with it!' )) if obtain_facebook_page_access_token_for_user(group, group.facebook_page_id, request.user): messages.success( request, _('Your Editor access for the linked Facebook Fan-Page was confirmed!' )) else: messages.warning( request, _('We could not obtain access to the Fan-Page for your connected Facebook Account. Please check that you entered the correct Fan-Page name, and that you are an Editor of that Fan-Page!' )) return redirect( group_aware_reverse('cosinnus:group-edit', kwargs={'group': group}) + '?tab=facebook', permanent=False)
class GroupSelect2MultipleChoiceField(Select2MultipleChoiceField): model = get_cosinnus_group_model() search_fields = [ 'name__icontains', ] data_view = '' select_type = 'group'
def do(self): field_names = ['week_before', 'day_before', 'hour_before'] queryset = get_cosinnus_group_model().objects for field_name in field_names: for conference in queryset.to_be_reminded(field_name=field_name): send_conference_reminder(conference, field_name=field_name) return
def filter_tagged_object_queryset_for_user(qs, user): """ A queryset filter to filter for TaggableObjects that respects the visibility tag of the object, checking group membership of the user and creator information of the object. This is used to filter all list views and queryset gets for BaseTaggableObjects. Since we are filtering on a many-to-many field (persons), we need to make the QS distinct. @return: the filtered queryset """ # always exclude all items from inactive groups qs = qs.filter(group__is_active=True) # admins may see everything if check_user_superuser(user): return qs q = Q(media_tag__isnull=True) # get all objects that don't have a media_tag (folders for example) q |= Q(media_tag__visibility=BaseTagObject.VISIBILITY_ALL) # All public tagged objects if user.is_authenticated(): gids = get_cosinnus_group_model().objects.get_for_user_pks(user) q |= Q( # all tagged objects in groups the user is a member of media_tag__visibility=BaseTagObject.VISIBILITY_GROUP, group_id__in=gids ) q |= Q( # all tagged objects the user is explicitly a linked to media_tag__visibility=BaseTagObject.VISIBILITY_USER, media_tag__persons__id__exact=user.id ) q |= Q( # all tagged objects of the user himself media_tag__visibility=BaseTagObject.VISIBILITY_USER, creator__id=user.id ) return qs.filter(q).distinct()
def get_data(self, *kwargs): followed = LikeObject.objects.filter(user=self.request.user, followed=True) objects = [] for follow in followed: ct = ContentType.objects.get_for_id(follow.content_type.id) obj = ct.get_object_for_this_type(pk=follow.object_id) # filter inactive groups if type(obj) is get_cosinnus_group_model() or issubclass( obj.__class__, get_cosinnus_group_model()): if not obj.is_active: continue dashboard_item = DashboardItem(obj) dashboard_item['id'] = obj.id dashboard_item['ct'] = obj.get_content_type() objects.append(dashboard_item) return {'items': objects}
def check_object_write_access(obj, user, fields=None): """ Checks write permissions for either a CosinnusGroup and BaseTaggableObject or any object with a creator attribute. For CosinnusGroups, check if the user can edit/update/delete the group iself: returns ``True`` if the user is either admin, staff member or group admin For BaseTaggableObjects, check if the user can edit/update/delete the item iself: returns ``True`` if the user is either admin, staff member, object owner or group admin of the group the item belongs to For Objects with a creator attribute, check if the user is the creator of that object or he is staff or admin. :param fields: Optional list of fields that are requested to be changed. This will be passed on to ` ``obj.grant_extra_write_permissions()`` so that objects can make fine-grained decisions whether to allow write access to only select fields. """ # check what kind of object was supplied (CosinnusGroup or BaseTaggableObject) if type(obj) is get_cosinnus_group_model() or issubclass( obj.__class__, get_cosinnus_group_model()): is_admin = check_ug_admin(user, obj) return is_admin or check_user_superuser(user) elif issubclass(obj.__class__, BaseTaggableObjectModel): # editing/deleting an object, check if we are owner or staff member or group admin or site admin is_admin = check_ug_admin(user, obj.group) if obj.group else False if obj.media_tag: is_private = obj.media_tag.visibility == BaseTagObject.VISIBILITY_USER else: # catch error cases where no media_tag was created. that case should break, but not here. is_private = False # folders can be edited by group members (except root folder) folder_for_group_member = issubclass(obj.__class__, BaseHierarchicalTaggableObjectModel) and \ obj.is_container and not obj.path == '/' and check_ug_membership(user, obj.group) return check_user_superuser(user) or obj.creator == user or (is_admin and not is_private) \ or obj.grant_extra_write_permissions(user, fields=fields) or folder_for_group_member elif issubclass(obj.__class__, BaseUserProfile): return obj.user == user or check_user_superuser(user) elif hasattr(obj, 'creator'): return obj.creator == user or check_user_superuser(user) elif hasattr(obj, 'grant_extra_write_permissions'): return obj.grant_extra_write_permissions( user, fields=fields) or check_user_superuser(user) raise Exception("cosinnus.core.permissions: You must either supply a CosinnusGroup " +\ "or a BaseTaggableObject or an object with a ``creator`` property " +\ "or an object with a ``grant_extra_write_permissions(self, user)`` function " +\ "to check_object_read_access(). The supplied object " +\ "type was: %s" % (str(obj.__class__) if obj else "None"))
def save_m2m(): old_save_m2m() new_group_slugs = [new_group.slug for new_group in self.cleaned_data['related_groups']] old_related_group_slugs = self.instance.related_groups.all().values_list('slug', flat=True) # remove no longer wanted related_groups for old_slug in old_related_group_slugs: if old_slug not in new_group_slugs: old_group_rel = get_object_or_None(RelatedGroups, to_group=self.instance, from_group__slug=old_slug) old_group_rel.delete() # add new related_groups user_group_ids = get_cosinnus_group_model().objects.get_for_user_pks(self.request.user) user_superuser = check_user_superuser(self.request.user) conference_notification_pairs = [] for related_group in self.cleaned_data['related_groups']: # non-superuser users can only tag groups they are in if not user_superuser and related_group.id not in user_group_ids: continue # only create group rel if it didn't exist existing_group_rel = get_object_or_None(RelatedGroups, to_group=self.instance, from_group=related_group) if not existing_group_rel: # create a new related group link RelatedGroups.objects.create(to_group=self.instance, from_group=related_group) # if the current group is a conference, and the related group is a society or project, # the conference will be reflected into the group, so we send a notification non_conference_group_types = [get_cosinnus_group_model().TYPE_PROJECT, get_cosinnus_group_model().TYPE_SOCIETY] if self.instance.group_is_conference and related_group.type in non_conference_group_types: audience_except_creator = [member for member in related_group.actual_members if member.id != self.request.user.id] # set the target group for the notification onto the group instance setattr(self.instance, 'notification_target_group', related_group) conference_notification_pairs.append((self.instance, audience_except_creator)) # send notifications in a session to avoid duplicate messages to any user session_id = uuid1().int for i, pair in enumerate(conference_notification_pairs): cosinnus_notifications.conference_created_in_group.send( sender=self, user=self.request.user, obj=pair[0], audience=pair[1], session_id=session_id, end_session=bool(i == len(conference_notification_pairs)-1) )
def make_marketplace_app_inactive_in_all_projects(apps, schema_editor): """ Sets cosinnus_marketplace as a disabled cosinnus app in all projects and groups """ CosinnusGroup = get_cosinnus_group_model() for group in CosinnusGroup.objects.all(): deactivated_apps = group.get_deactivated_apps() deactivated_apps.append('cosinnus_marketplace') group.deactivated_apps = ','.join(deactivated_apps) group.save(keep_unmodified=True, update_fields=['deactivated_apps'])
def convert_to_project(self, request, queryset): """ Converts this CosinnusGroup's type """ converted_names = [] refused_portal_names = [] for group in queryset: if group.portal_id != CosinnusPortal.get_current().id: refused_portal_names.append(group.name) continue group.type = CosinnusGroup.TYPE_PROJECT group.save(allow_type_change=True) if group.type == CosinnusGroup.TYPE_PROJECT: converted_names.append(group.name) CosinnusPermanentRedirect.create_for_pattern( group.portal, CosinnusGroup.TYPE_SOCIETY, group.slug, group) # all projects that had this group as parent, get set their parent=None and set this as related project # and all of those former child projects are also added as related to this newly-converted project for project in get_cosinnus_group_model().objects.filter( parent=group): project.parent = None project.save(update_fields=['parent']) RelatedGroups.objects.get_or_create(from_group=project, to_group=group) RelatedGroups.objects.get_or_create(from_group=group, to_group=project) # we beat the cache with a hammer on all class models, to be sure CosinnusProject._clear_cache(group=group) CosinnusSociety._clear_cache(group=group) get_cosinnus_group_model()._clear_cache(group=group) CosinnusGroupMembership.clear_member_cache_for_group(group) # delete and recreate all group widgets (there might be different ones for group than for porject) WidgetConfig.objects.filter(group_id=group.pk).delete() create_initial_group_widgets(group, group) if converted_names: message = _('The following Groups were converted to Projects:' ) + '\n' + ", ".join(converted_names) self.message_user(request, message, messages.SUCCESS) if refused_portal_names: message_error = 'These Groups could not be converted because they do not belong to this portal:' + '\n' + ", ".join( refused_portal_names) self.message_user(request, message_error, messages.ERROR)
def filter_searchqueryset_for_read_access(sqs, user): """ Given a SearchQuerySet, this function adds a filter that limits the result set to only include elements with read access. """ public_node = ( SQ(public__exact=True) | # public on the object itself (applicable for groups) SQ(mt_visibility__exact=BaseTagObject.VISIBILITY_ALL) | # public via "everyone can see me" visibility meta attribute SQ( always_visible__exact=True ) # special marker for indexed objects that should always show up in search ) if user.is_authenticated(): if check_user_superuser(user): pass else: logged_in_user_visibility = ( SQ(user_visibility_mode__exact=True) & # for UserProfile search index objects SQ( mt_visibility__exact=BaseTagObject.VISIBILITY_GROUP ) # logged in users can see users who are visible ) my_item = (SQ(creator__exact=user.id)) visible_for_all_authenticated_users = (SQ( visible_for_all_authenticated_users=True)) # FIXME: known problem: ``group_members`` is a stale indexed representation of the members # of an items group. New members of a group won't be able to find old indexed items if the index # is not refreshed regularly group_visible_and_in_my_group = ( SQ(mt_visibility__exact=BaseTagObject.VISIBILITY_GROUP) & SQ(group_members__contains=user.id)) ored_query = public_node | group_visible_and_in_my_group | my_item \ | logged_in_user_visibility | visible_for_all_authenticated_users users_group_ids = get_cosinnus_group_model( ).objects.get_for_user_pks(user) if users_group_ids: group_member_user_visibility = ( SQ(user_visibility_mode__exact=True) & # for UserProfile search index objects SQ(mt_visibility__exact=BaseTagObject.VISIBILITY_USER) & # team mambers can see this user SQ(membership_groups__in=users_group_ids)) ored_query = ored_query | group_member_user_visibility sqs = sqs.filter_and(ored_query) else: sqs = sqs.filter_and(public_node) return sqs
def __init__(self, *args, **kwargs): super(FormAttachableMixin, self).__init__(*args, **kwargs) # retrieve the attached objects ids to select them in the update view preresults = [] if self.instance and self.instance.pk and self.instance.attached_objects is not None: for attached in self.instance.attached_objects.all(): if attached and attached.target_object: obj = attached.target_object text_only = ( attached.model_name + ":" + str(obj.id), "%s" % (obj.title), ) #text_only = (attached.model_name+":"+str(obj.id), "<i>%s</i> %s" % (attached.model_name, obj.title),) # TODO: sascha: returning unescaped html here breaks the javascript of django-select2 html = build_attachment_field_result( attached.model_name, obj) preresults.append(text_only) # add a field for each model type of attachable file provided by cosinnus apps # each field's name is something like 'attached:cosinnus_file.FileEntry' # and fill the field with all available objects for that type (this is passed from our view) source_model_id = self._meta.model._meta.app_label + '.' + self._meta.model._meta.object_name # get target groups to add newly attached files to target_group = getattr(self, 'group', None) if not target_group: # if this form's model has no group, it may be a global object that can still have attachments, # so fall back to the forum group to add attached objects to. if this doesn't exist, attaching in not possible. forum_slug = getattr(settings, 'NEWW_FORUM_GROUP_SLUG', None) if forum_slug: target_group = get_object_or_None( get_cosinnus_group_model(), slug=forum_slug, portal=CosinnusPortal.get_current()) """ Add attachable objects field if this model is configured in settings.py to have objects that can be attached to it """ if target_group and attached_object_registry.get_attachable_to( source_model_id): self.fields[ 'attached_objects'] = AttachableObjectSelect2MultipleChoiceField( label=_("Attachments"), help_text=_("Type the title and/or type of attachment"), data_url=group_aware_reverse( 'cosinnus:attached_object_select2_view', kwargs={ 'group': target_group, 'model': source_model_id }), required=False) # we need to cheat our way around select2's annoying way of clearing initial data fields self.fields['attached_objects'].choices = preresults #((1, 'hi'),) self.fields['attached_objects'].initial = [ key for key, val in preresults ] #[1] setattr(self, 'target_group', target_group)
def get_group_clusters(self, user, sort_by_activity=False): clusters = [] projects = list(CosinnusProject.objects.get_for_user(user)) societies = list(CosinnusSociety.objects.get_for_user(user)) group_ct = ContentType.objects.get_for_model( get_cosinnus_group_model()) if sort_by_activity: group_last_visited_qs = LastVisitedObject.objects.filter( user=user, content_type=group_ct, portal=CosinnusPortal.get_current()) # a dict of group-id -> datetime group_last_visited = dict( group_last_visited_qs.values_list('object_id', 'visited')) else: group_last_visited = {} default_date = now() - relativedelta(years=100) class AttrList(list): last_visited = None for society in societies: if society.slug in get_default_user_group_slugs(): continue # the most recent visit time to any project or society in the cluster most_recent_dt = group_last_visited.get(society.id, default_date) items = AttrList([DashboardItem(society, is_emphasized=True)]) for i in range(len(projects) - 1, -1, -1): project = projects[i] if project.parent == society: items.append(DashboardItem(project)) projects.pop(i) project_dt = group_last_visited.get( project.id, default_date) most_recent_dt = project_dt if project_dt > most_recent_dt else most_recent_dt items.last_visited = most_recent_dt clusters.append(items) # add unclustered projects as own cluster for proj in projects: items = AttrList([DashboardItem(proj)]) items.last_visited = group_last_visited.get(proj.id, default_date) clusters.append(items) # sort clusters by last_visited if sort_by_activity: clusters = sorted(clusters, key=lambda cluster: cluster.last_visited, reverse=True) return clusters
def __init__(self, instance, *args, **kwargs): if 'request' in kwargs: self.request = kwargs.pop('request') super(CosinnusConferenceRoomForm, self).__init__(instance=instance, *args, **kwargs) # choosable groups are only projects inside this group qs = get_cosinnus_group_model().objects.filter( parent_id=kwargs['group'].id) self.fields['target_result_group'].queryset = qs if instance and instance.pk: self.fields['type'].disabled = True
def get_results(self, request, term, page, context): term = term.lower() start = (page - 1) * 10 end = page * 10 q = Q(name__icontains=term) # add all extra lookup fields defined by swapped out group models for lookup_field in get_cosinnus_group_model().NAME_LOOKUP_FIELDS: if lookup_field != 'name': q = q | Q(**{lookup_field + '__icontains': term}) qs = get_cosinnus_group_model().objects.filter(q).filter( portal_id=CosinnusPortal.get_current().id, is_active=True) # non-superusers may only select groups they are in if not check_user_superuser(request.user): user_group_ids = get_cosinnus_group_model( ).objects.get_for_user_pks(request.user) qs = qs.filter(id__in=user_group_ids) if request.GET.get('except', None): qs = qs.exclude(id=int(request.GET.get('except'))) # TODO: also search russian/other extension fields of name, make a good interface to generically grab those count = qs.count() if count < start: raise Http404 has_more = count > end groups = [] for group in qs[start:end]: # do/do not return the forum group #if group.slug == getattr(settings, 'NEWW_FORUM_GROUP_SLUG', None): # continue # access group.name by its dict lookup to support translation magic groups.append((group.id, group['name'])) return (NO_ERR_RESP, has_more, groups)
def get_parent_object_in_conference_setting_chain(source_object): """ Will traverse upwards one step in the conference-setting hierarchy chain for the given object and return that higher-level object. The hierarchy chain is: - cosinnus.BBBRoom - cosinnus_event.ConferenceEvent - cosinnus.CosinnusConferenceRoom - cosinnus.CosinnusGroup - cosinnus.CosinnusPortal @param return: None if it arrived at CosinnusPortal or was given None. Else, the higher object in the chain. """ if source_object is None: return None try: from cosinnus_event.models import ConferenceEvent # noqa except ImportError: ConferenceEvent = None from cosinnus.models.bbb_room import BBBRoom # BBBRoom --> tagged object for this room if there is one if type(source_object) is BBBRoom and ConferenceEvent is not None: conference_event = get_object_or_None( ConferenceEvent, media_tag__bbb_room=source_object) return conference_event # ConferenceEvent --> CosinnusConferenceRoom if ConferenceEvent is not None and type(source_object) is ConferenceEvent: return source_object.room # ConferenceRoom --> CosinnusGroup if type(source_object) is CosinnusConferenceRoom: return source_object.group # CoinnusGroup --> CosinnusPortal if type(source_object) is get_cosinnus_group_model() or issubclass( source_object.__class__, get_cosinnus_group_model()): return source_object.portal # else: return None return None
def user_unfollow_left_group_trigger(sender, user, group, **kwargs): """ Will automatically make a user unfollow a group after they left it """ group_ct = ContentType.objects.get_for_model( get_cosinnus_group_model()) # get an existing following object likeobj = get_object_or_None(LikeObject, content_type=group_ct, object_id=group.id, user=user, followed=True) # make the followed likeobject unfollowed if it exists if likeobj: likeobj.followed = False likeobj.save(update_fields=['followed']) group.clear_likes_cache()
def save(self, *args, **kwargs): created = bool(self.pk is None) slugs = [self.slug] if self.slug else [] self.title = clean_single_line_text(self.title) current_portal = self.portal or CosinnusPortal.get_current() unique_aware_slugify(self, 'title', 'slug', portal_id=current_portal) if not self.slug: raise ValidationError(_('Slug must not be empty.')) slugs.append(self.slug) # sanity check for missing media_tag: if not self.media_tag: from cosinnus.models.tagged import get_tag_object_model media_tag = get_tag_object_model()._default_manager.create() self.media_tag = media_tag if created and not self.portal: # set portal to current self.portal = CosinnusPortal.get_current() super(CosinnusIdea, self).save(*args, **kwargs) self._clear_cache(slugs=slugs) # force rebuild the pk --> slug cache. otherwise when we query that, this group might not be in it self.__class__.objects.get_pks(force=True) self._portal_id = self.portal_id self._slug = self.slug if created: forum_slug = getattr(settings, 'NEWW_FORUM_GROUP_SLUG', None) if forum_slug: forum_group = get_object_or_None( get_cosinnus_group_model(), slug=forum_slug, portal=CosinnusPortal.get_current()) if forum_group: # send creation signal signals.idea_object_ceated.send(sender=self, group=forum_group) # we need to patch a group onto the idea, because notifications need a group setattr(self, 'group', forum_group) # the audience is empty because this is a moderator-only notification cosinnus_notifications.idea_created.send(sender=self, user=self.creator, obj=self, audience=[])
def group_aware_reverse(viewname, urlconf=None, args=None, kwargs=None, prefix=None, current_app=None, skip_domain=False): """ CosinnusGroup.type aware, and Portal aware function that returns reverse URLs pointing to the correct Portal domain and the correct group type URL (society, project). NOTE: This will return a full URL, including protocol: ex.: http://wachstumswende.de/group/Blog/note/list/ WARNING: You MUST pass a group-object to kwargs['group'], not a slug, if you want to use the function's Portal-awareness! """ domain = '' if 'group' in kwargs: global _group_aware_url_name if not hasattr(_group_aware_url_name, '__call__'): _group_aware_url_name = import_module( 'cosinnus.templatetags.cosinnus_tags').group_aware_url_name portal_id = None if issubclass(kwargs['group'].__class__, get_cosinnus_group_model()): """ We accept a group object and swap it for its slug """ group = kwargs['group'] portal_id = group.portal_id domain = get_domain_for_portal(group.portal) kwargs['group'] = group.slug else: group = kwargs['group'] viewname = _group_aware_url_name(viewname, group, portal_id=portal_id) else: global _CosinnusPortal if _CosinnusPortal is None: _CosinnusPortal = apps.get_model('cosinnus', 'CosinnusPortal') domain = get_domain_for_portal(_CosinnusPortal.get_current()) # NOTE: this used to be: reverse(viewname, urlconf, args, kwargs, prefix, current_app) in Django 1.8 # we simply removed the prefix arg as it should still work return ('' if skip_domain else domain) + reverse(viewname, urlconf, args, kwargs, current_app)
def get_results(self, request, term, page, context): terms = term.strip().lower().split(' ') q = get_group_query_filter_for_search_terms(terms) groups = get_cosinnus_group_model().objects.filter(q) groups = groups.filter(portal_id=CosinnusPortal.get_current().id, is_active=True) groups = groups.exclude(organizations__organization=self.organization) groups = [ group for group in groups if check_object_read_access(group, request.user) ] groups = sorted(groups, key=lambda org: org.name.lower()) results = get_group_select2_pills(groups) # Any error response, Has more results, options list return (NO_ERR_RESP, False, results)