Beispiel #1
0
    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
Beispiel #3
0
 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)
Beispiel #4
0
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
Beispiel #5
0
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)
Beispiel #6
0
    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')}
Beispiel #7
0
 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)
Beispiel #9
0
    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
Beispiel #10
0
 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),
     }
Beispiel #12
0
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)
Beispiel #13
0
class GroupSelect2MultipleChoiceField(Select2MultipleChoiceField):
    model = get_cosinnus_group_model()
    search_fields = [
        'name__icontains',
    ]
    data_view = ''
    select_type = 'group'
Beispiel #14
0
 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
Beispiel #15
0
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}
Beispiel #17
0
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"))
Beispiel #18
0
 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'])
Beispiel #20
0
    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)
Beispiel #21
0
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), "&lt;i&gt;%s&lt;/i&gt; %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)
Beispiel #23
0
    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
Beispiel #24
0
    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
Beispiel #25
0
    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)
Beispiel #26
0
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
Beispiel #27
0
 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()
Beispiel #28
0
    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=[])
Beispiel #29
0
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)
Beispiel #30
0
    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)