def get_report_info(request): """Get information about an analytics report. analytics_report_id: string id obtained from get_available_analytics under 'value' { 'dimensions': [ { 'value': 'country', 'display': 'Country', 'interface_type': 'map:world', }, { 'value': 'title', 'display': 'Job Title', 'interface_type': 'string', }, ... ] } """ validator = ApiValidator() analytics_report_id = request.GET.get('analytics_report_id', '') if not analytics_report_id: validator.note_field_error( "analytics_report_id", "Value required.") if validator.has_errors(): return validator.build_error_response() report_data = get_analytics_reporttype_datatype(analytics_report_id) if not report_data: validator.note_field_error( "analytics_report_id", "No analytics report found.") if validator.has_errors(): return validator.build_error_response() config = report_data.configuration result = { 'dimensions': [ { 'value': r.column_name, 'display': r.filter_interface_display, 'interface_type': r.filter_interface_type, } for r in config.configurationcolumn_set.all().order_by('order') ], } return HttpResponse(json.dumps(result), content_type="application/json")
def run_dynamic_report(request): """Run a dynamic report. report_data_id: Report Presentation ID name: name of report filter_spec: JSON string with user filter to use response: {'id': new dynamic report id} """ validator = ApiValidator() company = get_company_or_404(request) report_data_id = request.POST['report_data_id'] name = request.POST.get('name', '') if not name: validator.note_field_error("name", "Report name must not be empty.") filter_spec = request.POST.get('filter', '{}') report_data = ReportTypeDataTypes.objects.get(id=report_data_id) if validator.has_errors(): return validator.build_error_response() report = DynamicReport.objects.create(report_data=report_data, filters=filter_spec, name=name, owner=company) report.regenerate() data = {'id': report.id} return HttpResponse(content_type='application/json', content=json.dumps(data))
def run_dynamic_report(request): """Run a dynamic report. report_data_id: Report Presentation ID name: name of report filter_spec: JSON string with user filter to use response: {'id': new dynamic report id} """ validator = ApiValidator() company = get_company_or_404(request) report_data_id = request.POST['report_data_id'] name = request.POST.get('name', '') if not name: validator.note_field_error("name", "Report name must not be empty.") filter_spec = request.POST.get('filter', '{}') report_data = ReportTypeDataTypes.objects.get(id=report_data_id) if validator.has_errors(): return validator.build_error_response() report = DynamicReport.objects.create( report_data=report_data, filters=filter_spec, name=name, owner=company) report.regenerate() data = {'id': report.id} return HttpResponse(content_type='application/json', content=json.dumps(data))
def test_note_error(self): '''We know when we have errors and can build error documents.''' validator = ApiValidator() self.assertEqual(False, validator.has_errors()) validator.note_error("aaa") self.assertEqual(True, validator.has_errors()) self.assertEqual([{ "message": "aaa", }], validator.build_document()) validator.note_error("bbb") self.assertEqual(True, validator.has_errors()) self.assertEqual([{ "message": "aaa", }, { "message": "bbb", }], validator.build_document())
def test_note_field_error(self): '''We can build error documents with field specific errors.''' validator = ApiValidator() validator.note_field_error("name", "aaa") self.assertEqual(True, validator.has_errors()) self.assertEqual([{ "field": "name", "message": "aaa", }], validator.build_document())
def get_dynamic_report_info(request): company = get_company_or_404(request) validator = ApiValidator() report_id = request.GET.get('report_id') if report_id is None: validator.note_field_error('report_id', 'Missing report id.') if validator.has_errors(): return validator.build_error_response() report_list = list(DynamicReport.objects.filter(id=report_id)) if len(report_list) < 1: validator.note_field_error('report_id', 'Unknown report id.') if validator.has_errors(): return validator.build_error_response() report = report_list[0] # Guessing here. Many to many makes this ambiguous. reporting_type = ( report.report_data.report_type.reportingtype_set.all()[0] .reporting_type) report_type = ( report.report_data.report_type.report_type) data_type = ( report.report_data.data_type.data_type) driver = ds_json_drivers[report.report_data.report_type.datasource] adorned_filter = driver.adorn_filter(company, report.filters) response = { 'report_details': { 'id': report.pk, 'report_data_id': report.report_data.pk, 'reporting_type': reporting_type, 'report_type': report_type, 'data_type': data_type, 'name': report.name, 'filter': adorned_filter, } } return HttpResponse(content_type='application/json', content=driver.serialize_filterlike(response))
def get_default_report_name(request): validator = ApiValidator() # We don't actually need this but it seems like it will be important # if we ever start picking meaningful names. report_data_id = request.POST.get('report_data_id') if not report_data_id: validator.note_field_error("report_data_id", "Report data id must not be empty.") if validator.has_errors(): return validator.build_error_response() data = {'name': str(datetime.now())} return HttpResponse(content_type='application/json', content=json.dumps(data))
def get_default_report_name(request): validator = ApiValidator() # We don't actually need this but it seems like it will be important # if we ever start picking meaningful names. report_data_id = request.POST.get('report_data_id') if not report_data_id: validator.note_field_error( "report_data_id", "Report data id must not be empty.") if validator.has_errors(): return validator.build_error_response() data = {'name': str(datetime.now())} return HttpResponse(content_type='application/json', content=json.dumps(data))
def export_options_api(request): """Get options and defaults, etc. needed to drive a UI for downloads. Parameters: :report_id: Id of the report to download Outputs an object shaped like this: { 'count': number of records in the report, 'report_options': { 'id': the report id, 'formats': [ { 'value': format key, 'display': user visible title for format, }, ], 'values': [ { 'value': key describing an available column, 'display': user visible title of column, }, ], 'name': string containing the report name. }, } """ company = get_company_or_404(request) validator = ApiValidator() report_id = request.GET.get('report_id') if report_id is None: validator.note_field_error('report_id', 'Missing report id.') if validator.has_errors(): return validator.build_error_response() report_list = list( DynamicReport.objects.filter(id=report_id, owner=company)) if len(report_list) < 1: validator.note_field_error('report_id', 'Unknown report id.') if validator.has_errors(): return validator.build_error_response() report = report_list[0] count = len(report.python) rps = (ReportPresentation.objects.active_for_report_type_data_type( report.report_data)) cols = (ConfigurationColumn.objects.active_for_report_data( report.report_data).filter( Q(filter_only__isnull=True) | Q(filter_only=False)).order_by('order')) values = [{ 'value': c.column_name, 'display': c.alias or c.column_name } for c in cols] data = { 'count': count, 'report_options': { 'id': report.id, 'formats': [{ 'value': rp.id, 'display': rp.display_name } for rp in rps], 'values': values, 'name': report.name, }, } return HttpResponse(content_type='application/json', content=json.dumps(data))
def export_options_api(request): """Get options and defaults, etc. needed to drive a UI for downloads. Parameters: :report_id: Id of the report to download Outputs an object shaped like this: { 'count': number of records in the report, 'report_options': { 'id': the report id, 'formats': [ { 'value': format key, 'display': user visible title for format, }, ], 'values': [ { 'value': key describing an available column, 'display': user visible title of column, }, ], 'name': string containing the report name. }, } """ company = get_company_or_404(request) validator = ApiValidator() report_id = request.GET.get('report_id') if report_id is None: validator.note_field_error('report_id', 'Missing report id.') if validator.has_errors(): return validator.build_error_response() report_list = list(DynamicReport.objects.filter( id=report_id, owner=company)) if len(report_list) < 1: validator.note_field_error('report_id', 'Unknown report id.') if validator.has_errors(): return validator.build_error_response() report = report_list[0] count = len(report.python) rps = (ReportPresentation.objects .active_for_report_type_data_type(report.report_data)) cols = ( ConfigurationColumn.objects .active_for_report_data(report.report_data) .filter(Q(filter_only__isnull=True) | Q(filter_only=False)) .order_by('order')) values = [ {'value': c.column_name, 'display': c.alias or c.column_name} for c in cols ] data = { 'count': count, 'report_options': { 'id': report.id, 'formats': [ {'value': rp.id, 'display': rp.display_name} for rp in rps ], 'values': values, 'name': report.name, }, } return HttpResponse(content_type='application/json', content=json.dumps(data))
def dynamic_chart(request): """ return charting data given a set of filters, date range, and drilldown selection request { "date_start": "01/01/2016 00:00:00", "date_end": "01/08/2016 00:00:00", "active_filters": [{"type": "country", "value": "USA"}, {"type": "state", "value": "Indiana"}], "report": "found_on", "group_overwrite": "browser", } response { "column_names": [ {"key": "browser", "label": "Browser"}, {"key": "job_views", "label": "Job Views"}, ], "rows": [ {"browser": "Chrome", "job_views": "101", "visits": "1050"}, {"browser": "IE11", "job_views": "231", "visits": "841"}, {"browser": "IE8", "job_views": "23", "visits": "341"}, {"browser": "Firefox", "job_views": "21", "visits": "298"}, {"browser": "Netscape Navigator", "job_views": "1", "visits": "1"}, {"browser": "Dolphin", "job_views": "1", "visits": "1"} ] } """ if request.method != 'POST': return HttpResponseNotAllowed(['POST']) validator = ApiValidator() query_data = json.loads(request.POST.get('request', '{}')) if not query_data: validator.note_error("No data provided.") if validator.has_errors(): return validator.build_error_response() required_fields = ['date_end', 'date_start', 'report'] for field in required_fields: if not query_data.get(field): validator.note_field_error(field, '%s is required' % field) if validator.has_errors(): return validator.build_error_response() try: date_start = dateparser.parse(query_data['date_start']) except ValueError: validator.note_field_error('date_start', 'Invalid date start: ' + query_data['date_end']) try: date_end = dateparser.parse(query_data['date_end']) except ValueError: validator.note_field_error('date_end', 'Invalid date end: ' + query_data['date_end']) report_data = get_analytics_reporttype_datatype(query_data['report']) if not report_data: validator.note_field_error( "analytics_report_id", "No analytics report found.") if validator.has_errors(): return validator.build_error_response() sample_size = 50000 # TODO: Add sample size to request object job_views = get_mongo_db().job_views buids = get_company_buids(request) top_query = build_top_query(date_start, date_end, buids) sample_query, total_count = retrieve_sampling_query_and_count(job_views, top_query, sample_size) if not sample_query: sample_size = total_count active_filter_query = build_active_filter_query(query_data) group_by, remaining_dimensions = determine_data_group_by_and_remaining( query_data, report_data ) group_query = build_group_by_query(group_by.column_name) query = [ {'$match': top_query}, ] + sample_query + active_filter_query + group_query records = job_views.aggregate(query, allowDiskUse=True) if sample_query: def curried_query(count): return calculate_error_and_count(total_count, sample_size, count) records = adjust_records_for_sampling(records, curried_query) response = { "column_names": [ {"key": group_by.column_name, "label": group_by.filter_interface_display}, {"key": "job_views", "label": "Job Views"}, {"key": "visitors", "label": "Visitors"}, ], "rows": [format_return_dict(r, group_by.column_name) for r in records], "chart_type": group_by.filter_interface_type, "group_by": group_by.column_name, "remaining_dimensions": [{"key": d.column_name, "label": d.filter_interface_display} for d in remaining_dimensions] } return HttpResponse(json.dumps(response))