Example #1
0
class GroupMembershipForm(forms.Form):
    selected_ids = forms.Field(
        label=ugettext_lazy("Group Membership"),
        required=False,
        widget=Select2Ajax(multiple=True),
    )

    def __init__(self, group_api_url, *args, **kwargs):
        submit_label = kwargs.pop('submit_label', "Update")
        fieldset_title = kwargs.pop(
            'fieldset_title', ugettext_lazy("Edit Group Membership"))

        super(GroupMembershipForm, self).__init__(*args, **kwargs)
        self.fields['selected_ids'].widget.set_url(group_api_url)

        self.helper = FormHelper()
        self.helper.label_class = 'col-sm-3 col-md-2'
        self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6'
        self.helper.form_tag = False

        self.helper.layout = crispy.Layout(
            crispy.Fieldset(
                fieldset_title,
                crispy.Field('selected_ids'),
            ),
            hqcrispy.FormActions(
                crispy.ButtonHolder(
                    Submit('submit', submit_label)
                )
            )
        )
Example #2
0
class UsersAtLocationForm(forms.Form):
    selected_ids = forms.Field(
        label=ugettext_lazy("Workers at Location"),
        required=False,
        widget=Select2Ajax(multiple=True),
    )

    def __init__(self, domain_object, location, *args, **kwargs):
        self.domain_object = domain_object
        self.location = location
        super(UsersAtLocationForm, self).__init__(
            initial={'selected_ids': self.get_users_at_location()},
            prefix="users", *args, **kwargs
        )

        from corehq.apps.reports.filters.api import MobileWorkersOptionsView
        self.fields['selected_ids'].widget.set_url(
            reverse(MobileWorkersOptionsView.urlname, args=(self.domain_object.name,))
        )
        self.fields['selected_ids'].widget.set_initial(self.get_users_at_location())
        self.helper = FormHelper()
        self.helper.label_class = 'col-sm-3 col-md-2'
        self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6'
        self.helper.form_tag = False

        self.helper.layout = crispy.Layout(
            crispy.Fieldset(
                _("Specify Workers at this Location"),
                crispy.Field('selected_ids'),
            ),
            hqcrispy.FormActions(
                crispy.ButtonHolder(
                    Submit('submit', ugettext_lazy("Update Location Membership"))
                )
            )
        )

    # Adding a 5 second timeout because that is the elasticsearch refresh interval.
    @memoized
    @quickcache(['self.domain_object.name', 'self.location.location_id'], memoize_timeout=0, timeout=5)
    def get_users_at_location(self):
        user_query = UserES().domain(
            self.domain_object.name
        ).mobile_users().location(
            self.location.location_id
        ).fields(['_id', 'username', 'first_name', 'last_name'])
        return [
            dict(id=u['_id'], text=user_display_string(
                u['username'], u.get('first_name', ''), u.get('last_name', '')
            )) for u in user_query.run().hits]

    def unassign_users(self, users):
        for doc in iter_docs(CommCareUser.get_db(), users):
            # This could probably be sped up by bulk saving, but there's a lot
            # of stuff going on - seems tricky.
            CommCareUser.wrap(doc).unset_location_by_id(self.location.location_id, fall_back_to_next=True)

    def assign_users(self, users):
        for doc in iter_docs(CommCareUser.get_db(), users):
            CommCareUser.wrap(doc).add_to_assigned_locations(self.location)

    def clean_selected_ids(self):
        # Django uses get by default, but selected_ids is actually a list
        return self.data.getlist('users-selected_ids')

    def save(self):
        selected_users = set(self.cleaned_data['selected_ids'])
        previous_users = set([u['id'] for u in self.get_users_at_location()])
        to_remove = previous_users - selected_users
        to_add = selected_users - previous_users
        self.unassign_users(to_remove)
        self.assign_users(to_add)
        self.cache_users_at_location(selected_users)

    def cache_users_at_location(self, selected_users):
        user_cache_list = []
        for doc in iter_docs(CommCareUser.get_db(), selected_users):
            display_username = user_display_string(
                doc['username'], doc.get('first_name', ''), doc.get('last_name', ''))
            user_cache_list.append({'text': display_username, 'id': doc['_id']})
        self.get_users_at_location.set_cached_value(self).to(user_cache_list)
Example #3
0
class DashboardFeedFilterForm(forms.Form):
    """
    A form used to configure the filters on a Dashboard Feed export
    """
    emwf_case_filter = forms.Field(
        label=ugettext_lazy("Case Owner(s)"),
        required=False,
        widget=Select2Ajax(multiple=True),
        help_text=ExpandedMobileWorkerFilter.location_search_help,
    )
    emwf_form_filter = forms.Field(
        label=ugettext_lazy("User(s)"),
        required=False,
        widget=Select2Ajax(multiple=True),
        help_text=ExpandedMobileWorkerFilter.location_search_help,
    )
    date_range = forms.ChoiceField(
        label=ugettext_lazy("Date Range"),
        required=True,
        initial="last7",
        choices=[
            ("last7", ugettext_lazy("Last 7 days")),
            ("last30", ugettext_lazy("Last 30 days")),
            ("lastmonth", ugettext_lazy("Last month")),
            ("lastyear", ugettext_lazy("Last year")),
            ("lastn", ugettext_lazy("Days ago")),
            ("since", ugettext_lazy("Since a date")),
            ("range", ugettext_lazy("From a date to a date")),
        ],
        help_text='''
            <span data-bind='visible: showEmwfFormFilter'>{}</span>
            <span data-bind='visible: showEmwfCaseFilter'>{}</span>
        '''.format(
            ugettext_lazy("Export forms received in this date range."),
            ugettext_lazy("Export cases modified in this date range."),
        ))
    days = forms.IntegerField(
        label=ugettext_lazy("Number of Days"),
        required=False,
    )
    start_date = forms.DateField(
        label=ugettext_lazy("Begin Date"),
        required=False,
        widget=forms.DateInput(format="%Y-%m-%d",
                               attrs={"placeholder": "YYYY-MM-DD"}),
        help_text="<small class='label label-default'>{}</small>".format(
            ugettext_lazy("YYYY-MM-DD")),
    )
    end_date = forms.DateField(
        label=ugettext_lazy("End Date"),
        required=False,
        widget=forms.DateInput(format="%Y-%m-%d",
                               attrs={"placeholder": "YYYY-MM-DD"}),
        help_text="<small class='label label-default'>{}</small>".format(
            ugettext_lazy("YYYY-MM-DD")),
    )

    def __init__(self, domain_object, *args, **kwargs):
        self.domain_object = domain_object
        super(DashboardFeedFilterForm, self).__init__(*args, **kwargs)

        self.fields['emwf_case_filter'].widget.set_url(
            reverse(CaseListFilter.options_url,
                    args=(self.domain_object.name, )))
        self.fields['emwf_form_filter'].widget.set_url(
            reverse(ExpandedMobileWorkerFilter.options_url,
                    args=(self.domain_object.name, )))

        self.helper = HQModalFormHelper()
        self.helper.form_tag = False
        self.helper.layout = Layout(*self.layout_fields)

    def clean(self):
        cleaned_data = super(DashboardFeedFilterForm, self).clean()
        errors = []

        if cleaned_data['emwf_form_filter'] and cleaned_data[
                'emwf_case_filter']:
            # This should only happen if a user builds the reqest manually or there is an error rendering the form
            forms.ValidationError(
                _("Cannot submit case and form users and groups filter"))

        date_range = cleaned_data['date_range']
        if date_range in ("since", "range") and not cleaned_data.get(
                'start_date', None):
            errors.append(
                forms.ValidationError(_("A valid start date is required")))
        if date_range == "range" and not cleaned_data.get('end_date', None):
            errors.append(
                forms.ValidationError(_("A valid end date is required")))
        if errors:
            raise forms.ValidationError(errors)

    def format_export_data(self, export):
        return {
            'domain': self.domain_object.name,
            'sheet_name': export.name,
            'export_id': export.get_id,
            'export_type': self._export_type,
            'name': export.name,
            'edit_url': self.get_edit_url(export),
        }

    @property
    def layout_fields(self):
        return [
            crispy.Div(
                crispy.Field('emwf_case_filter', ),
                data_bind="visible: showEmwfCaseFilter",
            ),
            crispy.Div(
                crispy.Field('emwf_form_filter', ),
                data_bind="visible: showEmwfFormFilter",
            ),
            crispy.Field(
                'date_range',
                data_bind='value: dateRange',
            ),
            crispy.Div(
                crispy.Field("days", data_bind="value: days"),
                data_bind="visible: showDays",
            ),
            crispy.Div(
                crispy.Field(
                    "start_date",
                    data_bind="value: startDate",
                ),
                data_bind=
                "visible: showStartDate, css: {'has-error': startDateHasError}",
            ),
            crispy.Div(
                crispy.Field(
                    "end_date",
                    data_bind="value: endDate",
                ),
                data_bind=
                "visible: showEndDate, css: {'has-error': endDateHasError}",
            )
        ]

    def to_export_instance_filters(self, can_access_all_locations,
                                   accessible_location_ids, export_type):
        """
        Serialize the bound form as an ExportInstanceFilters object.
        """
        # Confirm that either form filter data or case filter data but not both has been submitted.
        assert ((self.cleaned_data['emwf_form_filter'] is not None) !=
                (self.cleaned_data['emwf_case_filter'] is not None))
        assert (export_type == 'form' or export_type == 'case')
        if export_type == 'form':
            return self._to_form_export_instance_filters(
                can_access_all_locations, accessible_location_ids)
        else:
            return self._to_case_export_instance_filters(
                can_access_all_locations, accessible_location_ids)

    def _to_case_export_instance_filters(self, can_access_all_locations,
                                         accessible_location_ids):
        emwf_selections = self.cleaned_data["emwf_case_filter"]

        return CaseExportInstanceFilters(
            date_period=DatePeriod(
                period_type=self.cleaned_data['date_range'],
                days=self.cleaned_data['days'],
                begin=self.cleaned_data['start_date'],
                end=self.cleaned_data['end_date'],
            ),
            users=CaseListFilter.selected_user_ids(emwf_selections),
            reporting_groups=CaseListFilter.selected_reporting_group_ids(
                emwf_selections),
            locations=CaseListFilter.selected_location_ids(emwf_selections),
            user_types=CaseListFilter.selected_user_types(emwf_selections),
            can_access_all_locations=can_access_all_locations,
            accessible_location_ids=accessible_location_ids,
            sharing_groups=CaseListFilter.selected_sharing_group_ids(
                emwf_selections),
            show_all_data=CaseListFilter.show_all_data(emwf_selections)
            or CaseListFilter.no_filters_selected(emwf_selections),
            show_project_data=CaseListFilter.show_project_data(
                emwf_selections),
        )

    def _to_form_export_instance_filters(self, can_access_all_locations,
                                         accessible_location_ids):
        emwf_selections = self.cleaned_data["emwf_form_filter"]

        return FormExportInstanceFilters(
            date_period=DatePeriod(
                period_type=self.cleaned_data['date_range'],
                days=self.cleaned_data['days'],
                begin=self.cleaned_data['start_date'],
                end=self.cleaned_data['end_date'],
            ),
            users=ExpandedMobileWorkerFilter.selected_user_ids(
                emwf_selections),
            reporting_groups=ExpandedMobileWorkerFilter.
            selected_reporting_group_ids(emwf_selections),
            locations=ExpandedMobileWorkerFilter.selected_location_ids(
                emwf_selections),
            user_types=ExpandedMobileWorkerFilter.selected_user_types(
                emwf_selections),
            can_access_all_locations=can_access_all_locations,
            accessible_location_ids=accessible_location_ids,
        )

    @classmethod
    def get_form_data_from_export_instance_filters(cls,
                                                   export_instance_filters,
                                                   domain, export_type):
        """
        Return a dictionary representing the form data from a given ExportInstanceFilters.
        This is used to populate a form from an existing export instance
        :param export_instance_filters:
        :return:
        """
        if export_instance_filters:
            date_period = export_instance_filters.date_period
            selected_items = (export_instance_filters.users +
                              export_instance_filters.reporting_groups +
                              export_instance_filters.locations +
                              export_instance_filters.user_types)
            if isinstance(export_instance_filters, CaseExportInstanceFilters):
                selected_items += (
                    export_instance_filters.sharing_groups +
                    (["all_data"] if export_instance_filters.show_all_data else
                     []) + (["project_data"] if
                            export_instance_filters.show_project_data else []))

            emwf_utils_class = CaseListFilterUtils if export_type is CaseExportInstance else \
                EmwfUtils
            emwf_data = []
            for item in selected_items:
                choice_tuple = emwf_utils_class(domain).id_to_choice_tuple(
                    str(item))
                if choice_tuple:
                    emwf_data.append({
                        "id": choice_tuple[0],
                        "text": choice_tuple[1]
                    })

            return {
                "date_range": date_period.period_type if date_period else None,
                "days": date_period.days if date_period else None,
                "start_date": date_period.begin if date_period else None,
                "end_date": date_period.end if date_period else None,
                "emwf_form_filter": emwf_data,
                "emwf_case_filter": emwf_data,
            }
        else:
            return None
Example #4
0
class UsersAtLocationForm(forms.Form):
    selected_ids = forms.Field(
        label=ugettext_lazy("Group Membership"),
        required=False,
        widget=Select2Ajax(multiple=True),
    )

    def __init__(self, domain_object, location, *args, **kwargs):
        self.domain_object = domain_object
        self.location = location
        fieldset_title = kwargs.pop('fieldset_title',
                                    ugettext_lazy("Edit Group Membership"))
        submit_label = kwargs.pop('submit_label',
                                  ugettext_lazy("Update Membership"))

        super(UsersAtLocationForm,
              self).__init__(initial={'selected_ids': self.users_at_location},
                             *args,
                             **kwargs)

        from corehq.apps.reports.filters.api import MobileWorkersOptionsView
        self.fields['selected_ids'].widget.set_url(
            reverse(MobileWorkersOptionsView.urlname,
                    args=(self.domain_object.name, )))
        self.fields['selected_ids'].widget.set_initial(self.users_at_location)
        self.helper = FormHelper()
        self.helper.label_class = 'col-sm-3 col-md-2'
        self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6'
        self.helper.form_tag = False

        self.helper.layout = crispy.Layout(
            crispy.Fieldset(
                fieldset_title,
                crispy.Field('selected_ids'),
            ),
            hqcrispy.FormActions(
                crispy.ButtonHolder(Submit('submit', submit_label))))

    @property
    @memoized
    def users_at_location(self):
        user_query = UserES().domain(
            self.domain_object.name).mobile_users().location(
                self.location.location_id).fields(
                    ['_id', 'username', 'first_name', 'last_name'])
        return [
            dict(id=u['_id'],
                 text=user_display_string(u['username'],
                                          u.get('first_name', ''),
                                          u.get('last_name', '')))
            for u in user_query.run().hits
        ]

    def unassign_users(self, users):
        for doc in iter_docs(CommCareUser.get_db(), users):
            # This could probably be sped up by bulk saving, but there's a lot
            # of stuff going on - seems tricky.
            CommCareUser.wrap(doc).unset_location_by_id(
                self.location.location_id, fall_back_to_next=True)

    def assign_users(self, users):
        for doc in iter_docs(CommCareUser.get_db(), users):
            CommCareUser.wrap(doc).add_to_assigned_locations(self.location)

    def save(self):
        selected_users = set(self.cleaned_data['selected_ids'].split(','))
        previous_users = set([u['id'] for u in self.users_at_location])
        to_remove = previous_users - selected_users
        to_add = selected_users - previous_users
        self.unassign_users(to_remove)
        self.assign_users(to_add)