<commit_before># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals

import frappe
import os, json, datetime
import gzip

from frappe import _
from frappe.modules import scrub, get_module_path
from frappe.utils import flt, cint, get_html_format, cstr, get_url_to_form
from frappe.model.utils import render_include
from frappe.translate import send_translations
import frappe.desk.reportview
from frappe.permissions import get_role_permissions
from six import string_types, iteritems
from datetime import timedelta
from frappe.utils.file_manager import get_file

def get_report_doc(report_name):
	doc = frappe.get_doc("Report", report_name)
	if not doc.is_permitted():
		frappe.throw(_("You don't have access to Report: {0}").format(report_name), frappe.PermissionError)

	if not frappe.has_permission(doc.ref_doctype, "report"):
		frappe.throw(_("You don't have permission to get a report on: {0}").format(doc.ref_doctype),
			frappe.PermissionError)

	if doc.disabled:
		frappe.throw(_("Report {0} is disabled").format(report_name))

	return doc


def generate_report_result(report, filters=None, user=None):
	status = None
	if not user:
		user = frappe.session.user
	if not filters:
		filters = []

	if filters and isinstance(filters, string_types):
		filters = json.loads(filters)
	columns, result, message, chart, data_to_be_printed = [], [], None, None, None
	if report.report_type == "Query Report":
		if not report.query:
			status = "error"
			frappe.msgprint(_("Must specify a Query to run"), raise_exception=True)

		if not report.query.lower().startswith("select"):
			status = "error"
			frappe.msgprint(_("Query must be a SELECT"), raise_exception=True)

		result = [list(t) for t in frappe.db.sql(report.query, filters)]
		columns = [cstr(c[0]) for c in frappe.db.get_description()]
	else:
		module = report.module or frappe.db.get_value("DocType", report.ref_doctype, "module")
		if report.is_standard == "Yes":
			method_name = get_report_module_dotted_path(module, report.name) + ".execute"
			threshold = 10
			res = []

			start_time = datetime.datetime.now()
			# The JOB
			res = frappe.get_attr(method_name)(frappe._dict(filters))

			end_time = datetime.datetime.now()

			if (end_time - start_time).seconds > threshold and not report.prepared_report:
				report.db_set('prepared_report', 1)

			columns, result = res[0], res[1]
			if len(res) > 2:
				message = res[2]
			if len(res) > 3:
				chart = res[3]
			if len(res) > 4:
				data_to_be_printed = res[4]

	if result:
		result = get_filtered_data(report.ref_doctype, columns, result, user)

	return {
		"result": result,
		"columns": columns,
		"message": message,
		"chart": chart,
		"data_to_be_printed": data_to_be_printed,
		"status": status
	}

@frappe.whitelist()
def background_enqueue_run(report_name, filters=None, user=None):
	"""run reports in background"""
	if not user:
		user = frappe.session.user
	report = get_report_doc(report_name)
	track_instance = \
		frappe.get_doc({
			"doctype": "Prepared Report",
			"report_name": report_name,
			# This looks like an insanity but, without this it'd be very hard to find Prepared Reports matvhing given condition
			# We're ensuring that spacing is consistent. e.g. JS seems to put no spaces after ":", Python on the other hand does.
			"filters": json.dumps(json.loads(filters)),
			"ref_report_doctype": report_name,
			"report_type": report.report_type,
			"query": report.query,
			"module": report.module,
		})
	track_instance.insert(ignore_permissions=True)
	frappe.db.commit()
	return {
		"redirect_url": get_url_to_form("Prepared Report", track_instance.name)
	}


@frappe.whitelist()
def get_script(report_name):
	report = get_report_doc(report_name)

	module = report.module or frappe.db.get_value("DocType", report.ref_doctype, "module")
	module_path = get_module_path(module)
	report_folder = os.path.join(module_path, "report", scrub(report.name))
	script_path = os.path.join(report_folder, scrub(report.name) + ".js")
	print_path = os.path.join(report_folder, scrub(report.name) + ".html")

	script = None
	if os.path.exists(script_path):
		with open(script_path, "r") as f:
			script = f.read()

	html_format = get_html_format(print_path)

	if not script and report.javascript:
		script = report.javascript

	if not script:
		script = "frappe.query_reports['%s']={}" % report_name

	# load translations
	if frappe.lang != "en":
		send_translations(frappe.get_lang_dict("report", report_name))

	return {
		"script": render_include(script),
		"html_format": html_format
	}


@frappe.whitelist()
@frappe.read_only()
def run(report_name, filters=None, user=None):

	report = get_report_doc(report_name)
	if not user:
		user = frappe.session.user
	if not frappe.has_permission(report.ref_doctype, "report"):
		frappe.msgprint(_("Must have report permission to access this report."),
			raise_exception=True)

	result = None

	if report.prepared_report:
		if filters:
			if isinstance(filters, string_types):
				filters = json.loads(filters)

			dn = filters.get("prepared_report_name")
		else:
			dn = ""
		result = get_prepared_report_result(report, filters, dn)
	else:
		result = generate_report_result(report, filters, user)

	result["add_total_row"] = report.add_total_row

	return result


def get_prepared_report_result(report, filters, dn=""):
	latest_report_data = {}
	doc_list = frappe.get_all("Prepared Report", filters={"status": "Completed", "report_name": report.name})
	doc = None
	if len(doc_list):
		if dn:
			# Get specified dn
			doc = frappe.get_doc("Prepared Report", dn)
		else:
			# Get latest
			doc = frappe.get_doc("Prepared Report", doc_list[0])

		# Prepared Report data is stored in a GZip compressed JSON file
		attached_file_name = frappe.db.get_value("File", {"attached_to_doctype": doc.doctype, "attached_to_name":doc.name}, "name")
		compressed_content = get_file(attached_file_name)[1]
		uncompressed_content = gzip.decompress(compressed_content)
		data = json.loads(uncompressed_content)
		if data:
			latest_report_data = {
				"columns": json.loads(doc.columns) if doc.columns else data[0],
				"result": data[1:]
			}

	latest_report_data.update({
		"prepared_report": True,
		"doc": doc
	})

	return latest_report_data

@frappe.whitelist()
def export_query():
	"""export from query reports"""
<commit_msg>fix(prepared-report): Show data from report matching filters and owner<commit_after># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals

import frappe
import os, json, datetime
import gzip

from frappe import _
from frappe.modules import scrub, get_module_path
from frappe.utils import flt, cint, get_html_format, cstr, get_url_to_form
from frappe.model.utils import render_include
from frappe.translate import send_translations
import frappe.desk.reportview
from frappe.permissions import get_role_permissions
from six import string_types, iteritems
from datetime import timedelta
from frappe.utils.file_manager import get_file

def get_report_doc(report_name):
	doc = frappe.get_doc("Report", report_name)
	if not doc.is_permitted():
		frappe.throw(_("You don't have access to Report: {0}").format(report_name), frappe.PermissionError)

	if not frappe.has_permission(doc.ref_doctype, "report"):
		frappe.throw(_("You don't have permission to get a report on: {0}").format(doc.ref_doctype),
			frappe.PermissionError)

	if doc.disabled:
		frappe.throw(_("Report {0} is disabled").format(report_name))

	return doc


def generate_report_result(report, filters=None, user=None):
	status = None
	if not user:
		user = frappe.session.user
	if not filters:
		filters = []

	if filters and isinstance(filters, string_types):
		filters = json.loads(filters)
	columns, result, message, chart, data_to_be_printed = [], [], None, None, None
	if report.report_type == "Query Report":
		if not report.query:
			status = "error"
			frappe.msgprint(_("Must specify a Query to run"), raise_exception=True)

		if not report.query.lower().startswith("select"):
			status = "error"
			frappe.msgprint(_("Query must be a SELECT"), raise_exception=True)

		result = [list(t) for t in frappe.db.sql(report.query, filters)]
		columns = [cstr(c[0]) for c in frappe.db.get_description()]
	else:
		module = report.module or frappe.db.get_value("DocType", report.ref_doctype, "module")
		if report.is_standard == "Yes":
			method_name = get_report_module_dotted_path(module, report.name) + ".execute"
			threshold = 10
			res = []

			start_time = datetime.datetime.now()
			# The JOB
			res = frappe.get_attr(method_name)(frappe._dict(filters))

			end_time = datetime.datetime.now()

			if (end_time - start_time).seconds > threshold and not report.prepared_report:
				report.db_set('prepared_report', 1)

			columns, result = res[0], res[1]
			if len(res) > 2:
				message = res[2]
			if len(res) > 3:
				chart = res[3]
			if len(res) > 4:
				data_to_be_printed = res[4]

	if result:
		result = get_filtered_data(report.ref_doctype, columns, result, user)

	return {
		"result": result,
		"columns": columns,
		"message": message,
		"chart": chart,
		"data_to_be_printed": data_to_be_printed,
		"status": status
	}

@frappe.whitelist()
def background_enqueue_run(report_name, filters=None, user=None):
	"""run reports in background"""
	if not user:
		user = frappe.session.user
	report = get_report_doc(report_name)
	track_instance = \
		frappe.get_doc({
			"doctype": "Prepared Report",
			"report_name": report_name,
			# This looks like an insanity but, without this it'd be very hard to find Prepared Reports matvhing given condition
			# We're ensuring that spacing is consistent. e.g. JS seems to put no spaces after ":", Python on the other hand does.
			"filters": json.dumps(json.loads(filters)),
			"ref_report_doctype": report_name,
			"report_type": report.report_type,
			"query": report.query,
			"module": report.module,
		})
	track_instance.insert(ignore_permissions=True)
	frappe.db.commit()
	return {
		"redirect_url": get_url_to_form("Prepared Report", track_instance.name)
	}


@frappe.whitelist()
def get_script(report_name):
	report = get_report_doc(report_name)

	module = report.module or frappe.db.get_value("DocType", report.ref_doctype, "module")
	module_path = get_module_path(module)
	report_folder = os.path.join(module_path, "report", scrub(report.name))
	script_path = os.path.join(report_folder, scrub(report.name) + ".js")
	print_path = os.path.join(report_folder, scrub(report.name) + ".html")

	script = None
	if os.path.exists(script_path):
		with open(script_path, "r") as f:
			script = f.read()

	html_format = get_html_format(print_path)

	if not script and report.javascript:
		script = report.javascript

	if not script:
		script = "frappe.query_reports['%s']={}" % report_name

	# load translations
	if frappe.lang != "en":
		send_translations(frappe.get_lang_dict("report", report_name))

	return {
		"script": render_include(script),
		"html_format": html_format
	}


@frappe.whitelist()
@frappe.read_only()
def run(report_name, filters=None, user=None):

	report = get_report_doc(report_name)
	if not user:
		user = frappe.session.user
	if not frappe.has_permission(report.ref_doctype, "report"):
		frappe.msgprint(_("Must have report permission to access this report."),
			raise_exception=True)

	result = None

	if report.prepared_report:
		if filters:
			if isinstance(filters, string_types):
				filters = json.loads(filters)

			dn = filters.get("prepared_report_name")
		else:
			dn = ""
		result = get_prepared_report_result(report, filters, dn, user)
	else:
		result = generate_report_result(report, filters, user)

	result["add_total_row"] = report.add_total_row

	return result


def get_prepared_report_result(report, filters, dn="", user=None):
	latest_report_data = {}
	# Only look for completed prepared reports with given filters.
	doc_list = frappe.get_all("Prepared Report", filters={"status": "Completed", "report_name": report.name, "filters": json.dumps(filters), "owner": user})
	doc = None
	if len(doc_list):
		if dn:
			# Get specified dn
			doc = frappe.get_doc("Prepared Report", dn)
		else:
			# Get latest
			doc = frappe.get_doc("Prepared Report", doc_list[0])

		# Prepared Report data is stored in a GZip compressed JSON file
		attached_file_name = frappe.db.get_value("File", {"attached_to_doctype": doc.doctype, "attached_to_name":doc.name}, "name")
		compressed_content = get_file(attached_file_name)[1]
		uncompressed_content = gzip.decompress(compressed_content)
		data = json.loads(uncompressed_content)
		if data:
			latest_report_data = {
				"columns": json.loads(doc.columns) if doc.columns else data[0],
				"result": data[1:]
			}

	latest_report_data.update({
		"prepared_report": True,
		"doc": doc
	})

	return latest_report_data

@frappe.whitelist()
def export_query():
	"""export from query reports"""

{'fraction_non_alphanumeric': 0.12078152753108348, 'fraction_numerical': 0.003552397868561279, 'mean_word_length': 4.937643282897754, 'pattern_counts': {'":': 58, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3279572', 'n_tokens_mistral': 4771, 'n_tokens_neox': 4429, 'n_words': 1077}