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