Пример #1
0
def _generate_report_items(report):
    ''' calculate stats and generate data for graphs ahead of report rendering
    return a dict of the calculations and objects
    '''
    # get all relevant data for the project
    conditions = {
        'project': report.project
        , 'unique': True
        , 'visible': True
    }
    entries = Entry.objects(**conditions)

    items = []
    for component in report.components:
        # determine if component is a stat or graph
        component_type = None
        try:
            component.statistic_type
            component_type = 'statistic'
        except:
            pass
        
        try:
            component.xaxis
            component_type = 'graph'
        except:
            pass

        if component_type == 'statistic':
            # find the statistic
            statistics = Statistic.objects(name=component.name
                , project=report.project)
            if not statistics:
                flash('Statistic "%s" not found' % component.name, 'error')
                return redirect(url_for('reports'
                    , org_label=report.project.organization.label
                    , project_label=report.project.label
                    , report_label=report.label))

            statistic = statistics[0]
            # apply relevant filters and then computes the statistic
            if statistic.pivot:
                # returns dict keyed by the statistic's pivot_values
                result = utilities.compute_pivot_statistic(statistic
                    , entries)
            else:
                # returns a single result
                result = utilities.compute_statistic(statistic, entries)

            # save values for rendering
            items.append({
                'type': 'statistic'
                , 'name': component.name
                , 'instance': statistic
                , 'result': result
            })

        elif component_type == 'graph':
            # find the graph
            graphs = Graph.objects(name=component.name
                , project=report.project)
            if not graphs:
                flash('Graph "%s" not found' % component.name, 'error')
                return redirect(url_for('reports'
                    , org_label=report.project.organization.label
                    , project_label=report.project.label
                    , report_label=report.label))

            graph = graphs[0]
            if graph.graph_type == 'line':
                if graph.xaxis and graph.yaxis:
                    data, count = utilities.generate_line_graph_data(graph)
                else:
                    data = []
                    flash('Define an x-axis and y-axis for plotting'
                        , 'error')
            
            elif graph.graph_type == 'pie':
                if graph.pie_header:
                    data, count = utilities.generate_pie_chart_data(graph)
                else:
                    flash('define a column to create this pie chart'
                            , 'warning')
            
            # save values for rendering
            items.append({
                'type': 'graph'
                , 'name': component.name
                , 'instance': graph
                , 'data': data
            })
    
    return items
Пример #2
0
def graphs(org_label, project_label, graph_label):
    ''' graphin things
    /organizations/aquaya/projects/water-quality/graphs
        : view a list of all graphs for the project
    /organizations/aquaya/projects/water-quality/graphs?create=true
        : create a new graph config, immediately redirect to editing
    /organizations/aquaya/projects/water-quality/graphs/ph-vs-time
        : view a graph
    /organizations/aquaya/projects/water-quality/graphs/ph-vs-time?edit=true
        : edit a graph; accepts GET or POST
    '''
    user = User.objects(email=session['email'])[0]
    
    orgs = Organization.objects(label=org_label)
    if not orgs:
        flash('Organization "%s" not found, sorry!' % org_label, 'warning')
        return redirect(url_for('organizations'))
    org = orgs[0]

    # permission-check
    if org not in user.organizations and not user.admin_rights:
        app.logger.error('%s tried to view a project but was \
            denied for want of admin rights' % session['email'])
        abort(404)
    
    # find the project
    projects = Project.objects(label=project_label, organization=org) 
    if not projects:
        flash('Project "%s" not found, sorry!' % project_label, 'warning')
        return redirect(url_for('organizations', org_label=org.label))
    project = projects[0]

    if request.method == 'POST':
        # we have a graph_label
        graphs = Graph.objects(label=graph_label, project=project)
        if not graphs:
            abort(404)
        graph = graphs[0]

        form_type = request.form.get('form_type', '')
        if form_type == 'info':
            if graph.name != request.form.get('name', ''):
                name = request.form.get('name', '')
                graph.update(set__name = name)

                graphs = Graph.objects(project=project).only('label')
                labels = [g.label for g in graphs]
                graph.update(set__label = utilities.generate_label(name
                    , labels))

                # reload to catch the name change
                graph.reload()

            graph.update(set__description = 
                    request.form.get('description', ''))
            graph.update(set__graph_type = request.form.get('graph_type', ''))

            # axes specify a header and come of the form 'header_id__4abcd001'
            xaxis = request.form.get('xaxis', '')
            if xaxis:
                xaxis = xaxis.split('header_id__')[1]
                header = Header.objects(id=xaxis)[0]
                graph.update(set__xaxis = header)

            yaxis = request.form.get('yaxis', '')
            if yaxis:
                yaxis = yaxis.split('header_id__')[1]
                header = Header.objects(id=yaxis)[0]
                graph.update(set__yaxis = header)

            # pie chart headers are similar to axes..
            pie_header = request.form.get('pie_header', '')
            if pie_header:
                pie_header = pie_header.split('header_id__')[1]
                header = Header.objects(id=pie_header)[0]
                graph.update(set__pie_header = header)

        elif form_type == 'filters':
            # extract the 'any filters' vs 'all' distinction
            filter_settings = request.form.get('apply_any_filters', '')
            if filter_settings == 'true':
                graph.update(set__apply_any_filters = True)
            else:
                graph.update(set__apply_any_filters = False)

            # attach filter to graph
            requested_filter_ids = request.form.getlist('filters')
            attached_filters = []
            for requested_id in requested_filter_ids:
                prefix, filter_id = requested_id.split('__')
                filters = Filter.objects(id=filter_id)
                if not filters:
                    abort(404)
                attached_filters.append(filters[0])

            graph.update(set__filters = attached_filters)
                
        elif form_type == 'admin':
            # delete the graph
            name = graph.name
            utilities.delete_graph(graph, session['email'])
            flash('graph "%s" was deleted successfully' % name, 'success')
            return redirect(url_for('graphs', org_label=org.label
                , project_label=project.label))
        
        else:
            # bad 'form_type'
            abort(404)
       
        flash('changes saved successfully', 'success')
        return redirect(url_for('graphs', org_label=org.label
            , project_label=project.label, graph_label=graph.label))
    
    if request.method == 'GET':
        if graph_label:
            graphs = Graph.objects(label=graph_label, project=project)
            if not graphs:
                app.logger.error('%s tried to access a graph that does not \
                    exist' % session['email'])
                flash('Graph "%s" not found, sorry!' % graph_label
                    , 'warning')
                return redirect(url_for('projects'), org_label=org.label
                    , project_label=project.label)
            graph = graphs[0]

            if request.args.get('edit', '') == 'true':
                # valid graph types
                graph_types = ['line', 'scatter', 'bar', 'chart', 'pie']
                
                available_filters = Filter.objects(project=project)
                    
                return render_template('graph_edit.html', graph=graph
                    , graph_types = graph_types
                    , allowed_graph_types = constants.graph_types
                    , available_filters = available_filters)

            else:
                # render a graph
                data = []
                project_count = None
                filtered_count = None
                if graph.graph_type == 'line':
                    if graph.xaxis and graph.yaxis:
                        data, project_count = (
                                utilities.generate_line_graph_data(graph))
                        filtered_count = len(data)
                    else:
                        flash('define an x-axis and y-axis for plotting'
                            , 'warning')

                elif graph.graph_type == 'pie':
                    if graph.pie_header:
                        data, project_count = (
                                utilities.generate_pie_chart_data(graph))
                        filtered_count = sum([i['data'] for i in json.loads(data)])
                    else:
                        flash('define a column to create this pie chart'
                                , 'warning')

                return render_template('graph.html', graph=graph, data=data
                    , project_count=project_count
                    , filtered_count = filtered_count)

        if request.args.get('create', '') == 'true':
            # create a new graph

            # CSRF validation
            token = request.args.get('token', '')
            if not verify_token(token):
                abort(403)

            try:
                graph_name = 'graph-%s' % utilities.generate_random_string(6)
                new_graph = Graph(
                    creation_time = datetime.datetime.utcnow()
                    , creator = user
                    , label = graph_name.lower()
                    , project = project
                    , name = graph_name
                )
                new_graph.save() 
                app.logger.info('graph created by %s' % session['email'])
                flash('graph created; please change the defaults', 'success')
            except:
                app.logger.error('graph creation failed for %s' % \
                    session['email'])
                flash('There was an error, sorry :/', 'error')
                return redirect(url_for('projects', org_label=org.label
                    , project=project.label))
            
            # redirect to the editing screen
            return redirect(url_for('graphs', org_label=org.label
                , project_label=project.label, graph_label=new_graph.label
                , edit='true'))
        
        # no graph in particular was specified
        graphs = Graph.objects(project=project)
        return render_template('project_graphs.html', project=project
            , graphs=graphs)