예제 #1
0
def message_time_series(message_queryset):
    c_events = events.overlapping_events(g.event).order_by(Event.start.desc())
    current_events = c_events.all() if c_events.count() > 0 else [g.event]

    # add 30 days as an arbitrary end buffer
    upper_bound = current_events[0].end + timedelta(30)
    lower_bound = current_events[-1].start

    # limit the range of the displayed chart to prevent possible
    # DOS attacks
    query = message_queryset.filter(
        Message.direction == 'IN', Message.received >= lower_bound,
        Message.received <= upper_bound).with_entities(Message.received)

    df = pd.read_sql(query.statement, query.session.bind)

    # set a marker for each message
    df['marker'] = 1

    # set the index to the message timestamp, resample to hourly
    # and sum all markers in each hour, filling NaNs with 0
    if df.empty is not True:
        df = df.set_index('received').resample('1Min').sum().fillna(0)

        # return as UNIX timestamp, value pairs
        data = {
            'incoming':
            [(calendar.timegm(i[0].utctimetuple()) * 1000, int(i[1]))
             for i in sorted(df.to_dict()['marker'].items())]
        }
    else:
        data = {'incoming': []}

    return data
def message_time_series(message_queryset):
    current_events = list(
        events.overlapping_events(g.event).order_by('-start_date'))
    # add 30 days as an arbitrary end buffer
    upper_bound = current_events[0].end_date + timedelta(30)
    lower_bound = current_events[-1].start_date

    # limit the range of the displayed chart to prevent possible
    # DOS attacks
    df = pd.DataFrame(
        list(
            message_queryset(
                direction='IN',
                received__gte=lower_bound,
                received__lte=upper_bound).only('received').as_pymongo()))

    # set a marker for each message
    df['marker'] = 1

    # set the index to the message timestamp, resample to hourly
    # and sum all markers in each hour, filling NaNs with 0
    if df.empty is not True:
        df = df.set_index('received').resample('1Min', how='sum').fillna(0)

        # return as UNIX timestamp, value pairs
        data = {
            'incoming':
            [(calendar.timegm(i[0].utctimetuple()) * 1000, int(i[1]))
             for i in sorted(df.to_dict()['marker'].items())]
        }
    else:
        data = {'incoming': []}

    return data
예제 #3
0
def message_list():
    page_title = _('Messages')
    template_name = 'frontend/message_list.html'

    deployment = g.deployment
    message_events = set(events.overlapping_events(g.event)).union({g.event})
    qs = Message.objects(deployment=deployment,
                         event__in=message_events).order_by(
                             '-received', '-direction')
    queryset_filter = filters.messages_filterset()(qs, request.args)

    if request.args.get('export') and permissions.export_messages.can():
        # Export requested
        dataset = messages.export_list(queryset_filter.qs)
        basename = slugify_unicode(
            '%s messages %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:
        data = request.args.to_dict(flat=False)
        page_spec = data.pop(u'page', None) or [1]
        page = int(page_spec[0])
        context = {
            'page_title':
            page_title,
            'filter_form':
            queryset_filter.form,
            'args':
            data,
            'pager':
            queryset_filter.qs.paginate(
                page=page, per_page=current_app.config.get('PAGE_SIZE')),
            'chart_data':
            message_time_series(queryset_filter.qs)
        }

        return render_template(template_name, **context)
예제 #4
0
def concurrent_events(event_id):
    event = events.overlapping_events(g.event).get_or_404(pk=event_id)
    if event:
        set_event(event)
    return redirect(url_for('dashboard.index'))
예제 #5
0
        'location': location,
        'locationtype': getattr(next_location_type, 'id', ''),
        'group': group or ''
    }

    return render_template(
        template_name,
        **context
    )


@route(bp, '/event/<event_id>', methods=['GET'])
@register_menu(
    bp, 'user.concurrent_events', _('Concurrent Events'),
    visible_when=partial(
        lambda: events.overlapping_events(g.event).count() > 1),
    dynamic_list_constructor=partial(get_concurrent_events_list_menu))
@login_required
def concurrent_events(event_id):
    event = events.overlapping_events(g.event).get_or_404(pk=event_id)
    if event:
        set_event(event)
    return redirect(url_for('dashboard.index'))


@route(bp, '/event', methods=['GET', 'POST'])
@register_menu(
    bp, 'user.events', _('Events'),
    visible_when=partial(lambda: permissions.view_events.can()))
@permissions.view_events.require(403)
@login_required
예제 #6
0
def concurrent_events(event_id):
    event = events.overlapping_events(g.event).get_or_404(pk=event_id)
    if event:
        set_event(event)
    return redirect(url_for('dashboard.index'))
예제 #7
0
               visible_when=lambda: len(
                   get_checklist_form_dashboard_menu(form_type='SURVEY')) > 0,
               dynamic_list_constructor=partial(
                   get_checklist_form_dashboard_menu, form_type='SURVEY'))
@login_required
def checklists(form_id=None):
    return main_dashboard(form_id)


@route(bp, '/event/<event_id>', methods=['GET'])
@register_menu(
    bp,
    'user.concurrent_events',
    _('Concurrent Events'),
    visible_when=partial(
        lambda: events.overlapping_events(g.event).count() > 1),
    dynamic_list_constructor=partial(get_concurrent_events_list_menu))
@login_required
def concurrent_events(event_id):
    event = events.overlapping_events(g.event).get_or_404(pk=event_id)
    if event:
        set_event(event)
    return redirect(url_for('dashboard.index'))


@route(bp, '/events', methods=['GET', 'POST'])
@register_menu(bp,
               'user.events',
               _('Events'),
               visible_when=partial(lambda: permissions.view_events.can()))
@login_required
예제 #8
0
def message_list():
    breadcrumbs = [_('Messages')]
    template_name = 'frontend/message_list.html'

    deployment = g.deployment
    message_events = set(events.overlapping_events(g.event)).union({g.event})
    event_ids = [ev.id for ev in message_events]
    qs = Message.query.filter(Message.deployment == deployment,
                              Message.event_id.in_(event_ids)).order_by(
                                  Message.received.desc(),
                                  Message.direction.desc())

    if request.args.get('export') and permissions.export_messages.can():
        # Export requested
        queryset_filter = MessageFilterSet(qs, request.args)
        dataset = messages.export_list(queryset_filter.qs)
        basename = slugify('%s messages %s' %
                           (g.event.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")
    else:
        filter_form = MessageFilterForm(request.args)
        filter_form.validate()
        filter_errors = filter_form.errors
        filter_data = filter_form.data
        OutboundMsg = aliased(Message, name='outbound')

        split_messages = qs.filter(
            sa.or_(
                Message.direction == 'IN',
                sa.and_(
                    Message.originating_message_id == None,  # noqa
                    Message.direction == 'OUT'))
        ).outerjoin(
            Submission, Message.submission_id == Submission.id
        ).outerjoin(Form, Submission.form_id == Form.id).outerjoin(
            # TODO: add extra condition for 'OUT' message
            # if necessary
            OutboundMsg,
            sa.and_(
                OutboundMsg.originating_message_id == Message.id,
                OutboundMsg.direction == 'OUT',
            ))

        # filtering
        all_messages = split_messages.with_entities(
            Message, OutboundMsg, Submission.id,
            Form.form_type).order_by(Message.received.desc())

        if 'mobile' not in filter_errors and filter_data.get('mobile'):
            search_term = filter_data.get('mobile')
            numbers = list(
                chain(*[
                    term.strip().split() for term in search_term.split(',')
                    if not term.isspace()
                ]))

            all_messages = all_messages.filter(
                sa.or_(*[
                    sa.or_(
                        Message.sender.ilike(f'%{n.replace("+", "")}%'),
                        OutboundMsg.recipient.ilike(f'%{n.replace("+", "")}%'))
                    for n in numbers
                ]))

        if 'text' not in filter_errors and filter_data.get('text'):
            value = filter_data.get('text')
            all_messages = all_messages.filter(
                sa.or_(
                    sa.or_(
                        Message.text.ilike(f'%{value}%'),
                        Message.text.op('@@')(sa.func.plainto_tsquery(
                            'english', value))),
                    sa.or_(
                        OutboundMsg.text.ilike(f'%{value}%'),
                        OutboundMsg.text.op('@@')(sa.func.plainto_tsquery(
                            'english', value)))))

        if 'date' not in filter_errors and filter_data.get('date'):
            try:
                dt = parse(filter_data.get('date'), dayfirst=True)

                dt = dt.replace(tzinfo=APP_TZ)

                date_end = dt.replace(hour=23, minute=59, second=59)
                date_start = dt.replace(hour=0, minute=0, second=0)

                all_messages = all_messages.filter(
                    sa.or_(
                        sa.and_(Message.received >= date_start,
                                Message.received <= date_end),
                        sa.and_(OutboundMsg.received >= date_start,
                                OutboundMsg.received <= date_end),
                    ))

            except (OverflowError, ValueError):
                all_messages = all_messages.filter(False)

        if 'form_type' not in filter_errors and (filter_data.get('form_type')
                                                 != ''):
            if filter_data.get('form_type') == 'Invalid':
                all_messages = all_messages.filter(
                    Message.submission_id == None  # noqa
                )
            else:
                all_messages = all_messages.filter(
                    Form.form_type == filter_data.get('form_type'))

        data = request.args.to_dict(flat=False)
        page = int(data.pop('page', [1])[0])
        context = {
            'breadcrumbs':
            breadcrumbs,
            'filter_form':
            filter_form,
            'args':
            data,
            'pager':
            all_messages.paginate(
                page=page, per_page=current_app.config.get('PAGE_SIZE')),
            'chart_data':
            message_time_series(all_messages)
        }

        return render_template(template_name, **context)