def render(path=None, http_status_code=None): """render html page""" path = resolve_path(path or frappe.local.request.path.strip('/ ')) data = None # if in list of already known 404s, send it if can_cache() and frappe.cache().hget('website_404', frappe.request.url): data = render_page('404') http_status_code = 404 else: try: data = render_page_by_language(path) except frappe.DoesNotExistError, e: doctype, name = get_doctype_from_path(path) if doctype and name: path = "print" frappe.local.form_dict.doctype = doctype frappe.local.form_dict.name = name elif doctype: path = "list" frappe.local.form_dict.doctype = doctype else: # 404s are expensive, cache them! frappe.cache().hset('website_404', frappe.request.url, True) data = render_page('404') http_status_code = 404 if not data: try: data = render_page(path) except frappe.PermissionError, e: data, http_status_code = render_403(e, path)
def on_update(self): if self.enabled: if not self.flags.ignore_mandatory: self.enable_service() self.install_fixtures() frappe.cache().delete_value('scheduler_events')
def update(self, force=False): """extend session expiry""" if (frappe.session['user'] == "Guest" or frappe.form_dict.cmd=="logout"): return now = frappe.utils.now() self.data['data']['last_updated'] = now self.data['data']['lang'] = unicode(frappe.lang) # update session in db last_updated = frappe.cache().hget("last_db_session_update", self.sid) time_diff = frappe.utils.time_diff_in_seconds(now, last_updated) if last_updated else None # database persistence is secondary, don't update it too often updated_in_db = False if force or (time_diff==None) or (time_diff > 600): # update sessions table frappe.db.sql("""update tabSessions set sessiondata=%s, lastupdate=NOW() where sid=%s""" , (str(self.data['data']), self.data['sid'])) # update last active in user table frappe.db.sql("""update `tabUser` set last_active=%(now)s where name=%(name)s""", { "now": frappe.utils.now(), "name": frappe.session.user }) frappe.cache().hset("last_db_session_update", self.sid, now) updated_in_db = True # set in memcache frappe.cache().hset("session", self.sid, self.data) return updated_in_db
def get_page_context_from_doctypes(): routes = frappe.cache().get_value("website_generator_routes") if not routes: routes = {} for app in frappe.get_installed_apps(): for doctype in frappe.get_hooks("website_generators", app_name = app): condition = "" route_column_name = "page_name" controller = get_controller(doctype) meta = frappe.get_meta(doctype) if meta.get_field("parent_website_route"): route_column_name = """concat(ifnull(parent_website_route, ""), if(ifnull(parent_website_route, "")="", "", "/"), page_name)""" if controller.website.condition_field: condition ="where {0}=1".format(controller.website.condition_field) for r in frappe.db.sql("""select {0} as route, name, modified from `tab{1}` {2}""".format(route_column_name, doctype, condition), as_dict=True): routes[r.route] = {"doctype": doctype, "name": r.name, "modified": r.modified} frappe.cache().set_value("website_generator_routes", routes) return routes
def delete_session(sid=None, user=None): if not user: user = hasattr(frappe.local, "session") and frappe.session.user or "Guest" frappe.cache().hdel("session", sid) frappe.cache().hdel("last_db_session_update", sid) frappe.db.sql("""delete from tabSessions where sid=%s""", sid) frappe.db.commit()
def get_defaults_for(parent="__default"): """get all defaults""" defaults = frappe.cache().hget("defaults", parent) if defaults==None: # sort descending because first default must get precedence res = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue` where parent = %s order by creation""", (parent,), as_dict=1) defaults = frappe._dict({}) for d in res: if d.defkey in defaults: # listify if not isinstance(defaults[d.defkey], list) and defaults[d.defkey] != d.defvalue: defaults[d.defkey] = [defaults[d.defkey]] if d.defvalue not in defaults[d.defkey]: defaults[d.defkey].append(d.defvalue) elif d.defvalue is not None: defaults[d.defkey] = d.defvalue frappe.cache().hset("defaults", parent, defaults) return defaults
def execute(): frappe.cache().delete_value('doctypes_with_global_search') doctypes_with_global_search = get_doctypes_with_global_search(with_child_tables=False) for i, doctype in enumerate(doctypes_with_global_search): update_progress_bar("Updating Global Search", i, len(doctypes_with_global_search)) rebuild_for_doctype(doctype)
def get_notifications_for_doctypes(config, notification_count): """Notifications for DocTypes""" can_read = frappe.get_user().get_can_read() open_count_doctype = {} for d in config.for_doctype: if d in can_read: condition = config.for_doctype[d] if d in notification_count: open_count_doctype[d] = notification_count[d] else: try: if isinstance(condition, dict): result = len(frappe.get_list(d, fields=["name"], filters=condition, limit_page_length = 21, as_list=True, ignore_ifnull=True)) else: result = frappe.get_attr(condition)() except frappe.PermissionError: frappe.msgprint("Permission Error in notifications for {0}".format(d)) except Exception, e: # OperationalError: (1412, 'Table definition has changed, please retry transaction') if e.args[0]!=1412: raise else: open_count_doctype[d] = result frappe.cache().hset("notification_count:" + d, frappe.session.user, result)
def build_page(path): if not getattr(frappe.local, "path", None): frappe.local.path = path context = get_context(path) if context.source: html = frappe.render_template(context.source, context) elif context.template: html = frappe.get_template(context.template).render(context) if '{index}' in html: html = html.replace('{index}', get_toc(context.route)) if '{next}' in html: html = html.replace('{next}', get_next_link(context.route)) # html = frappe.get_template(context.base_template_path).render(context) if can_cache(context.no_cache): page_cache = frappe.cache().hget("website_page", path) or {} page_cache[frappe.local.lang] = html frappe.cache().hset("website_page", path, page_cache) return html
def update_password(new_password, key=None, old_password=None): result = test_password_strength(new_password, key, old_password) feedback = result.get("feedback", None) if feedback and not feedback.get('password_policy_validation_passed', False): handle_password_test_fail(result) res = _get_user_for_update_password(key, old_password) if res.get('message'): return res['message'] else: user = res['user'] _update_password(user, new_password) user_doc, redirect_url = reset_user_data(user) # get redirect url from cache redirect_to = frappe.cache().hget('redirect_after_login', user) if redirect_to: redirect_url = redirect_to frappe.cache().hdel('redirect_after_login', user) frappe.local.login_manager.login_as(user) if user_doc.user_type == "System User": return "/desk" else: return redirect_url if redirect_url else "/"
def set_user_info(self, resume=False): # set sid again frappe.local.cookie_manager.init_cookies() self.info = frappe.db.get_value("User", self.user, ["user_type", "first_name", "last_name", "user_image"], as_dict=1) self.full_name = " ".join(filter(None, [self.info.first_name, self.info.last_name])) self.user_type = self.info.user_type if self.info.user_type=="Website User": frappe.local.cookie_manager.set_cookie("system_user", "no") if not resume: frappe.local.response["message"] = "No App" frappe.local.response["home_page"] = get_website_user_home_page(self.user) else: frappe.local.cookie_manager.set_cookie("system_user", "yes") if not resume: frappe.local.response['message'] = 'Logged In' frappe.local.response["home_page"] = "/desk" if not resume: frappe.response["full_name"] = self.full_name # redirect information redirect_to = frappe.cache().hget('redirect_after_login', self.user) if redirect_to: frappe.local.response["redirect_to"] = redirect_to frappe.cache().hdel('redirect_after_login', self.user) frappe.local.cookie_manager.set_cookie("full_name", self.full_name) frappe.local.cookie_manager.set_cookie("user_id", self.user) frappe.local.cookie_manager.set_cookie("user_image", self.info.user_image or "")
def test_link_count(self): from frappe.model.utils.link_count import update_link_count update_link_count() doctype, name = 'User', '*****@*****.**' d = self.test_insert() d.ref_type = doctype d.ref_name = name link_count = frappe.cache().get_value('_link_count') or {} old_count = link_count.get((doctype, name)) or 0 d.save() link_count = frappe.cache().get_value('_link_count') or {} new_count = link_count.get((doctype, name)) or 0 self.assertEquals(old_count + 1, new_count) frappe.db.commit() before_update = frappe.db.get_value(doctype, name, 'idx') update_link_count() after_update = frappe.db.get_value(doctype, name, 'idx') self.assertEquals(before_update + new_count, after_update)
def get_context(path): context = None cache_key = "page_context:{}".format(path) # try from memcache if can_cache(): context = frappe.cache().get_value(cache_key) if not context: context = get_sitemap_options(path) # permission may be required for rendering context["access"] = get_access(context.pathname) context = build_context(context) if can_cache(context.no_cache): frappe.cache().set_value(cache_key, context) else: context["access"] = get_access(context.pathname) if not context.data: context.data = {} context.data["path"] = path context.update(context.data or {}) return context
def get_context(path, args=None): context = None context_cache = {} def add_data_path(context): if not context.data: context.data = {} context.data["path"] = path # try from cache if can_cache(): context_cache = frappe.cache().hget("page_context", path) or {} context = context_cache.get(frappe.local.lang, None) if not context: context = get_route_info(path) if args: context.update(args) context = build_context(context) add_data_path(context) if can_cache(context.no_cache): context_cache[frappe.local.lang] = context frappe.cache().hset("page_context", path, context_cache) else: add_data_path(context) context.update(context.data or {}) return context
def get_shipping_details(site_id=default_site_id): """Cache the eBay Shipping Details entries.""" cache_key = 'eBayShippingDetails_{}'.format(site_id) shipping_details = frappe.cache().get_value(cache_key) if shipping_details is not None: timestamp = shipping_details['Timestamp'][0:-5] cache_date = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S') age = (datetime.utcnow() - cache_date).days if age == 0: # Our cache is still acceptable return shipping_details # Either there is no cache, or it is out of date # Get a new entry shipping_details = get_eBay_details( site_id=site_id, detail_name='ShippingServiceDetails') # Calculate shipping name translation table shipping_option_dict = {} for shipping_option in shipping_details['ShippingServiceDetails']: shipping_option_dict[shipping_option['ShippingService']] = ( shipping_option['Description']) shipping_details['ShippingOptionDescriptions'] = shipping_option_dict # Store the new values in the cache and return frappe.cache().set_value(cache_key, shipping_details) return shipping_details
def test_link_count(self): if os.environ.get('CI'): # cannot run this test reliably in travis due to its handling # of parallelism return from frappe.model.utils.link_count import update_link_count update_link_count() doctype, name = 'User', '*****@*****.**' d = self.test_insert() d.append('event_participants', {"reference_doctype": doctype, "reference_docname": name}) d.save() link_count = frappe.cache().get_value('_link_count') or {} old_count = link_count.get((doctype, name)) or 0 frappe.db.commit() link_count = frappe.cache().get_value('_link_count') or {} new_count = link_count.get((doctype, name)) or 0 self.assertEqual(old_count + 1, new_count) before_update = frappe.db.get_value(doctype, name, 'idx') update_link_count() after_update = frappe.db.get_value(doctype, name, 'idx') self.assertEqual(before_update + new_count, after_update)
def install_app(name): """Install app, if app is not installed in local environment, install it via git url in `frappe/data/app_listing/`""" frappe.only_for("System Manager") if name not in frappe.get_all_apps(True): if not frappe.conf.disallow_app_listing: get_app(name) frappe.cache().delete_value(["app_hooks"]) # reload sys.path import site reload(site) else: # will only come via direct API frappe.throw("Listing app not allowed") app_hooks = frappe.get_hooks(app_name=name) if app_hooks.get('hide_in_installer'): frappe.throw(_("You cannot install this app")) frappe.publish_realtime("install_app_progress", {"status": _("Installing App {0}").format(name)}, user=frappe.session.user, now=True) frappe.installer.install_app(name) frappe.publish_realtime("install_app_progress", {"status": _("{0} Installed").format(name)}, user=frappe.session.user, now=True)
def update(self, force=False): """extend session expiry""" if frappe.session["user"] == "Guest" or frappe.form_dict.cmd == "logout": return now = frappe.utils.now() self.data["data"]["last_updated"] = now self.data["data"]["lang"] = unicode(frappe.lang) # update session in db last_updated = frappe.cache().hget("last_db_session_update", self.sid) time_diff = frappe.utils.time_diff_in_seconds(now, last_updated) if last_updated else None # database persistence is secondary, don't update it too often updated_in_db = False if force or (time_diff == None) or (time_diff > 600): frappe.db.sql( """update tabSessions set sessiondata=%s, lastupdate=NOW() where sid=%s""", (str(self.data["data"]), self.data["sid"]), ) frappe.cache().hset("last_db_session_update", self.sid, now) updated_in_db = True # set in memcache frappe.cache().hset("session", self.sid, self.data) return updated_in_db
def get_full_dict(lang): """Load and return the entire translations dictionary for a language from :meth:`frape.cache` :param lang: Language Code, e.g. `hi` """ if not lang: return {} # found in local, return! if frappe.local.lang_full_dict is not None: return frappe.local.lang_full_dict frappe.local.lang_full_dict = frappe.cache().hget("lang_full_dict", lang) if frappe.local.lang_full_dict is None: frappe.local.lang_full_dict = load_lang(lang) # only cache file translations in this frappe.cache().hset("lang_full_dict", lang, frappe.local.lang_full_dict) try: # get user specific transaltion data user_translations = get_user_translations(lang) except Exception: user_translations = None if user_translations: frappe.local.lang_full_dict.update(user_translations) return frappe.local.lang_full_dict
def clear_expired_jasper_cache_local_reports(force=False): if force: clear_jasper_cache_local_report() return version = getFrappeVersion().major if version <= 4: keys = list_all_memcached_keys_v4(value="site.all:jasper:local_report_") else: keys = list_all_redis_keys("site.all:jasper:local_report_") if not keys: return print "keys {}".format(keys) if isinstance(keys, basestring): keys = [keys] import time for key in keys: val = frappe.cache().get(key) t = int(time.time()) if t - int(val.get("t")) >= 600: frappe.cache().delete(key)
def clear_all_jasper_user_cache_v4(force=True): from memcache_stats import MemcachedStats removed = 0 #use memcache_stats for delete any cache that remains memc = MemcachedStats() for m in memc.keys(): if "jasper:user" in m: if force: #remove site from key value = m.split(":", 1) frappe.cache().delete_value(value[1]) removed += 1 else: #remove jasper from key value = m.split(":", 1) v = value[1].split(":", 1) deleted = check_if_expire(v[1]) if deleted: frappe.cache().delete_value(value[1]) removed += 1 if removed == 0: print _("No user cache was removed.") else: print _("Was removed {0} user cache(s)".format(removed)) return removed
def resolve_redirect(path): ''' Resolve redirects from hooks Example: website_redirect = [ # absolute location {"source": "/from", "target": "https://mysite/from"}, # relative location {"source": "/from", "target": "/main"}, # use regex {"source": r"/from/(.*)", "target": r"/main/\1"} # use r as a string prefix if you use regex groups or want to escape any string literal ] ''' redirects = frappe.get_hooks('website_redirects') if not redirects: return redirect_to = frappe.cache().hget('website_redirects', path) if redirect_to: frappe.flags.redirect_location = redirect_to raise frappe.Redirect for rule in redirects: pattern = rule['source'].strip('/ ') + '$' if re.match(pattern, path): redirect_to = re.sub(pattern, rule['target'], path) frappe.flags.redirect_location = redirect_to frappe.cache().hset('website_redirects', path, redirect_to) raise frappe.Redirect
def run_post_save_methods(self): """Run standard methods after `INSERT` or `UPDATE`. Standard Methods are: - `on_update` for **Save**. - `on_update`, `on_submit` for **Submit**. - `on_cancel` for **Cancel** - `update_after_submit` for **Update after Submit**""" if self._action=="save": self.run_method("on_update") elif self._action=="submit": self.run_method("on_update") self.run_method("on_submit") if not self.flags.ignore_submit_comment: self.add_comment("Submitted") elif self._action=="cancel": self.run_method("on_cancel") self.check_no_back_links_exist() if not self.flags.ignore_submit_comment: self.add_comment("Cancelled") elif self._action=="update_after_submit": self.run_method("on_update_after_submit") frappe.cache().hdel("last_modified", self.doctype) self.notify_update() self.latest = None
def clear_notifications(user="******"): if user == "*": frappe.cache().delete_keys("notification_count:") else: # delete count for user for key in frappe.cache().get_keys("notification_count:"): frappe.cache().hdel(key, user)
def get_notifications_for_doctypes(config, notification_count): can_read = frappe.get_user().get_can_read() open_count_doctype = {} for d in config.for_doctype: if d in can_read: condition = config.for_doctype[d] if d=='Appointment': pass #frappe.errprint(['condition in desk _notification',type(condition)]) if d in notification_count: open_count_doctype[d] = notification_count[d] else: try: result = frappe.get_list(d, fields=["count(*)"], filters=condition, as_list=True)[0][0] except frappe.PermissionError, e: frappe.msgprint("Permission Error in notifications for {0}".format(d)) except Exception, e: # OperationalError: (1412, 'Table definition has changed, please retry transaction') if e.args[0]!=1412: raise else: open_count_doctype[d] = result frappe.cache().hset("notification_count:" + d, frappe.session.user, result)
def confirm_otp_token(login_manager, otp=None, tmp_id=None): '''Confirm otp matches.''' if not otp: otp = frappe.form_dict.get('otp') if not otp: if two_factor_is_enabled_for_(login_manager.user): return False return True if not tmp_id: tmp_id = frappe.form_dict.get('tmp_id') hotp_token = frappe.cache().get(tmp_id + '_token') otp_secret = frappe.cache().get(tmp_id + '_otp_secret') if not otp_secret: raise ExpiredLoginException(_('Login session expired, refresh page to retry')) hotp = pyotp.HOTP(otp_secret) if hotp_token: if hotp.verify(otp, int(hotp_token)): frappe.cache().delete(tmp_id + '_token') return True else: login_manager.fail(_('Incorrect Verification code'), login_manager.user) totp = pyotp.TOTP(otp_secret) if totp.verify(otp): # show qr code only once if not frappe.db.get_default(login_manager.user + '_otplogin'): frappe.db.set_default(login_manager.user + '_otplogin', 1) delete_qrimage(login_manager.user) return True else: login_manager.fail(_('Incorrect Verification code'), login_manager.user)
def get_user_permissions(user=None): '''Get all users permissions for the user as a dict of doctype''' if not user: user = frappe.session.user out = frappe.cache().hget("user_permissions", user) if not out: out = {} try: for perm in frappe.get_all('User Permission', fields=['allow', 'for_value'], filters=dict(user=user)): out.setdefault(perm.allow, []).append(perm.for_value) # add profile match if user not in out.get("User", []): out.setdefault("User", []).append(user) frappe.cache().hset("user_permissions", user, out) except frappe.SQLError as e: if e.args[0]==1146: # called from patch pass return out
def clear_expired_jasper_error(force=False): for sessionId in ["connect_error", "login_error"]: if force: frappe.cache().delete_value("jasper:" + sessionId) continue clear_expired_jasper_error_help(sessionId)
def sign_up(email, full_name, redirect_to): user = frappe.db.get("User", {"email": email}) if user: if user.disabled: return _("Registered but disabled.") else: return _("Already Registered") else: if frappe.db.sql("""select count(*) from tabUser where HOUR(TIMEDIFF(CURRENT_TIMESTAMP, TIMESTAMP(modified)))=1""")[0][0] > 300: frappe.respond_as_web_page(_('Temperorily Disabled'), _('Too many users signed up recently, so the registration is disabled. Please try back in an hour'), http_status_code=429) from frappe.utils import random_string user = frappe.get_doc({ "doctype":"User", "email": email, "first_name": full_name, "enabled": 1, "new_password": random_string(10), "user_type": "Website User" }) user.flags.ignore_permissions = True user.insert() if redirect_to: frappe.cache().hset('redirect_after_login', user.name, redirect_to) if user.flags.email_sent: return _("Please check your email for verification") else: return _("Please ask your administrator to verify your sign-up")
def update(self, force=False): """extend session expiry""" self.data['data']['last_updated'] = frappe.utils.now() self.data['data']['lang'] = unicode(frappe.lang) # update session in db time_diff = None last_updated = frappe.cache().get_value("last_db_session_update:" + self.sid) if last_updated: time_diff = frappe.utils.time_diff_in_seconds(frappe.utils.now(), last_updated) if force or (frappe.session['user'] != 'Guest' and \ ((time_diff==None) or (time_diff > 1800))): # database persistence is secondary, don't update it too often frappe.db.sql("""update tabSessions set sessiondata=%s, lastupdate=NOW() where sid=%s""" , (str(self.data['data']), self.data['sid'])) if frappe.form_dict.cmd not in ("frappe.sessions.clear", "logout"): frappe.cache().set_value("last_db_session_update:" + self.sid, frappe.utils.now()) frappe.cache().set_value("session:" + self.sid, self.data)
def login_failed_time(self, timestamp): frappe.cache().hset('login_failed_time', self.user_name, timestamp)
def clear_desktop_icons_cache(user=None): frappe.cache().hdel('desktop_icons', user or frappe.session.user) frappe.cache().hdel('bootinfo', user or frappe.session.user)
def on_change(self): frappe.clear_cache(doctype=self.reference_doctype) frappe.cache().delete_keys("_user_settings")
def on_trash(self): for i in frappe.get_all('Event Update Log Consumer', {'consumer': self.name}): frappe.delete_doc('Event Update Log Consumer', i.name) frappe.cache().delete_value('event_consumer_document_type_map')
def get_time_zone(): if frappe.local.flags.in_test: return _get_time_zone() return frappe.cache().get_value("time_zone", _get_time_zone)
def clear_cache(user=None): if user: for p in ([user] + common_keys): frappe.cache().hdel("defaults", p) elif frappe.flags.in_install!="frappe": frappe.cache().delete_key("defaults")
def get_workflow_field_value(workflow_name, field): value = frappe.cache().hget('workflow_' + workflow_name, field) if value is None: value = frappe.db.get_value("Workflow", workflow_name, field) frappe.cache().hset('workflow_' + workflow_name, field, value) return value
def flush_memcache(): frappe.cache().flush_all()
def get_temp(self, key): """Return the temperory value and delete it.""" return frappe.cache().hget("temp", key)
def get_desktop_icons(user=None, enable_links_by_module=False): '''Return desktop icons for user''' if not user: user = frappe.session.user all_icons = frappe.cache().hget('desktop_icons', user) set_cache = False fields = [ 'module_name', 'hidden', 'label', 'link', 'type', 'icon', 'color', 'description', 'category', '_doctype', '_report', 'idx', 'force_show', 'reverse', 'custom', 'standard', 'blocked' ] active_domains = frappe.get_active_domains() if not all_icons: all_icons = {} all_icons["user_icons"] = [] all_icons["standard_icons"] = [] set_cache = True blocked_doctypes = frappe.get_all("DocType", filters={ "ifnull(restrict_to_domain, '')": ("not in", ",".join(active_domains)) }, fields=["name"]) blocked_doctypes = [d.get("name") for d in blocked_doctypes] standard_icons = frappe.db.get_all('Kard Desktop Icon', fields=fields, filters={'standard': 1}) standard_map = {} for icon in standard_icons: if icon._doctype in blocked_doctypes: icon.blocked = 1 if icon.hidden == 1: icon.hidden_in_standard = 1 else: icon.hidden_in_standard = 0 standard_map[icon.module_name] = icon user_icons = frappe.db.get_all('Kard Desktop Icon', fields=fields, filters={ 'standard': 0, 'owner': user }) # update hidden property for icon in user_icons: standard_icon = standard_map.get(icon.module_name, None) if icon._doctype in blocked_doctypes: icon.blocked = 1 # override properties from standard icon if standard_icon: for key in ('route', 'label', 'color', 'icon', 'link'): if standard_icon.get(key): icon[key] = standard_icon.get(key) if standard_icon.blocked: icon.hidden = 1 # flag for modules_select dialog icon.hidden_in_standard = 1 elif standard_icon.force_show: icon.hidden = 0 icon.standard = 1 # add missing standard icons (added via new install apps?) user_icon_names = [icon.module_name for icon in user_icons] for standard_icon in standard_icons: if standard_icon.module_name not in user_icon_names: # if blocked, hidden too! if standard_icon.blocked: standard_icon.hidden = 1 standard_icon.hidden_in_standard = 1 user_icons.append(standard_icon) domain_blocked_modules = frappe.get_all( "Module Def", filters={ "ifnull(restrict_to_domain, '')": ("not in", ",".join(active_domains)) }, fields=["name"]) domain_blocked_modules = [ d.get("name") for d in domain_blocked_modules ] user_blocked_modules = frappe.get_doc('User', user).get_blocked_modules() blocked_modules = domain_blocked_modules + user_blocked_modules from kard_theme.kard_theme.doctype.kard_theme_settings.kard_theme_settings import get_data for icon in user_icons: if icon.module_name in blocked_modules: icon.hidden = 1 icon.blocked = 1 if enable_links_by_module: if icon.blocked == 0: module_items = get_data(icon.module_name) if len(module_items) == 0: icon.hidden = 1 icon.hidden_in_standard = 1 icon["items"] = module_items if icon.get('category') == '' or icon.get('category') == None: icon.category = "Uncategorized" standard_icons = [m for m in user_icons if m.get('standard') == 1] user_icons = [m for m in user_icons if m.get('standard') == 0] # translate for d in user_icons: if d.label: d.label = _(d.label) # sort by idx user_icons.sort(key=lambda a: a.idx) # translate for d in standard_icons: if d.label: d.label = _(d.label) # sort by label standard_icons.sort(key=lambda a: a.label) categories = frappe.get_list("Kard Desktop Category", fields=["name"], order_by="idx") module_categories = [] for m in categories: module_categories.append(m.name) from collections import OrderedDict user_modules_by_category = OrderedDict() for category in module_categories: user_modules_by_category[category] = [ m for m in standard_icons if m.get('category') == category ] user_modules_by_category["Uncategorized"] = [ m for m in standard_icons if m.get('category') == 'Uncategorized' ] from frappe.desk.moduleview import get_home_settings home_settings = get_home_settings() # filter out hidden modules if home_settings.hidden_modules: for category in user_modules_by_category: hidden_modules = home_settings.hidden_modules or [] modules = user_modules_by_category[category] for module in modules: if module.blocked == 0: if module.module_name in hidden_modules: module.hidden = 1 set_cache = True all_icons["user_icons"] = user_icons all_icons["standard_icons"] = user_modules_by_category if set_cache: frappe.cache().hset('desktop_icons', user, all_icons) return all_icons
def clear_document_cache(): frappe.local.document_cache = {} frappe.cache().delete_key("document_cache")
def set_temp(self, value): """Set a temperory value and return a key.""" key = frappe.generate_hash() frappe.cache().hset("temp", key, value) return key
def clear_cache(self): frappe.cache().hdel("last_modified", self.doctype)
def clear_doctype_map(doctype, name): cache_key = frappe.scrub(doctype) + '_map' frappe.cache().hdel(cache_key, name)
def delete_cache(self): frappe.cache().delete_key(self.cache_key, user=frappe.session.user) if hasattr(bank_integration, self.cache_key): delattr(bank_integration, self.cache_key)
def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False): fiscal_years = frappe.cache().hget("fiscal_years", company) or [] if not fiscal_years: # if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate) cond = "" if fiscal_year: cond += " and fy.name = {0}".format(frappe.db.escape(fiscal_year)) if company: cond += """ and (not exists (select name from `tabFiscal Year Company` fyc where fyc.parent = fy.name) or exists(select company from `tabFiscal Year Company` fyc where fyc.parent = fy.name and fyc.company=%(company)s) ) """ fiscal_years = frappe.db.sql(""" select fy.name, fy.year_start_date, fy.year_end_date from `tabFiscal Year` fy where disabled = 0 {0} order by fy.year_start_date desc""".format(cond), {"company": company}, as_dict=True) frappe.cache().hset("fiscal_years", company, fiscal_years) if transaction_date: transaction_date = getdate(transaction_date) for fy in fiscal_years: matched = False if fiscal_year and fy.name == fiscal_year: matched = True if (transaction_date and getdate(fy.year_start_date) <= transaction_date and getdate(fy.year_end_date) >= transaction_date): matched = True if matched: if as_dict: return (fy, ) else: return ((fy.name, fy.year_start_date, fy.year_end_date), ) error_msg = _("""{0} {1} not in any active Fiscal Year.""").format( label, formatdate(transaction_date)) if verbose == 1: frappe.msgprint(error_msg) raise FiscalYearError(error_msg)
def delete_session(sid=None, user=None): frappe.cache().hdel("session", sid) frappe.cache().hdel("last_db_session_update", sid) frappe.db.sql("""delete from tabSessions where sid=%s""", sid) frappe.db.commit()
def upload( rows=None, submit_after_import=None, ignore_encoding_errors=False, no_email=True, overwrite=None, update_only=None, ignore_links=False, pre_process=None, via_console=False, from_data_import="No", skip_errors=True, data_import_doc=None, validate_template=False, user=None, ): """upload data""" # for translations if user: frappe.cache().hdel("lang", user) frappe.set_user_lang(user) if data_import_doc and isinstance(data_import_doc, string_types): data_import_doc = frappe.get_doc("Data Import Legacy", data_import_doc) if data_import_doc and from_data_import == "Yes": no_email = data_import_doc.no_email ignore_encoding_errors = data_import_doc.ignore_encoding_errors update_only = data_import_doc.only_update submit_after_import = data_import_doc.submit_after_import overwrite = data_import_doc.overwrite skip_errors = data_import_doc.skip_errors else: # extra input params params = json.loads(frappe.form_dict.get("params") or "{}") if params.get("submit_after_import"): submit_after_import = True if params.get("ignore_encoding_errors"): ignore_encoding_errors = True if not params.get("no_email"): no_email = False if params.get("update_only"): update_only = True if params.get("from_data_import"): from_data_import = params.get("from_data_import") if not params.get("skip_errors"): skip_errors = params.get("skip_errors") frappe.flags.in_import = True frappe.flags.mute_emails = no_email def get_data_keys_definition(): return get_data_keys() def bad_template(): frappe.throw( _("Please do not change the rows above {0}").format( get_data_keys_definition().data_separator)) def check_data_length(): if not data: frappe.throw( _("No data found in the file. Please reattach the new file with data." )) def get_start_row(): for i, row in enumerate(rows): if row and row[0] == get_data_keys_definition().data_separator: return i + 1 bad_template() def get_header_row(key): return get_header_row_and_idx(key)[0] def get_header_row_and_idx(key): for i, row in enumerate(header): if row and row[0] == key: return row, i return [], -1 def filter_empty_columns(columns): empty_cols = list(filter(lambda x: x in ("", None), columns)) if empty_cols: if columns[-1 * len(empty_cols):] == empty_cols: # filter empty columns if they exist at the end columns = columns[:-1 * len(empty_cols)] else: frappe.msgprint(_( "Please make sure that there are no empty columns in the file." ), raise_exception=1) return columns def make_column_map(): doctype_row, row_idx = get_header_row_and_idx( get_data_keys_definition().doctype) if row_idx == -1: # old style return dt = None for i, d in enumerate(doctype_row[1:]): if d not in ("~", "-"): if d and doctype_row[i] in (None, "", "~", "-", _("DocType") + ":"): dt, parentfield = d, None # xls format truncates the row, so it may not have more columns if len(doctype_row) > i + 2: parentfield = doctype_row[i + 2] doctypes.append((dt, parentfield)) column_idx_to_fieldname[(dt, parentfield)] = {} column_idx_to_fieldtype[(dt, parentfield)] = {} if dt: column_idx_to_fieldname[(dt, parentfield)][i + 1] = rows[row_idx + 2][i + 1] column_idx_to_fieldtype[(dt, parentfield)][i + 1] = rows[row_idx + 4][i + 1] def get_doc(start_idx): if doctypes: doc = {} attachments = [] last_error_row_idx = None for idx in range(start_idx, len(rows)): last_error_row_idx = idx # pylint: disable=W0612 if (not doc) or main_doc_empty(rows[idx]): for dt, parentfield in doctypes: d = {} for column_idx in column_idx_to_fieldname[( dt, parentfield)]: try: fieldname = column_idx_to_fieldname[( dt, parentfield)][column_idx] fieldtype = column_idx_to_fieldtype[( dt, parentfield)][column_idx] if not fieldname or not rows[idx][column_idx]: continue d[fieldname] = rows[idx][column_idx] if fieldtype in ("Int", "Check"): d[fieldname] = cint(d[fieldname]) elif fieldtype in ("Float", "Currency", "Percent"): d[fieldname] = flt(d[fieldname]) elif fieldtype == "Date": if d[fieldname] and isinstance( d[fieldname], string_types): d[fieldname] = getdate( parse_date(d[fieldname])) elif fieldtype == "Datetime": if d[fieldname]: if " " in d[fieldname]: _date, _time = d[fieldname].split() else: _date, _time = d[ fieldname], "00:00:00" _date = parse_date(d[fieldname]) d[fieldname] = get_datetime(_date + " " + _time) else: d[fieldname] = None elif fieldtype == "Duration": d[fieldname] = duration_to_seconds( cstr(d[fieldname])) elif fieldtype in ("Image", "Attach Image", "Attach"): # added file to attachments list attachments.append(d[fieldname]) elif fieldtype in ("Link", "Dynamic Link", "Data") and d[fieldname]: # as fields can be saved in the number format(long type) in data import template d[fieldname] = cstr(d[fieldname]) except IndexError: pass # scrub quotes from name and modified if d.get("name") and d["name"].startswith('"'): d["name"] = d["name"][1:-1] if sum([0 if not val else 1 for val in d.values()]): d["doctype"] = dt if dt == doctype: doc.update(d) else: if not overwrite and doc.get("name"): d["parent"] = doc["name"] d["parenttype"] = doctype d["parentfield"] = parentfield doc.setdefault(d["parentfield"], []).append(d) else: break return doc, attachments, last_error_row_idx else: doc = frappe._dict(zip(columns, rows[start_idx][1:])) doc["doctype"] = doctype return doc, [], None # used in testing whether a row is empty or parent row or child row # checked only 3 first columns since first two columns can be blank for example the case of # importing the item variant where item code and item name will be blank. def main_doc_empty(row): if row: for i in range(3, 0, -1): if len(row) > i and row[i]: return False return True def validate_naming(doc): autoname = frappe.get_meta(doctype).autoname if autoname: if autoname[0:5] == "field": autoname = autoname[6:] elif autoname == "naming_series:": autoname = "naming_series" else: return True if (autoname not in doc) or (not doc[autoname]): from frappe.model.base_document import get_controller if not hasattr(get_controller(doctype), "autoname"): frappe.throw( _("{0} is a mandatory field").format(autoname)) return True users = frappe.db.sql_list("select name from tabUser") def prepare_for_insert(doc): # don't block data import if user is not set # migrating from another system if not doc.owner in users: doc.owner = frappe.session.user if not doc.modified_by in users: doc.modified_by = frappe.session.user def is_valid_url(url): is_valid = False if url.startswith("/files") or url.startswith("/private/files"): url = get_url(url) try: r = requests.get(url) is_valid = True if r.status_code == 200 else False except Exception: pass return is_valid def attach_file_to_doc(doctype, docname, file_url): # check if attachment is already available # check if the attachement link is relative or not if not file_url: return if not is_valid_url(file_url): return files = frappe.db.sql( """Select name from `tabFile` where attached_to_doctype='{doctype}' and attached_to_name='{docname}' and (file_url='{file_url}' or thumbnail_url='{file_url}')""" .format(doctype=doctype, docname=docname, file_url=file_url)) if files: # file is already attached return _file = frappe.get_doc({ "doctype": "File", "file_url": file_url, "attached_to_name": docname, "attached_to_doctype": doctype, "attached_to_field": 0, "folder": "Home/Attachments", }) _file.save() # header filename, file_extension = ["", ""] if not rows: _file = frappe.get_doc("File", {"file_url": data_import_doc.import_file}) fcontent = _file.get_content() filename, file_extension = _file.get_extension() if file_extension == ".xlsx" and from_data_import == "Yes": from frappe.utils.xlsxutils import read_xlsx_file_from_attached_file rows = read_xlsx_file_from_attached_file( file_url=data_import_doc.import_file) elif file_extension == ".csv": from frappe.utils.csvutils import read_csv_content rows = read_csv_content(fcontent, ignore_encoding_errors) else: frappe.throw(_("Unsupported File Format")) start_row = get_start_row() header = rows[:start_row] data = rows[start_row:] try: doctype = get_header_row(get_data_keys_definition().main_table)[1] columns = filter_empty_columns( get_header_row(get_data_keys_definition().columns)[1:]) except: frappe.throw(_("Cannot change header content")) doctypes = [] column_idx_to_fieldname = {} column_idx_to_fieldtype = {} if skip_errors: data_rows_with_error = header if submit_after_import and not cint( frappe.db.get_value("DocType", doctype, "is_submittable")): submit_after_import = False parenttype = get_header_row(get_data_keys_definition().parent_table) if len(parenttype) > 1: parenttype = parenttype[1] # check permissions if not frappe.permissions.can_import(parenttype or doctype): frappe.flags.mute_emails = False return { "messages": [_("Not allowed to Import") + ": " + _(doctype)], "error": True } # Throw expception in case of the empty data file check_data_length() make_column_map() total = len(data) if validate_template: if total: data_import_doc.total_rows = total return True if overwrite == None: overwrite = params.get("overwrite") # delete child rows (if parenttype) parentfield = None if parenttype: parentfield = get_parent_field(doctype, parenttype) if overwrite: delete_child_rows(data, doctype) import_log = [] def log(**kwargs): if via_console: print( (kwargs.get("title") + kwargs.get("message")).encode("utf-8")) else: import_log.append(kwargs) def as_link(doctype, name): if via_console: return "{0}: {1}".format(doctype, name) else: return getlink(doctype, name) # publish realtime task update def publish_progress(achieved, reload=False): if data_import_doc: frappe.publish_realtime( "data_import_progress", { "progress": str(int(100.0 * achieved / total)), "data_import": data_import_doc.name, "reload": reload, }, user=frappe.session.user, ) error_flag = rollback_flag = False batch_size = frappe.conf.data_import_batch_size or 1000 for batch_start in range(0, total, batch_size): batch = data[batch_start:batch_start + batch_size] for i, row in enumerate(batch): # bypass empty rows if main_doc_empty(row): continue row_idx = i + start_row doc = None publish_progress(i) try: doc, attachments, last_error_row_idx = get_doc(row_idx) validate_naming(doc) if pre_process: pre_process(doc) original = None if parentfield: parent = frappe.get_doc(parenttype, doc["parent"]) doc = parent.append(parentfield, doc) parent.save() else: if overwrite and doc.get("name") and frappe.db.exists( doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"]) original_name = original.name original.update(doc) # preserve original name for case sensitivity original.name = original_name original.flags.ignore_links = ignore_links original.save() doc = original else: if not update_only: doc = frappe.get_doc(doc) prepare_for_insert(doc) doc.flags.ignore_links = ignore_links doc.insert() if attachments: # check file url and create a File document for file_url in attachments: attach_file_to_doc(doc.doctype, doc.name, file_url) if submit_after_import: doc.submit() # log errors if parentfield: log( **{ "row": doc.idx, "title": 'Inserted row for "%s"' % (as_link(parenttype, doc.parent)), "link": get_absolute_url(parenttype, doc.parent), "message": "Document successfully saved", "indicator": "green", }) elif submit_after_import: log( **{ "row": row_idx + 1, "title": 'Submitted row for "%s"' % (as_link(doc.doctype, doc.name)), "message": "Document successfully submitted", "link": get_absolute_url(doc.doctype, doc.name), "indicator": "blue", }) elif original: log( **{ "row": row_idx + 1, "title": 'Updated row for "%s"' % (as_link(doc.doctype, doc.name)), "message": "Document successfully updated", "link": get_absolute_url(doc.doctype, doc.name), "indicator": "green", }) elif not update_only: log( **{ "row": row_idx + 1, "title": 'Inserted row for "%s"' % (as_link(doc.doctype, doc.name)), "message": "Document successfully saved", "link": get_absolute_url(doc.doctype, doc.name), "indicator": "green", }) else: log( **{ "row": row_idx + 1, "title": "Ignored row for %s" % (row[1]), "link": None, "message": "Document updation ignored", "indicator": "orange", }) except Exception as e: error_flag = True # build error message if frappe.local.message_log: err_msg = "\n".join([ '<p class="border-bottom small">{}</p>'.format( json.loads(msg).get("message")) for msg in frappe.local.message_log ]) else: err_msg = '<p class="border-bottom small">{}</p>'.format( cstr(e)) error_trace = frappe.get_traceback() if error_trace: error_log_doc = frappe.log_error(error_trace) error_link = get_absolute_url("Error Log", error_log_doc.name) else: error_link = None log( **{ "row": row_idx + 1, "title": "Error for row %s" % (len(row) > 1 and frappe.safe_decode(row[1]) or ""), "message": err_msg, "indicator": "red", "link": error_link, }) # data with error to create a new file # include the errored data in the last row as last_error_row_idx will not be updated for the last row if skip_errors: if last_error_row_idx == len(rows) - 1: last_error_row_idx = len(rows) data_rows_with_error += rows[row_idx:last_error_row_idx] else: rollback_flag = True finally: frappe.local.message_log = [] start_row += batch_size if rollback_flag: frappe.db.rollback() else: frappe.db.commit() frappe.flags.mute_emails = False frappe.flags.in_import = False log_message = {"messages": import_log, "error": error_flag} if data_import_doc: data_import_doc.log_details = json.dumps(log_message) import_status = None if error_flag and data_import_doc.skip_errors and len(data) != len( data_rows_with_error): import_status = "Partially Successful" # write the file with the faulty row file_name = "error_" + filename + file_extension if file_extension == ".xlsx": from frappe.utils.xlsxutils import make_xlsx xlsx_file = make_xlsx(data_rows_with_error, "Data Import Template") file_data = xlsx_file.getvalue() else: from frappe.utils.csvutils import to_csv file_data = to_csv(data_rows_with_error) _file = frappe.get_doc({ "doctype": "File", "file_name": file_name, "attached_to_doctype": "Data Import Legacy", "attached_to_name": data_import_doc.name, "folder": "Home/Attachments", "content": file_data, }) _file.save() data_import_doc.error_file = _file.file_url elif error_flag: import_status = "Failed" else: import_status = "Successful" data_import_doc.import_status = import_status data_import_doc.save() if data_import_doc.import_status in [ "Successful", "Partially Successful" ]: data_import_doc.submit() publish_progress(100, True) else: publish_progress(0, True) frappe.db.commit() else: return log_message
def clear_linked_doctype_cache(): frappe.cache().delete_value( 'linked_doctypes_without_ignore_user_permissions_enabled')
def login_oauth_user(data=None, provider=None, state=None, email_id=None, key=None, generate_login_token=False): # NOTE: This could lead to security issue as the signed in user can type any email address in complete_signup # if email_id and key: # data = json.loads(frappe.db.get_temp(key)) # # What if data is missing because of an invalid key # data["email"] = email_id # # elif not (data.get("email") and get_first_name(data)) and not frappe.db.exists("User", data.get("email")): # # ask for user email # key = frappe.db.set_temp(json.dumps(data)) # frappe.db.commit() # frappe.local.response["type"] = "redirect" # frappe.local.response["location"] = "/complete_signup?key=" + key # return # json.loads data and state if isinstance(data, string_types): data = json.loads(data) if isinstance(state, string_types): state = json.loads(state) if not (state and state["token"]): frappe.respond_as_web_page(_("Invalid Request"), _("Token is missing"), http_status_code=417) return token = frappe.cache().get_value("{0}:{1}".format(provider, state["token"]), expires=True) if not token: frappe.respond_as_web_page(_("Invalid Request"), _("Invalid Token"), http_status_code=417) return user = get_email(data) if not user: frappe.respond_as_web_page( _("Invalid Request"), _("Please ensure that your profile has an email address")) return try: if update_oauth_user(user, data, provider) is False: return except SignupDisabledError: return frappe.respond_as_web_page( "Signup is Disabled", "Sorry. Signup from Website is disabled.", success=False, http_status_code=403) frappe.local.login_manager.user = user frappe.local.login_manager.post_login() # because of a GET request! frappe.db.commit() if frappe.utils.cint(generate_login_token): login_token = frappe.generate_hash(length=32) frappe.cache().set_value("login_token:{0}".format(login_token), frappe.local.session.sid, expires_in_sec=120) frappe.response["login_token"] = login_token else: redirect_post_login( desk_user=frappe.local.response.get('message') == 'Logged In')
def clear_doctype_map(doctype, name): frappe.cache().hdel(frappe.scrub(doctype) + '_map', name)
def clear_domain_cache(user=None): cache = frappe.cache() domain_cache_keys = ('domain_restricted_doctypes', 'domain_restricted_pages') cache.delete_value(domain_cache_keys)
def hdel_keys(self, name_starts_with, key): """Delete hash names with wildcard `*` and key""" for name in frappe.cache().get_keys(name_starts_with): name = name.split("|", 1)[1] self.hdel(name, key)
def get_incoming_server(self, in_receive=False, email_sync_rule="UNSEEN"): """Returns logged in POP3/IMAP connection object.""" if frappe.cache().get_value("workers:no-internet") == True: return None args = frappe._dict({ "email_account":self.name, "host": self.email_server, "use_ssl": self.use_ssl, "username": getattr(self, "login_id", None) or self.email_id, "use_imap": self.use_imap, "email_sync_rule": email_sync_rule, "uid_validity": self.uidvalidity, "incoming_port": get_port(self), "initial_sync_count": self.initial_sync_count or 100 }) if self.password: args.password = self.get_password() if not args.get("host"): frappe.throw(_("{0} is required").format("Email Server")) email_server = EmailServer(frappe._dict(args)) try: email_server.connect() except (error_proto, imaplib.IMAP4.error) as e: message = e.message.lower().replace(" ","") if in_receive and any(map(lambda t: t in message, ['authenticationfail', 'loginviayourwebbrowser', #abbreviated to work with both failure and failed 'loginfailed', 'err[auth]', 'errtemporaryerror'])): #temporary error to deal with godaddy # if called via self.receive and it leads to authentication error, disable incoming # and send email to system manager self.handle_incoming_connect_error( description=_('Authentication failed while receiving emails from Email Account {0}. Message from server: {1}'.format(self.name, e.message)) ) return None else: frappe.throw(e.message) except socket.error: if in_receive: # timeout while connecting, see receive.py connect method description = frappe.message_log.pop() if frappe.message_log else "Socket Error" if test_internet(): self.db_set("no_failed", self.no_failed + 1) if self.no_failed > 2: self.handle_incoming_connect_error(description=description) else: frappe.cache().set_value("workers:no-internet", True) return None else: raise if not in_receive: if self.use_imap: email_server.imap.logout() # reset failed attempts count self.set_failed_attempts_count(0) return email_server
def clear_cache(self): frappe.cache().hdel("last_modified", self.doctype) self.clear_linked_with_cache()
def login_failed_time(self): frappe.cache().hdel('login_failed_time', self.user_name)
def login_failed_count(self): frappe.cache().hdel('login_failed_count', self.user_name)
def get_failed_attempts_count(self): return cint(frappe.cache().get('{0}:email-account-failed-attempts'.format(self.name)))
def set_failed_attempts_count(self, value): frappe.cache().set('{0}:email-account-failed-attempts'.format(self.name), value)
def login_failed_time(self): """First failed login attempt time within lock interval. For every user we track only First failed login attempt time within lock interval of time. """ return frappe.cache().hget('login_failed_time', self.user_name)