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 )
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)
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')) )
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)