選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

572 行
16 KiB

  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. """
  4. globals attached to webnotes module
  5. + some utility functions that should probably be moved
  6. """
  7. from __future__ import unicode_literals
  8. from werkzeug.local import Local
  9. from werkzeug.exceptions import NotFound
  10. from MySQLdb import ProgrammingError as SQLError
  11. import os, sys, importlib
  12. import json
  13. import semantic_version
  14. local = Local()
  15. class _dict(dict):
  16. """dict like object that exposes keys as attributes"""
  17. def __getattr__(self, key):
  18. return self.get(key)
  19. def __setattr__(self, key, value):
  20. self[key] = value
  21. def __getstate__(self):
  22. return self
  23. def __setstate__(self, d):
  24. self.update(d)
  25. def update(self, d):
  26. """update and return self -- the missing dict feature in python"""
  27. super(_dict, self).update(d)
  28. return self
  29. def copy(self):
  30. return _dict(dict(self).copy())
  31. def __getattr__(self, key):
  32. return local.get("key", None)
  33. def _(msg):
  34. """translate object in current lang, if exists"""
  35. if local.lang == "en":
  36. return msg
  37. from webnotes.translate import get_full_dict
  38. return get_full_dict(local.lang).get(msg, msg)
  39. def get_lang_dict(fortype, name=None):
  40. if local.lang=="en":
  41. return {}
  42. from webnotes.translate import get_dict
  43. return get_dict(fortype, name)
  44. def set_user_lang(user, user_language=None):
  45. from webnotes.translate import get_lang_dict
  46. if not user_language:
  47. user_language = conn.get_value("Profile", user, "language")
  48. if user_language:
  49. lang_dict = get_lang_dict()
  50. if user_language in lang_dict:
  51. local.lang = lang_dict[user_language]
  52. # local-globals
  53. conn = local("conn")
  54. conf = local("conf")
  55. form = form_dict = local("form_dict")
  56. request = local("request")
  57. request_method = local("request_method")
  58. response = local("response")
  59. _response = local("_response")
  60. session = local("session")
  61. user = local("user")
  62. flags = local("flags")
  63. error_log = local("error_log")
  64. debug_log = local("debug_log")
  65. message_log = local("message_log")
  66. lang = local("lang")
  67. def init(site, sites_path=None):
  68. if getattr(local, "initialised", None):
  69. return
  70. if not sites_path:
  71. sites_path = '.'
  72. local.error_log = []
  73. local.site = site
  74. local.sites_path = sites_path
  75. local.site_path = os.path.join(sites_path, site)
  76. local.message_log = []
  77. local.debug_log = []
  78. local.response = _dict({})
  79. local.lang = "en"
  80. local.request_method = request.method if request else None
  81. local.conf = _dict(get_site_config())
  82. local.initialised = True
  83. local.flags = _dict({})
  84. local.rollback_observers = []
  85. local.module_app = None
  86. local.app_modules = None
  87. setup_module_map()
  88. def get_site_config():
  89. site_filepath = os.path.join(local.site_path, "site_config.json")
  90. if os.path.exists(site_filepath):
  91. with open(site_filepath, 'r') as f:
  92. return json.load(f)
  93. else:
  94. return _dict()
  95. def destroy():
  96. """closes connection and releases werkzeug local"""
  97. if conn:
  98. conn.close()
  99. from werkzeug.local import release_local
  100. release_local(local)
  101. _memc = None
  102. test_objects = {}
  103. # memcache
  104. def cache():
  105. global _memc
  106. if not _memc:
  107. from webnotes.memc import MClient
  108. _memc = MClient(['localhost:11211'])
  109. return _memc
  110. class DuplicateEntryError(Exception): pass
  111. class ValidationError(Exception): pass
  112. class AuthenticationError(Exception): pass
  113. class PermissionError(Exception): pass
  114. class UnknownDomainError(Exception): pass
  115. class SessionStopped(Exception): pass
  116. class MappingMismatchError(ValidationError): pass
  117. class InvalidStatusError(ValidationError): pass
  118. class DoesNotExistError(ValidationError): pass
  119. class MandatoryError(ValidationError): pass
  120. class InvalidSignatureError(ValidationError): pass
  121. def get_traceback():
  122. import utils
  123. return utils.get_traceback()
  124. def errprint(msg):
  125. from utils import cstr
  126. if not request:
  127. print cstr(msg)
  128. error_log.append(cstr(msg))
  129. def log(msg):
  130. if not request:
  131. import conf
  132. if conf.get("logging") or False:
  133. print repr(msg)
  134. from utils import cstr
  135. debug_log.append(cstr(msg))
  136. def msgprint(msg, small=0, raise_exception=0, as_table=False):
  137. def _raise_exception():
  138. if raise_exception:
  139. if flags.rollback_on_exception:
  140. conn.rollback()
  141. import inspect
  142. if inspect.isclass(raise_exception) and issubclass(raise_exception, Exception):
  143. raise raise_exception, msg
  144. else:
  145. raise ValidationError, msg
  146. if flags.mute_messages:
  147. _raise_exception()
  148. return
  149. from utils import cstr
  150. if as_table and type(msg) in (list, tuple):
  151. msg = '<table border="1px" style="border-collapse: collapse" cellpadding="2px">' + ''.join(['<tr>'+''.join(['<td>%s</td>' % c for c in r])+'</tr>' for r in msg]) + '</table>'
  152. if flags.print_messages:
  153. print "Message: " + repr(msg)
  154. message_log.append((small and '__small:' or '')+cstr(msg or ''))
  155. _raise_exception()
  156. def throw(msg, exc=ValidationError):
  157. msgprint(msg, raise_exception=exc)
  158. def create_folder(path):
  159. if not os.path.exists(path): os.makedirs(path)
  160. def connect(site=None, db_name=None):
  161. from db import Database
  162. if site:
  163. init(site)
  164. local.conn = Database(user=db_name or local.conf.db_name)
  165. local.response = _dict()
  166. local.form_dict = _dict()
  167. local.session = _dict()
  168. set_user("Administrator")
  169. def set_user(username):
  170. import webnotes.profile
  171. local.session["user"] = username
  172. local.user = webnotes.profile.Profile(username)
  173. def get_request_header(key, default=None):
  174. return request.headers.get(key, default)
  175. logger = None
  176. whitelisted = []
  177. guest_methods = []
  178. def whitelist(allow_guest=False, allow_roles=None):
  179. """
  180. decorator for whitelisting a function
  181. Note: if the function is allowed to be accessed by a guest user,
  182. it must explicitly be marked as allow_guest=True
  183. for specific roles, set allow_roles = ['Administrator'] etc.
  184. """
  185. def innerfn(fn):
  186. global whitelisted, guest_methods
  187. whitelisted.append(fn)
  188. if allow_guest:
  189. guest_methods.append(fn)
  190. if allow_roles:
  191. roles = get_roles()
  192. allowed = False
  193. for role in allow_roles:
  194. if role in roles:
  195. allowed = True
  196. break
  197. if not allowed:
  198. raise PermissionError, "Method not allowed"
  199. return fn
  200. return innerfn
  201. def clear_cache(user=None, doctype=None):
  202. """clear cache"""
  203. from webnotes.sessions import clear_cache
  204. if doctype:
  205. from webnotes.model.doctype import clear_cache
  206. clear_cache(doctype)
  207. reset_metadata_version()
  208. elif user:
  209. clear_cache(user)
  210. else: # everything
  211. clear_cache()
  212. reset_metadata_version()
  213. def get_roles(username=None):
  214. import webnotes.profile
  215. if not username or username==session.user:
  216. return user.get_roles()
  217. else:
  218. return webnotes.profile.Profile(username).get_roles()
  219. def check_admin_or_system_manager():
  220. if ("System Manager" not in get_roles()) and \
  221. (session.user!="Administrator"):
  222. msgprint("Only Allowed for Role System Manager or Administrator", raise_exception=True)
  223. def has_permission(doctype, ptype="read", refdoc=None):
  224. """check if user has permission"""
  225. from webnotes.utils import cint
  226. if session.user=="Administrator" or conn.get_value("DocType", doctype, "istable")==1:
  227. return True
  228. meta = get_doctype(doctype)
  229. # get user permissions
  230. user_roles = get_roles()
  231. perms = [p for p in meta.get({"doctype": "DocPerm"})
  232. if cint(p.get(ptype))==1 and cint(p.permlevel)==0 and (p.role=="All" or p.role in user_roles)]
  233. if refdoc:
  234. return has_match(meta, perms, refdoc)
  235. else:
  236. return perms and True or False
  237. def has_match(meta, perms, refdoc):
  238. from webnotes.defaults import get_user_default_as_list
  239. if isinstance(refdoc, basestring):
  240. refdoc = doc(meta[0].name, refdoc)
  241. match_failed = {}
  242. for p in perms:
  243. if p.match:
  244. if ":" in p.match:
  245. keys = p.match.split(":")
  246. else:
  247. keys = [p.match, p.match]
  248. if refdoc.fields.get(keys[0],"[No Value]") in get_user_default_as_list(keys[1]):
  249. return True
  250. else:
  251. match_failed[keys[0]] = refdoc.fields.get(keys[0],"[No Value]")
  252. else:
  253. # found a permission without a match
  254. return True
  255. # no valid permission found
  256. if match_failed:
  257. msg = _("Not allowed for: ")
  258. for key in match_failed:
  259. msg += "\n" + (meta.get_field(key) and meta.get_label(key) or key) \
  260. + " = " + (match_failed[key] or "None")
  261. msgprint(msg)
  262. return False
  263. def generate_hash():
  264. """Generates random hash for session id"""
  265. import hashlib, time
  266. return hashlib.sha224(str(time.time())).hexdigest()
  267. def reset_metadata_version():
  268. v = generate_hash()
  269. cache().set_value("metadata_version", v)
  270. return v
  271. def get_obj(dt = None, dn = None, doc=None, doclist=[], with_children = True):
  272. from webnotes.model.code import get_obj
  273. return get_obj(dt, dn, doc, doclist, with_children)
  274. def doc(doctype=None, name=None, fielddata=None):
  275. from webnotes.model.doc import Document
  276. return Document(doctype, name, fielddata)
  277. def new_doc(doctype, parent_doc=None, parentfield=None):
  278. from webnotes.model.create_new import get_new_doc
  279. return get_new_doc(doctype, parent_doc, parentfield)
  280. def new_bean(doctype):
  281. from webnotes.model.create_new import get_new_doc
  282. return bean([get_new_doc(doctype)])
  283. def doclist(lst=None):
  284. from webnotes.model.doclist import DocList
  285. return DocList(lst)
  286. def bean(doctype=None, name=None, copy=None):
  287. """return an instance of the object, wrapped as a Bean (webnotes.model.bean)"""
  288. from webnotes.model.bean import Bean
  289. if copy:
  290. return Bean(copy_doclist(copy))
  291. else:
  292. return Bean(doctype, name)
  293. def set_value(doctype, docname, fieldname, value):
  294. import webnotes.client
  295. return webnotes.client.set_value(doctype, docname, fieldname, value)
  296. def get_doclist(doctype, name=None):
  297. return bean(doctype, name).doclist
  298. def get_doctype(doctype, processed=False):
  299. import webnotes.model.doctype
  300. return webnotes.model.doctype.get(doctype, processed)
  301. def delete_doc(doctype=None, name=None, doclist = None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False):
  302. import webnotes.model.utils
  303. if not ignore_doctypes:
  304. ignore_doctypes = []
  305. if isinstance(name, list):
  306. for n in name:
  307. webnotes.model.utils.delete_doc(doctype, n, doclist, force, ignore_doctypes, for_reload, ignore_permissions)
  308. else:
  309. webnotes.model.utils.delete_doc(doctype, name, doclist, force, ignore_doctypes, for_reload, ignore_permissions)
  310. def clear_perms(doctype):
  311. conn.sql("""delete from tabDocPerm where parent=%s""", doctype)
  312. def reset_perms(doctype):
  313. clear_perms(doctype)
  314. reload_doc(conn.get_value("DocType", doctype, "module"), "DocType", doctype, force=True)
  315. def reload_doc(module, dt=None, dn=None, force=False):
  316. import webnotes.modules
  317. return webnotes.modules.reload_doc(module, dt, dn, force=force)
  318. def rename_doc(doctype, old, new, debug=0, force=False, merge=False):
  319. from webnotes.model.rename_doc import rename_doc
  320. return rename_doc(doctype, old, new, force=force, merge=merge)
  321. def insert(doclist):
  322. import webnotes.model
  323. return webnotes.model.insert(doclist)
  324. def get_module(modulename):
  325. return importlib.import_module(modulename)
  326. def scrub(txt):
  327. return txt.replace(' ','_').replace('-', '_').replace('/', '_').lower()
  328. def get_module_path(module, *joins):
  329. module = scrub(module)
  330. return get_pymodule_path(local.module_app[module] + "." + module, *joins)
  331. def get_pymodule_path(modulename, *joins):
  332. joins = [scrub(part) for part in joins]
  333. return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins)
  334. def get_module_list(app_name):
  335. return get_file_items(os.path.join(os.path.dirname(get_module(app_name).__file__), "modules.txt"))
  336. def get_all_apps(with_webnotes=False):
  337. apps = get_file_items(os.path.join(local.sites_path, "apps.txt"))
  338. if with_webnotes:
  339. apps.insert(0, 'webnotes')
  340. return apps
  341. def get_installed_apps():
  342. if flags.in_install_db:
  343. return []
  344. def load_installed_apps():
  345. return json.loads(conn.get_global("installed_apps") or "[]")
  346. return cache().get_value("installed_apps", load_installed_apps)
  347. def get_hooks(app_name=None):
  348. def load_app_hooks(app_name=None):
  349. hooks = {}
  350. for app in [app_name] if app_name else get_installed_apps():
  351. for item in get_file_items(get_pymodule_path(app, "hooks.txt")):
  352. key, value = item.split(None, 1)
  353. hooks.setdefault(key, [])
  354. hooks[key].append(value)
  355. return hooks
  356. if app_name:
  357. return _dict(load_app_hooks(app_name=None))
  358. else:
  359. return _dict(cache().get_value("app_hooks", load_app_hooks))
  360. def setup_module_map():
  361. _cache = cache()
  362. if conf.db_name:
  363. local.app_modules = _cache.get_value("app_modules")
  364. local.module_app = _cache.get_value("module_app")
  365. if not local.app_modules:
  366. local.module_app, local.app_modules = {}, {}
  367. for app in get_all_apps(True):
  368. for module in get_module_list(app):
  369. local.module_app[module] = app
  370. local.app_modules.setdefault(app, [])
  371. local.app_modules[app].append(module)
  372. if conf.db_name:
  373. _cache.set_value("app_modules", local.app_modules)
  374. _cache.set_value("module_app", local.module_app)
  375. def get_file_items(path):
  376. if os.path.exists(path):
  377. with open(path, "r") as f:
  378. content = unicode(f.read(), encoding="utf-8")
  379. return [p.strip() for p in content.splitlines() if p.strip() and not p.startswith("#")]
  380. else:
  381. return []
  382. def get_attr(method_string):
  383. modulename = '.'.join(method_string.split('.')[:-1])
  384. methodname = method_string.split('.')[-1]
  385. return getattr(get_module(modulename), methodname)
  386. def make_property_setter(args):
  387. args = _dict(args)
  388. bean([{
  389. 'doctype': "Property Setter",
  390. 'doctype_or_field': args.doctype_or_field or "DocField",
  391. 'doc_type': args.doctype,
  392. 'field_name': args.fieldname,
  393. 'property': args.property,
  394. 'value': args.value,
  395. 'property_type': args.property_type or "Data",
  396. '__islocal': 1
  397. }]).save()
  398. def get_application_home_page(user='Guest'):
  399. """get home page for user"""
  400. hpl = conn.sql("""select home_page
  401. from `tabDefault Home Page`
  402. where parent='Control Panel'
  403. and role in ('%s') order by idx asc limit 1""" % "', '".join(get_roles(user)))
  404. if hpl:
  405. return hpl[0][0]
  406. else:
  407. return conn.get_value("Control Panel", None, "home_page")
  408. def copy_doclist(in_doclist):
  409. new_doclist = []
  410. parent_doc = None
  411. for i, d in enumerate(in_doclist):
  412. is_dict = False
  413. if isinstance(d, dict):
  414. is_dict = True
  415. values = _dict(d.copy())
  416. else:
  417. values = _dict(d.fields.copy())
  418. newd = new_doc(values.doctype, parent_doc=(None if i==0 else parent_doc), parentfield=values.parentfield)
  419. newd.fields.update(values)
  420. if i==0:
  421. parent_doc = newd
  422. new_doclist.append(newd.fields if is_dict else newd)
  423. return doclist(new_doclist)
  424. def compare(val1, condition, val2):
  425. import webnotes.utils
  426. return webnotes.utils.compare(val1, condition, val2)
  427. def repsond_as_web_page(title, html):
  428. local.message_title = title
  429. local.message = "<h3>" + title + "</h3>" + html
  430. local.response['type'] = 'page'
  431. local.response['page_name'] = 'message.html'
  432. def build_match_conditions(doctype, fields=None, as_condition=True):
  433. import webnotes.widgets.reportview
  434. return webnotes.widgets.reportview.build_match_conditions(doctype, fields, as_condition)
  435. def get_list(doctype, filters=None, fields=None, docstatus=None,
  436. group_by=None, order_by=None, limit_start=0, limit_page_length=None,
  437. as_list=False, debug=False):
  438. import webnotes.widgets.reportview
  439. return webnotes.widgets.reportview.execute(doctype, filters=filters, fields=fields, docstatus=docstatus,
  440. group_by=group_by, order_by=order_by, limit_start=limit_start, limit_page_length=limit_page_length,
  441. as_list=as_list, debug=debug)
  442. jenv = None
  443. def get_jenv():
  444. global jenv
  445. if not jenv:
  446. from jinja2 import Environment, ChoiceLoader, PackageLoader
  447. from webnotes.utils import get_base_path, global_date_format
  448. from markdown2 import markdown
  449. from json import dumps
  450. # webnotes will be loaded last, so app templates will get precedence
  451. jenv = Environment(loader = ChoiceLoader([PackageLoader(app, ".") \
  452. for app in get_all_apps() + ["webnotes"]]))
  453. jenv.filters["global_date_format"] = global_date_format
  454. jenv.filters["markdown"] = markdown
  455. jenv.filters["json"] = dumps
  456. return jenv
  457. def get_template(path):
  458. return get_jenv().get_template(path)