Example #1
0
def participant_list(page=1):
    page_title = _('Participants')
    template_name = 'frontend/participant_list.html'

    sortable_columns = {
        'id': 'participant_id',
        'name': 'name',
        'gen': 'gender'
    }

    try:
        extra_fields = filter(
            lambda f: getattr(f, 'listview_visibility', False) is True,
            g.deployment.participant_extra_fields)
    except AttributeError:
        extra_fields = []
    location = None
    if request.args.get('location'):
        location = services.locations.find(
            pk=request.args.get('location')).first()

    for field in extra_fields:
        sortable_columns.update({field.name: field.name})

    queryset = services.participants.find()
    queryset_filter = filters.participant_filterset()(queryset, request.args)

    form = DummyForm(request.form)

    if request.form.get('action') == 'send_message':
        message = request.form.get('message', '')
        recipients = filter(
            lambda x: x is not '',
            [participant.phone if participant.phone else ''
                for participant in queryset_filter.qs])
        recipients.extend(current_app.config.get('MESSAGING_CC'))

        if message and recipients and permissions.send_messages.can():
            send_messages.delay(str(g.event.pk), message, recipients)
            return 'OK'
        else:
            abort(400)

    if request.args.get('export') and permissions.export_participants.can():
        # Export requested
        dataset = services.participants.export_list(queryset_filter.qs)
        basename = slugify_unicode('%s participants %s' % (
            g.event.name.lower(),
            datetime.utcnow().strftime('%Y %m %d %H%M%S')))
        content_disposition = 'attachment; filename=%s.csv' % basename
        return Response(
            dataset, headers={'Content-Disposition': content_disposition},
            mimetype="text/csv"
        )
    else:
        # request.args is immutable, so the .pop() call will fail on it.
        # using .copy() returns a mutable version of it.
        args = request.args.copy()
        page = int(args.pop('page', '1'))

        sort_by = sortable_columns.get(
            args.pop('sort_by', ''), 'participant_id')
        subset = queryset_filter.qs.order_by(sort_by)

        # load form context
        context = dict(
            args=args,
            extra_fields=extra_fields,
            filter_form=queryset_filter.form,
            form=form,
            location=location,
            page_title=page_title,
            location_types=helpers.displayable_location_types(
                is_administrative=True),
            participants=subset.paginate(
                page=page, per_page=current_app.config.get('PAGE_SIZE'))
        )

        return render_template(
            template_name,
            **context
        )
Example #2
0
def participant_list(participant_set_id=0, view=None):
    if participant_set_id:
        participant_set = ParticipantSet.query.filter(
            ParticipantSet.id == participant_set_id).first_or_404()
        template_name = 'admin/participant_list.html'
        breadcrumbs = [{
            'url': url_for('participantset.index_view'),
            'text': _('Participant Sets')
        }, participant_set.name,
                       _('Participants')]
    else:
        participant_set = g.event.participant_set or abort(404)
        template_name = 'frontend/participant_list.html'
        breadcrumbs = [_('Participants')]

    user_locale = get_locale().language
    deployment_locale = g.deployment.primary_locale or 'en'

    extra_fields = [field for field in participant_set.extra_fields
                    if field.visible_in_lists] \
        if participant_set.extra_fields else []

    location = None
    if request.args.get('location'):
        location = Location.query.filter(
            Location.id == request.args.get('location')).first()

    full_name_term = func.coalesce(
        Participant.full_name_translations.op('->>')(user_locale),
        Participant.full_name_translations.op('->>')(deployment_locale)).label(
            'full_name')
    first_name_term = func.coalesce(
        Participant.first_name_translations.op('->>')(user_locale),
        Participant.first_name_translations.op('->>')(
            deployment_locale)).label('first_name')
    other_names_term = func.coalesce(
        Participant.other_names_translations.op('->>')(user_locale),
        Participant.other_names_translations.op('->>')(
            deployment_locale)).label('other_names')
    last_name_term = func.coalesce(
        Participant.last_name_translations.op('->>')(user_locale),
        Participant.last_name_translations.op('->>')(deployment_locale)).label(
            'last_name')

    queryset = Participant.query.select_from(
        Participant, ).filter(Participant.participant_set == participant_set)

    # load the location set linked to the participant set
    location_set_id = participant_set.location_set_id
    filter_class = filters.participant_filterset(participant_set.id,
                                                 location_set_id)
    queryset_filter = filter_class(queryset, request.args)

    if request.args.get('export') and permissions.export_participants.can():
        # Export requested
        dataset = services.participants.export_list(queryset_filter.qs)
        basename = slugify('%s participants %s' %
                           (participant_set.name.lower(),
                            datetime.utcnow().strftime('%Y %m %d %H%M%S')))
        content_disposition = 'attachment; filename=%s.csv' % basename
        return Response(stream_with_context(dataset),
                        headers={'Content-Disposition': content_disposition},
                        mimetype="text/csv")

    # the following section defines the queryset for the participants
    # to be retrieved. due to the fact that we do specialized sorting
    # the queryset will depend heavily on what is being sorted.
    if (request.args.get('sort_by') == 'location'
            and request.args.get('sort_value')):
        # when sorting based on location, we generally want to be able
        # to sort participants based on a specific administrative division.
        # since we store the hierarchical structure in a separate table
        # we not only have to retrieve the table for the location data but
        # also join it based on results in the location hierarchy.

        # start out by getting all the locations (as a subquery) in a
        # particular division.

        division = models.Location.query.with_entities(
            models.Location.id).filter(
                models.Location.location_type_id == request.args.get(
                    'sort_value'), models.Location.location_set_id ==
                participant_set.location_set_id).subquery()
        # next is we retrieve all the descendant locations for all the
        # locations in that particular administrative division making sure
        # to retrieve the name translations which would be used in sorting
        # the participants when the time comes.
        descendants = models.LocationPath.query.join(
            models.Location, models.Location.id ==
            models.LocationPath.ancestor_id).with_entities(
                models.Location.name_translations,
                models.LocationPath.descendant_id).filter(
                    models.LocationPath.ancestor_id.in_(division)).subquery()

        # now we defined the actual queryset using the subqueries above
        # taking note to group by the translation name which essentially
        # is the division name.
        queryset = models.Participant.query.select_from(
            models.Participant,
            models.Location,
        ).filter(
            models.Participant.participant_set_id == participant_set.id).join(
                models.Location, models.Participant.location_id ==
                models.Location.id).outerjoin(
                    descendants, descendants.c.descendant_id ==
                    models.Participant.location_id).group_by(
                        descendants.c.name_translations, models.Participant.id)
    elif request.args.get('sort_by') == 'phone':
        queryset = models.Participant.query.filter(
            models.Participant.participant_set_id == participant_set.id).join(
                models.Location,
                models.Participant.location_id == models.Location.id).join(
                    models.PhoneContact, models.PhoneContact.participant_id ==
                    models.Participant.id)
    else:
        queryset = models.Participant.query.select_from(
            models.Participant,
        ).filter(
            models.Participant.participant_set_id == participant_set.id).join(
                models.Location,
                models.Participant.location_id == models.Location.id
            ).outerjoin(
                models.ParticipantRole,
                models.Participant.role_id == models.ParticipantRole.id
            ).outerjoin(
                models.ParticipantPartner,
                models.Participant.partner_id == models.ParticipantPartner.id)

    if request.args.get('sort_by') == 'id':
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(
                desc(models.Participant.participant_id.cast(BigInteger)))
        else:
            queryset = queryset.order_by(
                models.Participant.participant_id.cast(BigInteger))
    elif request.args.get('sort_by') == 'location_name':
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(
                desc(models.Location.name_translations.op('->>')(user_locale)),
                desc(
                    models.Location.name_translations.op('->>')(
                        deployment_locale)),
            )
        else:
            queryset = queryset.order_by(
                models.Location.name_translations.op('->>')(user_locale),
                models.Location.name_translations.op('->>')(deployment_locale),
            )
    elif request.args.get('sort_by') == 'location':
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(
                desc(descendants.c.name_translations.op('->>')(user_locale)),
                desc(
                    descendants.c.name_translations.op('->>')(
                        deployment_locale)),
            )
        else:
            queryset = queryset.order_by(
                descendants.c.name_translations.op('->>')(user_locale),
                descendants.c.name_translations.op('->>')(deployment_locale),
            )
    elif request.args.get('sort_by') == 'name':
        # specify the conditions for the order term
        condition1 = full_name_term == None  # noqa
        condition2 = full_name_term != None  # noqa

        # concatenation for the full name
        full_name_concat = func.concat_ws(
            ' ',
            first_name_term,
            other_names_term,
            last_name_term,
        ).alias('full_name_concat')

        # if the full name is empty, order by the concatenated
        # name, else order by the full name
        order_term = case([
            (condition1, full_name_concat),
            (condition2, full_name_term),
        ])
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(desc(order_term))
        else:
            queryset = queryset.order_by(order_term)
    elif request.args.get('sort_by') == 'phone':
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(desc(models.PhoneContact.number))
        else:
            queryset = queryset.order_by(models.PhoneContact.number)
    elif request.args.get('sort_by') == 'gen':
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(desc(models.Participant.gender))
        else:
            queryset = queryset.order_by(models.Participant.gender)
    elif request.args.get('sort_by') == 'role':
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(desc(models.ParticipantRole.name))
        else:
            queryset = queryset.order_by(models.ParticipantRole.name)
    elif request.args.get('sort_by') == 'org':
        if request.args.get('sort_direction') == 'desc':
            queryset = queryset.order_by(desc(models.ParticipantPartner.name))
        else:
            queryset = queryset.order_by(models.ParticipantPartner.name)
    else:
        queryset = queryset.order_by(
            models.Location.code.cast(BigInteger),
            models.Participant.participant_id.cast(BigInteger))

    # request.args is immutable, so the .pop() call will fail on it.
    # using .copy() returns a mutable version of it.
    args = request.args.to_dict(flat=False)
    page = int(args.pop('page', [1])[0])
    if participant_set_id:
        args['participant_set_id'] = participant_set_id

    queryset_filterset = filter_class(queryset, request.args)
    filter_form = queryset_filterset.form

    if request.form.get('action') == 'send_message':
        message = request.form.get('message', '')
        recipients = [
            x for x in [
                participant.primary_phone if participant.primary_phone else ''
                for participant in queryset_filterset.qs
            ] if x != ''
        ]
        recipients.extend(current_app.config.get('MESSAGING_CC'))

        if message and recipients and permissions.send_messages.can():
            send_messages.delay(g.event.id, message, recipients)
            return 'OK'
        else:
            abort(400)

    # load form context
    context = dict(args=args,
                   extra_fields=extra_fields,
                   filter_form=filter_form,
                   location=location,
                   location_set_id=location_set_id,
                   breadcrumbs=breadcrumbs,
                   participant_set=participant_set,
                   participant_set_id=participant_set.id,
                   location_types=helpers.displayable_location_types(
                       is_administrative=True,
                       location_set_id=location_set_id),
                   participants=queryset_filterset.qs.paginate(
                       page=page,
                       per_page=current_app.config.get('PAGE_SIZE')))

    if view:
        return view.render(template_name, **context)
    else:
        return render_template(template_name, **context)
Example #3
0
def submission_list(form_id):
    form = services.forms.get_or_404(pk=form_id)
    permissions.require_item_perm('view_forms', form)

    filter_class = generate_submission_filter(form)
    page_title = form.name
    template_name = 'frontend/submission_list.html'

    data = request.args.to_dict()
    data['form_id'] = unicode(form.pk)
    page = int(data.pop('page', 1))

    loc_types = displayable_location_types(is_administrative=True)

    location = None
    if request.args.get('location'):
        location = services.locations.find(
            pk=request.args.get('location')).first()

    if request.args.get('export') and permissions.export_submissions.can():
        mode = request.args.get('export')
        if mode in ['master', 'aggregated']:
            queryset = services.submissions.find(
                submission_type='M',
                form=form
            ).order_by('location')
        else:
            queryset = services.submissions.find(
                submission_type='O',
                form=form
            ).order_by('location', 'contributor')

        query_filterset = filter_class(queryset, request.args)
        basename = slugify_unicode('%s %s %s %s' % (
            g.event.name.lower(),
            form.name.lower(),
            datetime.utcnow().strftime('%Y %m %d %H%M%S'),
            mode))
        content_disposition = 'attachment; filename=%s.csv' % basename
        if mode == 'aggregated':
            # TODO: you want to change the float format or even remove it
            # if you have columns that have float values
            dataset = aggregated_dataframe(query_filterset.qs, form)\
                .to_csv(encoding='utf-8', index=False, float_format='%d')
        else:
            dataset = services.submissions.export_list(
                query_filterset.qs, g.deployment)

        return Response(
            dataset, headers={'Content-Disposition': content_disposition},
            mimetype="text/csv"
        )

    # first retrieve observer submissions for the form
    # NOTE: this implicitly restricts selected submissions
    # to the currently selected event.
    queryset = services.submissions.find(
        submission_type='O',
        form=form
    ).order_by('location', 'contributor')
    query_filterset = filter_class(queryset, request.args)
    filter_form = query_filterset.form

    if request.form.get('action') == 'send_message':
        message = request.form.get('message', '')
        recipients = filter(
            lambda x: x is not '',
            [submission.contributor.phone
                if submission.contributor and
                submission.contributor.phone else ''
                for submission in query_filterset.qs.only(
                    'contributor').select_related(1)])
        recipients.extend(current_app.config.get('MESSAGING_CC'))

        if message and recipients and permissions.send_messages.can():
            send_messages.delay(str(g.event.pk), message, recipients)
            return 'OK'
        else:
            abort(400)

    if form.form_type == 'CHECKLIST':
        form_fields = []
    else:
        form_fields = [field for group in form.groups
                       for field in group.fields if not field.is_comment_field]

    return render_template(
        template_name,
        args=data,
        filter_form=filter_form,
        form=form,
        form_fields=form_fields,
        location_types=loc_types,
        location=location,
        page_title=page_title,
        pager=query_filterset.qs.paginate(
            page=page, per_page=current_app.config.get('PAGE_SIZE'))
    )
Example #4
0
def participant_list(page=1):
    page_title = _('Participants')
    template_name = 'frontend/participant_list.html'

    sortable_columns = {
        'id': 'participant_id',
        'name': 'name',
        'gen': 'gender'
    }

    try:
        extra_fields = filter(
            lambda f: getattr(f, 'listview_visibility', False) is True,
            g.deployment.participant_extra_fields)
    except AttributeError:
        extra_fields = []
    location = None
    if request.args.get('location'):
        location = services.locations.find(
            pk=request.args.get('location')).first()

    for field in extra_fields:
        sortable_columns.update({field.name: field.name})

    queryset = services.participants.find()
    queryset_filter = filters.participant_filterset()(queryset, request.args)

    form = DummyForm(request.form)

    if request.form.get('action') == 'send_message':
        message = request.form.get('message', '')
        recipients = filter(lambda x: x is not '', [
            participant.phone if participant.phone else ''
            for participant in queryset_filter.qs
        ])
        recipients.extend(current_app.config.get('MESSAGING_CC'))

        if message and recipients and permissions.send_messages.can():
            send_messages.delay(str(g.event.pk), message, recipients)
            return 'OK'
        else:
            abort(400)

    if request.args.get('export') and permissions.export_participants.can():
        # Export requested
        dataset = services.participants.export_list(queryset_filter.qs)
        basename = slugify_unicode(
            '%s participants %s' %
            (g.event.name.lower(),
             datetime.utcnow().strftime('%Y %m %d %H%M%S')))
        content_disposition = 'attachment; filename=%s.csv' % basename
        return Response(dataset,
                        headers={'Content-Disposition': content_disposition},
                        mimetype="text/csv")
    else:
        # request.args is immutable, so the .pop() call will fail on it.
        # using .copy() returns a mutable version of it.
        args = request.args.to_dict(flat=False)
        page_spec = args.pop(u'page', None) or [1]
        page = int(page_spec[0])

        sort_by = sortable_columns.get(args.pop('sort_by', ''),
                                       'participant_id')
        subset = queryset_filter.qs.order_by(sort_by)

        # load form context
        context = dict(args=args,
                       extra_fields=extra_fields,
                       filter_form=queryset_filter.form,
                       form=form,
                       location=location,
                       page_title=page_title,
                       location_types=helpers.displayable_location_types(
                           is_administrative=True),
                       participants=subset.paginate(
                           page=page,
                           per_page=current_app.config.get('PAGE_SIZE')))

        return render_template(template_name, **context)