def get_payment_url(self): if self.reference_doctype != "Fees": data = frappe.db.get_value(self.reference_doctype, self.reference_name, ["company", "customer_name"], as_dict=1) else: data = frappe.db.get_value(self.reference_doctype, self.reference_name, ["student_name"], as_dict=1) data.update({"company": frappe.defaults.get_defaults().company}) controller = get_payment_gateway_controller(self.payment_gateway) controller.validate_transaction_currency(self.currency) if hasattr(controller, 'validate_minimum_transaction_amount'): controller.validate_minimum_transaction_amount( self.currency, self.grand_total) return controller.get_payment_url( **{ "amount": flt(self.grand_total, self.precision("grand_total")), "title": frappe.as_unicode(data.company), "description": frappe.as_unicode(self.subject), "reference_doctype": "Payment Request", "reference_docname": self.name, "payer_email": self.email_to or frappe.session.user, "payer_name": frappe.as_unicode(data.customer_name), "order_id": self.name, "currency": self.currency })
def execute(): ignore_doctypes = ["Lead", "Opportunity", "POS Profile", "Tax Rule", "Pricing Rule"] customers = frappe.get_all('Customer', fields=["name", "customer_group"]) customer_group_fetch = get_fetch_fields('Customer', 'Customer Group', ignore_doctypes) batch_size = 1000 for i in range(0, len(customers), batch_size): batch_customers = customers[i:i + batch_size] for d in customer_group_fetch: when_then = [] for customer in batch_customers: value = frappe.db.escape(frappe.as_unicode(customer.get("customer_group"))) when_then.append(''' WHEN `%s` = "%s" and %s != "%s" THEN "%s" '''%(d["master_fieldname"], frappe.db.escape(frappe.as_unicode(customer.name)), d["linked_to_fieldname"], value, value)) frappe.db.sql(""" update `tab%s` set %s = CASE %s ELSE `%s` END """%(d['doctype'], d.linked_to_fieldname, " ".join(when_then), d.linked_to_fieldname))
def _create_reference_document(self, doctype): """ Create reference document if it does not exist in the system. """ parent = frappe.new_doc(doctype) email_fileds = self.get_email_fields(doctype) if email_fileds.subject_field: parent.set(email_fileds.subject_field, frappe.as_unicode(self.subject)[:140]) if email_fileds.sender_field: parent.set(email_fileds.sender_field, frappe.as_unicode(self.from_email)) parent.flags.ignore_mandatory = True try: parent.insert(ignore_permissions=True) except frappe.DuplicateEntryError: # try and find matching parent parent_name = frappe.db.get_value(self.email_account.append_to, {email_fileds.sender_field: self.from_email} ) if parent_name: parent.name = parent_name else: parent = None return parent
def execute(): ignore_doctypes = [ "Lead", "Opportunity", "POS Profile", "Tax Rule", "Pricing Rule" ] customers = frappe.get_all('Customer', fields=["name", "customer_group"]) customer_group_fetch = get_fetch_fields('Customer', 'Customer Group', ignore_doctypes) batch_size = 1000 for i in range(0, len(customers), batch_size): batch_customers = customers[i:i + batch_size] for d in customer_group_fetch: when_then = [] for customer in batch_customers: value = frappe.db.escape( frappe.as_unicode(customer.get("customer_group"))) when_then.append(''' WHEN `%s` = "%s" and %s != "%s" THEN "%s" ''' % (d["master_fieldname"], frappe.db.escape(frappe.as_unicode( customer.name)), d["linked_to_fieldname"], value, value)) frappe.db.sql(""" update `tab%s` set %s = CASE %s ELSE `%s` END """ % (d['doctype'], d.linked_to_fieldname, " ".join(when_then), d.linked_to_fieldname))
def create_new_parent(self, communication, email): '''If no parent found, create a new reference document''' # no parent found, but must be tagged # insert parent type doc parent = frappe.new_doc(self.append_to) if self.subject_field: parent.set(self.subject_field, frappe.as_unicode(email.subject)[:140]) if self.sender_field: parent.set(self.sender_field, frappe.as_unicode(email.from_email)) if parent.meta.has_field("email_account"): parent.email_account = self.name parent.flags.ignore_mandatory = True try: parent.insert(ignore_permissions=True) except frappe.DuplicateEntryError: # try and find matching parent parent_name = frappe.db.get_value( self.append_to, {self.sender_field: email.from_email}) if parent_name: parent.name = parent_name else: parent = None # NOTE if parent isn't found and there's no subject match, it is likely that it is a new conversation thread and hence is_first = True communication.is_first = True return parent
def create_new_parent(self, communication, email): '''If no parent found, create a new reference document''' # no parent found, but must be tagged # insert parent type doc parent = frappe.new_doc(self.append_to) if self.subject_field: parent.set(self.subject_field, frappe.as_unicode(email.subject)) if self.sender_field: parent.set(self.sender_field, frappe.as_unicode(email.from_email)) parent.flags.ignore_mandatory = True try: parent.insert(ignore_permissions=True) except frappe.DuplicateEntryError: # try and find matching parent parent_name = frappe.db.get_value(self.append_to, {self.sender_field: email.from_email}) if parent_name: parent.name = parent_name else: parent = None # NOTE if parent isn't found and there's no subject match, it is likely that it is a new conversation thread and hence is_first = True communication.is_first = True return parent
def test_base_template(self): content = get_page_content('/_test/_test_custom_base.html') # assert the text in base template is rendered self.assertTrue('<h1>This is for testing</h1>' in frappe.as_unicode(content)) # assert template block rendered self.assertTrue('<p>Test content</p>' in frappe.as_unicode(content))
def login(): # LDAP LOGIN LOGIC args = frappe.form_dict user = authenticate_ldap_user(frappe.as_unicode(args.usr), frappe.as_unicode(args.pwd)) frappe.local.login_manager.user = user.name frappe.local.login_manager.post_login() # because of a GET request! frappe.db.commit()
def login(): #### LDAP LOGIN LOGIC ##### args = frappe.form_dict user = authenticate_ldap_user(frappe.as_unicode(args.usr), frappe.as_unicode(args.pwd)) frappe.local.login_manager.user = user.name frappe.local.login_manager.post_login() # because of a GET request! frappe.db.commit()
def employee_shift(work_shift): count = 0 employees = frappe.get_all("Employee", fields=["name", "work_shift"], filters={'status': 'Active'}) for emp in employees: ws = emp.work_shift if ws and frappe.as_unicode(work_shift.strip()) == frappe.as_unicode( emp.work_shift.strip()): count += 1 return count
def login(): # LDAP LOGIN LOGIC args = frappe.form_dict ldap = frappe.get_doc("LDAP Settings") user = ldap.authenticate(frappe.as_unicode(args.usr), frappe.as_unicode(args.pwd)) frappe.local.login_manager.user = user.name frappe.local.login_manager.post_login() # because of a GET request! frappe.db.commit()
def escape(self, s, percent=True): """Excape quotes and percent in given string.""" # pymysql expects unicode argument to escape_string with Python 3 s = as_unicode(pymysql.escape_string(as_unicode(s)), "utf-8").replace("`", "\\`") # NOTE separating % escape, because % escape should only be done when using LIKE operator # or when you use python format string to generate query that already has a %s # for example: sql("select name from `tabUser` where name=%s and {0}".format(conditions), something) # defaulting it to True, as this is the most frequent use case # ideally we shouldn't have to use ESCAPE and strive to pass values via the values argument of sql if percent: s = s.replace("%", "%%") return s
def escape(s, percent=True): """Excape quotes and percent in given string.""" # pymysql expects unicode argument to escape_string with Python 3 s = frappe.as_unicode(pymysql.escape_string(frappe.as_unicode(s)), "utf-8").replace("`", "\\`") # NOTE separating % escape, because % escape should only be done when using LIKE operator # or when you use python format string to generate query that already has a %s # for example: sql("select name from `tabUser` where name=%s and {0}".format(conditions), something) # defaulting it to True, as this is the most frequent use case # ideally we shouldn't have to use ESCAPE and strive to pass values via the values argument of sql if percent: s = s.replace("%", "%%") return "'" + s + "'"
def find_parent_based_on_subject_and_sender(self, communication, email): '''Find parent document based on subject and sender match''' parent = None if self.append_to and self.sender_field: if self.subject_field: # try and match by subject and sender # if sent by same sender with same subject, # append it to old coversation subject = frappe.as_unicode(strip(re.sub("(^\s*(Fw|FW|fwd)[^:]*:|\s*(Re|RE)[^:]*:\s*)*", "", email.subject))) parent = frappe.db.get_all(self.append_to, filters={ self.sender_field: email.from_email, self.subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") # match only subject field # when the from_email is of a user in the system # and subject is atleast 10 chars long if not parent and len(subject) > 10 and is_system_user(email.from_email): parent = frappe.db.get_all(self.append_to, filters={ self.subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=10)).strftime(DATE_FORMAT)) }, fields="name") if parent: parent = frappe._dict(doctype=self.append_to, name=parent[0].name) return parent
def extract_messages_from_code(code): """ Extracts translatable strings from a code file :param code: code from which translatable files are to be extracted :param is_py: include messages in triple quotes e.g. `_('''message''')` """ from jinja2 import TemplateError try: code = frappe.as_unicode(render_include(code)) # Exception will occur when it encounters John Resig's microtemplating code except (TemplateError, ImportError, InvalidIncludePath, IOError) as e: if isinstance(e, InvalidIncludePath): frappe.clear_last_message() pass messages = [] for m in TRANSLATE_PATTERN.finditer(code): message = m.group("message") context = m.group("py_context") or m.group("js_context") pos = m.start() if is_translatable(message): messages.append([pos, message, context]) return add_line_number(messages, code)
def make_boilerplate(template, doc, opts=None): target_path = get_doc_path(doc.module, doc.doctype, doc.name) template_name = template.replace("controller", scrub(doc.name)) if template_name.endswith('._py'): template_name = template_name[:-4] + '.py' target_file_path = os.path.join(target_path, template_name) if not doc: doc = {} app_publisher = get_app_publisher(doc.module) if not os.path.exists(target_file_path): if not opts: opts = {} with open(target_file_path, 'w') as target: with open( os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype), "boilerplate", template), 'r') as source: target.write( frappe.as_unicode( frappe.utils.cstr(source.read()).format( app_publisher=app_publisher, year=frappe.utils.nowdate()[:4], classname=doc.name.replace(" ", ""), doctype=doc.name, **opts)))
def extract_messages_from_code(code, is_py=False): """Extracts translatable srings from a code file :param code: code from which translatable files are to be extracted :param is_py: include messages in triple quotes e.g. `_('''message''')`""" try: code = frappe.as_unicode(render_include(code)) except (TemplateError, ImportError, InvalidIncludePath, IOError): # Exception will occur when it encounters John Resig's microtemplating code pass messages = [] messages += [(m.start(), m.groups()[0]) for m in re.compile('_\("([^"]*)"').finditer(code)] messages += [(m.start(), m.groups()[0]) for m in re.compile("_\('([^']*)'").finditer(code)] if is_py: messages += [ (m.start(), m.groups()[0]) for m in re.compile('_\("{3}([^"]*)"{3}.*\)').finditer(code) ] messages = [(pos, message) for pos, message in messages if is_translatable(message)] return pos_to_line_no(messages, code)
def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False, parent=None): '''Returns a value form a document :param doctype: DocType to be queried :param fieldname: Field to be returned (default `name`) :param filters: dict or string for identifying the record''' if frappe.is_table(doctype): check_parent_permission(parent, doctype) if not frappe.has_permission(doctype): frappe.throw(_("No permission for {0}".format(doctype)), frappe.PermissionError) try: filters = json.loads(filters) if isinstance(filters, (integer_types, float)): filters = frappe.as_unicode(filters) except (TypeError, ValueError): # filters are not passesd, not json pass try: fieldname = json.loads(fieldname) except (TypeError, ValueError): # name passed, not json pass # check whether the used filters were really parseable and usable # and did not just result in an empty string or dict if not filters: filters = None return frappe.db.get_value(doctype, filters, fieldname, as_dict=as_dict, debug=debug)
def get_chart(chart_template, existing_company=None): chart = {} if existing_company: return get_account_tree_from_existing_company(existing_company) elif chart_template == "Standard": from erpnext.accounts.doctype.account.chart_of_accounts.verified import standard_chart_of_accounts return standard_chart_of_accounts.get() elif chart_template == "Standard with Numbers": from erpnext.accounts.doctype.account.chart_of_accounts.verified \ import standard_chart_of_accounts_with_account_number return standard_chart_of_accounts_with_account_number.get() else: folders = ("verified",) if frappe.local.flags.allow_unverified_charts: folders = ("verified", "unverified") for folder in folders: path = os.path.join(os.path.dirname(__file__), folder) for fname in os.listdir(path): fname = frappe.as_unicode(fname) if fname.endswith(".json"): with open(os.path.join(path, fname), "r") as f: chart = f.read() if chart and json.loads(chart).get("name") == chart_template: return json.loads(chart).get("tree")
def get_charts_for_country(country, with_standard=False): charts = [] def _get_chart_name(content): if content: content = json.loads(content) if (content and content.get("disabled", "No") == "No") \ or frappe.local.flags.allow_unverified_charts: charts.append(content["name"]) country_code = frappe.db.get_value("Country", country, "code") if country_code: folders = ("verified",) if frappe.local.flags.allow_unverified_charts: folders = ("verified", "unverified") for folder in folders: path = os.path.join(os.path.dirname(__file__), folder) for fname in os.listdir(path): fname = frappe.as_unicode(fname) if (fname.startswith(country_code) or fname.startswith(country)) and fname.endswith(".json"): with open(os.path.join(path, fname), "r") as f: _get_chart_name(f.read()) if len(charts) != 1 or with_standard: charts += ["Standard", "Standard with Numbers"] return charts
def get_chart(chart_template, existing_company=None): chart = {} if existing_company: return get_account_tree_from_existing_company(existing_company) elif chart_template == "Standard": from erpnext.accounts.doctype.account.chart_of_accounts.verified import standard_chart_of_accounts return standard_chart_of_accounts.get() elif chart_template == "Standard with Numbers": from erpnext.accounts.doctype.account.chart_of_accounts.verified \ import standard_chart_of_accounts_with_account_number return standard_chart_of_accounts_with_account_number.get() else: folders = ("verified", ) if frappe.local.flags.allow_unverified_charts: folders = ("verified", "unverified") for folder in folders: path = os.path.join(os.path.dirname(__file__), folder) for fname in os.listdir(path): fname = frappe.as_unicode(fname) if fname.endswith(".json"): with open(os.path.join(path, fname), "r") as f: chart = f.read() if chart and json.loads(chart).get( "name") == chart_template: return json.loads(chart).get("tree")
def make_boilerplate(template, doc, opts=None): target_path = get_doc_path(doc.module, doc.doctype, doc.name) template_name = template.replace("controller", scrub(doc.name)) if template_name.endswith("._py"): template_name = template_name[:-4] + ".py" target_file_path = os.path.join(target_path, template_name) if not doc: doc = {} app_publisher = get_app_publisher(doc.module) if not os.path.exists(target_file_path): if not opts: opts = {} base_class = "Document" base_class_import = "from frappe.model.document import Document" if doc.get("is_tree"): base_class = "NestedSet" base_class_import = "from frappe.utils.nestedset import NestedSet" custom_controller = "pass" if doc.get("is_virtual"): custom_controller = """ def db_insert(self): pass def load_from_db(self): pass def db_update(self): pass def get_list(self, args): pass def get_count(self, args): pass def get_stats(self, args): pass""" with open(target_file_path, "w") as target: with open( os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype), "boilerplate", template), "r", ) as source: target.write( frappe.as_unicode( frappe.utils.cstr(source.read()).format( app_publisher=app_publisher, year=frappe.utils.nowdate()[:4], classname=doc.name.replace(" ", ""), base_class_import=base_class_import, base_class=base_class, doctype=doc.name, **opts, custom_controller=custom_controller)))
def auth(username=None, password=None): username = username or frappe.form_dict.username password = password or frappe.form_dict.password print('auth', username, password) if username == 'root': root_password = frappe.db.get_single_value( "IOT HDB Settings", "mqtt_root_password") or 'bXF0dF9pb3RfYWRtaW4K' if password == root_password: return http_200ok() else: return http_403("Auth Error") else: sid = frappe.db.get_single_value( "IOT HDB Settings", "mqtt_device_password_sid") or 'ZGV2aWNlIGlkCg==' m = hashlib.md5() m.update(frappe.as_unicode(username + sid).encode('utf-8')) if password == m.hexdigest(): # TODO: for the one which is not in IOT Device should we check the frappe-make module to see if it is our device? if frappe.get_value("IOT Device", username, "enabled") == 1: return http_200ok() else: return http_403("Auth Error") else: try: frappe.local.login_manager.authenticate(username, password) if frappe.local.login_manager.user == username: return http_200ok() else: return http_403("Auth Error") except Exception as ex: return http_403("Auth Error") return http_403("Auth Error")
def handle_html(data): # return if no html tags found data = frappe.as_unicode(data) if '<' not in data: return data if '>' not in data: return data from html2text import HTML2Text h = HTML2Text() h.unicode_snob = True h = h.unescape(data or "") obj = HTML2Text() obj.ignore_links = True obj.body_width = 0 try: value = obj.handle(h) except Exception: # unable to parse html, send it raw return value value = ", ".join(value.split(' \n')) value = " ".join(value.split('\n')) value = ", ".join(value.split('# ')) return value
def login(): # LDAP LOGIN LOGIC args = frappe.form_dict ldap = frappe.get_doc("LDAP Settings") user = ldap.authenticate(frappe.as_unicode(args.usr), frappe.as_unicode(args.pwd)) frappe.local.login_manager.user = user.name if should_run_2fa(user.name): authenticate_for_2factor(user.name) if not confirm_otp_token(frappe.local.login_manager): return False frappe.local.login_manager.post_login() # because of a GET request! frappe.db.commit()
def handle_html(data): from html2text import HTML2Text # return if no html tags found data = frappe.as_unicode(data) if "<" not in data or ">" not in data: return data h = unescape_html(data or "") obj = HTML2Text() obj.ignore_links = True obj.body_width = 0 try: value = obj.handle(h) except Exception: # unable to parse html, send it raw return data value = ", ".join(value.split(" \n")) value = " ".join(value.split("\n")) value = ", ".join(value.split("# ")) return value
def get_charts_for_country(country, with_standard=False): charts = [] def _get_chart_name(content): if content: content = json.loads(content) if (content and content.get("disabled", "No") == "No") \ or frappe.local.flags.allow_unverified_charts: charts.append(content["name"]) country_code = frappe.db.get_value("Country", country, "code") if country_code: folders = ("verified", ) if frappe.local.flags.allow_unverified_charts: folders = ("verified", "unverified") for folder in folders: path = os.path.join(os.path.dirname(__file__), folder) for fname in os.listdir(path): fname = frappe.as_unicode(fname) if (fname.startswith(country_code) or fname.startswith(country)) and fname.endswith(".json"): with open(os.path.join(path, fname), "r") as f: _get_chart_name(f.read()) if len(charts) != 1 or with_standard: charts += ["Standard", "Standard with Numbers"] return charts
def extract_messages_from_code(code): """ Extracts translatable strings from a code file :param code: code from which translatable files are to be extracted :param is_py: include messages in triple quotes e.g. `_('''message''')` """ from jinja2 import TemplateError try: code = frappe.as_unicode(render_include(code)) except (TemplateError, ImportError, InvalidIncludePath, IOError): # Exception will occur when it encounters John Resig's microtemplating code pass messages = [] pattern = r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,\s*(.)*?\s*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)" for m in re.compile(pattern).finditer(code): message = m.group('message') context = m.group('py_context') or m.group('js_context') pos = m.start() if is_translatable(message): messages.append([pos, message, context]) return add_line_number(messages, code)
def make_boilerplate(template, doc, opts=None): target_path = get_doc_path(doc.module, doc.doctype, doc.name) template_name = template.replace("controller", scrub(doc.name)) if template_name.endswith('._py'): template_name = template_name[:-4] + '.py' target_file_path = os.path.join(target_path, template_name) if not doc: doc = {} app_publisher = get_app_publisher(doc.module) if not os.path.exists(target_file_path): if not opts: opts = {} with open(target_file_path, 'w') as target: with open(os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype), "boilerplate", template), 'r') as source: target.write(frappe.as_unicode( frappe.utils.cstr(source.read()).format( app_publisher=app_publisher, year=frappe.utils.nowdate()[:4], classname=doc.name.replace(" ", ""), doctype=doc.name, **opts) ))
def update_app_details(self): pkg_info_file = os.path.join('..', 'apps', self.app_name, '{app_name}.egg-info'.format(app_name=self.app_name), 'PKG-INFO') if os.path.isfile(pkg_info_file): app_data_path = pkg_info_file with open(app_data_path, 'r') as f: app_data = f.readlines() app_data = frappe.as_unicode(''.join(app_data)).split('\n') if '' in app_data: app_data.remove('') app_data = [x+'\n' for x in app_data] for data in app_data: if 'Version:' in data: self.version = ''.join(re.findall('Version: (.*?)\\n', data)) elif 'Summary:' in data: self.app_description = ''.join(re.findall('Summary: (.*?)\\n', data)) elif 'Author:' in data: self.app_publisher = ''.join(re.findall('Author: (.*?)\\n', data)) elif 'Author-email:' in data: self.app_email = ''.join(re.findall('Author-email: (.*?)\\n', data)) self.app_title = self.app_name self.app_title = self.app_title.replace('-', ' ') self.app_title = self.app_title.replace('_', ' ') if os.path.isdir(os.path.join('..', 'apps', self.app_name, '.git')): self.current_git_branch = safe_decode(check_output("git rev-parse --abbrev-ref HEAD".split(), cwd=os.path.join('..', 'apps', self.app_name))).strip('\n') self.is_git_repo = True else: self.current_git_branch = None self.is_git_repo = False else: frappe.throw("Hey developer, the app you're trying to create an \ instance of doesn't actually exist. You could consider setting \ developer flag to 0 to actually create the app")
def handle_html(data): # return if no html tags found data = frappe.as_unicode(data) if '<' not in data: return data if '>' not in data: return data from html2text import HTML2Text h = HTML2Text() h.unicode_snob = True h = h.unescape(data or "") obj = HTML2Text() obj.ignore_links = True obj.body_width = 0 try: value = obj.handle(h) except Exception: # unable to parse html, send it raw return data value = ", ".join(value.split(' \n')) value = " ".join(value.split('\n')) value = ", ".join(value.split('# ')) return value
def find_parent_based_on_subject_and_sender(self, communication, email): '''Find parent document based on subject and sender match''' parent = None if self.append_to and self.sender_field: if self.subject_field: # try and match by subject and sender # if sent by same sender with same subject, # append it to old coversation subject = frappe.as_unicode(strip(re.sub(r"(^\s*(fw|fwd|wg)[^:]*:|\s*(re|aw)[^:]*:\s*)*", "", email.subject, 0, flags=re.IGNORECASE))) parent = frappe.db.get_all(self.append_to, filters={ self.sender_field: email.from_email, self.subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=60)).strftime(DATE_FORMAT)) }, fields="name") # match only subject field # when the from_email is of a user in the system # and subject is atleast 10 chars long if not parent and len(subject) > 10 and is_system_user(email.from_email): parent = frappe.db.get_all(self.append_to, filters={ self.subject_field: ("like", "%{0}%".format(subject)), "creation": (">", (get_datetime() - relativedelta(days=60)).strftime(DATE_FORMAT)) }, fields="name") if parent: parent = frappe._dict(doctype=self.append_to, name=parent[0].name) return parent
def make_boilerplate(template, doc, opts=None): target_path = get_doc_path(doc.module, doc.doctype, doc.name) template_name = template.replace("controller", scrub(doc.name)) if template_name.endswith('._py'): template_name = template_name[:-4] + '.py' target_file_path = os.path.join(target_path, template_name) if not doc: doc = {} app_publisher = get_app_publisher(doc.module) if not os.path.exists(target_file_path): if not opts: opts = {} base_class = 'Document' base_class_import = 'from frappe.model.document import Document' if doc.get('is_tree'): base_class = 'NestedSet' base_class_import = 'from frappe.utils.nestedset import NestedSet' with open(target_file_path, 'w') as target: with open(os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype), "boilerplate", template), 'r') as source: target.write(frappe.as_unicode( frappe.utils.cstr(source.read()).format( app_publisher=app_publisher, year=frappe.utils.nowdate()[:4], classname=doc.name.replace(" ", ""), base_class_import=base_class_import, base_class=base_class, doctype=doc.name, **opts) ))
def export_query(): """export from report builder""" form_params = get_form_params() form_params["limit_page_length"] = None form_params["as_list"] = True doctype = form_params.doctype add_totals_row = None file_format_type = form_params["file_format_type"] del form_params["doctype"] del form_params["file_format_type"] if 'add_totals_row' in form_params and form_params['add_totals_row'] == '1': add_totals_row = 1 del form_params["add_totals_row"] frappe.permissions.can_export(doctype, raise_exception=True) if 'selected_items' in form_params: si = json.loads(frappe.form_dict.get('selected_items')) form_params["filters"] = {"name": ("in", si)} del form_params["selected_items"] db_query = DatabaseQuery(doctype) ret = db_query.execute(**form_params) if add_totals_row: ret = append_totals_row(ret) data = [['Sr'] + get_labels(db_query.fields, doctype)] for i, row in enumerate(ret): data.append([i + 1] + list(row)) if file_format_type == "CSV": # convert to csv import csv from frappe.utils.xlsxutils import handle_html f = StringIO() writer = csv.writer(f) for r in data: # encode only unicode type strings and not int, floats etc. writer.writerow([handle_html(frappe.as_unicode(v)).encode('utf-8') \ if isinstance(v, string_types) else v for v in r]) f.seek(0) frappe.response['result'] = text_type(f.read(), 'utf-8') frappe.response['type'] = 'csv' frappe.response['doctype'] = doctype elif file_format_type == "Excel": from frappe.utils.xlsxutils import make_xlsx xlsx_file = make_xlsx(data, doctype) frappe.response['filename'] = doctype + '.xlsx' frappe.response['filecontent'] = xlsx_file.getvalue() frappe.response['type'] = 'binary'
def export_query(): """export from report builder""" form_params = get_form_params() form_params["limit_page_length"] = None form_params["as_list"] = True doctype = form_params.doctype add_totals_row = None file_format_type = form_params["file_format_type"] del form_params["doctype"] del form_params["file_format_type"] if 'add_totals_row' in form_params and form_params['add_totals_row']=='1': add_totals_row = 1 del form_params["add_totals_row"] frappe.permissions.can_export(doctype, raise_exception=True) if 'selected_items' in form_params: si = json.loads(frappe.form_dict.get('selected_items')) form_params["filters"] = {"name": ("in", si)} del form_params["selected_items"] db_query = DatabaseQuery(doctype) ret = db_query.execute(**form_params) if add_totals_row: ret = append_totals_row(ret) data = [['Sr'] + get_labels(db_query.fields, doctype)] for i, row in enumerate(ret): data.append([i+1] + list(row)) if file_format_type == "CSV": # convert to csv import csv from frappe.utils.xlsxutils import handle_html f = StringIO() writer = csv.writer(f) for r in data: # encode only unicode type strings and not int, floats etc. writer.writerow([handle_html(frappe.as_unicode(v)).encode('utf-8') \ if isinstance(v, string_types) else v for v in r]) f.seek(0) frappe.response['result'] = text_type(f.read(), 'utf-8') frappe.response['type'] = 'csv' frappe.response['doctype'] = doctype elif file_format_type == "Excel": from frappe.utils.xlsxutils import make_xlsx xlsx_file = make_xlsx(data, doctype) frappe.response['filename'] = doctype + '.xlsx' frappe.response['filecontent'] = xlsx_file.getvalue() frappe.response['type'] = 'binary'
def clean_script_and_style(html): # remove script and style from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'html5lib') for s in soup(['script', 'style']): s.decompose() return frappe.as_unicode(soup)
def clean_script_and_style(html): # remove script and style from bs4 import BeautifulSoup soup = BeautifulSoup(html, "html5lib") for s in soup(["script", "style"]): s.decompose() return frappe.as_unicode(soup)
def decode_email(self, email): if not email: return decoded = "" for part, encoding in decode_header(frappe.as_unicode(email).replace("\""," ").replace("\'"," ")): if encoding: decoded += part.decode(encoding) else: decoded += safe_decode(part) return decoded
def authenticate_ldap_user(user=None, password=None): dn = None params = {} settings = get_ldap_settings() try: import ldap except: msg = """ <div> {{_("Seems ldap is not installed on system.")}}<br> <a href"https://discuss.erpnext.com/t/frappe-v-7-1-beta-ldap-dependancies/15841">{{_("Click here")}}</a>, {{_("Guidelines to install ldap dependancies and python")}} </div> """ frappe.throw(msg, title=_("LDAP Not Installed")) conn = ldap.initialize(settings.ldap_server_url) try: try: # set TLS settings for secure connection if settings.ssl_tls_mode == 'StartTLS': conn.set_option(ldap.OPT_X_TLS_DEMAND, True) if self.require_trusted_certificate == 'Yes': conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) conn.start_tls_s() except: frappe.throw(_("StartTLS is not supported")) # simple_bind_s is synchronous binding to server, it takes two param DN and password conn.simple_bind_s(settings.base_dn, settings.get_password(raise_exception=False)) #search for surnames beginning with a #available options for how deep a search you want. #LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL,LDAP_SCOPE_SUBTREE, result = conn.search_s(settings.organizational_unit, ldap.SCOPE_SUBTREE, settings.ldap_search_string.format(user)) for dn, r in result: dn = cstr(dn) params["email"] = cstr(r[settings.ldap_email_field][0]) params["username"] = cstr(r[settings.ldap_username_field][0]) params["first_name"] = cstr(r[settings.ldap_first_name_field][0]) if dn: conn.simple_bind_s(dn, frappe.as_unicode(password)) return create_user(params) else: frappe.throw(_("Not a valid LDAP user")) except ldap.LDAPError: conn.unbind_s() frappe.throw(_("Incorrect UserId or Password"))
def validate_file(self): """Validates existence of public file TODO: validate for private file """ if (self.file_url or "").startswith("/files/"): if not self.file_name: self.file_name = self.file_url.split("/files/")[-1] if not os.path.exists(get_files_path(frappe.as_unicode(self.file_name.lstrip("/")))): frappe.throw(_("File {0} does not exist").format(self.file_url), IOError)
def authenticate_ldap_user(user=None, password=None): dn = None params = {} settings = get_ldap_settings() try: import ldap except: msg = """ <div> {{_("Seems ldap is not installed on system.")}}<br> <a href"https://discuss.erpnext.com/t/frappe-v-7-1-beta-ldap-dependancies/15841">{{_("Click here")}}</a>, {{_("Guidelines to install ldap dependancies and python")}} </div> """ frappe.throw(msg, title=_("LDAP Not Installed")) conn = ldap.initialize(settings.ldap_server_url) try: try: # set TLS settings for secure connection if settings.ssl_tls_mode == 'StartTLS': conn.set_option(ldap.OPT_X_TLS_DEMAND, True) if settings.require_trusted_certificate == 'Yes': conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) conn.start_tls_s() except: frappe.throw(_("StartTLS is not supported")) # simple_bind_s is synchronous binding to server, it takes two param DN and password conn.simple_bind_s(settings.base_dn, settings.get_password(raise_exception=False)) #search for surnames beginning with a #available options for how deep a search you want. #LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL,LDAP_SCOPE_SUBTREE, result = conn.search_s(settings.organizational_unit, ldap.SCOPE_SUBTREE, settings.ldap_search_string.format(user)) for dn, r in result: dn = cstr(dn) params["email"] = cstr(r[settings.ldap_email_field][0]) params["username"] = cstr(r[settings.ldap_username_field][0]) params["first_name"] = cstr(r[settings.ldap_first_name_field][0]) if dn: conn.simple_bind_s(dn, frappe.as_unicode(password)) return create_user(params) else: frappe.throw(_("Not a valid LDAP user")) except ldap.LDAPError: conn.unbind_s() frappe.throw(_("Incorrect UserId or Password"))
def get_safe_filters(filters): try: filters = json.loads(filters) if isinstance(filters, (integer_types, float)): filters = frappe.as_unicode(filters) except (TypeError, ValueError): # filters are not passed, not json pass return filters
def get_server_messages(app): """Extracts all translatable strings (tagged with :func:`frappe._`) from Python modules inside an app""" messages = [] for basepath, folders, files in os.walk(frappe.get_pymodule_path(app)): for dontwalk in (".git", "public", "locale"): if dontwalk in folders: folders.remove(dontwalk) for f in files: f = frappe.as_unicode(f) if f.endswith(".py") or f.endswith(".html") or f.endswith(".js"): messages.extend(get_messages_from_file(os.path.join(basepath, f))) return messages
def get_email_seen_status(self, uid, flag_string): """ parse the email FLAGS response """ if not flag_string: return None flags = [] for flag in imaplib.ParseFlags(flag_string) or []: pattern = re.compile("\w+") match = re.search(pattern, frappe.as_unicode(flag)) flags.append(match.group(0)) if "Seen" in flags: self.seen_status.update({ uid: "SEEN" }) else: self.seen_status.update({ uid: "UNSEEN" })
def get_page_info_from_template(path): '''Return page_info from path''' for app in frappe.get_installed_apps(frappe_last=True): app_path = frappe.get_app_path(app) folders = get_start_folders() for start in folders: search_path = os.path.join(app_path, start, path) options = (search_path, search_path + '.html', search_path + '.md', search_path + '/index.html', search_path + '/index.md') for o in options: option = frappe.as_unicode(o) if os.path.exists(option) and not os.path.isdir(option): return get_page_info(option, app, start, app_path=app_path) return None
def add_missing_headers(): '''Walk and add missing headers in docs (to be called from bench execute)''' path = frappe.get_app_path('erpnext', 'docs') for basepath, folders, files in os.walk(path): for fname in files: if fname.endswith('.md'): with open(os.path.join(basepath, fname), 'r') as f: content = frappe.as_unicode(f.read()) if not content.startswith('# ') and not '<h1>' in content: with open(os.path.join(basepath, fname), 'w') as f: if fname=='index.md': fname = os.path.basename(basepath) else: fname = fname[:-3] h = fname.replace('_', ' ').replace('-', ' ').title() content = '# {0}\n\n'.format(h) + content f.write(content.encode('utf-8'))
def extract_messages_from_code(code, is_py=False): """Extracts translatable srings from a code file :param code: code from which translatable files are to be extracted :param is_py: include messages in triple quotes e.g. `_('''message''')`""" try: code = frappe.as_unicode(render_include(code)) except (TemplateError, ImportError, InvalidIncludePath): # Exception will occur when it encounters John Resig's microtemplating code pass messages = [] messages += [(m.start(), m.groups()[0]) for m in re.compile('_\("([^"]*)"').finditer(code)] messages += [(m.start(), m.groups()[0]) for m in re.compile("_\('([^']*)'").finditer(code)] if is_py: messages += [(m.start(), m.groups()[0]) for m in re.compile('_\("{3}([^"]*)"{3}.*\)').finditer(code)] messages = [(pos, message) for pos, message in messages if is_translatable(message)] return pos_to_line_no(messages, code)
def has_gravatar(email): '''Returns gravatar url if user has set an avatar at gravatar.com''' if (frappe.flags.in_import or frappe.flags.in_install or frappe.flags.in_test): # no gravatar if via upload # since querying gravatar for every item will be slow return '' hexdigest = md5.md5(frappe.as_unicode(email).encode('utf-8')).hexdigest() gravatar_url = "https://secure.gravatar.com/avatar/{hash}?d=404&s=200".format(hash=hexdigest) try: res = requests.get(gravatar_url) if res.status_code==200: return gravatar_url else: return '' except requests.exceptions.ConnectionError: return ''
def _sanitize_content(self): """Sanitize HTML and Email in field values. Used to prevent XSS. - Ignore if 'Ignore XSS Filter' is checked or fieldtype is 'Code' """ if frappe.flags.in_install: return for fieldname, value in self.get_valid_dict().items(): if not value or not isinstance(value, string_types): continue value = frappe.as_unicode(value) if (u"<" not in value and u">" not in value): # doesn't look like html so no need continue elif "<!-- markdown -->" in value and not ("<script" in value or "javascript:" in value): # should be handled separately via the markdown converter function continue df = self.meta.get_field(fieldname) sanitized_value = value if df and df.get("fieldtype") in ("Data", "Code", "Small Text") and df.get("options")=="Email": sanitized_value = sanitize_email(value) elif df and (df.get("ignore_xss_filter") or (df.get("fieldtype")=="Code" and df.get("options")!="Email") or df.get("fieldtype") in ("Attach", "Attach Image") # cancelled and submit but not update after submit should be ignored or self.docstatus==2 or (self.docstatus==1 and not df.get("allow_on_submit"))): continue else: sanitized_value = sanitize_html(value, linkify=df.fieldtype=='Text Editor') self.set(fieldname, sanitized_value)
def clean_script_and_style(html): # remove script and style soup = BeautifulSoup(html, 'html5lib') for s in soup(['script', 'style']): s.decompose() return frappe.as_unicode(soup)
def add_breadcrumbs_tag(path): with open(path, 'r') as f: content = frappe.as_unicode(f.read()) with open(path, 'wb') as f: f.write(('<!-- add-breadcrumbs -->\n' + content).encode('utf-8'))
def cstr(s, encoding='utf-8'): return frappe.as_unicode(s, encoding)