No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

__init__.py 16 KiB

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