예제 #1
0
def render_cosinnus_topics_field(escape_html=None):
    topics = CommaSeparatedSelect2MultipleChoiceField(choices=TAG_OBJECT.TOPIC_CHOICES, required=False, 
            widget=CommaSeparatedSelect2MultipleWidget(select2_options={'closeOnSelect': 'true'}))
    topics_field_name = 'topics'
    topics_field_value = None
    topics_html = topics.widget.render(topics_field_name, topics_field_value, {'id': 'id_topics', 'placeholder': _('Topics')})
    topics_html = topics_html.replace('\r', '').replace('\n', '')
    if escape_html:
        topics_html = escape(topics_html)
    return topics_html
예제 #2
0
class BaseTagObjectForm(GroupKwargModelFormMixin, UserKwargModelFormMixin,
                        forms.ModelForm):

    like = forms.BooleanField(label=_('Like'), required=False)
    approach = Select2ChoiceField(choices=TagObject.APPROACH_CHOICES,
                                  required=False)
    topics = CommaSeparatedSelect2MultipleChoiceField(
        choices=TagObject.TOPIC_CHOICES, required=False)
    visibility = Select2ChoiceField(
        choices=TagObject.VISIBILITY_CHOICES,
        required=False,
        widget=Select2Widget(select2_options={'allowClear': False})
    )  # the widget currently ignores the allowClear setting!

    # persons = will be defined in __init__

    class Meta(object):
        model = TagObject
        exclude = (
            'group',
            'likes',
            'likers',
        )
        widgets = {
            'location_lat': forms.HiddenInput(),
            'location_lon': forms.HiddenInput(),
        }

    def __init__(self, *args, **kwargs):
        """ Initialize and populate the select2 tags field
        """
        super(BaseTagObjectForm, self).__init__(*args, **kwargs)

        # needs to be initialized here because using reverser_lazy() at model instantiation time causes problems
        self.fields['tags'] = TagSelect2Field(
            required=False, data_url=reverse_lazy('cosinnus:select2:tags'))
        # inherit tags from group for new TaggableObjects
        preresults = []
        if self.instance.pk:
            preresults = self.instance.tags.values_list('name', 'name').all()
        elif self.group:
            preresults = self.group.media_tag.tags.values_list('name',
                                                               'name').all()

        if preresults:
            self.fields['tags'].choices = preresults
            self.fields['tags'].initial = [
                key for key, val in preresults
            ]  #[tag.name for tag in self.instance.tags.all()]
            self.initial['tags'] = self.fields['tags'].initial

        # if no media tag data was supplied the object was created directly and not through a frontend form
        # we then manually inherit the group's media_tag topics by adding them to the data
        # (usually they would have been added into the form's initial data)
        if self.data and not any(
            [key.startswith('media_tag-') for key in list(self.data.keys())]
        ) and self.group and self.group.media_tag and self.group.media_tag.topics:
            self.data._mutable = True
            self.data.setlist('media_tag-topics',
                              self.group.media_tag.topics.split(','))

        if self.group and not self.instance.pk:
            # for new TaggableObjects (not groups), set the default visibility corresponding to the group's public status
            self.fields[
                'visibility'].initial = get_inherited_visibility_from_group(
                    self.group)

        if self.group:
            data_url = group_aware_reverse('cosinnus:select2:group-members',
                                           kwargs={'group': self.group})
        else:
            data_url = reverse('cosinnus:select2:all-members')

        # override the default persons field with select2
        #self.fields['persons'] = HeavySelect2MultipleChoiceField(label=_("Persons"), help_text='', required=False, data_url=data_url)
        self.fields['persons'] = UserSelect2MultipleChoiceField(
            label=_("Persons"),
            help_text='',
            required=False,
            data_url=data_url)

        if self.instance.pk:
            # choices and initial must be set so pre-existing form fields can be prepopulated
            preresults = get_user_select2_pills(self.instance.persons.all(),
                                                text_only=False)
            self.fields['persons'].choices = preresults
            self.fields['persons'].initial = [key for key, val in preresults]
            self.initial['persons'] = self.fields['persons'].initial

        if self.group and self.group.media_tag_id:
            group_media_tag = self.group.media_tag
            if group_media_tag and group_media_tag is not self.instance:
                # We must only take data from the group's media tag iff we are
                # working on a TaggableObjectModel, not on a group
                opts = self._meta

                # 1. Use all the data from the group's media tag
                # 2. Use the explicitly defined initial data (self.initial) and
                #    override the data from the group media tag
                # 3. Set the combined data as new initial data
                group_data = forms.model_to_dict(group_media_tag, opts.fields,
                                                 opts.exclude)
                group_data.update(self.initial)

                old_initial = self.initial
                self.initial = group_data

                # the default visibility corresponds to group's public setting
                if 'visibility' in old_initial:
                    self.initial['visibility'] = old_initial['visibility']
                else:
                    self.initial[
                        'visibility'] = get_inherited_visibility_from_group(
                            self.group)

        if (self.user and self.instance.pk
                and self.instance.likers.filter(id=self.user.id).exists()):
            self.fields['like'].initial = True

        # use select2 widgets for m2m fields
        for field in [
                self.fields['text_topics'],
        ]:
            if type(field.widget) is SelectMultiple:
                field.widget = Select2MultipleWidget(choices=field.choices)

        # since the widget currently ignores the allowClear setting we have
        # to use this hack to remove the clear-button
        self.fields['visibility'].widget.is_required = True

        # save BBB room
        if self.instance.pk and self.instance.bbb_room:
            self.initial['bbb_room'] = self.instance.bbb_room

    def save(self, commit=True):
        self.instance = super(BaseTagObjectForm, self).save(commit=False)

        # restore BBB room
        if 'bbb_room' in self.initial:
            self.instance.bbb_room = self.initial['bbb_room']

        # the tag inherits the visibility default from the instance's group
        # if no or no valid visibility has been selected in the form,
        visibility_data_value = get_int_or_None(
            self.cleaned_data.get('visibility', None))
        if visibility_data_value not in BaseTagObject.VISIBILITY_VALID_VALUES:
            # check if our tag object belongs to a group (i.e: isn't itself a group, or a user):
            if hasattr(self.instance, 'group') and self.instance.group:
                self.instance.visibility = get_inherited_visibility_from_group(
                    self.instance.group)

        if self.user:
            if not self.instance.pk:
                # We need to save the tag here to allow add/remove of the user
                self.instance.save()

            if self.cleaned_data.get('like', False):
                self.instance.likers.add(self.user)
            else:
                self.instance.likers.remove(self.user)
            # like count is updated in model.save()

        if commit:
            self.instance.save()
            # For future reference: we skip the call to `save_m2m` here, because the django-multiform `MultiModelForm` already calls it!
            # This should be safe, but maybe in a bug corner case it could cause the `save_m2m` call to be skipped entirely
            # self.save_m2m()
        return self.instance
예제 #3
0
class TaggableModelSearchForm(SearchForm):
    """
    This is almost the same search form as shipped with django-haystack except
    it limits the choices to models that are a subclasses of the
    :class:`~cosinnus.models.BaseTaggableObjectModel`.
    """
    
    MAX_RESULTS = 200

    groups = forms.ChoiceField(label=_('Limit to teams'), required=False, initial='all',
        choices=(('all', _('All')), ('mine', _('My teams')), ('others', _('Other teams'))),
        widget=forms.RadioSelect)
    models = forms.MultipleChoiceField(required=False)
    topics = CommaSeparatedSelect2MultipleChoiceField(required=False, choices=BaseTagObject.TOPIC_CHOICES,
            widget=CommaSeparatedSelect2MultipleWidget(select2_options={'closeOnSelect': 'true'}))

    location = forms.CharField(required=False)
    valid_start = forms.DateField(required=False)
    valid_end = forms.DateField(required=False)
    
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request')
        super(TaggableModelSearchForm, self).__init__(*args, **kwargs)
        self.fields['models'].choices = list(MODEL_ALIASES.items())

    def get_models(self):
        """ Return the models of types user has selected to filter search on """
        search_models = []

        if self.is_valid():
            # we either use the models given to us from the form, or if empty,
            # all models available for search
            model_aliases_query = self.cleaned_data.get('models', [])
            if not model_aliases_query:
                model_aliases_query = list(MODEL_ALIASES.keys())
            for model_alias in model_aliases_query:
                if model_alias in list(MODEL_ALIASES.keys()):
                    model_string = MODEL_ALIASES[model_alias]
                    if model_string == '<userprofile>':
                        model = get_user_profile_model()
                    else:
                        model = apps.get_model(*model_string.split('.'))
                    search_models.append(model)
        
        return search_models

    def search(self):
        sqs = super(TaggableModelSearchForm, self).search()
        
        if hasattr(self, 'cleaned_data'):
            sqs = filter_searchqueryset_for_read_access(sqs, self.request.user)
            sqs = filter_searchqueryset_for_portal(sqs)
            sqs = self._filter_group_selection(sqs)
            sqs = self._filter_media_tags(sqs)
            if self.cleaned_data.get('q', None):
                sqs = self._boost_search_query(sqs)
            if self.request.GET.get('o', None) == 'newest':
                sqs = sqs.order_by('-created', '-_score')
        ret = sqs.models(*self.get_models())
        ret = ret[:self.MAX_RESULTS]
        return ret
    
    def no_query_found(self):
        """ Overriding default behaviour to allow topic searches without textual query. """
        if hasattr(self, 'cleaned_data') and self.cleaned_data.get('topics', None):
            return self.searchqueryset.all()
        return EmptySearchQuerySet()

    def _boost_search_query(self, sqs):
        q = self.cleaned_data['q']
        sqs = sqs.filter(SQ(boosted=AutoQuery(q)) | SQ(text=AutoQuery(q)))
        return sqs

    def _filter_group_selection(self, sqs):
        """
        Checks the request for an query parameter ``groups`` which can be one of

        ``all``
            Don't filter on groups (except the respective permissions)

        ``mine``
            Only include results of groups the current user is a member of

        ``others``
            Only include results of groups the current user is not a member of

        Any other value will be interpreted as ``all``.
        """
        user = self.request.user
        if user.is_authenticated:
            term = self.cleaned_data.get('groups', 'all').lower()
            if term == 'mine':
                sqs = sqs.filter_and(group_members__contains=user.id)
            elif term == 'others':
                sqs = sqs.exclude(group_members__contains=user.id)
            else:
                pass
        # we don't need to limit the result set on anonymous user. They are not
        # a member of any group.
        return sqs

    def _filter_media_tags(self, sqs):
        topics = ensure_list_of_ints(self.cleaned_data.get('topics', []))
        if topics:
            sqs = sqs.filter_and(mt_topics__in=topics)
        location = self.cleaned_data.get('location', None)
        if location:
            sqs = sqs.filter_and(mt_location__contains=location.lower())
        start = self.cleaned_data.get('valid_start', None)
        if start:
            sqs = sqs.filter_and(mt_valid_start__gte=start)
        end = self.cleaned_data.get('valid_end', None)
        if end:
            sqs = sqs.filter_and(mt_valid_end__gte=end)
        return sqs