You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11 年之前
12 年之前
11 年之前
12 年之前
12 年之前
12 年之前
12 年之前
12 年之前
12 年之前
11 年之前
12 年之前
12 年之前
11 年之前
11 年之前
12 年之前
13 年之前
11 年之前
11 年之前
11 年之前
11 年之前
11 年之前
11 年之前
11 年之前
11 年之前
11 年之前
11 年之前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  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, release_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. restrictions = local("restrictions")
  64. error_log = local("error_log")
  65. debug_log = local("debug_log")
  66. message_log = local("message_log")
  67. lang = local("lang")
  68. def init(site, sites_path=None):
  69. if getattr(local, "initialised", None):
  70. return
  71. if not sites_path:
  72. sites_path = '.'
  73. local.error_log = []
  74. local.site = site
  75. local.sites_path = sites_path
  76. local.site_path = os.path.join(sites_path, site)
  77. local.message_log = []
  78. local.debug_log = []
  79. local.response = _dict({})
  80. local.lang = "en"
  81. local.request_method = request.method if request else None
  82. local.conf = _dict(get_site_config())
  83. local.initialised = True
  84. local.flags = _dict({})
  85. local.rollback_observers = []
  86. local.module_app = None
  87. local.app_modules = None
  88. local.user = None
  89. local.restrictions = None
  90. setup_module_map()
  91. def get_site_config():
  92. site_filepath = os.path.join(local.site_path, "site_config.json")
  93. if os.path.exists(site_filepath):
  94. with open(site_filepath, 'r') as f:
  95. return json.load(f)
  96. else:
  97. return _dict()
  98. def destroy():
  99. """closes connection and releases werkzeug local"""
  100. if conn:
  101. conn.close()
  102. release_local(local)
  103. _memc = None
  104. test_objects = {}
  105. # memcache
  106. def cache():
  107. global _memc
  108. if not _memc:
  109. from webnotes.memc import MClient
  110. _memc = MClient(['localhost:11211'])
  111. return _memc
  112. class DuplicateEntryError(Exception): pass
  113. class ValidationError(Exception): pass
  114. class AuthenticationError(Exception): pass
  115. class PermissionError(Exception): pass
  116. class DataError(Exception): pass
  117. class UnknownDomainError(Exception): pass
  118. class SessionStopped(Exception): pass
  119. class MappingMismatchError(ValidationError): pass
  120. class InvalidStatusError(ValidationError): pass
  121. class DoesNotExistError(ValidationError): pass
  122. class MandatoryError(ValidationError): pass
  123. class InvalidSignatureError(ValidationError): pass
  124. class RateLimitExceededError(ValidationError): pass
  125. def get_traceback():
  126. import utils
  127. return utils.get_traceback()
  128. def errprint(msg):
  129. from utils import cstr
  130. if not request:
  131. print cstr(msg)
  132. error_log.append(cstr(msg))
  133. def log(msg):
  134. if not request:
  135. if conf.get("logging") or False:
  136. print repr(msg)
  137. from utils import cstr
  138. debug_log.append(cstr(msg))
  139. def msgprint(msg, small=0, raise_exception=0, as_table=False):
  140. def _raise_exception():
  141. if raise_exception:
  142. if flags.rollback_on_exception:
  143. conn.rollback()
  144. import inspect
  145. if inspect.isclass(raise_exception) and issubclass(raise_exception, Exception):
  146. raise raise_exception, msg
  147. else:
  148. raise ValidationError, msg
  149. if flags.mute_messages:
  150. _raise_exception()
  151. return
  152. from utils import cstr
  153. if as_table and type(msg) in (list, tuple):
  154. 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>'
  155. if flags.print_messages:
  156. print "Message: " + repr(msg)
  157. message_log.append((small and '__small:' or '')+cstr(msg or ''))
  158. _raise_exception()
  159. def throw(msg, exc=ValidationError):
  160. msgprint(msg, raise_exception=exc)
  161. def create_folder(path):
  162. if not os.path.exists(path): os.makedirs(path)
  163. def connect(site=None, db_name=None):
  164. from db import Database
  165. if site:
  166. init(site)
  167. local.conn = Database(user=db_name or local.conf.db_name)
  168. local.response = _dict()
  169. local.form_dict = _dict()
  170. local.session = _dict()
  171. set_user("Administrator")
  172. def set_user(username):
  173. import webnotes.profile
  174. local.session["user"] = username
  175. local.user = webnotes.profile.Profile(username)
  176. local.restrictions = None
  177. def get_request_header(key, default=None):
  178. return request.headers.get(key, default)
  179. logger = None
  180. whitelisted = []
  181. guest_methods = []
  182. def whitelist(allow_guest=False):
  183. """
  184. decorator for whitelisting a function
  185. Note: if the function is allowed to be accessed by a guest user,
  186. it must explicitly be marked as allow_guest=True
  187. for specific roles, set allow_roles = ['Administrator'] etc.
  188. """
  189. def innerfn(fn):
  190. global whitelisted, guest_methods
  191. whitelisted.append(fn)
  192. if allow_guest:
  193. guest_methods.append(fn)
  194. return fn
  195. return innerfn
  196. def only_for(roles):
  197. if not isinstance(roles, (tuple, list)):
  198. roles = (roles,)
  199. roles = set(roles)
  200. myroles = set(get_roles())
  201. if not roles.intersection(myroles):
  202. raise PermissionError
  203. def clear_cache(user=None, doctype=None):
  204. """clear cache"""
  205. import webnotes.sessions
  206. if doctype:
  207. import webnotes.model.doctype
  208. webnotes.model.doctype.clear_cache(doctype)
  209. reset_metadata_version()
  210. elif user:
  211. webnotes.sessions.clear_cache(user)
  212. else: # everything
  213. import translate
  214. webnotes.sessions.clear_cache()
  215. translate.clear_cache()
  216. reset_metadata_version()
  217. def get_roles(username=None):
  218. import webnotes.profile
  219. if not local.session:
  220. return ["Guest"]
  221. elif not username or username==local.session.user:
  222. return local.user.get_roles()
  223. else:
  224. return webnotes.profile.Profile(username).get_roles()
  225. def has_permission(doctype, ptype="read", refdoc=None):
  226. import webnotes.permissions
  227. return webnotes.permissions.has_permission(doctype, ptype, refdoc)
  228. def clear_perms(doctype):
  229. conn.sql("""delete from tabDocPerm where parent=%s""", doctype)
  230. def reset_perms(doctype):
  231. clear_perms(doctype)
  232. reload_doc(conn.get_value("DocType", doctype, "module"),
  233. "DocType", doctype, force=True)
  234. def generate_hash(txt=None):
  235. """Generates random hash for session id"""
  236. import hashlib, time
  237. return hashlib.sha224((txt or "") + str(time.time())).hexdigest()
  238. def reset_metadata_version():
  239. v = generate_hash()
  240. cache().set_value("metadata_version", v)
  241. return v
  242. def get_obj(dt = None, dn = None, doc=None, doclist=None, with_children = True):
  243. from webnotes.model.code import get_obj
  244. return get_obj(dt, dn, doc, doclist, with_children)
  245. def doc(doctype=None, name=None, fielddata=None):
  246. from webnotes.model.doc import Document
  247. return Document(doctype, name, fielddata)
  248. def new_doc(doctype, parent_doc=None, parentfield=None):
  249. from webnotes.model.create_new import get_new_doc
  250. return get_new_doc(doctype, parent_doc, parentfield)
  251. def new_bean(doctype):
  252. from webnotes.model.create_new import get_new_doc
  253. return bean([get_new_doc(doctype)])
  254. def doclist(lst=None):
  255. from webnotes.model.doclist import DocList
  256. return DocList(lst)
  257. def bean(doctype=None, name=None, copy=None):
  258. """return an instance of the object, wrapped as a Bean (webnotes.model.bean)"""
  259. from webnotes.model.bean import Bean
  260. if copy:
  261. return Bean(copy_doclist(copy))
  262. else:
  263. return Bean(doctype, name)
  264. def set_value(doctype, docname, fieldname, value):
  265. import webnotes.client
  266. return webnotes.client.set_value(doctype, docname, fieldname, value)
  267. def get_doclist(doctype, name=None):
  268. return bean(doctype, name).doclist
  269. def get_doctype(doctype, processed=False):
  270. import webnotes.model.doctype
  271. return webnotes.model.doctype.get(doctype, processed)
  272. def delete_doc(doctype=None, name=None, doclist = None, force=0, ignore_doctypes=None,
  273. for_reload=False, ignore_permissions=False):
  274. import webnotes.model.delete_doc
  275. if not ignore_doctypes:
  276. ignore_doctypes = []
  277. if isinstance(name, list):
  278. for n in name:
  279. webnotes.model.delete_doc.delete_doc(doctype, n, doclist, force, ignore_doctypes,
  280. for_reload, ignore_permissions)
  281. else:
  282. webnotes.model.delete_doc.delete_doc(doctype, name, doclist, force, ignore_doctypes,
  283. for_reload, ignore_permissions)
  284. def reload_doc(module, dt=None, dn=None, force=False):
  285. import webnotes.modules
  286. return webnotes.modules.reload_doc(module, dt, dn, force=force)
  287. def rename_doc(doctype, old, new, debug=0, force=False, merge=False):
  288. from webnotes.model.rename_doc import rename_doc
  289. return rename_doc(doctype, old, new, force=force, merge=merge)
  290. def insert(doclist):
  291. import webnotes.model
  292. return webnotes.model.insert(doclist)
  293. def get_module(modulename):
  294. return importlib.import_module(modulename)
  295. def scrub(txt):
  296. return txt.replace(' ','_').replace('-', '_').replace('/', '_').lower()
  297. def get_module_path(module, *joins):
  298. module = scrub(module)
  299. return get_pymodule_path(local.module_app[module] + "." + module, *joins)
  300. def get_pymodule_path(modulename, *joins):
  301. joins = [scrub(part) for part in joins]
  302. return os.path.join(os.path.dirname(get_module(scrub(modulename)).__file__), *joins)
  303. def get_module_list(app_name):
  304. return get_file_items(os.path.join(os.path.dirname(get_module(app_name).__file__), "modules.txt"))
  305. def get_all_apps(with_webnotes=False):
  306. apps = get_file_items(os.path.join(local.sites_path, "apps.txt")) \
  307. + get_file_items(os.path.join(local.site_path, "apps.txt"))
  308. if with_webnotes:
  309. apps.insert(0, 'webnotes')
  310. return apps
  311. def get_installed_apps():
  312. if flags.in_install_db:
  313. return []
  314. return json.loads(conn.get_global("installed_apps") or "[]")
  315. def get_hooks(app_name=None):
  316. def load_app_hooks(app_name=None):
  317. hooks = {}
  318. for app in [app_name] if app_name else get_installed_apps():
  319. for item in get_file_items(get_pymodule_path(app, "hooks.txt")):
  320. key, value = item.split("=", 1)
  321. key, value = key.strip(), value.strip()
  322. hooks.setdefault(key, [])
  323. hooks[key].append(value)
  324. return hooks
  325. if app_name:
  326. return _dict(load_app_hooks(app_name))
  327. else:
  328. return _dict(cache().get_value("app_hooks", load_app_hooks))
  329. def setup_module_map():
  330. _cache = cache()
  331. if conf.db_name:
  332. local.app_modules = _cache.get_value("app_modules")
  333. local.module_app = _cache.get_value("module_app")
  334. if not local.app_modules:
  335. local.module_app, local.app_modules = {}, {}
  336. for app in get_all_apps(True):
  337. local.app_modules.setdefault(app, [])
  338. for module in get_module_list(app):
  339. local.module_app[module] = app
  340. local.app_modules[app].append(module)
  341. if conf.db_name:
  342. _cache.set_value("app_modules", local.app_modules)
  343. _cache.set_value("module_app", local.module_app)
  344. def get_file_items(path):
  345. content = read_file(path)
  346. if content:
  347. return [p.strip() for p in content.splitlines() if p.strip() and not p.startswith("#")]
  348. else:
  349. return []
  350. def read_file(path):
  351. if os.path.exists(path):
  352. with open(path, "r") as f:
  353. return unicode(f.read(), encoding="utf-8")
  354. else:
  355. return None
  356. def get_attr(method_string):
  357. modulename = '.'.join(method_string.split('.')[:-1])
  358. methodname = method_string.split('.')[-1]
  359. return getattr(get_module(modulename), methodname)
  360. def make_property_setter(args):
  361. args = _dict(args)
  362. bean([{
  363. 'doctype': "Property Setter",
  364. 'doctype_or_field': args.doctype_or_field or "DocField",
  365. 'doc_type': args.doctype,
  366. 'field_name': args.fieldname,
  367. 'property': args.property,
  368. 'value': args.value,
  369. 'property_type': args.property_type or "Data",
  370. '__islocal': 1
  371. }]).save()
  372. def get_application_home_page(user='Guest'):
  373. """get home page for user"""
  374. hpl = conn.sql("""select home_page
  375. from `tabDefault Home Page`
  376. where parent='Control Panel'
  377. and role in ('%s') order by idx asc limit 1""" % "', '".join(get_roles(user)))
  378. if hpl:
  379. return hpl[0][0]
  380. else:
  381. return conn.get_value("Control Panel", None, "home_page")
  382. def copy_doclist(in_doclist):
  383. new_doclist = []
  384. parent_doc = None
  385. for i, d in enumerate(in_doclist):
  386. is_dict = False
  387. if isinstance(d, dict):
  388. is_dict = True
  389. values = _dict(d.copy())
  390. else:
  391. values = _dict(d.fields.copy())
  392. newd = new_doc(values.doctype, parent_doc=(None if i==0 else parent_doc), parentfield=values.parentfield)
  393. newd.fields.update(values)
  394. if i==0:
  395. parent_doc = newd
  396. new_doclist.append(newd.fields if is_dict else newd)
  397. return doclist(new_doclist)
  398. def compare(val1, condition, val2):
  399. import webnotes.utils
  400. return webnotes.utils.compare(val1, condition, val2)
  401. def repsond_as_web_page(title, html):
  402. local.message_title = title
  403. local.message = "<h3>" + title + "</h3>" + html
  404. local.response['type'] = 'page'
  405. local.response['page_name'] = 'message.html'
  406. return obj
  407. def build_match_conditions(doctype, fields=None, as_condition=True):
  408. import webnotes.widgets.reportview
  409. return webnotes.widgets.reportview.build_match_conditions(doctype, fields, as_condition)
  410. def get_list(doctype, filters=None, fields=None, docstatus=None,
  411. group_by=None, order_by=None, limit_start=0, limit_page_length=None,
  412. as_list=False, debug=False):
  413. import webnotes.widgets.reportview
  414. return webnotes.widgets.reportview.execute(doctype, filters=filters, fields=fields, docstatus=docstatus,
  415. group_by=group_by, order_by=order_by, limit_start=limit_start, limit_page_length=limit_page_length,
  416. as_list=as_list, debug=debug)
  417. jenv = None
  418. def get_jenv():
  419. global jenv
  420. if not jenv:
  421. from jinja2 import Environment, ChoiceLoader, PackageLoader
  422. from webnotes.utils import global_date_format
  423. from markdown2 import markdown
  424. from json import dumps
  425. # webnotes will be loaded last, so app templates will get precedence
  426. jenv = Environment(loader = ChoiceLoader([PackageLoader(app, ".") \
  427. for app in get_all_apps() + ["webnotes"]]))
  428. jenv.filters["global_date_format"] = global_date_format
  429. jenv.filters["markdown"] = markdown
  430. jenv.filters["json"] = dumps
  431. return jenv
  432. def get_template(path):
  433. return get_jenv().get_template(path)