Fixed Website Response, Startup JS loading,

Conditions involving STANDARD_USERS, removed Validate Max Users,
Cast Floats and Ints for Single DocTypes, Ability to Disable Scheduler
This commit is contained in:
Anand Doshi 2014-03-13 20:38:08 +05:30
parent 0a43add3d3
commit cec016be2a
14 changed files with 126 additions and 91 deletions

View file

@ -54,7 +54,6 @@ def get_bootinfo():
add_allowed_pages(bootinfo)
load_translations(bootinfo)
load_conf_settings(bootinfo)
load_startup_js(bootinfo)
# ipinfo
if frappe.session['data'].get('ipinfo'):
@ -120,10 +119,11 @@ def get_fullnames():
return d
def load_startup_js(bootinfo):
bootinfo.startup_js = ""
def get_startup_js():
startup_js = []
for method in frappe.get_hooks().startup_js or []:
bootinfo.startup_js += frappe.get_attr(method)()
startup_js.append(frappe.get_attr(method)() or "")
return "\n".join(startup_js)
def get_user(bootinfo):
"""get user info"""

View file

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, cint, add_months, date_diff, add_days, nowdate
from frappe.core.doctype.user.user import STANDARD_USERS
weekdays = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
@ -52,7 +53,9 @@ def send_event_digest():
today = nowdate()
for user in frappe.db.sql("""select name, email, language
from tabUser where ifnull(enabled,0)=1
and user_type='System User' and name not in ('Guest', 'Administrator')""", as_dict=1):
and user_type='System User' and name not in ({})""".format(", ".join(["%s"]*len(STANDARD_USERS))),
STANDARD_USERS, as_dict=1):
events = get_events(today, today, user.name, for_reminder=True)
if events:
text = ""

View file

@ -7,6 +7,8 @@ from frappe.utils import cint, now, cstr
from frappe import throw, msgprint, _
from frappe.auth import _update_password
STANDARD_USERS = ("Guest", "Administrator")
class DocType:
def __init__(self, doc, doclist):
self.doc = doc
@ -14,7 +16,7 @@ class DocType:
def autoname(self):
"""set name as email id"""
if self.doc.name not in ('Guest','Administrator'):
if self.doc.name not in STANDARD_USERS:
self.doc.email = self.doc.email.strip()
self.doc.name = self.doc.email
@ -23,31 +25,16 @@ class DocType:
def validate(self):
self.in_insert = self.doc.fields.get("__islocal")
if self.doc.name not in ('Guest','Administrator'):
if self.doc.name not in STANDARD_USERS:
self.validate_email_type(self.doc.email)
self.validate_max_users()
self.add_system_manager_role()
self.check_enable_disable()
if self.in_insert:
if self.doc.name not in ("Guest", "Administrator"):
if self.doc.new_password:
# new password given, no email required
_update_password(self.doc.name, self.doc.new_password)
if not getattr(self, "no_welcome_mail", False):
self.send_welcome_mail()
msgprint(_("Welcome Email Sent"))
else:
try:
self.email_new_password()
except frappe.OutgoingEmailError:
pass # email server not set, don't send email
self.doc.new_password = ""
self.update_gravatar()
def check_enable_disable(self):
# do not allow disabling administrator/guest
if not cint(self.doc.enabled) and self.doc.name in ["Administrator", "Guest"]:
if not cint(self.doc.enabled) and self.doc.name in STANDARD_USERS:
throw("{msg}: {name}".format(**{
"msg": _("Hey! You cannot disable user"),
"name": self.doc.name
@ -60,26 +47,6 @@ class DocType:
if not cint(self.doc.enabled) and getattr(frappe, "login_manager", None):
frappe.local.login_manager.logout(user=self.doc.name)
def validate_max_users(self):
"""don't allow more than max users if set in conf"""
from frappe import conf
# check only when enabling a user
if 'max_users' in conf and self.doc.enabled and \
self.doc.name not in ["Administrator", "Guest"] and \
cstr(self.doc.user_type).strip() in ("", "System User"):
active_users = frappe.db.sql("""select count(*) from tabUser
where ifnull(enabled, 0)=1 and docstatus<2
and ifnull(user_type, "System User") = "System User"
and name not in ('Administrator', 'Guest', %s)""", (self.doc.name,))[0][0]
if active_users >= conf.max_users and conf.max_users:
throw("""
You already have <b>%(active_users)s</b> active users, \
which is the maximum number that you are currently allowed to add. <br /><br /> \
So, to add more users, you can:<br /> \
1. <b>Upgrade to the unlimited users plan</b>, or<br /> \
2. <b>Disable one or more of your existing users and try again</b>""" \
% {'active_users': active_users})
def add_system_manager_role(self):
# if adding system manager, do nothing
if not cint(self.doc.enabled) or ("System Manager" in [user_role.role for user_role in
@ -107,6 +74,21 @@ class DocType:
frappe.db.set(self.doc, 'owner', self.doc.name)
frappe.clear_cache(user=self.doc.name)
try:
if self.in_insert:
if self.doc.name not in STANDARD_USERS:
if self.doc.new_password:
# new password given, no email required
_update_password(self.doc.name, self.doc.new_password)
if not getattr(self, "no_welcome_mail", False):
self.send_welcome_mail()
msgprint(_("Welcome Email Sent"))
else:
self.email_new_password()
except frappe.OutgoingEmailError:
pass # email server not set, don't send email
def update_gravatar(self):
import md5
if not self.doc.user_image:
@ -168,7 +150,7 @@ class DocType:
args.update(add_args)
sender = frappe.session.user not in ("Administrator", "Guest") and frappe.session.user or None
sender = frappe.session.user not in STANDARD_USERS and frappe.session.user or None
frappe.sendmail(recipients=self.doc.email, sender=sender, subject=subject,
message=frappe.get_template(template).render(args))
@ -179,7 +161,7 @@ class DocType:
def on_trash(self):
frappe.clear_cache(user=self.doc.name)
if self.doc.name in ["Administrator", "Guest"]:
if self.doc.name in STANDARD_USERS:
throw("{msg}: {name}".format(**{
"msg": _("Hey! You cannot delete user"),
"name": self.doc.name
@ -215,7 +197,7 @@ class DocType:
def validate_rename(self, olddn, newdn):
# do not allow renaming administrator and guest
if olddn in ["Administrator", "Guest"]:
if olddn in STANDARD_USERS:
throw("{msg}: {name}".format(**{
"msg": _("Hey! You are restricted from renaming the user"),
"name": olddn
@ -357,35 +339,50 @@ def reset_password(user):
def user_query(doctype, txt, searchfield, start, page_len, filters):
from frappe.widgets.reportview import get_match_cond
txt = "%{}%".format(txt)
return frappe.db.sql("""select name, concat_ws(' ', first_name, middle_name, last_name)
from `tabUser`
where ifnull(enabled, 0)=1
and docstatus < 2
and name not in ('Administrator', 'Guest')
and name not in ({standard_users})
and user_type != 'Website User'
and (%(key)s like "%(txt)s"
or concat_ws(' ', first_name, middle_name, last_name) like "%(txt)s")
%(mcond)s
and ({key} like %s
or concat_ws(' ', first_name, middle_name, last_name) like %s)
{mcond}
order by
case when name like "%(txt)s" then 0 else 1 end,
case when concat_ws(' ', first_name, middle_name, last_name) like "%(txt)s"
case when name like %s then 0 else 1 end,
case when concat_ws(' ', first_name, middle_name, last_name) like %s
then 0 else 1 end,
name asc
limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt,
'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len})
limit %s, %s""".format(standard_users=", ".join(["%s"]*len(STANDARD_USERS)),
key=searchfield, mcond=get_match_cond(doctype)),
tuple(list(STANDARD_USERS) + [txt, txt, txt, txt, start, page_len]))
def get_total_users():
def get_total_users(exclude_users=None):
"""Returns total no. of system users"""
return frappe.db.sql("""select count(*) from `tabUser`
where enabled = 1 and user_type != 'Website User'
and name not in ('Administrator', 'Guest')""")[0][0]
return len(get_system_users(exclude_users=exclude_users))
def get_system_users(exclude_users=None):
if not exclude_users:
exclude_users = []
elif not isinstance(exclude_users, (list, tuple)):
exclude_users = [exclude_users]
exclude_users += list(STANDARD_USERS)
system_users = frappe.db.sql_list("""select name from `tabUser`
where enabled=1 and user_type != 'Website User'
and name not in ({})""".format(", ".join(["%s"]*len(exclude_users))),
exclude_users)
return system_users
def get_active_users():
"""Returns No. of system users who logged in, in the last 3 days"""
return frappe.db.sql("""select count(*) from `tabUser`
where enabled = 1 and user_type != 'Website User'
and name not in ('Administrator', 'Guest')
and hour(timediff(now(), last_login)) < 72""")[0][0]
and name not in ({})
and hour(timediff(now(), last_login)) < 72""".format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS)[0][0]
def get_website_users():
"""Returns total no. of website users"""

View file

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.core.doctype.notification_count.notification_count import delete_notification_count_for
from frappe.core.doctype.user.user import STANDARD_USERS
@frappe.whitelist()
def get_list(arg=None):
@ -51,8 +51,8 @@ def get_active_users():
from tabUser
where ifnull(enabled,0)=1 and
ifnull(user_type, '')!='Website User' and
name not in ('Administrator', 'Guest')
order by first_name""", as_dict=1)
name not in ({})
order by first_name""".format(", ".join(["%s"]*len(STANDARD_USERS))), STANDARD_USERS, as_dict=1)
@frappe.whitelist()
def post(arg=None):

View file

@ -5,13 +5,12 @@ from __future__ import unicode_literals
import frappe
import frappe.defaults
import frappe.permissions
from frappe.core.doctype.user.user import get_system_users
@frappe.whitelist()
def get_users_and_links():
return {
"users": frappe.db.sql_list("""select name from tabUser where
ifnull(enabled,0)=1 and
name not in ("Administrator", "Guest")"""),
"users": get_system_users(),
"link_fields": get_restrictable_doctypes()
}

View file

@ -68,9 +68,6 @@ class Bean:
self.set_doclist(doclist)
if dt == dn:
self.convert_type(self.doc)
def __iter__(self):
return self.doclist.__iter__()
@ -91,6 +88,10 @@ class Bean:
self.doclist = frappe.doclist(doclist)
self.doc = self.doclist[0]
if self.doc.get_meta().issingle:
self.doc.cast_floats_and_ints()
if self.obj:
self.obj.doclist = self.doclist
self.obj.doc = self.doc
@ -444,16 +445,6 @@ class Bean:
raise frappe.MandatoryError, ", ".join([fieldname for msg, fieldname in missing])
def convert_type(self, doc):
if doc.doctype==doc.name and doc.doctype!="DocType":
for df in self.meta.get({"doctype": "DocField", "parent": doc.doctype}):
if df.fieldtype in ("Int", "Check"):
doc.fields[df.fieldname] = cint(doc.fields.get(df.fieldname))
elif df.fieldtype in ("Float", "Currency"):
doc.fields[df.fieldname] = flt(doc.fields.get(df.fieldname))
doc.docstatus = cint(doc.docstatus)
def extract_images_from_text_editor(self):
from frappe.utils.file_manager import extract_images_from_html
if self.doc.doctype != "DocType":

View file

@ -161,7 +161,18 @@ class Document:
def _loadsingle(self):
self.name = self.doctype
self.fields.update(getsingle(self.doctype))
self.cast_floats_and_ints()
def cast_floats_and_ints(self):
for df in frappe.get_doctype(self.doctype).get_docfields():
if df.fieldtype in ("Int", "Check"):
self.fields[df.fieldname] = cint(self.fields.get(df.fieldname))
elif df.fieldtype in ("Float", "Currency"):
self.fields[df.fieldname] = flt(self.fields.get(df.fieldname))
if self.docstatus is not None:
self.docstatus = cint(self.docstatus)
def __setattr__(self, name, value):
# normal attribute
if not self.__dict__.has_key('_Document__initialized'):

View file

@ -380,10 +380,12 @@ class DocTypeDocList(frappe.model.doclist.DocList):
return fieldname in self.get_fieldnames()
def get_fieldnames(self, filters=None):
return map(lambda df: df.fieldname, self.get_docfields(filters))
def get_docfields(self, filters=None):
if not filters: filters = {}
filters.update({"doctype": "DocField", "parent": self[0].name})
return map(lambda df: df.fieldname, self.get(filters))
return self.get(filters)
def get_options(self, fieldname, parent=None, parentfield=None):
return self.get_field(fieldname, parent, parentfield).options

View file

@ -68,24 +68,26 @@ def get():
"""get session boot info"""
from frappe.core.doctype.notification_count.notification_count import \
get_notification_info_for_boot, get_notifications
from frappe.boot import get_bootinfo, get_startup_js
bootinfo = None
if not getattr(frappe.conf,'disable_session_cache',None):
if not getattr(frappe.conf,'disable_session_cache', None):
# check if cache exists
bootinfo = frappe.cache().get_value('bootinfo:' + frappe.session.user)
if bootinfo:
bootinfo['from_cache'] = 1
bootinfo["user"]["recent"] = json.dumps(frappe.cache().get_value("recent:" + frappe.session.user))
bootinfo["notification_info"].update(get_notifications())
bootinfo["startup_js"] = get_startup_js()
if not bootinfo:
if not frappe.cache().get_stats():
frappe.msgprint("memcached is not working / stopped. Please start memcached for best results.")
# if not create it
from frappe.boot import get_bootinfo
bootinfo = get_bootinfo()
bootinfo["notification_info"] = get_notification_info_for_boot()
bootinfo["startup_js"] = get_startup_js()
frappe.cache().set_value('bootinfo:' + frappe.session.user, bootinfo)
return bootinfo

View file

@ -5,12 +5,14 @@ from __future__ import unicode_literals
import unittest
import frappe
from frappe.test_runner import make_test_records
from frappe.core.doctype.user.user import STANDARD_USERS
class TestDB(unittest.TestCase):
def test_get_value(self):
from frappe.utils import now_datetime
import time
frappe.db.sql("""delete from `tabUser` where name not in ('Administrator', 'Guest')""")
frappe.db.sql("""delete from `tabUser` where name not in ({})""".format(", ".join(["%s"]*len(STANDARD_USERS))),
STANDARD_USERS)
now = now_datetime()

View file

@ -13,7 +13,7 @@ def send(email, as_bulk=False):
if frappe.flags.mute_emails or frappe.conf.get("mute_emails") or False:
frappe.msgprint("Emails are muted")
return
try:
smtpserver = SMTPServer()
if hasattr(smtpserver, "always_use_login_id_as_sender") and \

View file

@ -18,6 +18,9 @@ from datetime import datetime
DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
def enqueue_events(site):
if is_scheduler_disabled():
return
# lock before queuing begins
try:
lock = create_lock('scheduler')
@ -103,6 +106,15 @@ def log(method, message=None):
return message
def is_scheduler_disabled():
return frappe.utils.cint(frappe.db.get_global("disable_scheduler"))
def enable_scheduler():
frappe.db.set_global("disable_scheduler", 0)
def disable_scheduler():
frappe.db.set_global("disable_scheduler", 1)
def get_errors(from_date, to_date, limit):
errors = frappe.db.sql("""select modified, method, error from `tabScheduler Log`
where date(modified) between %s and %s
@ -127,6 +139,6 @@ def get_error_report(from_date=None, to_date=None, limit=10):
limit=limit, url=get_url(), errors="<hr>".join(errors))
else:
return 0, "<p>Scheduler didn't encounter any problems.</p>"
if __name__=='__main__':
execute()

View file

@ -179,13 +179,15 @@ def get_user_fullname(user):
def get_system_managers(only_name=False):
"""returns all system manager's user details"""
import email.utils
from frappe.core.doctype.user.user import STANDARD_USERS
system_managers = frappe.db.sql("""select distinct name,
concat_ws(" ", if(first_name="", null, first_name), if(last_name="", null, last_name))
as fullname from tabUser p
where docstatus < 2 and enabled = 1
and name not in ("Administrator", "Guest")
and name not in ({})
and exists (select * from tabUserRole ur
where ur.parent = p.name and ur.role="System Manager")""", as_dict=True)
where ur.parent = p.name and ur.role="System Manager")""".format(", ".join(["%s"]*len(STANDARD_USERS))),
STANDARD_USERS, as_dict=True)
if only_name:
return [p.name for p in system_managers]

View file

@ -16,16 +16,28 @@ def render(path):
"""render html page"""
frappe.local.is_ajax = frappe.get_request_header("X-Requested-With")=="XMLHttpRequest"
path = resolve_path(path.lstrip("/"))
http_status_code = 200
try:
data = render_page(path)
except frappe.DoesNotExistError, e:
path = "404"
data = render_page(path)
http_status_code = e.http_status_code
except Exception:
path = "error"
data = render_page(path)
http_status_code = 500
return build_response(path, data, http_status_code)
def build_response(path, data, http_status_code):
# build response
response = Response()
response.data = set_content_type(response, data, path)
response.status_code = http_status_code
response.headers[b"X-Page-Name"] = path.encode("utf-8")
response.headers[b"X-From-Cache"] = frappe.local.response.from_cache or False
return response
@ -53,14 +65,16 @@ def build(path):
frappe.connect()
build_method = (build_json if is_ajax() else build_page)
try:
return build_method(path)
except frappe.DoesNotExistError:
hooks = frappe.get_hooks()
if hooks.website_catch_all:
return build_method(hooks.website_catch_all[0])
path = hooks.website_catch_all[0]
return build_method(path)
else:
return build_method("404")
raise
def build_json(path):
return get_context(path).data