diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000..62463aa35a --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,130 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/WNFramework.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WNFramework.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/WNFramework" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/WNFramework" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/README b/docs/README new file mode 100644 index 0000000000..19efc7eaf8 --- /dev/null +++ b/docs/README @@ -0,0 +1,34 @@ +Documentation Help: +=================== + +1. To rebuild documentation +--------------------------- + +(set webnotes path in conf.py in this folder) +make html + +2. Install +----------- + +easy_install sphinx + +3. Build modules again (if you have added new modules) +---------------------- + +python generate_modules.py ../cgi-bin -d . -f + +help: + +NOTE: if you do this, all existing changes to the source files will be lost +python generate_modules.py [source] -d [destination] [-f to rebuild] + +4. General Sphinx Help +---------------------- + +1. install sphinx +2. create a docs folder +3. in the docs folder, do sphinx-quickstart (say yes to autodocs and viewcode) +4. generate module .txt files using generate_modules.py script by Thomas Waldmann +5. add cool css and icons in _static folder +6. update conf.py and add sys.path.append - change .rst to .txt +7. run "make html" diff --git a/docs/_build/doctrees/backupall.doctree b/docs/_build/doctrees/backupall.doctree new file mode 100644 index 0000000000..b2715fa801 Binary files /dev/null and b/docs/_build/doctrees/backupall.doctree differ diff --git a/docs/_build/doctrees/core.doctree b/docs/_build/doctrees/core.doctree new file mode 100644 index 0000000000..dc6d0ebca2 Binary files /dev/null and b/docs/_build/doctrees/core.doctree differ diff --git a/docs/_build/doctrees/core.doctype.control_panel.doctree b/docs/_build/doctrees/core.doctype.control_panel.doctree new file mode 100644 index 0000000000..200ba0a841 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.control_panel.doctree differ diff --git a/docs/_build/doctrees/core.doctype.custom_field.doctree b/docs/_build/doctrees/core.doctype.custom_field.doctree new file mode 100644 index 0000000000..bdacb728f7 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.custom_field.doctree differ diff --git a/docs/_build/doctrees/core.doctype.doctree b/docs/_build/doctrees/core.doctype.doctree new file mode 100644 index 0000000000..f135df0227 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.doctree differ diff --git a/docs/_build/doctrees/core.doctype.doctype.doctree b/docs/_build/doctrees/core.doctype.doctype.doctree new file mode 100644 index 0000000000..4d7c9d5645 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.doctype.doctree differ diff --git a/docs/_build/doctrees/core.doctype.doctype_mapper.doctree b/docs/_build/doctrees/core.doctype.doctype_mapper.doctree new file mode 100644 index 0000000000..fdea08687f Binary files /dev/null and b/docs/_build/doctrees/core.doctype.doctype_mapper.doctree differ diff --git a/docs/_build/doctrees/core.doctype.letter_head.doctree b/docs/_build/doctrees/core.doctype.letter_head.doctree new file mode 100644 index 0000000000..efb6e1ea77 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.letter_head.doctree differ diff --git a/docs/_build/doctrees/core.doctype.module_def.doctree b/docs/_build/doctrees/core.doctype.module_def.doctree new file mode 100644 index 0000000000..dd47cbce27 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.module_def.doctree differ diff --git a/docs/_build/doctrees/core.doctype.page.doctree b/docs/_build/doctrees/core.doctype.page.doctree new file mode 100644 index 0000000000..a00a088773 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.page.doctree differ diff --git a/docs/_build/doctrees/core.doctype.page_template.doctree b/docs/_build/doctrees/core.doctype.page_template.doctree new file mode 100644 index 0000000000..15f2560308 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.page_template.doctree differ diff --git a/docs/_build/doctrees/core.doctype.profile.doctree b/docs/_build/doctrees/core.doctype.profile.doctree new file mode 100644 index 0000000000..1c5f0b0e99 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.profile.doctree differ diff --git a/docs/_build/doctrees/core.doctype.property_setter.doctree b/docs/_build/doctrees/core.doctype.property_setter.doctree new file mode 100644 index 0000000000..e75fc2ada2 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.property_setter.doctree differ diff --git a/docs/_build/doctrees/core.doctype.search_criteria.doctree b/docs/_build/doctrees/core.doctype.search_criteria.doctree new file mode 100644 index 0000000000..d86aa0cb50 Binary files /dev/null and b/docs/_build/doctrees/core.doctype.search_criteria.doctree differ diff --git a/docs/_build/doctrees/core.doctype.stylesheet.doctree b/docs/_build/doctrees/core.doctype.stylesheet.doctree new file mode 100644 index 0000000000..5aea29b77c Binary files /dev/null and b/docs/_build/doctrees/core.doctype.stylesheet.doctree differ diff --git a/docs/_build/doctrees/core.doctype.system_console.doctree b/docs/_build/doctrees/core.doctype.system_console.doctree new file mode 100644 index 0000000000..665ee83faa Binary files /dev/null and b/docs/_build/doctrees/core.doctype.system_console.doctree differ diff --git a/docs/_build/doctrees/core.page.doctree b/docs/_build/doctrees/core.page.doctree new file mode 100644 index 0000000000..6a8051af36 Binary files /dev/null and b/docs/_build/doctrees/core.page.doctree differ diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle new file mode 100644 index 0000000000..7acff5f24f Binary files /dev/null and b/docs/_build/doctrees/environment.pickle differ diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree new file mode 100644 index 0000000000..92858ce913 Binary files /dev/null and b/docs/_build/doctrees/index.doctree differ diff --git a/docs/_build/doctrees/modules.doctree b/docs/_build/doctrees/modules.doctree new file mode 100644 index 0000000000..633c58eeb1 Binary files /dev/null and b/docs/_build/doctrees/modules.doctree differ diff --git a/docs/_build/doctrees/pypi-setup.doctree b/docs/_build/doctrees/pypi-setup.doctree new file mode 100644 index 0000000000..9b26f6cc54 Binary files /dev/null and b/docs/_build/doctrees/pypi-setup.doctree differ diff --git a/docs/_build/doctrees/webnotes.doctree b/docs/_build/doctrees/webnotes.doctree new file mode 100644 index 0000000000..916ce8cc6b Binary files /dev/null and b/docs/_build/doctrees/webnotes.doctree differ diff --git a/docs/_build/doctrees/webnotes.install_lib.doctree b/docs/_build/doctrees/webnotes.install_lib.doctree new file mode 100644 index 0000000000..ff83d7d8b5 Binary files /dev/null and b/docs/_build/doctrees/webnotes.install_lib.doctree differ diff --git a/docs/_build/doctrees/webnotes.model.doctree b/docs/_build/doctrees/webnotes.model.doctree new file mode 100644 index 0000000000..b74db3bd24 Binary files /dev/null and b/docs/_build/doctrees/webnotes.model.doctree differ diff --git a/docs/_build/doctrees/webnotes.modules.doctree b/docs/_build/doctrees/webnotes.modules.doctree new file mode 100644 index 0000000000..68c9d425c2 Binary files /dev/null and b/docs/_build/doctrees/webnotes.modules.doctree differ diff --git a/docs/_build/doctrees/webnotes.multi_tenant.doctree b/docs/_build/doctrees/webnotes.multi_tenant.doctree new file mode 100644 index 0000000000..3a774037c6 Binary files /dev/null and b/docs/_build/doctrees/webnotes.multi_tenant.doctree differ diff --git a/docs/_build/doctrees/webnotes.utils.doctree b/docs/_build/doctrees/webnotes.utils.doctree new file mode 100644 index 0000000000..650260de95 Binary files /dev/null and b/docs/_build/doctrees/webnotes.utils.doctree differ diff --git a/docs/_build/doctrees/webnotes.utils.email_lib.doctree b/docs/_build/doctrees/webnotes.utils.email_lib.doctree new file mode 100644 index 0000000000..1138683b9f Binary files /dev/null and b/docs/_build/doctrees/webnotes.utils.email_lib.doctree differ diff --git a/docs/_build/doctrees/webnotes.widgets.doctree b/docs/_build/doctrees/webnotes.widgets.doctree new file mode 100644 index 0000000000..41c52c7806 Binary files /dev/null and b/docs/_build/doctrees/webnotes.widgets.doctree differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo new file mode 100644 index 0000000000..d045baa95a --- /dev/null +++ b/docs/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 544565fc4fe326492516ee681f9cf316 +tags: fbb0d17656682115ca4d033fb2f83ba1 diff --git a/docs/_build/html/_modules/core/doctype/page/page.html b/docs/_build/html/_modules/core/doctype/page/page.html new file mode 100644 index 0000000000..3f6f8a6da0 --- /dev/null +++ b/docs/_build/html/_modules/core/doctype/page/page.html @@ -0,0 +1,143 @@ + + + + + + + + + core.doctype.page.page — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for core.doctype.page.page

+
[docs]class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d,dl + +
[docs] def autoname(self): + if (self.doc.name and self.doc.name.startswith('New Page')) or not self.doc.name: + self.doc.name = self.doc.page_name.lower().replace(' ', '-') +
+
[docs] def onload(self): + import os + from webnotes.modules import get_module_path, scrub + + # load content + try: + file = open(os.path.join(get_module_path(self.doc.module), 'page', scrub(self.doc.name) + '.html'), 'r') + self.doc.content = file.read() or '' + file.close() + except IOError, e: # no file / permission + if e.args[0]!=2: + raise e + + # replace $image + # ------------------
+
[docs] def validate(self): + import re + p = re.compile('\$image\( (?P<name> [^)]*) \)', re.VERBOSE) + if self.doc.content: + self.doc.content = p.sub(self.replace_by_img, self.doc.content) +
+
[docs] def replace_by_img(self, match): + import webnotes + name = match.group('name') + return '<img src="cgi-bin/getfile.cgi?ac=%s&name=%s">' % (webnotes.conn.get('Control Panel', None, 'account_id'), name) + + # export
+
[docs] def on_update(self): + from webnotes.modules.export_module import export_to_files + from webnotes.modules import get_module_path, scrub + import os + from webnotes import defs + + if getattr(defs,'developer_mode', 0): + export_to_files(record_list=[['Page', self.doc.name]]) + + if self.doc.write_content and self.doc.content: + file = open(os.path.join(get_module_path(self.doc.module), 'page', scrub(self.doc.name), scrub(self.doc.name) + '.html'), 'w') + file.write(self.doc.content) + file.close() +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/core/doctype/page_template/page_template.html b/docs/_build/html/_modules/core/doctype/page_template/page_template.html new file mode 100644 index 0000000000..016ccee35f --- /dev/null +++ b/docs/_build/html/_modules/core/doctype/page_template/page_template.html @@ -0,0 +1,114 @@ + + + + + + + + + core.doctype.page_template.page_template — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for core.doctype.page_template.page_template

+import webnotes
+
+
[docs]class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d,dl + + # export +
[docs] def on_update(self): + import webnotes.defs + from webnotes.modules.export_module import export_to_files + from webnotes.modules import get_module_path, scrub + import os + + if hasattr(webnotes.defs, 'developer_mode') and webnotes.defs.developer_mode: + + export_to_files(record_list=[['Page Template', self.doc.name]]) + + file = open(os.path.join(get_module_path(self.doc.module), 'Page Template', self.doc.name, self.doc.name + '.html'), 'w') + file.write(self.doc.content) + file.close()
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/core/doctype/property_setter/property_setter.html b/docs/_build/html/_modules/core/doctype/property_setter/property_setter.html new file mode 100644 index 0000000000..289b015ef5 --- /dev/null +++ b/docs/_build/html/_modules/core/doctype/property_setter/property_setter.html @@ -0,0 +1,123 @@ + + + + + + + + + core.doctype.property_setter.property_setter — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for core.doctype.property_setter.property_setter

+import webnotes
+
+
[docs]class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d, dl + +
[docs] def get_property_list(self, dt): + return webnotes.conn.sql("""select fieldname, label, fieldtype + from tabDocField + where parent=%s + and fieldtype not in ('Section Break', 'Column Break', 'HTML', 'Read Only', 'Table') + and ifnull(fieldname, '') != '' + order by label asc""", dt, as_dict=1) +
+
[docs] def get_setup_data(self): + return { + 'doctypes': [d[0] for d in webnotes.conn.sql("select name from tabDocType")], + 'dt_properties': self.get_property_list('DocType'), + 'df_properties': self.get_property_list('DocField') + } +
+
[docs] def get_field_ids(self): + return webnotes.conn.sql("select name, fieldtype, label, fieldname from tabDocField where parent=%s", self.doc.doc_type, as_dict = 1) +
+
[docs] def get_defaults(self): + if self.doc.doc_type == self.doc.doc_name: + return webnotes.conn.sql("select * from `tabDocType` where name=%s", self.doc.doc_name, as_dict = 1)[0] + else: + return webnotes.conn.sql("select * from `tabDocField` where name=%s", self.doc.doc_name, as_dict = 1)[0]
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/core/doctype/stylesheet/stylesheet.html b/docs/_build/html/_modules/core/doctype/stylesheet/stylesheet.html new file mode 100644 index 0000000000..634a0e863d --- /dev/null +++ b/docs/_build/html/_modules/core/doctype/stylesheet/stylesheet.html @@ -0,0 +1,112 @@ + + + + + + + + + core.doctype.stylesheet.stylesheet — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for core.doctype.stylesheet.stylesheet

+
[docs]class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d,dl + + # export +
[docs] def on_update(self): + import webnotes.defs + + if hasattr(webnotes.defs, 'developer_mode') and webnotes.defs.developer_mode: + from webnotes.modules.export_module import export_to_files + from webnotes.modules import get_module_path, scurb + import os + + export_to_files(record_list=[['Stylesheet', self.doc.name]]) + + file = open(os.path.join(get_module_path(self.doc.module), 'Stylesheet', scrub(self.doc.name), scrub(self.doc.name) + '.html'), 'w') + file.write(self.doc.content) + file.close()
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/index.html b/docs/_build/html/_modules/index.html new file mode 100644 index 0000000000..fc1469a30f --- /dev/null +++ b/docs/_build/html/_modules/index.html @@ -0,0 +1,148 @@ + + + + + + + + + Overview: module code — WNFramework v1.8 documentation + + + + + + + + + + + +
+
+
+
+ +

All modules for which code is available

+ + +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes.html b/docs/_build/html/_modules/webnotes.html new file mode 100644 index 0000000000..bf4c3f4ad6 --- /dev/null +++ b/docs/_build/html/_modules/webnotes.html @@ -0,0 +1,325 @@ + + + + + + + + + webnotes — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes

+#
+# import modules path
+# 
+import os, sys
+
+try:
+	import webnotes.defs
+	m = getattr(webnotes.defs,'modules_path',None)
+	m and sys.path.append(m)
+except Exception,e:
+	raise e
+
+#
+# map for identifying which field values come from files
+#
+code_fields_dict = {
+	'Page':[('script', 'js'), ('content', 'html'), ('style', 'css'), ('static_content', 'html'), ('server_code', 'py')],
+	'DocType':[('server_code_core', 'py'), ('client_script_core', 'js')],
+	'Search Criteria':[('report_script', 'js'), ('server_script', 'py'), ('custom_query', 'sql')],
+	'Patch':[('patch_code', 'py')],
+	'Stylesheet':['stylesheet', 'css'],
+	'Page Template':['template', 'html'],
+	'Control Panel':[('startup_code', 'js'), ('startup_css', 'css')]
+}
+
+#
+# globals
+#
+#: "v170" 
+version = 'v170'
+form_dict = {}
+auth_obj = None
+
+#: The database connection :class:`webnotes.db.Database` setup by :mod:`auth`
+conn = None
+
+#: The cgi.FieldStorage() object (Dictionary representing the formdata from the URL)
+form = None
+
+session = None
+"""
+   Global session dictionary.
+
+   * session['user'] - Current user   
+   * session['data'] - Returns a dictionary of the session cache
+"""
+
+user = None
+is_testing = None
+"""    Flag to identify if system is in :term:`Testing Mode` """
+
+incoming_cookies = {}
+add_cookies = {}
+"""    Dictionary of additional cookies appended by custom code """
+
+cookies = {}
+auto_masters = {}
+tenant_id = None
+
+#
+# Custom Class (no traceback)
+#
+
[docs]class ValidationError(Exception): + pass + +# +# HTTP standard response +#
+response = {'message':'', 'exc':''} +""" + The JSON response object. Default is:: + + {'message':'', 'exc':''} +""" + +# +# the logs +# +debug_log = [] +""" List of exceptions to be shown in the :term:`Error Console` """ + +message_log = [] +""" List of messages to be shown to the user in a popup box at the end of the request """ + +
[docs]def getTraceback(): + import webnotes.utils + return webnotes.utils.getTraceback() +
+
[docs]def errprint(msg): + """ + Append to the :data:`debug log` + """ + debug_log.append(str(msg or '')) +
+
[docs]def msgprint(msg, small=0, raise_exception=0): + """ + Append to the :data:`message_log` + """ + message_log.append((small and '__small:' or '')+str(msg or '')) + if raise_exception: + raise ValidationError +
+
[docs]def is_apache_user(): + import os + if os.environ.get('USER') == 'apache': + return True + else: + return (not os.environ.get('USER')) + # os.environ does not have user, so allows a security vulnerability,fixed now. +
+
[docs]def get_index_path(): + import os + return os.sep.join(os.path.dirname(os.path.abspath(__file__)).split(os.sep)[:-2]) +
+
[docs]def get_files_path(): + global conn + import defs, os + + if not conn: + raise Exception, 'You must login first' + + if defs.files_path: + return os.path.join(defs.files_path, conn.cur_db_name) + else: + return os.path.join(get_index_path(), 'user_files', conn.cur_db_name) +
+
[docs]def create_folder(path): + """ + Wrapper function for os.makedirs (does not throw exception if directory exists) + """ + import os + + try: + os.makedirs(path) + except Exception, e: + if e.args[0]==17: + pass + else: + raise e + + +############################################################################### +# BEGIN: TENTATIVE CODE FEELS LIKE A CLASS/TEMPLATE IS A BETTER IDEA FOR THESE VARIABLES. +# Bad idea combining/using one function to set conn,user,session variables. +# Need to split up. +############################################################################### +
+
[docs]def set_as_account_master(): + import webnotes.db + global conn + conn = webnotes.db.Database(use_default = 1) +
+
[docs]def set_as_administrator(): + + global user + + if is_apache_user(): + raise Exception, 'Not for web users!' + + import webnotes.profile + user = webnotes.profile.Profile('Administrator') +
+
[docs]def set_as_admin_session(): + global session + session = {'user':'Administrator'} + +############################################################################### +#END +############################################################################### + +
+
[docs]def set_as_admin(db_name=None, ac_name=None): + + import os + if is_apache_user(): + raise Exception, 'Not for web users!' + + global conn + global session + global user + + import webnotes.db + if ac_name: + conn = webnotes.db.Database(ac_name = ac_name) + else: + set_as_account_master() + if db_name: + conn.use(db_name) + + session = {'user':'Administrator'} + import webnotes.profile + user = webnotes.profile.Profile('Administrator') + + +# Environment Variables +#-----------------------------------------------------------
+
[docs]def get_env_vars(env_var): + return os.environ.get(env_var,'None') +
+remote_ip = get_env_vars('REMOTE_ADDR') #Required for login from python shell + +# Logging +# ----------------------------------------------------------- + +logger = None + + +
[docs]def setup_logging(): + import logging + import logging.handlers + # Also please set umask for apache to 002. + global logger + + try: + logger = logging.getLogger('WNLogger') + logger.setLevel(eval(defs.log_level)) + + log_handler = logging.handlers.RotatingFileHandler(defs.log_file_name, maxBytes = defs.log_file_size, backupCount = defs.log_file_backup_count) + formatter = logging.Formatter('%(name)s - %(asctime)s - %(levelname)s\n%(message)s\n-------------------') + + log_handler.setFormatter(formatter) + logger.addHandler(log_handler) + + except IOError,e: + if e.args == 13: + open(defs.log_file_name).close() + +
+if getattr(defs, 'log_file_name', None): + setup_logging() + +
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/auth.html b/docs/_build/html/_modules/webnotes/auth.html new file mode 100644 index 0000000000..d89048cf5b --- /dev/null +++ b/docs/_build/html/_modules/webnotes/auth.html @@ -0,0 +1,520 @@ + + + + + + + + + webnotes.auth — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.auth

+import webnotes
+import webnotes.db
+import webnotes.utils
+import webnotes.profile
+import webnotes.defs
+
+# =================================================================================
+# HTTPRequest
+# =================================================================================
+
+
[docs]class HTTPRequest: + def __init__(self): + + # Get Environment variables + self.domain = webnotes.get_env_vars('HTTP_HOST') + if self.domain and self.domain.startswith('www.'): + self.domain = self.domain[4:] + + webnotes.remote_ip = webnotes.get_env_vars('REMOTE_ADDR') + + # load cookies + webnotes.cookie_manager = CookieManager() + + # set db + self.set_db() + + # check status + if webnotes.conn.get_global("__session_status")=='stop': + webnotes.msgprint(webnotes.conn.get_global("__session_status_message")) + raise Exception + + # ----------------------------- + # start transaction + webnotes.conn.begin() + + # login + webnotes.login_manager = LoginManager() + + # start session + webnotes.session_obj = Session() + webnotes.session = webnotes.session_obj.data + webnotes.tenant_id = webnotes.session.get('tenant_id', 0) + + # write out cookies if sid is supplied (this is a pre-logged in redirect) + if webnotes.form_dict.get('sid'): + webnotes.cookie_manager.set_cookies() + + # run login triggers + if webnotes.form_dict.get('cmd')=='login': + webnotes.login_manager.run_trigger('on_login_post_session') + + # load profile + self.setup_profile() + + webnotes.conn.commit() + # end transaction + # ----------------------------- + + # setup profile + # ------------- + +
[docs] def setup_profile(self): + webnotes.user = webnotes.profile.Profile() + # load the profile data + if webnotes.session['data'].get('profile'): + webnotes.user.load_from_session(webnotes.session['data']['profile']) + else: + webnotes.user.load_profile() + + + # get account name + # ------------------ +
+
[docs] def get_ac_name(self): + # login + if webnotes.form_dict.get('acx'): + return webnotes.form_dict.get('acx') + + # in form + elif webnotes.form_dict.get('ac_name'): + return webnotes.form_dict.get('ac_name') + + # in cookie + elif webnotes.incoming_cookies.get('ac_name'): + return webnotes.incoming_cookies.get('ac_name') + + + # set database login + # ------------------ +
+
[docs] def set_db(self, ac_name = None): + + + # select based on subdomain + if getattr(webnotes.defs,'domain_name_map', {}).get(self.domain): + db_name = webnotes.defs.domain_name_map[self.domain] + + # select based on ac_name + else: + ac_name = self.get_ac_name() + if ac_name: + db_name = getattr(webnotes.defs,'db_name_map',{}).\ + get(ac_name, ac_name) + else: + db_name = getattr(webnotes.defs,'default_db_name','') + + webnotes.conn = webnotes.db.Database(user = db_name,password = getattr(webnotes.defs,'db_password','')) + webnotes.ac_name = ac_name + +# ================================================================================= +# Login Manager +# ================================================================================= +
+
[docs]class LoginManager: + def __init__(self): + self.cp = None + if webnotes.form_dict.get('cmd')=='login': + # clear cache + from webnotes.session_cache import clear_cache + clear_cache(webnotes.form_dict.get('usr')) + + self.authenticate() + self.post_login() + webnotes.response['message'] = 'Logged In' + + # run triggers, write cookies + # --------------------------- + +
[docs] def post_login(self): + self.validate_ip_address() + self.run_trigger() + + # check password + # -------------- +
+
[docs] def authenticate(self, user=None, pwd=None): + if not (user and pwd): + user, pwd = webnotes.form_dict.get('usr'), webnotes.form_dict.get('pwd') + + if not (user and pwd): + webnotes.msgprint('Incomplete Login Details', raise_exception=1) + + # custom authentication (for single-sign on) + self.load_control_panel() + if hasattr(self.cp, 'authenticate'): + self.user = self.cp.authenticate() + + # check the password + if user=='Administrator': + p = webnotes.conn.sql("select name from tabProfile where name=%s and (`password`=%s OR `password`=PASSWORD(%s))", (user, pwd, pwd)) + else: + p = webnotes.conn.sql("select name from tabProfile where name=%s and (`password`=%s OR `password`=PASSWORD(%s)) and IFNULL(enabled,0)=1", (user, pwd, pwd)) + + if not p: + webnotes.msgprint('Authentication Failed', raise_exception=1) + + self.user = p[0][0] + + # triggers + # -------- +
+
[docs] def load_control_panel(self): + import webnotes.model.code + try: + if not self.cp: + self.cp = webnotes.model.code.get_obj('Control Panel') + except Exception, e: + webnotes.response['Control Panel Exception'] = webnotes.utils.getTraceback() + + # --------
+
[docs] def run_trigger(self, method='on_login'): + try: + import event_handlers + if hasattr(event_handlers, method): + getattr(event_handlers, method)(self) + return + except ImportError, e: + pass + + # deprecated + self.load_control_panel() + if self.cp and hasattr(self.cp, method): + getattr(self.cp, method)(self) + + # ip validation + # ------------- +
+
[docs] def validate_ip_address(self): + try: + ip = webnotes.conn.sql("select ip_address from tabProfile where name = '%s'" % self.user)[0][0] or '' + except: return + + ip = ip.replace(",", "\n").split('\n') + ip = [i.strip() for i in ip] + + if ret and ip: + if not (webnotes.remote_ip.startswith(ip[0]) or (webnotes.remote_ip in ip)): + raise Exception, 'Not allowed from this IP Address' + + # login as guest + # -------------- +
+
[docs] def login_as_guest(self): + res = webnotes.conn.sql("select name from tabProfile where name='Guest' and ifnull(enabled,0)=1") + if not res: + raise Exception, "No Guest Access" + self.user = 'Guest' + self.post_login() + + # Logout + # ------ +
+
[docs] def call_on_logout_event(self): + import webnotes.model.code + cp = webnotes.model.code.get_obj('Control Panel', 'Control Panel') + if hasattr(cp, 'on_logout'): + cp.on_logout(self) +
+
[docs] def logout(self, arg=''): + self.run_trigger('on_logout') + webnotes.conn.sql('update tabSessions set status="Logged Out" where sid="%s"' % webnotes.session['sid']) + +# ================================================================================= +# Cookie Manager +# ================================================================================= +
+
[docs]class CookieManager: + def __init__(self): + import Cookie + webnotes.cookies = Cookie.SimpleCookie() + self.get_incoming_cookies() + + # get incoming cookies + # -------------------- +
[docs] def get_incoming_cookies(self): + import os + cookies = {} + if 'HTTP_COOKIE' in os.environ: + c = os.environ['HTTP_COOKIE'] + webnotes.cookies.load(c) + for c in webnotes.cookies.values(): + cookies[c.key] = c.value + + webnotes.incoming_cookies = cookies + + # Set cookies + # ----------- +
+
[docs] def set_cookies(self): + if webnotes.conn.cur_db_name: + webnotes.cookies['account_id'] = webnotes.conn.cur_db_name + + # ac_name + webnotes.cookies['ac_name'] = webnotes.ac_name or '' + + if webnotes.session.get('sid'): + webnotes.cookies['sid'] = webnotes.session['sid'] + + # sid expires in 3 days + import datetime + expires = datetime.datetime.now() + datetime.timedelta(days=3) + + webnotes.cookies['sid']['expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S') + + # Set Remember Me + # --------------- +
+
[docs] def set_remember_me(self): + if webnotes.utils.cint(webnotes.form_dict.get('remember_me')): + remember_days = webnotes.conn.get_value('Control Panel',None,'remember_for_days') or 7 + webnotes.cookies['remember_me'] = 1 + + import datetime + expires = datetime.datetime.now() + datetime.timedelta(days=remember_days) + + for k in webnotes.cookies.keys(): + webnotes.cookies[k]['expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S') + +# ================================================================================= +# Session +# ================================================================================= +
+
[docs]class Session: + def __init__(self, user=None): + self.user = user + self.sid = webnotes.form_dict.get('sid') or webnotes.incoming_cookies.get('sid') + self.data = {'user':user,'data':{}} + + if webnotes.form_dict.get('cmd')=='login': + self.start() + return + + self.load() + + # start a session + # --------------- +
[docs] def load(self): + import webnotes + + r=None + try: + r = webnotes.conn.sql("select user, sessiondata, status from tabSessions where sid='%s'" % self.sid) + except Exception, e: + if e.args[0]==1054: + self.add_status_column() + else: + raise e + + if r: + r=r[0] + + # ExipredSession + if r[2]=='Expired' and (webnotes.form_dict.get('cmd')!='resume_session'): + if r[0]=='Guest' or (not webnotes.form_dict.get('cmd')) or webnotes.form_dict.get('cmd')=='logout': + webnotes.login_manager.login_as_guest() + self.start() + else: + webnotes.response['session_status'] = 'Session Expired' + raise Exception, 'Session Expired' + elif r[2]=='Logged Out': + webnotes.login_manager.login_as_guest() + self.start() + # allow refresh or logout + if webnotes.form_dict.get('cmd') and webnotes.form_dict.get('cmd')!='logout': + webnotes.response['session_status'] = 'Logged Out' + raise Exception, 'Logged Out' + else: + self.data = {'data':eval(r[1]), 'user':r[0], 'sid': self.sid} + else: + webnotes.login_manager.login_as_guest() + self.start() + + + # start a session + # ---------------
+
[docs] def start(self): + import os + import webnotes + import webnotes.utils + + # generate sid + self.data['user'] = webnotes.login_manager.user + self.data['sid'] = webnotes.utils.generate_hash() + self.data['data']['session_ip'] = os.environ.get('REMOTE_ADDR'); + self.data['data']['tenant_id'] = webnotes.form_dict.get('tenant_id', 0) + + # get ipinfo + if webnotes.conn.get_global('get_ip_info'): + self.get_ipinfo() + + # insert session + try: + self.insert_session_record() + except Exception, e: + if e.args[0]==1054: + self.add_status_column() + self.insert_session_record() + else: + raise e + + # update profile + webnotes.conn.sql("UPDATE tabProfile SET last_login = '%s', last_ip = '%s' where name='%s'" % (webnotes.utils.now(), webnotes.remote_ip, self.data['user'])) + + # set cookies to write + webnotes.session = self.data + webnotes.cookie_manager.set_cookies() + + + # resume session + # --------------
+
[docs] def resume(self): + pwd = webnotes.form_dict.get('pwd') + webnotes.login_manager.authenticate(self.data['user'], pwd) + webnotes.conn.sql("update tabSessions set status='Active' where sid=%s", self.data['sid']) + return 'Logged In' + + # update session + # --------------
+
[docs] def update(self): + # update session + webnotes.conn.sql("update tabSessions set sessiondata=%s, user=%s, lastupdate=NOW() where sid=%s" , (str(self.data['data']), self.data['user'], self.data['sid'])) + + self.check_expired() + + # check expired + # -------------
+
[docs] def check_expired(self): + # in control panel? + exp_sec = webnotes.conn.get_value('Control Panel', None, 'session_expiry') or '6:00:00' + + # set sessions as expired + try: + webnotes.conn.sql("update from tabSessions where TIMEDIFF(NOW(), lastupdate) > %s SET `status`='Expired'", exp_sec) + except Exception, e: + if e.args[0]==1054: + self.add_status_column() + + # clear out old sessions + webnotes.conn.sql("delete from tabSessions where TIMEDIFF(NOW(), lastupdate) > '72:00:00'") + + # -----------------------------
+
[docs] def add_status_column(self): + webnotes.conn.commit() + webnotes.conn.sql("alter table tabSessions add column `status` varchar(20)") + webnotes.conn.begin() + + + # Get IP Info from ipinfodb.com + # -----------------------------
+
[docs] def get_ipinfo(self): + import os + + try: + import pygeoip + except: + return + + gi = pygeoip.GeoIP('data/GeoIP.dat') + self.data['data']['ipinfo'] = {'countryName': gi.country_name_by_addr(os.environ.get('REMOTE_ADDR'))} + + # -----------------------------
+
[docs] def insert_session_record(self): + webnotes.conn.sql("insert into tabSessions (sessiondata, user, lastupdate, sid, status) values (%s , %s, NOW(), %s, 'Active')", (str(self.data['data']), self.data['user'], self.data['sid'])) +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/db.html b/docs/_build/html/_modules/webnotes/db.html new file mode 100644 index 0000000000..9e232df1f2 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/db.html @@ -0,0 +1,407 @@ + + + + + + + + + webnotes.db — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.db

+# Database Module
+# --------------------
+
+import MySQLdb
+from webnotes import defs
+import webnotes
+
+
[docs]class Database: + """ + Open a database connection with the given parmeters, if use_default is True, use the + login details from `defs.py`. This is called by the request handler and is accessible using + the `conn` global variable. the `sql` method is also global to run queries + """ + def __init__(self, host='', user='', password='', ac_name = '', use_default = 0): + self.host = host or 'localhost' + self.user = user or getattr(defs, 'default_db_name', '') + self.password = password or getattr(defs, 'db_password', '') + + if ac_name: + self.user = self.get_db_login(ac_name) or defs.default_db_name + + if use_default: + self.user = defs.default_db_name + + self.is_testing = 0 + self.in_transaction = 0 + self.transaction_writes = 0 + self.testing_tables = [] + + self.connect() + if self.user != 'root': + self.use(self.user) + + if webnotes.logger: + webnotes.logger.debug('Database object initialized for:%s',self.user) + +
[docs] def get_db_login(self, ac_name): + return getattr(defs,'db_name_map').get(ac_name, getattr(defs,'default_db_name')) +
+
[docs] def connect(self): + """ + Connect to a database + """ + self._conn = MySQLdb.connect(user=self.user, host=self.host, passwd=self.password) + try: + self._conn.set_character_set('utf8') + except: + pass + + self._cursor = self._conn.cursor() + + return self._cursor +
+
[docs] def use(self, db_name): + """ + `USE` db_name + """ + self._conn.select_db(db_name) + self.cur_db_name = db_name +
+
[docs] def check_transaction_status(self, query): + """ + Update *in_transaction* and check if "START TRANSACTION" is not called twice + """ + if self.in_transaction and query and query.strip().split()[0].lower() in ['start', 'alter', 'drop', 'create']: + raise Exception, 'This statement can cause implicit commit' + + if query and query.strip().lower()=='start transaction': + self.in_transaction = 1 + self.transaction_writes = 0 + + if query and query.strip().split()[0].lower() in ['commit', 'rollback']: + self.in_transaction = 0 + + if self.in_transaction and query[:6].lower() in ['update', 'insert']: + self.transaction_writes += 1 + if self.transaction_writes > 5000: + webnotes.msgprint('A very long query was encountered. If you are trying to import data, please do so using smaller files') + raise Exception, 'Bad Query!!! Too many writes' +
+
[docs] def fetch_as_dict(self, formatted=0): + """ + Internal - get results as dictionary + """ + result = self._cursor.fetchall() + ret = [] + for r in result: + dict = {} + for i in range(len(r)): + dict[self._cursor.description[i][0]] = self.convert_to_simple_type(r[i], formatted) + ret.append(dict) + return ret +
+
[docs] def validate_query(self, q): + cmd = q.strip().lower().split()[0] + if cmd in ['alter', 'drop', 'truncate'] and webnotes.user.name != 'Administrator': + webnotes.msgprint('Not allowed to execute query') + raise Execption + + # ====================================================================================== +
+
[docs] def sql(self, query, values=(), as_dict = 0, as_list = 0, formatted = 0, ignore_no_table = 1, debug=0): + """ + * Execute a `query`, with given `values` + * returns as a dictionary if as_dict = 1 + * returns as a list of lists (with cleaned up dates and decimals) if as_list = 1 + """ + # in transaction validations + self.check_transaction_status(query) + + if getattr(defs,'multi_tenant',None): + query = self.add_multi_tenant_condition(query) + + # execute + if values!=(): + self._cursor.execute(query, values) + if debug: webnotes.msgprint(query % values) + + else: + self._cursor.execute(query) + if debug: webnotes.msgprint(query) + + # scrub output if required + if as_dict: + return self.fetch_as_dict(formatted) + elif as_list: + return self.convert_to_lists(self._cursor.fetchall(), formatted) + else: + return self._cursor.fetchall() + + # add condition for tenant id + # ======================================================================================
+
[docs] def add_multi_tenant_condition(query): + import webnotes.multi_tenant + return webnotes.multi_tenant.query_parser.add_condition(query) + + # ====================================================================================== +
+
[docs] def get_description(self): + """ + Get metadata of the last query + """ + return self._cursor.description + + # ====================================================================================== +
+
[docs] def convert_to_simple_type(self, v, formatted=0): + try: import decimal # for decimal Python 2.5 onwards + except: pass + import datetime + from webnotes.utils import formatdate, fmt_money + + # date + if type(v)==datetime.date: + v = str(v) + if formatted: + v = formatdate(v) + + # time + elif type(v)==datetime.timedelta: + h = int(v.seconds/60/60) + v = str(h) + ':' + str(v.seconds/60 - h*60) + if v[1]==':': + v='0'+v + + # datetime + elif type(v)==datetime.datetime: + v = str(v) + + # long + elif type(v)==long: + v=int(v) + + # decimal + try: + if type(v)==decimal.Decimal: + v=float(v) + except: pass + + # convert to strings... (if formatted) + if formatted: + if type(v)==float: + v=fmt_money(v) + if type(v)==int: + v=str(v) + + return v + + # ====================================================================================== +
+
[docs] def convert_to_lists(self, res, formatted=0): + """ + Convert the given result set to a list of lists (with cleaned up dates and decimals) + """ + nres = [] + for r in res: + nr = [] + for c in r: + nr.append(self.convert_to_simple_type(c, formatted)) + nres.append(nr) + return nres + + # ====================================================================================== +
+
[docs] def replace_tab_by_test(self, query): + """ + Relace all ``tab`` + doctype to ``test`` + doctype + """ + if self.is_testing: + tl = self.get_testing_tables() + for t in tl: + query = query.replace(t, 'test' + t[3:]) + return query +
+
[docs] def get_testing_tables(self): + """ + Get list of all tables for which `tab` is to be replaced by `test` before a query is executed + """ + if not self.testing_tables: + testing_tables = ['tab'+r[0] for r in self.sql('SELECT name from tabDocType where docstatus<2 and (issingle=0 or issingle is null)', allow_testing = 0)] + testing_tables+=['tabSeries','tabSingles'] # tabSessions is not included here + return self.testing_tables + + # ====================================================================================== + # get a single value from a record +
+
[docs] def get_value(self, doctype, docname, fieldname): + """ + Get a single / multiple value from a record. + + For Single DocType, let docname be = None + """ + + fl = fieldname + if docname and (docname!=doctype or docname=='DocType'): + if type(fieldname) in (list, tuple): + fl = '`, `'.join(fieldname) + + r = self.sql("select `%s` from `tab%s` where name='%s'" % (fl, doctype, docname)) + return r and (len(r[0]) > 1 and r[0] or r[0][0]) or None + else: + if type(fieldname) in (list, tuple): + fl = "', '".join(fieldname) + + r = self.sql("select value from tabSingles where field in ('%s') and doctype='%s'" % (fieldname, doctype)) + return r and (len(r) > 1 and (i[0] for i in r) or r[0][0]) or None +
+
[docs] def set_value(self, dt, dn, field, val): + from webnotes.utils import now + if dn and dt!=dn: + self.sql("update `tab"+dt+"` set `"+field+"`=%s, modified=%s where name=%s", (val, now(), dn)) + else: + if self.sql("select value from tabSingles where field=%s and doctype=%s", (field, dt)): + self.sql("update tabSingles set value=%s where field=%s and doctype=%s", (val, field, dt)) + else: + self.sql("insert into tabSingles(doctype, field, value) values (%s, %s, %s)", (dt, field, val)) +
+
[docs] def set(self, doc, field, val): + self.set_value(doc.doctype, doc.name, field, val) + doc.fields[field] = val + + # ====================================================================================== +
+
[docs] def set_global(self, key, val, user='__global'): + res = self.sql('select defkey from `tabDefaultValue` where defkey=%s and parent=%s', (key, user)) + if res: + self.sql('update `tabDefaultValue` set defvalue=%s where parent=%s and defkey=%s', (str(val), user, key)) + else: + self.sql('insert into `tabDefaultValue` (name, defkey, defvalue, parent) values (%s,%s,%s,%s)', (user+'_'+key, key, str(val), user)) +
+
[docs] def get_global(self, key, user='__global'): + g = self.sql("select defvalue from tabDefaultValue where defkey=%s and parent=%s", (key, user)) + return g and g[0][0] or None + + # ====================================================================================== +
+
[docs] def begin(self): + if not self.in_transaction: + self.sql("start transaction") +
+
[docs] def commit(self): + self.sql("commit") + +
+
[docs] def rollback(self): + self.sql("ROLLBACK") + + # ====================================================================================== +
+
[docs] def field_exists(self, dt, fn): + """ + Returns True if `fn` exists in `DocType` `dt` + """ + return self.sql("select name from tabDocField where fieldname=%s and parent=%s", (dt, fn)) +
+
[docs] def exists(self, dt, dn): + """ + Returns true if the record exists + """ + try: + return self.sql('select name from `tab%s` where name=%s' % (dt, '%s'), dn) + except: + return None + + # ======================================================================================
+
[docs] def close(self): + """ + Close my connection + """ + if self._conn: + self._conn.close()
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/handler.html b/docs/_build/html/_modules/webnotes/handler.html new file mode 100644 index 0000000000..2cab7b991f --- /dev/null +++ b/docs/_build/html/_modules/webnotes/handler.html @@ -0,0 +1,533 @@ + + + + + + + + + webnotes.handler — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.handler

+import sys, os
+import webnotes
+import webnotes.defs
+import webnotes.utils
+
+form = webnotes.form
+form_dict = webnotes.form_dict
+
+sql = None
+session = None
+errdoc = ''
+errdoctype = ''
+errmethod = ''
+fw_folder = '/Users/rushabh/workbench/www/'
+
+
+# Logs
+
+# refresh / start page
+# ------------------------------------------------------------------------------------
+
+
[docs]def startup(): + import webnotes + import webnotes.session_cache + + webnotes.response.update(webnotes.session_cache.get()) +
+
[docs]def cleanup_docs(): + import webnotes.model.doclist + if webnotes.response.get('docs') and type(webnotes.response['docs'])!=dict: + webnotes.response['docs'] = webnotes.model.doclist.compress(webnotes.response['docs']) + +# server calls +# ------------------------------------------------------------------------------------ +
+
[docs]def runserverobj(arg=None): + import webnotes.widgets.form + webnotes.widgets.form.runserverobj() +
+
[docs]def logout(): + webnotes.login_manager.logout() + +# DocType Mapper +# ------------------------------------------------------------------------------------ +
+
[docs]def dt_map(): + import webnotes + import webnotes.model.doclist + from webnotes.model.code import get_obj + from webnotes.model.doc import Document + + form_dict = webnotes.form_dict + + dt_list = webnotes.model.doclist.expand(form_dict.get('docs')) + from_doctype = form_dict.get('from_doctype') + to_doctype = form_dict.get('to_doctype') + from_docname = form_dict.get('from_docname') + from_to_list = form_dict.get('from_to_list') + + dm = get_obj('DocType Mapper', from_doctype +'-' + to_doctype) + doclist = dm.dt_map(from_doctype, to_doctype, from_docname, Document(fielddata = dt_list[0]), [], from_to_list) + + webnotes.response['docs'] = doclist + +# Load Month Events +# ------------------------------------------------------------------------------------ +
+
[docs]def load_month_events(): + import webnotes + form = webnotes.form + + mm = form.getvalue('month') + yy = form.getvalue('year') + m_st = str(yy) + '-' + str(mm) + '-01' + m_end = str(yy) + '-' + str(mm) + '-31' + + import webnotes.widgets.event + webnotes.response['docs'] = webnotes.widgets.event.get_cal_events(m_st, m_end) + +# Data import +# ------------------------------------------------------------------------------------ +
+
[docs]def import_csv(): + import webnotes.model.import_docs + form = webnotes.form + from webnotes.utils import cint + + i = webnotes.model.import_docs.CSVImport() + r = i.import_csv(form.getvalue('csv_file'), form.getvalue('dateformat'), form_dict.get('overwrite', 0) and 1) + + webnotes.response['type']='iframe' + rhead = '''<style>body, html {font-family: Arial; font-size: 12px;}</style>''' + webnotes.response['result']= rhead + r +
+
[docs]def get_template(): + import webnotes.model.import_docs + webnotes.model.import_docs.get_template() + + +# File Upload +# ------------------------------------------------------------------------------------ +
+
[docs]def uploadfile(): + import webnotes.utils.file_manager + if webnotes.form_dict.get('from_form'): + webnotes.utils.file_manager.upload() + else: + # save the file + fid, fname = webnotes.utils.file_manager.save_uploaded() + + # do something with the uploaded file + if fid and webnotes.form_dict.get('server_obj'): + from webnotes.model.code import get_obj + getattr(get_obj(webnotes.form_dict.get('server_obj')), webnotes.form_dict.get('method'))(fid, fname) + + # return the upload + if fid: + webnotes.response['result'] = '<script>window.parent.upload_callback("'+webnotes.form_dict.get('uploader_id')+'", "'+fid+'")</script>' + +# File upload (from scripts) +# ------------------------------------------------------------------------------------ +
+
[docs]def upload_many(): + from webnotes.model.code import get_obj + + # pass it on to upload_many method in Control Panel + cp = get_obj('Control Panel') + cp.upload_many(webnotes.form) + + webnotes.response['result'] = """ +<script type='text/javascript'> +%s +</script> +%s +%s""" % (cp.upload_callback(webnotes.form), '\n----\n'.join(webnotes.message_log).replace("'", "\'"), '\n----\n'.join(webnotes.debug_log).replace("'", "\'").replace("\n","<br>")) + webnotes.response['type'] = 'iframe' + + +# File download +# ------------------------------------------------------------------------------------
+
[docs]def get_file(): + import webnotes.utils.file_manager + + res = webnotes.utils.file_manager.get_file(form.getvalue('fname')) + if res: + webnotes.response['type'] = 'download' + webnotes.response['filename'] = res[0] + + if hasattr(res[1], 'tostring'): + webnotes.response['filecontent'] = res[1].tostring() + else: + webnotes.response['filecontent'] = res[1] + else: + webnotes.msgprint('[get_file] Unknown file name') + +# Get Graph +# ------------------------------------------------------------------------------------
+
[docs]def get_graph(): + form = webnotes.form + + import StringIO + f = StringIO.StringIO() + + # call the object + obj = server.get_obj(form_dict.get('dt')) + plt = server.run_server_obj(obj, form_dict.get('method'), form_dict.get('arg')) + plt.savefig(f) + + # stream out + webnotes.response['type'] = 'download' + webnotes.response['filename'] = webnotes.user.get_random_password() + '.png' + webnotes.response['filecontent'] = f.getvalue() + +# Reset Password +# ------------------------------------------------------------------------------------ +
+
[docs]def reset_password(): + form_dict = webnotes.form_dict + + act = form_dict.get('account', '') + user = form_dict.get('user', '') + if act: + webnotes.conn.set_db(act) + + try: + p = webnotes.profile.Profile(user) + p.reset_password() + webnotes.msgprint("Password has been reset and sent to your email id.") + except Exception, e: + webnotes.msgprint(str(e)) + +# Resume session +# ------------------------------------------------------------------------------------ +
+
[docs]def resume_session(): + webnotes.response['message'] = webnotes.session_obj.resume() + +# ------------- +# Create Backup +# ------------- +
+
[docs]def backupdb(form_dict, session): + db_name = server.decrypt(form_dict.get('db_name')) + + server.backup_db(db_name) + + webnotes.response['type'] = 'download' + webnotes.response['filename'] = db_name+'.tar.gz' + webnotes.response['filecontent'] = open('../backups/' + db_name+'.tar.gz','rb').read() + +# --------------------------------------------------------------------- +
+
[docs]def validate_cmd(cmd): + # check if there is no direct possibility of malicious script injection + if cmd.startswith('webnotes.model.code'): + raise Exception, 'Cannot call any methods from webnotes.model.code directly from the handler' + + if cmd.startswith('webnotes.model.db_schema'): + raise Exception, 'Cannot call any methods from webnotes.model.db_schema directly from the handler' + + if cmd.startswith('webnotes.conn'): + raise Exception, 'Cannot call database connection method directly from the handler' + +# Execution Starts Here +# --------------------------------------------------------------------- +
+import webnotes.auth +import webnotes.db + +# reset password +# --------------------------------------------------------------------- + +if form_dict.has_key('cmd') and (form_dict.get('cmd')=='reset_password'): + webnotes.conn = webnotes.db.Database(use_default = 1) + sql = webnotes.conn.sql + sql("START TRANSACTION") + try: + reset_password() + sql("COMMIT") + except Exception, e: + webnotes.errprint(str(e)) + sql("ROLLBACK") + +# pre-login access - for registration etc. +# --------------------------------------------------------------------- + +elif form_dict.has_key('cmd') and (form_dict.get('cmd')=='prelogin'): + webnotes.conn = webnotes.db.Database(use_default = 1) + sql = webnotes.conn.sql + webnotes.session = {'user':'Administrator'} + + import webnotes.model.code + + sql("START TRANSACTION") + try: + webnotes.response['message'] = webnotes.model.code.get_obj('Profile Control').prelogin(form_dict) or '' + sql("COMMIT") + except: + webnotes.errprint(webnotes.utils.getTraceback()) + sql("ROLLBACK") + +# main stuff +# --------------------------------------------------------------------- + +else: + + try: + webnotes.request = webnotes.auth.HTTPRequest() + + if form_dict.get('cmd') != 'login' and webnotes.conn: + sql = webnotes.conn.sql + + # NOTE: + # guest should only be allowed: + # getdoc (if Guest access) + # runserverobj (if Guest access) + + # get command cmd + cmd = form_dict.has_key('cmd') and form_dict.get('cmd') or '' + read_only = form_dict.has_key('_read_only') and form_dict.get('_read_only') or None + + validate_cmd(cmd) + + module = '' + if '.' in cmd: + module = '.'.join(cmd.split('.')[:-1]) + cmd = cmd.split('.')[-1] + + exec 'from %s import %s' % (module, cmd) in locals() + + + # execute + if locals().has_key(cmd): + if (not webnotes.conn.in_transaction) and (not read_only): + webnotes.conn.begin() + + if webnotes.form_dict.get('arg'): + # direct method call + ret = locals()[cmd](webnotes.form_dict.get('arg')) + else: + ret = locals()[cmd]() + + # returns with a message + if ret: + webnotes.response['message'] = ret + + # update session + webnotes.session_obj.update() + + if webnotes.conn.in_transaction: + webnotes.conn.commit() + else: + if cmd!='login': + webnotes.msgprint('No Method: %s' % cmd) + + except webnotes.ValidationError: + webnotes.conn.rollback() + except: + webnotes.errprint(webnotes.utils.getTraceback()) + webnotes.conn and webnotes.conn.rollback() + + +#### cleanup +#----------- + +if webnotes.conn: + webnotes.conn.close() + +#### go + +import string +import os + +acceptsGzip, out_buf, str_out = 0, None, None +try: + if string.find(os.environ["HTTP_ACCEPT_ENCODING"], "gzip") != -1: + acceptsGzip = 1 # problem in win ? +except: + pass + +
[docs]def compressBuf(buf): + import gzip, cStringIO + zbuf = cStringIO.StringIO() + zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 5) + zfile.write(buf) + zfile.close() + return zbuf.getvalue() + +# CSV +# ------------------------------------------------------------------- +
+if webnotes.response.get('type')=='csv': + print "Content-Type: text/csv" + print "Content-Disposition: attachment; filename="+webnotes.response['doctype'].replace(' ', '_')+".csv" + print + print webnotes.response['result'] + +# IFRAME +# ------------------------------------------------------------------- + +elif webnotes.response.get('type')=='iframe': + print "Content-Type: text/html" + print + if webnotes.response.get('result'): + print webnotes.response['result'] + if webnotes.debug_log: + print '''<script type='text/javascript'>alert("%s");</script>''' % ('-------'.join(webnotes.debug_log).replace('"', '').replace('\n','')) + +# file +# ------------------------------------------------------------------- + +elif webnotes.response.get('type')=='download': + import mimetypes + print "Content-Type: %s" % (mimetypes.guess_type(webnotes.response['filename'])[0] or 'application/unknown') + print "Content-Disposition: filename="+webnotes.response['filename'].replace(' ', '_') + print + print webnotes.response['filecontent'] + +# JSON +# ------------------------------------------------------------------- + +else: + if webnotes.debug_log: + save_log = 1 + if webnotes.debug_log[0].startswith('[Validation Error]'): + save_log = 0 + + t = '\n----------------\n'.join(webnotes.debug_log) + if errdoctype: + t = t + '\nDocType: ' + errdoctype + if errdoc: + t = t + '\nName: ' + errdoc + if errmethod: + t = t + '\nMethod: ' + errmethod + webnotes.response['exc'] = '<pre>'+t.replace('\n','<br>')+'</pre>' + + if save_log: # don't save validation errors + try: save_log(t, 'Server') + except: pass + + if webnotes.message_log: + webnotes.response['server_messages'] = '\n----------------\n'.join(webnotes.message_log) + + cleanup_docs() + + # Convert to JSON + # --------------- + try: + import json + except: # python 2.4 + import simplejson as json + + try: + str_out = json.dumps(webnotes.response) + except: + str_out = str(webnotes.response).replace(', None', ', ""') + + if acceptsGzip and len(str_out)>512: + out_buf = compressBuf(str_out) + print "Content-Encoding: gzip" + print "Content-Length: %d" % (len(out_buf)) + + print "Content-Type: text/html; Charset: ISO-8859-1" + + # if there ar additional cookies defined during the request, add them here + if webnotes.cookies or webnotes.add_cookies: + for c in webnotes.add_cookies.keys(): + webnotes.cookies[c] = webnotes.add_cookies[c] + + print webnotes.cookies + + print # Headers end + +if out_buf: + sys.stdout.write(out_buf) +elif str_out: + print str_out +
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/install_lib/db_init.html b/docs/_build/html/_modules/webnotes/install_lib/db_init.html new file mode 100644 index 0000000000..e3367c5c7d --- /dev/null +++ b/docs/_build/html/_modules/webnotes/install_lib/db_init.html @@ -0,0 +1,380 @@ + + + + + + + + + webnotes.install_lib.db_init — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.install_lib.db_init

+"""
+	Create a database from scratch (wip)
+"""
+
+
[docs]class DatabaseInstance: + + def __init__(self, conn = None,db_name = None): + self.conn = conn + self.db_name = db_name + + +# def setup(self): +# self.create_db_and_user() +# self.create_base_tables() +# self.import_system_module() +# self.setup_users() + +
[docs] def create_db_and_user(self): + import webnotes.defs + + # create user and db + self.conn.sql("CREATE USER '%s'@'localhost' IDENTIFIED BY '%s'" % (self.db_name, webnotes.defs.db_password)) + self.conn.sql("CREATE DATABASE IF NOT EXISTS `%s` ;" % self.db_name) + self.conn.sql("GRANT ALL PRIVILEGES ON `%s` . * TO '%s'@'localhost';" % (self.db_name, self.db_name)) + self.conn.sql("FLUSH PRIVILEGES") + self.conn.sql("SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;") + self.conn.sql("USE %s"%self.db_name) + + + + +
+
[docs] def create_base_tables(self): + self.create_singles() + self.create_sessions() + self.create_doctypecache() + self.create_role() + self.create_docfield() + self.create_docperm() + self.create_docformat() + self.create_doctype() +
+
[docs] def import_system_module(self): + docs = [ + ['DocType','Role'] + ,['Role','Administrator'] + ,['Role','Guest'] + ,['Role','All'] + ,['DocType','DocPerm'] + ,['DocType','DocFormat'] + ,['DocType','DocField'] + ,['DocType','DocType'] + ,['DocType','DefaultValue'] + ,['DocType','Profile'] + ,['DocType','UserRole'] + ] + + # import in sequence + for d in docs: + import_module.import_from_files(record_list=[['System',d[0],d[1]]]) + + # import all + import_module.import_from_files([['System']]) + + + # singles + # ------------------------------------------------------ +
+
[docs] def create_singles(self): + self.conn.sql("DROP TABLE IF EXISTS `tabSingles`") + self.conn.sql("""CREATE TABLE `tabSingles` ( + `doctype` varchar(40) default NULL, + `field` varchar(40) default NULL, + `value` text, + KEY `doctype` (`doctype`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1;""") + + # sessions + # ------------------------------------------------------ +
+
[docs] def create_sessions(self): + self.conn.sql("DROP TABLE IF EXISTS `tabSessions`;") + self.conn.sql("""CREATE TABLE `tabSessions` ( + `user` varchar(40) default NULL, + `sid` varchar(120) default NULL, + `sessiondata` longtext, + `ipaddress` varchar(16) default NULL, + `lastupdate` datetime default NULL + ) ENGINE=MyISAM DEFAULT CHARSET=latin1;""") + + # doc type cache + # ------------------------------------------------------ +
+
[docs] def create_doctypecache(self): + self.conn.sql("DROP TABLE IF EXISTS `__DocTypeCache`") + self.conn.sql("create table `__DocTypeCache` (name VARCHAR(120), modified DATETIME, content TEXT, server_code_compiled TEXT)") + + + + + # Role + # ------------------------------------------------------ +
+
[docs] def create_role(self): + self.conn.sql("DROP TABLE IF EXISTS `tabRole`") + self.conn.sql("""CREATE TABLE `tabRole` ( + `name` varchar(120) NOT NULL, + `creation` datetime default NULL, + `modified` datetime default NULL, + `modified_by` varchar(40) default NULL, + `owner` varchar(40) default NULL, + `docstatus` int(1) default '0', + `parent` varchar(120) default NULL, + `parentfield` varchar(120) default NULL, + `parenttype` varchar(120) default NULL, + `idx` int(8) default NULL, + `role_name` varchar(180) default NULL, + `module` varchar(180) default NULL, + PRIMARY KEY (`name`), + KEY `parent` (`parent`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1;""") + + # DocField + # ------------------------------------------------------ +
+
[docs] def create_docfield(self): + self.conn.sql("DROP TABLE IF EXISTS `tabDocField`") + self.conn.sql("""CREATE TABLE `tabDocField` ( + `name` varchar(120) NOT NULL, + `creation` datetime default NULL, + `modified` datetime default NULL, + `modified_by` varchar(40) default NULL, + `owner` varchar(40) default NULL, + `docstatus` int(1) default '0', + `parent` varchar(120) default NULL, + `parentfield` varchar(120) default NULL, + `parenttype` varchar(120) default NULL, + `idx` int(8) default NULL, + `fieldname` varchar(180) default NULL, + `label` varchar(180) default NULL, + `oldfieldname` varchar(180) default NULL, + `fieldtype` varchar(180) default NULL, + `oldfieldtype` varchar(180) default NULL, + `options` text, + `search_index` int(3) default NULL, + `hidden` int(3) default NULL, + `print_hide` int(3) default NULL, + `report_hide` int(3) default NULL, + `reqd` int(3) default NULL, + `no_copy` int(3) default NULL, + `allow_on_submit` int(3) default NULL, + `trigger` varchar(180) default NULL, + `depends_on` varchar(180) default NULL, + `permlevel` int(3) default NULL, + `width` varchar(180) default NULL, + `default` text, + `description` text, + `colour` varchar(180) default NULL, + `icon` varchar(180) default NULL, + `in_filter` int(3) default NULL, + PRIMARY KEY (`name`), + KEY `parent` (`parent`), + KEY `label` (`label`), + KEY `fieldtype` (`fieldtype`), + KEY `fieldname` (`fieldname`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1;""") + + # DocPerm + # ------------------------------------------------------ +
+
[docs] def create_docperm(self): + self.conn.sql("DROP TABLE IF EXISTS `tabDocPerm`") + self.conn.sql("""CREATE TABLE `tabDocPerm` ( + `name` varchar(120) NOT NULL, + `creation` datetime default NULL, + `modified` datetime default NULL, + `modified_by` varchar(40) default NULL, + `owner` varchar(40) default NULL, + `docstatus` int(1) default '0', + `parent` varchar(120) default NULL, + `parentfield` varchar(120) default NULL, + `parenttype` varchar(120) default NULL, + `idx` int(8) default NULL, + `permlevel` int(11) default NULL, + `role` varchar(180) default NULL, + `match` varchar(180) default NULL, + `read` int(3) default NULL, + `write` int(3) default NULL, + `create` int(3) default NULL, + `submit` int(3) default NULL, + `cancel` int(3) default NULL, + `amend` int(3) default NULL, + `execute` int(3) default NULL, + PRIMARY KEY (`name`), + KEY `parent` (`parent`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1;""") + + # DocFormat + # ------------------------------------------------------ +
+
[docs] def create_docformat(self): + self.conn.sql("DROP TABLE IF EXISTS `tabDocFormat`") + self.conn.sql("""CREATE TABLE `tabDocFormat` ( + `name` varchar(120) NOT NULL, + `creation` datetime default NULL, + `modified` datetime default NULL, + `modified_by` varchar(40) default NULL, + `owner` varchar(40) default NULL, + `docstatus` int(1) default '0', + `parent` varchar(120) default NULL, + `parentfield` varchar(120) default NULL, + `parenttype` varchar(120) default NULL, + `idx` int(8) default NULL, + `format` varchar(180) default NULL, + PRIMARY KEY (`name`), + KEY `parent` (`parent`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1;""") + + # DocType + # ------------------------------------------------------ +
+
[docs] def create_doctype(self): + self.conn.sql("DROP TABLE IF EXISTS `tabDocType`") + self.conn.sql("""CREATE TABLE `tabDocType` ( + `name` varchar(180) NOT NULL default '', + `creation` datetime default NULL, + `modified` datetime default NULL, + `modified_by` varchar(40) default NULL, + `owner` varchar(180) default NULL, + `docstatus` int(1) default '0', + `parent` varchar(120) default NULL, + `parentfield` varchar(120) default NULL, + `parenttype` varchar(120) default NULL, + `idx` int(8) default NULL, + `search_fields` varchar(180) default NULL, + `issingle` int(1) default NULL, + `istable` int(1) default NULL, + `version` int(11) default NULL, + `module` varchar(180) default NULL, + `autoname` varchar(180) default NULL, + `name_case` varchar(180) default NULL, + `description` text, + `colour` varchar(180) default NULL, + `read_only` int(1) default NULL, + `in_create` int(1) default NULL, + `show_in_menu` int(3) default NULL, + `menu_index` int(11) default NULL, + `parent_node` varchar(180) default NULL, + `smallicon` varchar(180) default NULL, + `allow_print` int(1) default NULL, + `allow_email` int(1) default NULL, + `allow_copy` int(1) default NULL, + `allow_rename` int(1) default NULL, + `hide_toolbar` int(1) default NULL, + `hide_heading` int(1) default NULL, + `allow_attach` int(1) default NULL, + `use_template` int(1) default NULL, + `max_attachments` int(11) default NULL, + `section_style` varchar(180) default NULL, + `client_script` text, + `client_script_core` text, + `server_code` text, + `server_code_core` text, + `server_code_compiled` text, + `client_string` text, + `server_code_error` varchar(180) default NULL, + `print_outline` varchar(180) default NULL, + `dt_template` text, + `is_transaction_doc` int(1) default NULL, + `change_log` text, + `read_only_onload` int(1) default NULL, + PRIMARY KEY (`name`), + KEY `parent` (`parent`) + ) ENGINE=InnoDB DEFAULT CHARSET=latin1;""") +
+
[docs] def create_module_def(self): + self.conn.sql("DROP TABLE IF EXISTS `tabModule Def`") + self.conn.sql("CREATE TABLE `tabModule Def` (`name` varchar(120) NOT NULL, `creation` datetime default NULL, `modified` datetime default NULL,`modified_by` varchar(40) default NULL,`owner` varchar(40) default NULL,`docstatus` int(1) default '0', `parent` varchar(120) default NULL,`parentfield` varchar(120) default NULL, `parenttype` varchar(120) default NULL, `idx` int(8) default NULL,`module_name` varchar(180) default NULL,`doctype_list` text, PRIMARY KEY (`name`), KEY `parent` (`parent`)) ENGINE=InnoDB") + +
+
[docs] def post_cleanup(self): + self.conn.sql("use %s;" % self.db_name) + self.conn.sql("update tabProfile set password = password('admin') where name='Administrator'") + self.conn.sql("update tabDocType set server_code_compiled = NULL")
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/install_lib/install.html b/docs/_build/html/_modules/webnotes/install_lib/install.html new file mode 100644 index 0000000000..4f0a3a7138 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/install_lib/install.html @@ -0,0 +1,346 @@ + + + + + + + + + webnotes.install_lib.install — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.install_lib.install

+import os,sys
+
+cgi_bin_path = os.path.sep.join(__file__.split(os.path.sep)[:-3])
+
+sys.path.append(cgi_bin_path)
+
+
+		
+#
+# make a copy of defs.py (if not exists)
+#		
+
[docs]def copy_defs(): + global cgi_bin_path + if not os.path.exists(os.path.join(cgi_bin_path, 'webnotes', 'defs.py')): + ret = os.system('cp '+ os.path.join(cgi_bin_path, 'webnotes', 'defs_template.py')+\ + ' '+os.path.join(cgi_bin_path, 'webnotes', 'defs.py')) + print 'Made copy of defs.py' + +# +# Main Installer Class +#
+
[docs]class Installer: + def __init__(self, root_login, root_password): + + import webnotes + import webnotes.db + import webnotes.defs + + self.root_password = root_password + from webnotes.model.db_schema import DbManager + + self.conn = webnotes.db.Database(user=root_login, password=root_password) + webnotes.conn=self.conn + webnotes.session= {'user':'Administrator'} + self.dbman = DbManager(self.conn) + self.mysql_path = hasattr(webnotes.defs, 'mysql_path') and webnotes.defs.mysql_path or '' + + # + # run framework related cleanups + # +
[docs] def framework_cleanups(self, target): + + import webnotes + self.dbman.drop_table('__DocTypeCache') + webnotes.conn.sql("create table `__DocTypeCache` (name VARCHAR(120), modified DATETIME, content TEXT, server_code_compiled TEXT)") + + # set the basic passwords + webnotes.conn.begin() + webnotes.conn.sql("update tabProfile set password = password('admin') where name='Administrator'") + webnotes.conn.commit() +
+
[docs] def import_core_module(self): + """ + Imports the "Core" module from .txt file and creates + Creates profile Administrator + """ + import webnotes + from webnotes.modules.import_module import import_module + from webnotes.modules.module_manager import reload_doc + + reload_doc('core','doctype','doctype') + reload_doc('core','doctype','docfield') + reload_doc('core','doctype','docperm') + + import_module('core') +
+
[docs] def create_users(self): + """ + Create Administrator / Guest + """ + webnotes.conn.begin() + + from webnotes.model.doc import Document + p = Document('Profile') + p.name = p.first_name = 'Administrator' + p.email = 'admin@localhost' + p.save(new = 1) + + ur = Document('UserRole') + ur.parent = 'Administrator' + ur.role = 'Administrator' + ur.parenttype = 'Profile' + ur.parentfield = 'userroles' + p.enabled = 1 + ur.save(1) + + p = Document('Profile') + p.name = p.first_name = 'Guest' + p.email = 'guest@localhost' + p.enabled = 1 + p.save(new = 1) + + ur = Document('UserRole') + ur.parent = 'Guest' + ur.role = 'Guest' + ur.parenttype = 'Profile' + ur.parentfield = 'userroles' + ur.save(1) + + webnotes.conn.commit() + + # + # main script to create a database from + #
+
[docs] def import_from_db(self, target, source_path='', password = 'admin', verbose=0): + """ + a very simplified version, just for the time being..will eventually be deprecated once the framework stabilizes. + """ + import webnotes.defs + + # delete user (if exists) + self.dbman.delete_user(target) + + # create user and db + self.dbman.create_user(target,getattr(webnotes.defs,'db_password',None)) + if verbose: print "Created user %s" % target + + # create a database + self.dbman.create_database(target) + if verbose: print "Created database %s" % target + + # grant privileges to user + self.dbman.grant_all_privileges(target,target) + if verbose: print "Granted privileges to user %s and database %s" % (target, target) + + # flush user privileges + self.dbman.flush_privileges() + + self.conn.use(target) + + # import in target + if verbose: print "Starting database import..." + + # get the path of the sql file to import + source_given = True + if not source_path: + source_given = False + source_path = os.path.join(os.path.sep.join(os.path.abspath(webnotes.__file__).split(os.path.sep)[:-3]), 'data', 'Framework.sql') + + self.dbman.restore_database(target, source_path, self.root_password) + if verbose: print "Imported from database %s" % source_path + + if not source_given: + if verbose: print "Importing core module..." + self.import_core_module() + self.create_users() + + # framework cleanups + self.framework_cleanups(target) + if verbose: print "Ran framework startups on %s" % target + + return target +
+
[docs]def make_scheduler(root_login, root_password, verbose): + """ + Make the database where all scheduler events will be stored from multiple datbases + See webnotes.utils.scheduler for more information + """ + conn = webnotes.db.Database(user=root_login, password=root_password) + + from webnotes.model.db_schema import DbManager + + dbman = DbManager(conn) + + # delete user (if exists) + dbman.delete_user('master_scheduler') + + # create user and db + dbman.create_user('master_scheduler', getattr(webnotes.defs,'db_password',None)) + if verbose: print "Created user master_scheduler" + + # create a database + dbman.create_database('master_scheduler') + if verbose: print "Created database master_scheduler" + + # grant privileges to user + dbman.grant_all_privileges('master_scheduler','master_scheduler') + + # flush user privileges + dbman.flush_privileges() + + conn.use('master_scheduler') + + # create events table + conn.sql("""create table Event( + `db_name` varchar(60), + `event` varchar(180), + `interval` int(20), + `next_execution` timestamp, + `recurring` int(1), + primary key (`db_name`, `event`), + index next_execution(next_execution) + )""") + + conn.sql("""create table EventLog( + `db_name` varchar(180), + `event` varchar(180), + `executed_on` timestamp, + `log` text, + index executed_on(executed_on)) + """) +# +# load the options +#
+
[docs]def get_parser(): + from optparse import OptionParser + + parser = OptionParser(usage="usage: %prog [options] ROOT_LOGIN ROOT_PASSWORD DBNAME") + parser.add_option("-x", "--database-password", dest="password", default="admin", help="Optional: New password for the Framework Administrator, default 'admin'") + parser.add_option("-s", "--source", dest="source_path", default=None, help="Optional: Path of the sql file from which you want to import the instance, default 'data/Framework.sql'") + + return parser + + +# +# execution here +#
+if __name__=='__main__': + + parser = get_parser() + (options, args) = parser.parse_args() + + try: + + import webnotes + import webnotes.db + import webnotes.defs + except ImportError: + copy_defs() + import webnotes + import webnotes.db + import webnotes.defs + + if len(args)==3: + + root_login, root_password, db_name = args[0], args[1], args[2] + + if db_name=='master_scheduler': + make_scheduler(root_login, root_password, 1) + else: + inst = Installer(root_login, root_password) + + inst.import_from_db(db_name, source_path=options.source_path, \ + password = options.password, verbose = 1) + + + print "Database created, please edit defs.py to get started" + else: + parser.print_help() + +
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model.html b/docs/_build/html/_modules/webnotes/model.html new file mode 100644 index 0000000000..52e934e705 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model.html @@ -0,0 +1,307 @@ + + + + + + + + + webnotes.model — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model

+# model __init__.py
+import webnotes
+
+no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable', 'Button', 'Image', 'Graph']
+default_fields = ['doctype','name','owner','creation','modified','modified_by','parent','parentfield','parenttype','idx','docstatus']
+
+#=================================================================================
+
+
[docs]def check_if_doc_is_linked(dt, dn): + """ + Raises excption if the given doc(dt, dn) is linked in another record. + """ + sql = webnotes.conn.sql + + ll = get_link_fields(dt) + for l in ll: + link_dt, link_field = l + issingle = sql("select issingle from tabDocType where name = '%s'" % link_dt) + + # no such doctype (?) + if not issingle: continue + + if issingle[0][0]: + item = sql("select doctype from `tabSingles` where field='%s' and value = '%s' and doctype = '%s' " % (link_field, dn, l[0])) + if item: + webnotes.msgprint("Cannot delete %s <b>%s</b> because it is linked in <b>%s</b>" % (dt, dn, item[0][0]), raise_exception=1) + + else: + item = sql("select name from `tab%s` where `%s`='%s' and docstatus!=2 limit 1" % (link_dt, link_field, dn)) + if item: + webnotes.msgprint("Cannot delete %s <b>%s</b> because it is linked in %s <b>%s</b>" % (dt, dn, link_dt, item[0][0]), raise_exception=1) + +
+
[docs]def delete_doc(doctype=None, name=None, doclist = None): + """ + Deletes a doc(dt, dn) and validates if it is not submitted and not linked in a live record + """ + import webnotes.model.meta + sql = webnotes.conn.sql + + # get from form + if not doctype: + doctype = webnotes.form_dict.get('dt') + name = webnotes.form_dict.get('dn') + + if not doctype: + webnotes.msgprint('Nothing to delete!', raise_exception =1) + + # already deleted..? + if not webnotes.conn.exists(doctype, name): + return + + tablefields = webnotes.model.meta.get_table_fields(doctype) + + # check if submitted + d = webnotes.conn.sql("select docstatus from `tab%s` where name=%s" % (doctype, '%s'), name) + if d and int(d[0][0]) == 1: + webnotes.msgprint("Submitted Record '%s' '%s' cannot be deleted" % (doctype, name)) + raise Exception + + # call on_trash if required + from webnotes.model.code import get_obj + if doclist: + obj = get_obj(doclist=doclist) + else: + obj = get_obj(doctype, name) + + if hasattr(obj,'on_trash'): + obj.on_trash() + + # check if links exist + check_if_doc_is_linked(doctype, name) + + try: + webnotes.conn.sql("delete from `tab%s` where name='%s' limit 1" % (doctype, name)) + for t in tablefields: + webnotes.conn.sql("delete from `tab%s` where parent = %s" % (t[0], '%s'), name) + except Exception, e: + if e.args[0]==1451: + webnotes.msgprint("Cannot delete %s '%s' as it is referenced in another record. You must delete the referred record first" % (doctype, name)) + + raise e + + return 'okay' + +#================================================================================= +# new feature added 9-Jun-10 to allow doctypes to have labels
+
[docs]def get_dt_labels(): + d = {} + try: + res = webnotes.conn.sql("select name, dt_label from `tabDocType Label`") + except: + return {} + + for r in res: + d[r[0]] = r[1] + + return d +#================================================================================= +
+
[docs]def get_search_criteria(dt): + import webnotes.model.doc + # load search criteria for reports (all) + dl = [] + try: # bc + sc_list = webnotes.conn.sql("select name from `tabSearch Criteria` where doc_type = '%s' or parent_doc_type = '%s' and (disabled!=1 OR disabled IS NULL)" % (dt, dt)) + for sc in sc_list: + dl += webnotes.model.doc.get('Search Criteria', sc[0]) + except Exception, e: + pass # no search criteria + return dl + + +# Rename Doc +#================================================================================= +
+ +
[docs]def rename(dt, old, new, is_doctype = 0): + """ + Renames a doc(dt, old) to doc(dt, new) and updates all linked fields of type "Link" or "Select" with "link:" + """ + sql = webnotes.conn.sql + + # rename doc + sql("update `tab%s` set name='%s' where name='%s'" % (dt, new, old)) + + # get child docs + ct = sql("select options from tabDocField where parent = '%s' and fieldtype='Table'" % dt) + for c in ct: + sql("update `tab%s` set parent='%s' where parent='%s'" % (c[0], new, old)) + + # get links (link / select) + ll = get_link_fields(dt) + for l in ll: + is_single = sql("select issingle from tabDocType where name = '%s'" % l[0]) + is_single = is_single and webnotes.utils.cint(is_single[0][0]) or 0 + if is_single: + sql("update `tabSingles` set value='%s' where field='%s' and value = '%s' and doctype = '%s' " % (new, l[1], old, l[0])) + else: + sql("update `tab%s` set `%s`='%s' where `%s`='%s'" % (l[0], l[1], new, l[1], old)) + + # doctype + if is_doctype: + sql("RENAME TABLE `tab%s` TO `tab%s`" % (old, new)) + + # get child docs (update parenttype) + ct = sql("select options from tabDocField where parent = '%s' and fieldtype='Table'" % new) + for c in ct: + sql("update `tab%s` set parenttype='%s' where parenttype='%s'" % (c[0], new, old)) + +#================================================================================= +
+
[docs]def clear_recycle_bin(): + """ + Clears temporary records that have been deleted + """ + sql = webnotes.conn.sql + + tl = sql('show tables') + total_deleted = 0 + for t in tl: + fl = [i[0] for i in sql('desc `%s`' % t[0])] + + if 'name' in fl: + total_deleted += sql("select count(*) from `%s` where name like '__overwritten:%%'" % t[0])[0][0] + sql("delete from `%s` where name like '__overwritten:%%'" % t[0]) + + if 'parent' in fl: + total_deleted += sql("select count(*) from `%s` where parent like '__oldparent:%%'" % t[0])[0][0] + sql("delete from `%s` where parent like '__oldparent:%%'" % t[0]) + + total_deleted += sql("select count(*) from `%s` where parent like 'oldparent:%%'" % t[0])[0][0] + sql("delete from `%s` where parent like 'oldparent:%%'" % t[0]) + + total_deleted += sql("select count(*) from `%s` where parent like 'old_parent:%%'" % t[0])[0][0] + sql("delete from `%s` where parent like 'old_parent:%%'" % t[0]) + + webnotes.msgprint("%s records deleted" % str(int(total_deleted))) + + +# Make Table Copy +#================================================================================= +
+
[docs]def copytables(srctype, src, srcfield, tartype, tar, tarfield, srcfields, tarfields=[]): + import webnotes.model.doc + + if not tarfields: + tarfields = srcfields + l = [] + data = webnotes.model.doc.getchildren(src.name, srctype, srcfield) + for d in data: + newrow = webnotes.model.doc.addchild(tar, tarfield, tartype, local = 1) + newrow.idx = d.idx + + for i in range(len(srcfields)): + newrow.fields[tarfields[i]] = d.fields[srcfields[i]] + + l.append(newrow) + return l + +# DB Exists +#================================================================================= +
+
[docs]def db_exists(dt, dn): + import webnotes + return webnotes.conn.exists(dt, dn)
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/code.html b/docs/_build/html/_modules/webnotes/model/code.html new file mode 100644 index 0000000000..472854817d --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/code.html @@ -0,0 +1,321 @@ + + + + + + + + + webnotes.model.code — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.code

+"""
+This is where all the plug-in code is executed. The standard method for DocTypes is declaration of a 
+standardized `DocType` class that has the methods of any DocType. When an object is instantiated using the
+`get_obj` method, it creates an instance of the `DocType` class of that particular DocType and sets the 
+`doc` and `doclist` attributes that represent the fields (properties) of that record.
+
+methods in following modules are imported for backward compatibility
+
+	* webnotes.*
+	* webnotes.utils.*
+	* webnotes.model.doc.*
+	* webnotes.model.doclist.*
+"""
+custom_class = '''
+# Please edit this list and import only required elements
+import webnotes
+
+from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
+from webnotes.model import db_exists
+from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType
+from webnotes.model.doclist import getlist, copy_doclist
+from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
+from webnotes import session, form, is_testing, msgprint, errprint
+
+set = webnotes.conn.set
+sql = webnotes.conn.sql
+get_value = webnotes.conn.get_value
+in_transaction = webnotes.conn.in_transaction
+convert_to_lists = webnotes.conn.convert_to_lists
+
+# -----------------------------------------------------------------------------------------
+
+class CustomDocType(DocType):
+  def __init__(self, doc, doclist):
+    DocType.__init__(self, doc, doclist)
+'''
+
+
+#=================================================================================
+# execute a script with a lot of globals - deprecated
+#=================================================================================
+
+
[docs]def execute(code, doc=None, doclist=[]): + """ + Execute the code, if doc is given, then return the instance of the `DocType` class created + """ + # functions used in server script of DocTypes + # -------------------------------------------------- + from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add + from webnotes.model import db_exists + from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType + from webnotes.model.doclist import getlist, copy_doclist + from webnotes import session, form, is_testing, msgprint, errprint + + import webnotes + + set = webnotes.conn.set + sql = webnotes.conn.sql + get_value = webnotes.conn.get_value + in_transaction = webnotes.conn.in_transaction + convert_to_lists = webnotes.conn.convert_to_lists + if webnotes.user: + get_roles = webnotes.user.get_roles + locals().update({'get_obj':get_obj, 'get_server_obj':get_server_obj, 'run_server_obj':run_server_obj, 'updatedb':updatedb, 'check_syntax':check_syntax}) + version = 'v170' + NEWLINE = '\n' + BACKSLASH = '\\' + + # execute it + # ----------------- + exec code in locals() + + # if doc + # ----------------- + if doc: + d = DocType(doc, doclist) + return d + + if locals().get('page_html'): + return page_html + + if locals().get('out'): + return out + +#================================================================================= +# load the DocType class from module & return an instance +#================================================================================= +
+
[docs]def get_custom_script(doctype, script_type): + """ + Returns custom script if set in doctype `Custom Script` + """ + import webnotes + try: + custom_script = webnotes.conn.sql("select script from `tabCustom Script` where dt=%s and script_type=%s", (doctype, script_type)) + except Exception, e: + if e.args[0]==1146: + return None + else: raise e + + if custom_script and custom_script[0][0]: + return custom_script[0][0] +
+
[docs]def get_server_obj(doc, doclist = [], basedoctype = ''): + """ + Returns the instantiated `DocType` object. Will also manage caching & compiling + """ + # for test + import webnotes + + + # get doctype details + module = webnotes.conn.get_value('DocType', doc.doctype, 'module') + + # no module specified (must be really old), can't get code so quit + if not module: + return + + module = module.replace(' ','_').lower() + dt = doc.doctype.replace(' ','_').lower() + + # import + try: + exec 'from %s.doctype.%s.%s import DocType' % (module, dt, dt) + except ImportError, e: + # declare it here + class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d, dl + + # custom? + custom_script = get_custom_script(doc.doctype, 'Server') + if custom_script: + global custom_class + + exec custom_class + custom_script.replace('\t',' ') in locals() + + return CustomDocType(doc, doclist) + else: + return DocType(doc, doclist) + +#================================================================================= +# get object (from dt and/or dn or doclist) +#================================================================================= +
+
[docs]def get_obj(dt = None, dn = None, doc=None, doclist=[], with_children = 0): + """ + Returns the instantiated `DocType` object. Here you can pass the DocType and name (ID) to get the object. + If with_children is true, then all child records will be laoded and added in the doclist. + """ + if dt: + import webnotes.model.doc + + if not dn: + dn = dt + if with_children: + doclist = webnotes.model.doc.get(dt, dn, from_get_obj=1) + else: + doclist = webnotes.model.doc.get(dt, dn, with_children = 0, from_get_obj=1) + return get_server_obj(doclist[0], doclist) + else: + return get_server_obj(doc, doclist) + +#================================================================================= +# get object and run method +#================================================================================= +
+
[docs]def run_server_obj(server_obj, method_name, arg=None): + """ + Executes a method (`method_name`) from the given object (`server_obj`) + """ + if server_obj and hasattr(server_obj, method_name): + if arg: + return getattr(server_obj, method_name)(arg) + else: + return getattr(server_obj, method_name)() + else: + raise Exception, 'No method %s' % method_name + +#================================================================================= +# deprecated methods to keep v160 apps happy +#================================================================================= +
+
[docs]def updatedb(doctype, userfields = [], args = {}): + pass +
+
[docs]def check_syntax(code): + return '' + +#===================================================================================
+
[docs]def get_code(module, dt, dn, extn, is_static=None, fieldname=None): + from webnotes.modules import scrub, get_module_path + import os, webnotes + + # get module (if required) + if not module: + module = webnotes.conn.sql("select module from `tab%s` where name=%s" % (dt,'%s'),dn)[0][0] + + # no module, quit + if not module: + return '' + + # file names + if scrub(dt) in ('page','doctype','search_criteria'): + dt, dn = scrub(dt), scrub(dn) + + # get file name + fname = dn + '.' + extn + if is_static: + fname = dn + '_static.' + extn + + # code + code = '' + try: + file = open(os.path.join(get_module_path(scrub(module)), dt, dn, fname), 'r') + code = file.read() + file.close() + except IOError, e: + # no file, try from db + if fieldname: + code = webnotes.conn.get_value(dt, dn, fieldname) + + return code
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/db_schema.html b/docs/_build/html/_modules/webnotes/model/db_schema.html new file mode 100644 index 0000000000..4af1a83814 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/db_schema.html @@ -0,0 +1,528 @@ + + + + + + + + + webnotes.model.db_schema — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.db_schema

+"""
+Syncs a database table to the `DocType` (metadata)
+
+.. note:: This module is only used internally
+
+"""
+import os
+import webnotes
+
+type_map = {
+	'currency':		('decimal', '14,2')
+	,'int':			('int', '11')
+	,'float':		('decimal', '14,6')
+	,'check':		('int', '1')
+	,'small text':	('text', '')
+	,'long text':	('text', '')
+	,'code':		('text', '')
+	,'text editor':	('text', '')
+	,'date':		('date', '')
+	,'time':		('time', '')
+	,'text':		('text', '')
+	,'data':		('varchar', '180')
+	,'link':		('varchar', '180')
+	,'password':	('varchar', '180')
+	,'select':		('varchar', '180')
+	,'read only':	('varchar', '180')
+	,'blob':		('longblob', '')
+}
+
+default_columns = ['name', 'creation', 'modified', 'modified_by', 'owner', 'docstatus', 'parent',\
+	 'parentfield', 'parenttype', 'idx']
+
+default_shortcuts = ['_Login', '__user', '_Full Name', 'Today', '__today']
+
+
+from webnotes.utils import cint
+
+# -------------------------------------------------
+# Class database table
+# -------------------------------------------------
+
+
[docs]class DbTable: + def __init__(self, doctype, prefix = 'tab'): + self.doctype = doctype + self.name = prefix + doctype + self.columns = {} + self.current_columns = {} + + # lists for change + self.add_column = [] + self.change_type = [] + self.add_index = [] + self.drop_index = [] + self.set_default = [] + + # load + self.get_columns_from_docfields() + +
[docs] def create(self): + add_text = '' + + # columns + t = self.get_column_definitions() + if t: add_text += ',\n'.join(self.get_column_definitions()) + ',\n' + + # index + t = self.get_index_definitions() + if t: add_text += ',\n'.join(self.get_index_definitions()) + ',\n' + + # create table + webnotes.conn.sql("""create table `%s` ( + name varchar(120) not null primary key, + creation datetime, + modified datetime, + modified_by varchar(40), + owner varchar(40), + docstatus int(1) default '0', + parent varchar(120), + parentfield varchar(120), + parenttype varchar(120), + idx int(8), + %sindex parent(parent)) ENGINE=InnoDB""" % (self.name, add_text)) +
+
[docs] def get_columns_from_docfields(self): + fl = webnotes.conn.sql("SELECT * FROM tabDocField WHERE parent = '%s'" % self.doctype, as_dict = 1) + + for f in fl: + if not f.get('no_column'): + self.columns[f['fieldname']] = DbColumn(self, f['fieldname'], f['fieldtype'], f.get('length'), f['default'], f['search_index'], f['options']) +
+
[docs] def get_columns_from_db(self): + self.show_columns = webnotes.conn.sql("desc `%s`" % self.name) + for c in self.show_columns: + self.current_columns[c[0]] = {'name': c[0], 'type':c[1], 'index':c[3], 'default':c[4]} +
+
[docs] def get_column_definitions(self): + column_list = [] + default_columns + ret = [] + for k in self.columns.keys(): + if k not in column_list: + d = self.columns[k].get_definition() + if d: + ret.append('`'+ k+ '` ' + d) + column_list.append(k) + return ret +
+
[docs] def get_index_definitions(self): + ret = [] + for k in self.columns.keys(): + if type_map.get(self.columns[k].fieldtype) and type_map.get(self.columns[k].fieldtype.lower())[0] not in ('text', 'blob'): + ret.append('index `' + k + '`(`' + k + '`)') + return ret + + + # GET foreign keys
+
[docs] def get_foreign_keys(self): + fk_list = [] + txt = webnotes.conn.sql("show create table `%s`" % self.name)[0][1] + for line in txt.split('\n'): + if line.strip().startswith('CONSTRAINT') and line.find('FOREIGN')!=-1: + try: + fk_list.append((line.split('`')[3], line.split('`')[1])) + except IndexError, e: + pass + + return fk_list + + # Drop foreign keys
+
[docs] def drop_foreign_keys(self): + if not self.drop_foreign_key: + return + + fk_list = self.get_foreign_keys() + + # make dictionary of constraint names + fk_dict = {} + for f in fk_list: + fk_dict[f[0]] = f[1] + + # drop + for col in self.drop_foreign_key: + webnotes.conn.sql("set foreign_key_checks=0") + webnotes.conn.sql("alter table `%s` drop foreign key `%s`" % (self.name, fk_dict[col.fieldname])) + webnotes.conn.sql("set foreign_key_checks=1") +
+
[docs] def sync(self): + if not self.name in DbManager(webnotes.conn).get_tables_list(webnotes.conn.cur_db_name): + self.create() + else: + self.alter() +
+
[docs] def alter(self): + self.get_columns_from_db() + for col in self.columns.values(): + col.check(self.current_columns.get(col.fieldname, None)) + + for col in self.add_column: + webnotes.conn.sql("alter table `%s` add column `%s` %s" % (self.name, col.fieldname, col.get_definition())) + + for col in self.change_type: + webnotes.conn.sql("alter table `%s` change `%s` `%s` %s" % (self.name, col.fieldname, col.fieldname, col.get_definition())) + + for col in self.add_index: + webnotes.conn.sql("alter table `%s` add index `%s`(`%s`)" % (self.name, col.fieldname, col.fieldname)) + + for col in self.drop_index: + if col.fieldname != 'name': # primary key + webnotes.conn.sql("alter table `%s` drop index `%s`" % (self.name, col.fieldname)) + + + for col in self.set_default: + webnotes.conn.sql("alter table `%s` alter column `%s` set default %s" % (self.name, col.fieldname, '%s'), col.default) + + +# ------------------------------------------------- +# Class database column +# ------------------------------------------------- +
+
[docs]class DbColumn: + def __init__(self, table, fieldname, fieldtype, length, default, set_index, options): + self.table = table + self.fieldname = fieldname + self.fieldtype = fieldtype + self.length = length + self.set_index = set_index + self.default = default + self.options = options + +
[docs] def get_definition(self, with_default=1): + d = type_map.get(self.fieldtype.lower()) + + if not d: + return + + ret = d[0] + if d[1]: + ret += '(' + d[1] + ')' + if with_default and self.default and (self.default not in default_shortcuts): + ret += ' default "' + self.default.replace('"', '\"') + '"' + return ret +
+
[docs] def check(self, current_def): + column_def = self.get_definition(0) + + # no columns + if not column_def: + return + + # to add? + if not current_def: + self.fieldname = validate_column_name(self.fieldname) + self.table.add_column.append(self) + return + + # type + if current_def['type'] != column_def: + self.table.change_type.append(self) + + # index + else: + if (current_def['index'] and not self.set_index): + self.table.drop_index.append(self) + + if (not current_def['index'] and self.set_index and not (column_def in ['text','blob'])): + self.table.add_index.append(self) + + # default + if (self.default and (current_def['default'] != self.default) and (self.default not in default_shortcuts) and not (column_def in ['text','blob'])): + self.table.set_default.append(self) + +
+
[docs]class DbManager: + """ + Basically, a wrapper for oft-used mysql commands. like show tables,databases, variables etc... + + #TODO: + 0. Simplify / create settings for the restore database source folder + 0a. Merge restore database and extract_sql(from webnotes_server_tools). + 1. Setter and getter for different mysql variables. + 2. Setter and getter for mysql variables at global level?? + """ + def __init__(self,conn): + """ + Pass root_conn here for access to all databases. + """ + if conn: + self.conn = conn + + +
[docs] def get_variables(self,regex): + """ + Get variables that match the passed pattern regex + """ + return list(self.conn.sql("SHOW VARIABLES LIKE '%s'"%regex)) + +
+
[docs] def drop_all_databases(self): + """ + Danger: will delete all databases except test,mysql. + """ + db_list = self.get_database_list() + for db in db_list: + self.drop_database(db) +
+
[docs] def get_table_schema(self,table): + """ + Just returns the output of Desc tables. + """ + return list(self.conn.sql("DESC %s"%table)) + +
+
[docs] def get_tables_list(self,target): + """ + + """ + try: + self.conn.use(target) + res = self.conn.sql("SHOW TABLES;") + table_list = [] + for table in res: + table_list.append(table[0]) + return table_list + + except Exception,e: + raise e +
+
[docs] def create_user(self,user,password): + #Create user if it doesn't exist. + try: + if password: + self.conn.sql("CREATE USER '%s'@'localhost' IDENTIFIED BY '%s';" % (user[:16], password)) + else: + self.conn.sql("CREATE USER '%s'@'localhost';"%user[:16]) + except Exception, e: + raise e + +
+
[docs] def delete_user(self,target): + # delete user if exists + try: + self.conn.sql("DROP USER '%s'@'localhost';" % target) + except Exception, e: + if e.args[0]==1396: + pass + else: + raise e +
+
[docs] def create_database(self,target): + + try: + self.conn.sql("CREATE DATABASE IF NOT EXISTS `%s` ;" % target) + except Exception,e: + raise e + +
+
[docs] def drop_database(self,target): + try: + self.conn.sql("DROP DATABASE IF EXISTS `%s`;"%target) + except Exception,e: + raise e +
+
[docs] def grant_all_privileges(self,target,user): + try: + self.conn.sql("GRANT ALL PRIVILEGES ON `%s` . * TO '%s'@'localhost';" % (target, user)) + except Exception,e: + raise e +
+
[docs] def grant_select_privilges(self,db,table,user): + try: + if table: + self.conn.sql("GRANT SELECT ON %s.%s to '%s'@'localhost';" % (db,table,user)) + else: + self.conn.sql("GRANT SELECT ON %s.* to '%s'@'localhost';" % (db,user)) + except Exception,e: + raise e +
+
[docs] def flush_privileges(self): + try: + self.conn.sql("FLUSH PRIVILEGES") + except Exception,e: + raise e + +
+
[docs] def get_database_list(self): + try: + db_list = [] + ret_db_list = self.conn.sql("SHOW DATABASES") + for db in ret_db_list: + if db[0] not in ['information_schema', 'mysql', 'test', 'accounts']: + db_list.append(db[0]) + return db_list + except Exception,e: + raise e +
+
[docs] def restore_database(self,target,source,root_password): + import webnotes.defs + mysql_path = getattr(webnotes.defs, 'mysql_path', None) + mysql = mysql_path and os.path.join(mysql_path, 'mysql') or 'mysql' + + try: + ret = os.system("%s -u root -p%s %s < %s"%(mysql, root_password, target, source)) + except Exception,e: + raise e +
+
[docs] def drop_table(self,table_name): + try: + self.conn.sql("DROP TABLE IF EXISTS %s "%(table_name)) + except Exception,e: + raise e +
+
[docs] def set_transaction_isolation_level(self,scope='SESSION',level='READ COMMITTED'): + #Sets the transaction isolation level. scope = global/session + try: + self.conn.sql("SET %s TRANSACTION ISOLATION LEVEL %s"%(scope,level)) + except Exception,e: + raise e + + + +# ------------------------------------------------- +# validate column name to be code-friendly +# ------------------------------------------------- +
+
[docs]def validate_column_name(n): + n = n.replace(' ','_').strip().lower() + import re + if not re.match("[a-zA-Z_][a-zA-Z0-9_]*$", n): + webnotes.msgprint('err:%s is not a valid fieldname.<br>A valid name must contain letters / numbers / spaces.<br><b>Tip: </b>You can change the Label after the fieldname has been set' % n) + raise Exception + return n + +# ------------------------------------------------- +# sync table - called from form.py +# ------------------------------------------------- +
+
[docs]def updatedb(dt, archive=0): + """ + Syncs a `DocType` to the table + * creates if required + * updates columns + * updates indices + """ + res = webnotes.conn.sql("select ifnull(issingle, 0) from tabDocType where name=%s", dt) + if not res: + raise Exception, 'Wrong doctype "%s" in updatedb' % dt + + if not res[0][0]: + webnotes.conn.commit() + tab = DbTable(dt, archive and 'arc' or 'tab') + tab.sync() + webnotes.conn.begin() + +# patch to remove foreign keys +# ---------------------------- +
+
[docs]def remove_all_foreign_keys(): + webnotes.conn.sql("set foreign_key_checks = 0") + webnotes.conn.commit() + for t in webnotes.conn.sql("select name from tabDocType where ifnull(issingle,0)=0"): + dbtab = webnotes.model.db_schema.DbTable(t[0]) + try: + fklist = dbtab.get_foreign_keys() + except Exception, e: + if e.args[0]==1146: + fklist = [] + else: + raise e + + for f in fklist: + webnotes.conn.sql("alter table `tab%s` drop foreign key `%s`" % (t[0], f[1]))
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/doc.html b/docs/_build/html/_modules/webnotes/model/doc.html new file mode 100644 index 0000000000..8498fbaa6e --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/doc.html @@ -0,0 +1,769 @@ + + + + + + + + + webnotes.model.doc — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.doc

+"""
+Contains the Document class representing an object / record
+"""
+
+import webnotes
+import webnotes.model.meta
+
+from webnotes.utils import *
+
+# actually should be "BaseDocType" - deprecated. Only for v160
+
[docs]class SuperDocType: + def __init__(self): + pass + + def __getattr__(self, name): + if self.__dict__.has_key(name): + return self.__dict__[name] + elif self.super and hasattr(self.super, name): + return getattr(self.super, name) + else: + raise AttributeError, 'BaseDocType Attribute Error' +
+
[docs]class Document: + """ + The wn(meta-data)framework equivalent of a Database Record. + Stores,Retrieves,Updates the record in the corresponding table. + Runs the triggers required. + + The `Document` class represents the basic Object-Relational Mapper (ORM). The object type is defined by + `DocType` and the object ID is represented by `name`:: + + Please note the anamoly in the Web Notes Framework that `ID` is always called as `name` + + If both `doctype` and `name` are specified in the constructor, then the object is loaded from the database. + If only `doctype` is given, then the object is not loaded + If `fielddata` is specfied, then the object is created from the given dictionary. + + **Note 1:** + + The getter and setter of the object are overloaded to map to the fields of the object that + are loaded when it is instantiated. + + For example: doc.name will be the `name` field and doc.owner will be the `owner` field + + **Note 2 - Standard Fields:** + + * `name`: ID / primary key + * `owner`: creator of the record + * `creation`: datetime of creation + * `modified`: datetime of last modification + * `modified_by` : last updating user + * `docstatus` : Status 0 - Saved, 1 - Submitted, 2- Cancelled + * `parent` : if child (table) record, this represents the parent record + * `parenttype` : type of parent record (if any) + * `parentfield` : table fieldname of parent record (if any) + * `idx` : Index (sequence) of the child record + """ + + def __init__(self, doctype = '', name = '', fielddata = {}, prefix='tab'): + self._roles = [] + self._perms = [] + self._user_defaults = {} + self._prefix = prefix + + if fielddata: + self.fields = fielddata + else: + self.fields = {} + + if not self.fields.has_key('name'): + self.fields['name']='' # required on save + if not self.fields.has_key('doctype'): + self.fields['doctype']='' # required on save + if not self.fields.has_key('owner'): + self.fields['owner']='' # required on save + + if doctype: + self.fields['doctype'] = doctype + if name: + self.fields['name'] = name + self.__initialized = 1 + + if (doctype and name): + self._loadfromdb(doctype, name) + + def __nonzero__(self): + return True + + def __str__(self): + return str(self.fields) + + # Load Document + # --------------------------------------------------------------------------- + + def _loadfromdb(self, doctype = None, name = None): + if name: self.name = name + if doctype: self.doctype = doctype + + if webnotes.model.meta.is_single(self.doctype): + self._loadsingle() + else: + dataset = webnotes.conn.sql('select * from `%s%s` where name="%s"' % (self._prefix, self.doctype, self.name.replace('"', '\"'))) + if not dataset: + webnotes.msgprint('%s %s does not exist' % (self.doctype, self.name), 1) + raise Exception, '[WNF] %s %s does not exist' % (self.doctype, self.name) + self._load_values(dataset[0], webnotes.conn.get_description()) + + # Load Fields from dataset + # --------------------------------------------------------------------------- + + def _load_values(self, data, description): + for i in range(len(description)): + v = data[i] + self.fields[description[i][0]] = webnotes.conn.convert_to_simple_type(v) + + def _merge_values(self, data, description): + for i in range(len(description)): + v = data[i] + if v: # only if value, over-write + self.fields[description[i][0]] = webnotes.conn.convert_to_simple_type(v) + + # Load Single Type + # --------------------------------------------------------------------------- + + def _loadsingle(self): + self.name = self.doctype + dataset = webnotes.conn.sql("select field, value from tabSingles where doctype='%s'" % self.doctype) + for d in dataset: self.fields[d[0]] = d[1] + + # Setter + # --------------------------------------------------------------------------- + + def __setattr__(self, name, value): + # normal attribute + if not self.__dict__.has_key('_Document__initialized'): + self.__dict__[name] = value + elif self.__dict__.has_key(name): + self.__dict__[name] = value + else: + # field attribute + f = self.__dict__['fields'] + f[name] = value + + # Getter + # --------------------------------------------------------------------------- + + def __getattr__(self, name): + if self.__dict__.has_key(name): + return self.__dict__[name] + elif self.fields.has_key(name): + return self.fields[name] + else: + return '' + + # Get Amendement number + # --------------------------------------------------------------------------- + + def _get_amended_name(self): + am_id = 1 + am_prefix = self.amended_from + if webnotes.conn.sql('select amended_from from `tab%s` where name = "%s"' % (self.doctype, self.amended_from))[0][0] or '': + am_id = cint(self.amended_from.split('-')[-1]) + 1 + am_prefix = '-'.join(self.amended_from.split('-')[:-1]) # except the last hyphen + + self.name = am_prefix + '-' + str(am_id) + + # Set Name + # --------------------------------------------------------------------------- + + def _set_name(self, autoname, istable): + self.localname = self.name + + # get my object + import webnotes.model.code + so = webnotes.model.code.get_server_obj(self, []) + + # amendments + if self.amended_from: + self._get_amended_name() + + # by method + elif so and hasattr(so, 'autoname'): + r = webnotes.model.code.run_server_obj(so, 'autoname') + if r: return r + + # based on a field + elif autoname and autoname.startswith('field:'): + n = self.fields[autoname[6:]] + if not n: + raise Exception, 'Name is required' + self.name = n.strip() + + # based on expression + elif autoname and autoname.startswith('eval:'): + doc = self # for setting + self.name = eval(autoname[5:]) + + # call the method! + elif autoname and autoname!='Prompt': + self.name = make_autoname(autoname, self.doctype) + + # given + elif self.fields.get('__newname',''): + self.name = self.fields['__newname'] + + # default name for table + elif istable: + self.name = make_autoname('#########', self.doctype) + + # Validate Name + # --------------------------------------------------------------------------- + + def _validate_name(self, case): + + if webnotes.conn.sql('select name from `tab%s` where name=%s' % (self.doctype,'%s'), self.name): + raise NameError, 'Name %s already exists' % self.name + + # no name + if not self.name: return 'No Name Specified for %s' % self.doctype + + # new.. + if self.name.startswith('New '+self.doctype): + return 'There were some errors setting the name, please contact the administrator' + + if case=='Title Case': self.name = self.name.title() + if case=='UPPER CASE': self.name = self.name.upper() + + self.name = self.name.strip() # no leading and trailing blanks + + forbidden = ['%', "'", '"', '#', '*', '?', '`'] + for f in forbidden: + if f in self.name: + webnotes.msgprint('%s not allowed in ID (name)' % f, raise_exception =1) + + # Insert + # --------------------------------------------------------------------------- + + def _makenew(self, autoname, istable, case='', make_autoname=1): + # set owner + if not self.owner: self.owner = webnotes.session['user'] + + # set name + if make_autoname: + self._set_name(autoname, istable) + + # validate name + self._validate_name(case) + + # insert! + webnotes.conn.sql("""insert into `tab%s` (name, owner, creation, modified, modified_by) values ('%s', '%s', '%s', '%s', '%s')""" % (self.doctype, self.name, webnotes.session['user'], now(), now(), webnotes.session['user'])) + + + # Update Values + # --------------------------------------------------------------------------- + + def _update_single(self, link_list): + update_str = ["(%s, 'modified', %s)",] + values = [self.doctype, now()] + + webnotes.conn.sql("delete from tabSingles where doctype='%s'" % self.doctype) + for f in self.fields.keys(): + if not (f in ('modified', 'doctype', 'name', 'perm', 'localname', 'creation'))\ + and (not f.startswith('__')): # fields not saved + + # validate links + if link_list and link_list.get(f): + self.fields[f] = self._validate_link(link_list[f][0], self.fields[f]) + + if self.fields[f]==None: + update_str.append("(%s,%s,NULL)") + values.append(self.doctype) + values.append(f) + else: + update_str.append("(%s,%s,%s)") + values.append(self.doctype) + values.append(f) + values.append(self.fields[f]) + webnotes.conn.sql("insert into tabSingles(doctype, field, value) values %s" % (', '.join(update_str)), values) + + # Validate Links + # --------------------------------------------------------------------------- + + + + def _validate_link(self, dt, dn): + if not dt: return dn + if not dn: return None + if dt.lower().startswith('link:'): + dt = dt[5:] + if '\n' in dt: + dt = dt.split('\n')[0] + tmp = webnotes.conn.sql("""SELECT name FROM `tab%s` WHERE name = %s""" % (dt, '%s'), dn) + return tmp and tmp[0][0] or ''# match case + + # Update query + # --------------------------------------------------------------------------- + + def _update_values(self, issingle, link_list, ignore_fields=0): + if issingle: + self._update_single(link_list) + else: + update_str, values = [], [] + # set modified timestamp + self.modified = now() + self.modified_by = webnotes.session['user'] + for f in self.fields.keys(): + if (not (f in ('doctype', 'name', 'perm', 'localname', 'creation','_user_tags'))) \ + and (not f.startswith('__')): # fields not saved + + # validate links + if link_list and link_list.get(f): + self.fields[f] = self._validate_link(link_list[f][0], self.fields[f]) + + if self.fields[f]==None or self.fields[f]=='': + update_str.append("`%s`=NULL" % f) + if ignore_fields: + try: r = webnotes.conn.sql("update `tab%s` set `%s`=NULL where name=%s" % (self.doctype, f, '%s'), self.name) + except: pass + else: + values.append(self.fields[f]) + update_str.append("`%s`=%s" % (f, '%s')) + if ignore_fields: + try: r = webnotes.conn.sql("update `tab%s` set `%s`=%s where name=%s" % (self.doctype, f, '%s', '%s'), (self.fields[f], self.name)) + except: pass + if values: + if not ignore_fields: + # update all in one query + r = webnotes.conn.sql("update `tab%s` set %s where name='%s'" % (self.doctype, ', '.join(update_str), self.name), values) + + # Save values + # --------------------------------------------------------------------------- + +
[docs] def save(self, new=0, check_links=1, ignore_fields=0, make_autoname = 1): + """ + Saves the current record in the database. If new = 1, creates a new instance of the record. + Also clears temperory fields starting with `__` + + * if check_links is set, it validates all `Link` fields + * if ignore_fields is sets, it does not throw an exception for any field that does not exist in the + database table + """ + res = webnotes.model.meta.get_dt_values(self.doctype, 'autoname, issingle, istable, name_case', as_dict=1) + res = res and res[0] or {} + + # if required, make new + if new or (not new and self.fields.get('__islocal')) and (not res.get('issingle')): + r = self._makenew(res.get('autoname'), res.get('istable'), res.get('name_case'), make_autoname) + if r: + return r + + # save the values + self._update_values(res.get('issingle'), check_links and self.make_link_list() or {}, ignore_fields) + self._clear_temp_fields() + + # check permissions + # --------------------------------------------------------------------------- +
+ def _get_perms(self): + if not self._perms: + self._perms = webnotes.conn.sql("select role, `match` from tabDocPerm where parent=%s and ifnull(`read`,0) = 1 and ifnull(permlevel,0)=0", self.doctype) + + def _get_roles(self): + # check if roles match/ + if not self._roles: + if webnotes.user: + self._roles = webnotes.user.get_roles() + else: + self._roles = ['Guest'] + + def _get_user_defaults(self): + if not self._user_defaults: + self._user_defaults = webnotes.user.get_defaults() + +
[docs] def check_perm(self, verbose=0): + import webnotes + + # find roles with read access for this record at 0 + self._get_perms() + self._get_roles() + self._get_user_defaults() + + has_perm, match = 0, [] + + # loop through everything to find if there is a match + for r in self._perms: + if r[0] in self._roles: + has_perm = 1 + if r[1] and match != -1: + match.append(r[1]) # add to match check + else: + match = -1 # has permission and no match, so match not required! + + if has_perm and match and match != -1: + for m in match: + if self.fields.get(m, 'no value') in self._user_defaults.get(m, 'no default'): + has_perm = 1 + break # permission found! break + else: + has_perm = 0 + if verbose: + webnotes.msgprint("Value not allowed: '%s' for '%s'" % (self.fields.get(m, 'no value'), m)) + + + # check for access key + if webnotes.form and webnotes.form.has_key('akey'): + import webnotes.utils.encrypt + if webnotes.utils.encrypt.decrypt(webnotes.form.getvalue('akey')) == self.name: + has_perm = 1 + webnotes.response['print_access'] = 1 + + return has_perm + + # Cleanup + # --------------------------------------------------------------------------- +
+ def _clear_temp_fields(self): + # clear temp stuff + keys = self.fields.keys() + for f in keys: + if f.startswith('__'): + del self.fields[f] + + # Table methods + # --------------------------------------------------------------------------- + +
[docs] def clear_table(self, doclist, tablefield, save=0): + """ + Clears the child records from the given `doclist` for a particular `tablefield` + """ + import webnotes.model.doclist + + for d in webnotes.model.doclist.getlist(doclist, tablefield): + d.fields['__oldparent'] = d.parent + d.parent = 'old_parent:' + d.parent # for client to send it back while saving + d.docstatus = 2 + if save and not d.fields.get('__islocal'): + d.save() + self.fields['__unsaved'] = 1 +
+
[docs] def addchild(self, fieldname, childtype = '', local=0, doclist=None): + """ + Returns a child record of the give `childtype`. + + * if local is set, it does not save the record + * if doclist is passed, it append the record to the doclist + """ + if not childtype: + childtype = db_getchildtype(self.doctype, fieldname) + + d = Document() + d.parent = self.name + d.parenttype = self.doctype + d.parentfield = fieldname + d.doctype = childtype + d.docstatus = 0; + d.name = '' + d.owner = webnotes.session['user'] + + if local: + d.fields['__islocal'] = '1' # for Client to identify unsaved doc + else: + d.save(new=1) + + if doclist != None: + doclist.append(d) + + return d +
+
[docs]def addchild(parent, fieldname, childtype = '', local=0, doclist=None): + """ + + Create a child record to the parent doc. + + Example:: + + c = Document('Contact','ABC') + d = addchild(c, 'contact_updates', 'Contact Update', local = 1) + d.last_updated = 'Phone call' + d.save(1) + """ + return parent.addchild(fieldname, childtype, local, doclist) + +# Remove Child +# ------------ +
+
[docs]def removechild(d, is_local = 0): + """ + Sets the docstatus of the object d to 2 (deleted) and appends an 'old_parent:' to the parent name + """ + if not is_local: + set(d, 'docstatus', 2) + set(d, 'parent', 'old_parent:' + d.parent) + else: + d.parent = 'old_parent:' + d.parent + d.docstatus = 2 + +# Naming +# ------
+
[docs]def make_autoname(key, doctype=''): + """ + Creates an autoname from the given key: + + **Autoname rules:** + + * The key is separated by '.' + * '####' represents a series. The string before this part becomes the prefix: + Example: ABC.#### creates a series ABC0001, ABC0002 etc + * 'MM' represents the current month + * 'YY' and 'YYYY' represent the current year + + + *Example:* + + * DE/./.YY./.MM./.##### will create a series like + DE/09/01/0001 where 09 is the year, 01 is the month and 0001 is the series + """ + n = '' + l = key.split('.') + for e in l: + en = '' + if e.startswith('#'): + digits = len(e) + en = getseries(n, digits, doctype) + elif e=='YY': + import time + en = time.strftime('%y') + elif e=='MM': + import time + en = time.strftime('%m') + elif e=='YYYY': + import time + en = time.strftime('%Y') + else: en = e + n+=en + return n + +# Get Series for Autoname +# -----------------------
+
[docs]def getseries(key, digits, doctype=''): + # series created ? + if webnotes.conn.sql("select name from tabSeries where name='%s'" % key): + + # yes, update it + webnotes.conn.sql("update tabSeries set current = current+1 where name='%s'" % key) + + # find the series counter + r = webnotes.conn.sql("select current from tabSeries where name='%s'" % key) + n = r[0][0] + else: + + # no, create it + webnotes.conn.sql("insert into tabSeries (name, current) values ('%s', 1)" % key) + n = 1 + return ('%0'+str(digits)+'d') % n + + +# Get Children +# ------------ +
+
[docs]def getchildren(name, childtype, field='', parenttype='', from_doctype=0, prefix='tab'): + import webnotes + + tmp = '' + + if field: + tmp = ' and parentfield="%s" ' % field + if parenttype: + tmp = ' and parenttype="%s" ' % parenttype + + try: + dataset = webnotes.conn.sql("select * from `%s%s` where parent='%s' %s order by idx" % (prefix, childtype, name, tmp)) + desc = webnotes.conn.get_description() + except Exception, e: + if prefix=='arc' and e.args[0]==1146: + return [] + else: + raise e + + l = [] + + for i in dataset: + d = Document() + d.doctype = childtype + d._load_values(i, desc) + l.append(d) + + return l + +# Check if "Guest" is allowed to view this page +# --------------------------------------------- +
+
[docs]def check_page_perm(doc): + if doc.name=='Login Page': + return + if doc.publish: + return + + if not webnotes.conn.sql("select name from `tabPage Role` where parent=%s and role='Guest'", doc.name): + webnotes.response['exc_type'] = 'PermissionError' + raise Exception, '[WNF] No read permission for %s %s' % ('Page', doc.name) +
+
[docs]def get_report_builder_code(doc): + if doc.doctype=='Search Criteria': + from webnotes.model.code import get_code + + if doc.standard != 'No': + doc.report_script = get_code(doc.module, 'Search Criteria', doc.name, 'js') + doc.custom_query = get_code(doc.module, 'Search Criteria', doc.name, 'sql') + + +# called from everywhere +# load a record and its child records and bundle it in a list - doclist +# --------------------------------------------------------------------- +
+
[docs]def get(dt, dn='', with_children = 1, from_get_obj = 0, prefix = 'tab'): + """ + Returns a doclist containing the main record and all child records + """ + import webnotes + import webnotes.model + import webnotes.defs + + dn = dn or dt + + # load the main doc + doc = Document(dt, dn, prefix=prefix) + + # check permission - for doctypes, pages + if (dt in ('DocType', 'Page', 'Control Panel', 'Search Criteria')) or (from_get_obj and webnotes.session.get('user') != 'Guest'): + if dt=='Page' and webnotes.session['user'] == 'Guest': + check_page_perm(doc) + else: + if not doc.check_perm(): + webnotes.response['exc_type'] = 'PermissionError' + raise webnotes.ValidationError, '[WNF] No read permission for %s %s' % (dt, dn) + + # import report_builder code + get_report_builder_code(doc) + + if not with_children: + # done + return [doc,] + + # get all children types + tablefields = webnotes.model.meta.get_table_fields(dt) + + # load chilren + doclist = [doc,] + for t in tablefields: + doclist += getchildren(doc.name, t[0], t[1], dt, prefix=prefix) + + return doclist
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/doclist.html b/docs/_build/html/_modules/webnotes/model/doclist.html new file mode 100644 index 0000000000..08611123a0 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/doclist.html @@ -0,0 +1,289 @@ + + + + + + + + + webnotes.model.doclist — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.doclist

+import webnotes
+import webnotes.model
+import webnotes.model.doc
+
+
[docs]def xzip(a,b): + d = {} + for i in range(len(a)): + d[a[i]] = b[i] + return d +
+
[docs]def expand(docs): + """ + Expand a doclist sent from the client side. (Internally used by the request handler) + """ + from webnotes.utils import load_json + + docs = load_json(docs) + clist = [] + for d in docs['_vl']: + doc = xzip(docs['_kl'][d[0]], d); + clist.append(doc) + return clist +
+
[docs]def compress(doclist): + """ + Compress a doclist before sending it to the client side. (Internally used by the request handler) + + """ + if doclist and hasattr(doclist[0],'fields'): + docs = [d.fields for d in doclist] + else: + docs = doclist + + kl, vl = {}, [] + for d in docs: + dt = d['doctype'] + if not (dt in kl.keys()): + fl = d.keys() + forbidden = ['server_code_compiled'] + nl = ['doctype','localname','__oldparent','__unsaved'] + + # add client script for doctype, doctype due to ambiguity + if dt=='DocType': nl.append('__client_script') + + for f in fl: + if not (f in nl) and not (f in forbidden): + nl.append(f) + kl[dt] = nl + + ## values + fl = kl[dt] + nl = [] + for f in fl: + v = d.get(f) + + if type(v)==long: + v=int(v) + nl.append(v) + vl.append(nl) + #errprint(str({'_vl':vl,'_kl':kl})) + return {'_vl':vl,'_kl':kl} + +# Get Children List (for scripts utility) +# --------------------------------------- +
+
[docs]def getlist(doclist, field): + """ + Filter a list of records for a specific field from the full doclist + + Example:: + + # find all phone call details + dl = getlist(self.doclist, 'contact_updates') + pl = [] + for d in dl: + if d.type=='Phone': + pl.append(d) + """ + + l = [] + for d in doclist: + if d.parent and (not d.parent.lower().startswith('old_parent:')) and d.parentfield == field: + l.append(d) + return l + +# Copy doclist +# ------------ +
+
[docs]def copy_doclist(doclist, no_copy = []): + """ + Save & return a copy of the given doclist + Pass fields that are not to be copied in `no_copy` + """ + from webnotes.model.doc import Document + + cl = [] + + # main doc + c = Document(fielddata = doclist[0].fields.copy()) + + # clear no_copy fields + for f in no_copy: + if c.fields.has_key(f): + c.fields[f] = None + + c.name = None + c.save(1) + cl.append(c) + + # new parent name + parent = c.name + + # children + for d in doclist[1:]: + c = Document(fielddata = d.fields.copy()) + c.name = None + + # clear no_copy fields + for f in no_copy: + if c.fields.has_key(f): + c.fields[f] = None + + c.parent = parent + c.save(1) + cl.append(c) + + return cl + +# Validate Multiple Links +# ----------------------- +
+ +
[docs]def getvaluelist(doclist, fieldname): + """ + Returns a list of values of a particualr fieldname from all Document object in a doclist + """ + l = [] + for d in doclist: + l.append(d.fields[fieldname]) + return l +
+def _make_html(doc, link_list): + + from webnotes.utils import cstr + out = '<table class="simpletable">' + for k in doc.fields.keys(): + if k!='server_code_compiled': + v = cstr(doc.fields[k]) + + # link field + if v and (k in link_list.keys()): + dt = link_list[k] + if type(dt)==str and dt.startswith('link:'): + dt = dt[5:] + v = '<a href="index.cgi?page=Form/%s/%s">%s</a>' % (dt, v, v) + + out += '\t<tr><td>%s</td><td>%s</td></tr>\n' % (cstr(k), v) + + out += '</table>' + return out + +
[docs]def to_html(doclist): + """ +Return a simple HTML format of the doclist + """ + out = '' + link_lists = {} + + for d in doclist: + if not link_lists.get(d.doctype): + link_lists[d.doctype] = d.make_link_list() + + out += _make_html(d, link_lists[d.doctype]) + + return out +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/doctype.html b/docs/_build/html/_modules/webnotes/model/doctype.html new file mode 100644 index 0000000000..e3d22828d3 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/doctype.html @@ -0,0 +1,380 @@ + + + + + + + + + webnotes.model.doctype — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.doctype

+"""
+ DocType module
+ ==============
+ 
+ This module has the DocType class that represents a "DocType" as metadata.
+ This is usually called by the form builder or report builder.
+
+ Key functions:
+	* manage cache - read / write
+	* merge client-side scripts
+	* update properties from the modules .txt files
+
+ Cache management:
+	* Cache is stored in __DocTypeCache
+"""
+
+import webnotes
+import webnotes.model
+import webnotes.model.doclist
+import webnotes.model.doc
+
+from webnotes.utils import cstr
+
+class _DocType:
+	"""
+	   The _DocType object is created internally using the module's `get` method.
+	"""
+	def __init__(self, name):
+		self.name = name
+	
+	# is cache modified ?
+	# =================================================================
+	
+	def is_modified(self):
+		"""
+			Returns true if modified
+		"""		
+		try:
+			# doctype modified
+			modified = webnotes.conn.sql("select modified from tabDocType where name=%s", self.name)[0][0]
+	
+			# cache modified
+			cache_modified = webnotes.conn.sql("SELECT modified from `__DocTypeCache` where name='%s'" % self.name)[0][0]
+			
+		except IndexError, e:
+			return 1
+
+		return cache_modified != modified
+
+	# write to cache
+	# =================================================================
+
+	def _update_cache(self, doclist):
+		import zlib
+
+		if webnotes.conn.sql("SELECT name FROM __DocTypeCache WHERE name=%s", self.name):
+			webnotes.conn.sql("UPDATE `__DocTypeCache` SET `modified`=%s, `content`=%s WHERE name=%s", (doclist[0].modified, zlib.compress(str([d.fields for d in doclist]),2), self.name))
+		else:
+			webnotes.conn.sql("INSERT INTO `__DocTypeCache` (`name`, `modified`, `content`) VALUES (%s, %s, %s)" , (self.name, doclist[0].modified, zlib.compress(str([d.fields for d in doclist]))))
+
+	# read from cache
+	# =================================================================
+
+	def _load_from_cache(self):
+		import zlib
+	
+		doclist = eval(zlib.decompress(webnotes.conn.sql("SELECT content from `__DocTypeCache` where name=%s", self.name)[0][0]))
+		return [webnotes.model.doc.Document(fielddata = d) for d in doclist]
+
+
+	# load options for "link:" type 'Select' fields
+	# =================================================================
+			
+	def _load_select_options(self, doclist):
+		for d in doclist:
+			if d.doctype=='DocField' and d.fieldtype=='Select' and d.options and d.options[:5].lower()=='link:':
+				op = d.options.split('\n')
+				if len(op)>1 and op[1][:4].lower() == 'sql:':
+					ol = webnotes.conn.sql(op[1][4:].replace('__user', webnotes.session['user']))	
+				else:
+					t = op[0][5:].strip()
+					op = op[1:]
+					op = [oc.replace('__user', webnotes.session['user']) for oc in op]
+					
+					try:
+						# select options will always come from the user db
+						ol = webnotes.conn.sql("select name from `tab%s` where %s docstatus!=2 order by name asc" % (t, op and (' AND '.join(op) + ' AND ') or ''))
+					except:
+						ol = []
+				ol = [''] + [o[0] or '' for o in ol]
+				d.options = '\n'.join(ol)
+
+	# clear un-necessary code from going to the client side
+	# =================================================================
+
+	def _clear_code(self, doclist):
+		if self.name != 'DocType':
+			if doclist[0].server_code: doclist[0].server_code = None
+			if doclist[0].server_code_core: doclist[0].server_code_core = None
+			if doclist[0].client_script: doclist[0].client_script = None
+			if doclist[0].client_script_core: doclist[0].client_script_core = None
+			doclist[0].server_code_compiled = None
+
+	# build a list of all the records required for the DocType
+	# =================================================================
+	
+	def _get_last_update(self, dt):
+		"""
+			Returns last update timestamp
+		"""
+		try:
+			last_update = webnotes.conn.sql("select _last_update from tabDocType where name=%s", dt)[0][0]
+		except Exception, e:
+			if e.args[0]==1054: 
+				self._setup_last_update(dt)
+				last_update = None
+		
+		return last_update
+
+	def _setup_last_update(self, doctype):
+		"""
+			Adds _last_update column to tabDocType
+
+		"""
+		webnotes.conn.commit()
+		webnotes.conn.sql("alter table `tabDocType` add column _last_update varchar(32)")
+		webnotes.conn.begin()
+		
+	def _get_fields(self, file_name):
+		"""
+			Returns a dictionary of DocFields by fieldname or label
+		"""
+		try:
+			doclist = open(file_name, 'r').read()
+		except:
+			return
+		doclist = eval(doclist)
+		fields = {}
+		for d in doclist:
+			if d['doctype']=='DocField':
+				if d['fieldname'] or d['label']:
+					fields[d['fieldname'] or d['label']] = d
+		return fields
+		
+	def _update_field_properties(self, doclist):
+		"""
+			Updates properties like description, depends on from the database based on the timestamp
+			of the .txt file. Adds a column _last_updated if not exists in the database and uses
+			it to update the file..
+			
+			This feature is built because description is changed / updated quite often and is tedious to
+			write a patch every time. Can be extended to cover more updates
+		"""
+		
+		update_fields = ('description', 'depends_on')
+
+		from webnotes.modules import get_file_timestamp, get_item_file
+
+		doc = doclist[0] # main doc
+		file_name = get_item_file(doc.module, 'DocType', doc.name)
+		time_stamp = get_file_timestamp(file_name)
+		last_update = self._get_last_update(doc.name)
+		
+		# this is confusing because we are updating the fields of fields
+		
+		if last_update != time_stamp:
+
+			# there are updates!
+			fields = self._get_fields(file_name)
+			if fields:
+				for d in doclist:
+				
+					# for each field in teh outgoing doclist
+					if d.doctype=='DocField':
+						key = d.fieldname or d.label
+					
+						# if it has a fieldname or label
+						if key and key in fields:
+						
+							# update the values
+							for field_to_update in update_fields:
+								new_value = fields[key][field_to_update]
+							
+								# in doclist
+								d.fields[field_to_update] = new_value
+							
+								# in database
+								webnotes.conn.sql("update tabDocField set `%s` = %s where parent=%s and `%s`=%s" % \
+									(field_to_update, '%s', '%s', (d.fieldname and 'fieldname' or 'label'), '%s'), \
+									(new_value, doc.name, key))
+					
+				webnotes.conn.sql("update tabDocType set _last_update=%s where name=%s", (time_stamp, doc.name))
+	
+	def _override_field_properties(self, doclist):
+		"""
+			Override field properties that are updated by "Property Setter"
+			The term "property" is used to define a fieldname of a field to avoid confusing
+			terminology
+		"""
+		# load field properties and add them to a dictionary
+		property_dict = {}
+		dt = doclist[0].name
+		try:
+			for f in webnotes.conn.sql("select doc_name, property, property_type, value from `tabProperty Setter` where doc_type=%s", dt, as_dict=1):
+				if not f['doc_name'] in property_dict:
+					property_dict[f['doc_name']] = []
+				property_dict[f['doc_name']].append(f)
+		except Exception, e:
+			if e.args[0]==1146:
+				# no override table
+				pass
+			else: 
+				raise e
+
+		# loop over fields and override property
+		for d in doclist:
+			if d.doctype=='DocField' and d.name in property_dict:
+				for p in property_dict[d.name]:
+					if p['property_type']=='Check':
+						d.fields[p['property']] = int(p['value'])
+					else:
+						d.fields[p['property']] = p['value']
+					
+		# override properties in the main doctype
+		if dt in property_dict:
+			for p in property_dict[self.name]:
+				doclist[0].fields[p['property']] = p['value']
+				
+
+	def make_doclist(self):
+		"""
+		      returns the :term:`doclist` for consumption by the client
+		      
+		      * it cleans up the server code
+		      * executes all `$import` tags in client code
+		      * replaces `link:` in the `Select` fields
+		      * loads all related `Search Criteria`
+		      * updates the cache
+		"""
+		from webnotes.modules import compress
+		
+		tablefields = webnotes.model.meta.get_table_fields(self.name)
+
+		if self.is_modified():
+			# yes
+			doclist = webnotes.model.doc.get('DocType', self.name, 1)
+			
+			self._update_field_properties(doclist)
+			self._override_field_properties(doclist)
+			
+			# table doctypes
+			for t in tablefields: 
+				table_doclist = webnotes.model.doc.get('DocType', t[0], 1)
+				
+				self._override_field_properties(table_doclist)
+				doclist += table_doclist
+
+			# don't save compiled server code
+
+		else:
+			doclist = self._load_from_cache()
+			
+		doclist[0].fields['__client_script'] = compress.get_doctype_js(self.name)
+		self._load_select_options(doclist)
+		self._clear_code(doclist)
+
+		return doclist
+
+
[docs]def clear_cache(): + webnotes.conn.sql("delete from __DocTypeCache") + +# Load "DocType" - called by form builder, report buider and from code.py (when there is no cache) +#================================================================================================= +
+
[docs]def get(dt): + """ + Load "DocType" - called by form builder, report buider and from code.py (when there is no cache) + """ + doclist = _DocType(dt).make_doclist() + + return doclist +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/import_docs.html b/docs/_build/html/_modules/webnotes/model/import_docs.html new file mode 100644 index 0000000000..86d712aee0 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/import_docs.html @@ -0,0 +1,512 @@ + + + + + + + + + webnotes.model.import_docs — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.import_docs

+import webnotes
+
+
[docs]def import_docs(docs = []): + from webnotes.model.doc import Document + import webnotes.model.code + + doc_list = {} + created_docs = [] + already_exists = [] + + out, tmp ="", "" + + for d in docs: + cur_doc = Document(fielddata = d) + if not cur_doc.parent in already_exists: # parent should not exist + try: + cur_doc.save(1) + out += "Created: " + cur_doc.name + "\n" + created_docs.append(cur_doc) + + # make in groups + if cur_doc.parent: + if not doc_list.has_key(cur_doc.parent): + doc_list[cur_doc.parent] = [] + doc_list[cur_doc.parent].append(cur_doc) + + except Exception, e: + out += "Creation Warning/Error: " + cur_doc.name + " :"+ str(e) + "\n" + already_exists.append(cur_doc.name) + + # Run scripts for main docs + for m in created_docs: + if doc_list.has_key(m.name): + tmp = webnotes.model.code.run_server_obj(webnotes.model.code.get_server_obj(m, doc_list.get(m.name, [])),'on_update') + + # update database (in case of DocType) + if m.doctype=='DocType': + import webnotes.model.doctype + try: webnotes.model.doctype.update_doctype(doc_list.get(m.name, [])) + except: pass + out += 'Executed: '+ str(m.name) + ', Err:' + str(tmp) + "\n" + + return out + +#====================================================================================================================================== +
+import webnotes +import webnotes.utils +sql = webnotes.conn.sql +flt = webnotes.utils.flt +cint = webnotes.utils.cint +cstr = webnotes.utils.cstr + +
[docs]class CSVImport: + def __init__(self): + self.msg = [] + self.csv_data = None + self.import_date_format = None + +
[docs] def validate_doctype(self, dt_list): + cl, tables, self.dt_list, self.prompt_autoname_flag = 0, [t[0] for t in sql("show tables")], [], 0 + self.msg.append('<p><b>Identifying Documents</b></p>') + dtd = sql("select name, istable, autoname from `tabDocType` where name = '%s' " % dt_list[0]) + if dtd and dtd[0][0]: + self.msg.append('<div style="color: GREEN">Identified Document: ' + dt_list[0] + '</div>') + self.dt_list.append(dt_list[0]) + if dtd[0][2] and 'Prompt' in dtd[0][2]: self.prompt_autoname_flag = 1 + if flt(dtd[0][1]): + res1 = sql("select parent, fieldname from tabDocField where options='%s' and fieldtype='Table' and docstatus!=2" % self.dt_list[0]) + if res1 and res1[0][0] == dt_list[1]: + self.msg.append('<div style="color: GREEN">Identified Document: ' + dt_list[1] + '</div>') + self.dt_list.append(dt_list[1]) + else : + self.msg.append('<div style="color:RED"> Error: At Row 1, Column 2 => %s is not a valid Document </div>' % dt_list[1]) + self.validate_success = 0 + + if res1 and res1[0][1] == dt_list[2]: + self.msg.append('<div style="color: GREEN" >Identified Document Fieldname: ' + dt_list[2] + '</div>') + self.dt_list.append(dt_list[2]) + else : + self.msg.append('<div style="color:RED"> Error: At Row 1, Column 3 => %s is not a valid Fieldname </div>' % dt_list[2]) + self.validate_success = 0 + elif dt_list[1]: + self.msg.append('<div style="color:RED"> Error: At Row 1, Column 1 => %s is not a Table. </div>' % dt_list[0]) + self.validate_success = 0 + else: + self.msg.append('<div style="color:RED"> Error: At Row 1, Column 1 => %s is not a valid Document </div>' % dt_list[0]) + self.validate_success = 0 + +
+
[docs] def validate_fields(self, lb_list): + self.msg.append('<p><b>Checking fieldnames for %s</b></p>' % self.dt_list[0]) + if len(self.dt_list) > 1 and self.overwrite: + self.msg.append('<div style="color:RED"> Error: Overwrite is not possible for Document %s </div>' % self.dt_list[0]) + self.validate_success = 0 + return + + elif self.overwrite and 'Name' != lb_list[0]: + self.msg.append('<div style="color:RED"> Error : At Row 4 and Column 1: To Overwrite fieldname should be Name </div>') + self.validate_success = 0 + return + # labelnames + res = self.validate_success and [d[0] for d in sql("select label from tabDocField where parent='%s' and docstatus!=2 and ifnull(hidden,'') in ('',0)" % self.dt_list[0])] or [] + + if len(self.dt_list) > 1 and self.dt_list[1]: + self.fields.append('parent') + lb_list.pop(lb_list.index(self.dt_list[1])) + + dtd = sql("select autoname from `tabDocType` where name = '%s' " % self.dt_list[0])[0][0] + if self.prompt_autoname_flag or self.overwrite: + self.fields.append('name') + res.append('Name') + lb_list.pop(lb_list.index('Name')) + + cl = 1 + for l in lb_list: + try: + if l: + if not (l in res): + self.msg.append('<div style="color: RED">Error : At Row 4 and Column %s Field %s is not present in %s</div>' % (cl, l, self.dt_list[0])) + self.validate_success = 0 + # this condition is for child doctype + + else: self.fields.append(sql("select fieldname from tabDocField where parent ='%s' and label = '%s' and ifnull(fieldname,'') !='' " % (self.dt_list[0], l))[0][0] or '') + except Exception, e: + self.msg.append('<div style="color: RED"> At Row 4 and Column %s : =>ERROR: %s </div>' % ( cl, e)) + self.validate_success = 0 + cl = cl + 1 + + if not self.overwrite: + # get_reqd_fields + reqd_list = [d[0] for d in sql("select label from `tabDocField` where parent = '%s' and ifnull(reqd,'') not in ('', 0) and docstatus !=2" % self.dt_list[0]) if d[0] not in lb_list] or [] + + # Check if Reqd field not present in self.fields + if reqd_list: + self.msg.append('<div style="color: RED"> Error : At Row 4 Mandatory Fields %s of Document %s are Required. </div>' %(reqd_list , self.dt_list[0])) + self.validate_success = 0 + if self.validate_success: + self.msg.append('<div style="color: GREEN">Fields OK for %s</div>' % self.dt_list[0]) +
+
[docs] def validate_headers(self): + self.validate_doctype(self.doctype_data) + if self.validate_success: + self.validate_fields(self.labels) + + # Date parsing + # --------------------------------------------------------------------
+
[docs] def parse_date(self, r, c, d): + out = '' + try: + if self.import_date_format=='yyyy-mm-dd': + tmpd = d.split('-') + + if len(tmpd)==3: + out = tmpd[0] + '-'+tmpd[1] + '-' + tmpd[2] + + elif d and self.import_date_format=='dd-mm-yyyy': + tmpd = d.split('-') + + if len(tmpd)==3: + out = tmpd[2]+'-'+tmpd[1]+'-'+tmpd[0] + + elif d and self.import_date_format=='mm/dd/yyyy': + tmpd = d.split('/') + + if len(tmpd)==3: + out = tmpd[2]+'-'+tmpd[0]+'-'+tmpd[1] + + elif d and self.import_date_format=='mm/dd/yy': + tmpd = d.split('/') + + if len(tmpd)==3: + out = '20'+tmpd[2]+'-'+tmpd[0]+'-'+tmpd[1] + + elif d and self.import_date_format=='dd/mm/yyyy': + tmpd = d.split('/') + if len(tmpd)==3: + out = tmpd[2]+'-'+tmpd[1]+'-'+tmpd[0] + + elif d and self.import_date_format=='dd/mm/yy': + tmpd = d.split('/') + if len(tmpd)==3: + out = '20'+tmpd[2]+'-'+tmpd[1]+'-'+tmpd[0] + + if len(tmpd) != 3: + self.msg.append('<div style="color: RED"> At Row %s and Column %s : => Date Format selected as %s does not match with Date Format in File</div>' % (r, c, str(self.import_date_format))) + self.validate_success = 0 + else: + + import datetime + dt = out.split('-') + datetime.date(int(dt[0]),int(dt[1]), int(dt[2])) + except Exception, e: + self.msg.append('<div style="color: RED"> At Row %s and Column %s : =>ERROR: %s </div>' % (r, c, e)) + self.validate_success = 0 + self.msg.append(out) + return out +
+ +
[docs] def get_field_type_list(self): + # get_date_fields + date_list = [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and fieldtype='Date' and docstatus !=2" % self.dt_list[0])] + + # get_link_fields + link_list = [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and ((fieldtype='Link' and ifnull(options,'') != '') or (fieldtype='Select' and ifnull(options,'') like '%%link:%%')) and docstatus !=2 " % self.dt_list[0])] + + # get_select_fileds + select_list = [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and fieldtype='Select' and ifnull(options,'') not like '%%link:%%' and docstatus !=2" % self.dt_list[0])] + + # get_reqd_fields + reqd_list = self.overwrite and ['name'] or [d[0] for d in sql("select fieldname from `tabDocField` where parent = '%s' and ifnull(reqd,'') not in ('', 0) and docstatus !=2" % self.dt_list[0])] + + if len(self.dt_list)> 1 and 'parent' not in reqd_list: reqd_list.append('parent') + + if self.prompt_autoname_flag and 'name' not in reqd_list: reqd_list.append('name') + + return date_list, link_list, select_list, reqd_list + +
+
[docs] def validate_data(self): + self.msg.append('<p><b>Checking Data for %s</b></p>' % self.dt_list[0]) + date_list, link_list, select_list, reqd_list = self.get_field_type_list() + + + # load data + row = 5 + for d in self.data: + self.validate_success, fd, col = 1, {}, 1 + self.msg.append('<p><b>Checking Row %s </b></p>' % (row)) + for i in range(len(d)): + if i < len(self.fields): + f = self.fields[i] + try: + # Check Reqd Fields + if (f in reqd_list) and not d[i]: + self.msg.append('<div style="color: RED">Error: At Row %s and Column %s, Field %s is Mandatory.</div>' % (row, col, f)) + self.validate_success = 0 + + # Check Date Fields + if d[i] and f and f in date_list : fd[f] = self.parse_date(row, col, d[i]) + + # Check Link Fields + elif d[i] and f in link_list: + fd[f] = self.check_select_link_data(row, col, f, d[i], l='Link') + + # Check Select Fields + elif d[i] and f in select_list: + fd[f] = self.check_select_link_data(row, col, f, d[i], s= 'Select') + + # Need To Perform Check For Other Data Type Too + else: fd[f] = d[i] + + except Exception: + self.msg.append('<div style="color: RED"> ERROR: %sData:%s and %s and %s and %s</div>' % (str(webnotes.utils.getTraceback()) + '\n', str(d), str(f), str(date_list), str(link_list))) + self.validate_success = 0 + elif d[i]: + self.validate_success = 0 + self.msg.append('<div style="color: RED">At Row %s and Column %s</div>' % (row,col)) + self.msg.append('<div style="color: ORANGE">Ignored</div>') + col = col + 1 + if self.validate_success: + self.msg.append('<div style="color: GREEN">At Row %s and Column %s, Data Verification Completed </div>' % (row,col)) + self.update_data(fd,row) + row = row + 1 +
+
[docs] def update_data(self, fd, row): + # load metadata + from webnotes.model.doc import Document + cur_doc = Document(fielddata = fd) + cur_doc.doctype, cur_doc.parenttype, cur_doc.parentfield = self.dt_list[0], len(self.dt_list) > 1 and self.dt_list[1] or '', len(self.dt_list) > 1 and self.dt_list[2] or '' + obj = '' + # save the document + try: + if webnotes.conn.in_transaction: + sql("COMMIT") + sql("START TRANSACTION") + if cur_doc.name and webnotes.conn.exists(self.dt_list[0], cur_doc.name): + if self.overwrite: + cur_doc.save() + obj = webnotes.model.code.get_obj(cur_doc.parent and cur_doc.parent_type or cur_doc.doctype, cur_doc.parent or cur_doc.name, with_children = 1) + self.msg.append('<div style="color: ORANGE">Row %s => Over-written: %s</div>' % (row, cur_doc.name)) + else: + self.msg.append('<div style="color: ORANGE">Row %s => Ignored: %s</div>' % (row, cur_doc.name)) + else: + if cur_doc.parent and webnotes.conn.exists(cur_doc.parenttype, cur_doc.parent) or not cur_doc.parent: + cur_doc.save(1) + obj = webnotes.model.code.get_obj(cur_doc.parent and cur_doc.parenttype or cur_doc.doctype, cur_doc.parent or cur_doc.name, with_children = 1) + self.msg.append('<div style="color: GREEN">Row %s => Created: %s</div>' % (row, cur_doc.name)) + else: + self.msg.append('<div style="color: RED">Row %s => Invalid %s : %s</div>' % (row, cur_doc.parenttype, cur_doc.parent)) + except Exception: + self.msg.append('<div style="color: RED"> Validation: %s</div>' % str(webnotes.utils.getTraceback())) + try: + if obj: + if hasattr(obj, 'validate') : obj.validate() + if hasattr(obj, 'on_update') : obj.on_update() + if hasattr(obj, 'on_submit') : obj.on_submit() + sql("COMMIT") + + except Exception: + sql("ROLLBACK") + self.msg.append('<div style="color: RED"> Validation: %s</div>' % str(webnotes.message_log[-1:])) + + # do import + # --------------------------------------------------------------------
+
[docs] def import_csv(self, csv_data, import_date_format = 'yyyy-mm-dd', overwrite = 0): + import csv + self.validate_success, self.csv_data = 1, self.convert_csv_data_into_list(csv.reader(csv_data.splitlines())) + self.import_date_format, self.overwrite = import_date_format, overwrite + if len(self.csv_data) > 4: + + self.doctype_data, self.labels, self.data = self.csv_data[0][:4], self.csv_data[3], self.csv_data[4:] + self.fields = [] + + import webnotes.model.code + from webnotes.model.doc import Document + sql = webnotes.conn.sql + + self.validate_headers() + if self.validate_success: + self.validate_data() + else: + self.msg.append('<p><b>No data entered in file.</b></p>') + return '\n'.join(self.msg) +
+
[docs] def convert_csv_data_into_list(self,csv_data): + st_list = [] + for s in csv_data: + st_list.append([d.strip() for d in s]) + return st_list + +# Get Template method +# ----------------------------------------------------------------- +
+
[docs]def get_template(): + import webnotes.model + + from webnotes.utils import getCSVelement + + form = webnotes.form + sql = webnotes.conn.sql + # get form values + dt = form.getvalue('dt') + overwrite = cint(form.getvalue('overwrite')) or 0 + + pt, pf = '', '' + tmp_lbl, tmp_ml = [],[] + + # is table? + dtd = sql("select istable, autoname from tabDocType where name='%s'" % dt) + if dtd and dtd[0][0]: + res1 = sql("select parent, fieldname from tabDocField where options='%s' and fieldtype='Table' and docstatus!=2" % dt) + if res1: + pt, pf = res1[0][0], res1[0][1] + + # line 1 + dset = [] + if pt and pf: + lbl, ml = [pt], ['[Mandatory]'] + line1 = '%s,%s,%s' % (getCSVelement(dt), getCSVelement(pt), getCSVelement(pf)) + line2 = ',,,,,,Please fill valid %(p)s No in %(p)s column.' % {'p':getCSVelement(pt)} + else: + if dtd[0][1]=='Prompt' or overwrite: + lbl, ml= ['Name'], ['[Mandatory][Special Characters are not allowed]'] + else: + lbl, ml= [], [] + line1 = '%s' % getCSVelement(dt) + line2 = (overwrite and ',,,,,,Please fill valid %(d)s No in %(n)s' % {'d':dt,'n': 'Name'}) or ',,' + + # Help on Line + line1 = line1 + ',,,Please fill columns which are Mandatory., Please do not modify the structure' + + # fieldnames + res = sql("select fieldname, fieldtype, label, reqd, hidden from tabDocField where parent='%s' and docstatus!=2" % dt) + + for r in res: + # restrict trash_reason field, hidden and required fields + if not r[1] in webnotes.model.no_value_fields and r[0] != 'trash_reason' and not r[4] and not r[3]: + tmp_lbl.append(getCSVelement(r[2])) + tmp_ml.append('') + # restrict trash_reason field and hidden fields and add Mandatory indicator for required fields + elif not r[1] in webnotes.model.no_value_fields and r[0] != 'trash_reason' and not r[4] and r[3]: + lbl.append(getCSVelement(r[2])) + ml.append(getCSVelement('[Mandatory]')) + + dset.append(line1) + dset.append(line2) + dset.append(','.join(ml + tmp_ml)) + dset.append(','.join(lbl + tmp_lbl)) + + txt = '\n'.join(dset) + webnotes.response['result'] = txt + webnotes.response['type'] = 'csv' + webnotes.response['doctype'] = dt +
+ +
+
+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/meta.html b/docs/_build/html/_modules/webnotes/model/meta.html new file mode 100644 index 0000000000..18aae5a0ad --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/meta.html @@ -0,0 +1,155 @@ + + + + + + + + + webnotes.model.meta — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.meta

+# metadata
+
+import webnotes
+	
+#=================================================================================
+
+
[docs]def get_dt_values(doctype, fields, as_dict = 0): + return webnotes.conn.sql('SELECT %s FROM tabDocType WHERE name="%s"' % (fields, doctype), as_dict = as_dict) +
+
[docs]def set_dt_value(doctype, field, value): + return webnotes.conn.set_value('DocType', doctype, field, value) +
+
[docs]def is_single(doctype): + try: + return get_dt_values(doctype, 'issingle')[0][0] + except IndexError, e: + raise Exception, 'Cannot determine whether %s is single' % doctype + +#================================================================================= +
+
[docs]def get_parent_dt(dt): + parent_dt = webnotes.conn.sql('select parent from tabDocField where fieldtype="Table" and options="%s" and (parent not like "old_parent:%%") limit 1' % dt) + return parent_dt and parent_dt[0][0] or '' + +#================================================================================= +
+
[docs]def set_fieldname(field_id, fieldname): + webnotes.conn.set_value('DocField', field_id, 'fieldname', fieldname) + +#================================================================================= +
+ +
[docs]def get_table_fields(doctype): + return webnotes.conn.sql("select options, fieldname from tabDocField where parent='%s' and fieldtype='Table'" % doctype) + +#================================================================================= +
+
[docs]def get_search_criteria(dt): + import webnotes.model.doc + # load search criteria for reports (all) + dl = [] + sc_list = webnotes.conn.sql("select name from `tabSearch Criteria` where doc_type = '%s' or parent_doc_type = '%s' and (disabled!=1 OR disabled IS NULL)" % (dt, dt)) + for sc in sc_list: + if sc[0]: + dl += webnotes.model.doc.get('Search Criteria', sc[0]) + return dl + +#================================================================================= +
+
[docs]def get_print_format_html(name): + html = webnotes.conn.sql('select html from `tabPrint Format` where name="%s"' % name) + return html and html[0][0] or '' +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/modules.html b/docs/_build/html/_modules/webnotes/model/modules.html new file mode 100644 index 0000000000..ccaecb03be --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/modules.html @@ -0,0 +1,124 @@ + + + + + + + + + webnotes.model.modules — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.modules

+# Modules
+# -----------
+
+
[docs]def get_module_items(mod, only_dt=0): + dl = [] + if only_dt: + transfer_types = ['DocType'] + else: + transfer_types = ['Role', 'Page', 'DocType', 'DocType Mapper', 'Search Criteria'] + dl = ['Module Def,'+mod] + + for dt in transfer_types: + try: + dl2 = sql('select name from `tab%s` where module="%s"' % (dt,mod)) + dl += [(dt+','+e[0]) for e in dl2] + except: + pass + + if not only_dt: + dl1 = sql('select doctype_list from `tabModule Def` where name=%s', mod) + dl += dl1[0][0].split('\n') + + # build finally + dl = [e.split(',') for e in dl] + dl = [[e[0].strip(), e[1].strip()] for e in dl] # remove blanks + return dl
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/model/triggers.html b/docs/_build/html/_modules/webnotes/model/triggers.html new file mode 100644 index 0000000000..02e39261e9 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/model/triggers.html @@ -0,0 +1,166 @@ + + + + + + + + + webnotes.model.triggers — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.model.triggers

+"""
+Add, manage, fire triggers (events / observers)
+Standard events called by the framework are "save, submit, cancel"
+"""
+
+import webnotes
+
+
[docs]def insert_trigger(doctype, docname, event_name, method): + "inserts a new trigger record" + + from webnotes.model.doc import Document + d = Document('DocTrigger') + d.doc_type = doctype + d.doc_name = docname + d.event_name = event_name + d.method = method + d.save(1) +
+
[docs]def add_trigger(doctype, docname, event_name, method): + """Add a trigger to an event on a doctype, docname. The specified method will be called. + Wild card '*' is allowed in doctype, docname and/or event_name""" + + try: + if not trigger_exists(doctype, docname, event_name, method): + insert_trigger(doctype, docname, event_name, method) + except Exception, e: + if e.args[0]==1146: + setup() + insert_trigger(doctype, docname, event_name, method) + else: raise e +
+
[docs]def trigger_exists(doctype, docname, event_name, method): + "returns true if trigger exists" + return webnotes.conn.sql("select name from tabDocTrigger where doc_name=%s and doc_type=%s and event_name=%s and method=%s", \ + (doctype, docname, event_name, method)) +
+
[docs]def remove_trigger(doctype, docname, event_name, method): + "Remove a trigger on an event" + webnotes.conn.sql("delete from tabDocTrigger where doc_name=%s and doc_type=%s and event_name=%s and method=%s", \ + (doctype, docname, event_name, method)) +
+
[docs]def fire_event(doc, event_name): + "Fire all triggers on an event and passes the doc to the trigger" + try: + tl = webnotes.conn.sql("""select method from tabDocTrigger + where (doc_type=%s or doc_type='*') + and (doc_name=%s or doc_name='*') + and (event_name=%s or event_name='*')""", (doc.doctype, doc.name, event_name)) + except Exception, e: + if e.args[0]==1146: + setup() + tl = [] + else: raise e + + for t in tl: + module, method = '.'.join(t[0].split('.')[:-1]), t[0].split('.')[-1] + exec 'from %s import %s' % (module, method) in locals() + locals()[method](doc) +# +# setup +#
+
[docs]def setup(): + "creates the DocTrigger table from core" + webnotes.conn.commit() + from webnotes.modules.module_manager import reload_doc + reload_doc('core','doctype','doctrigger') + webnotes.conn.begin() +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/modules.html b/docs/_build/html/_modules/webnotes/modules.html new file mode 100644 index 0000000000..cdcb3ea711 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/modules.html @@ -0,0 +1,183 @@ + + + + + + + + + webnotes.modules — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.modules

+"""
+	Utilities for using modules
+"""
+
+transfer_types = ['Role', 'Print Format','DocType','Page','DocType Mapper','GL Mapper','Search Criteria', 'Patch']
+
+
[docs]def scrub(txt): + return txt.replace(' ','_').replace('-', '_').replace('/', '_').lower() +
+
[docs]def scrub_dt_and_dn(dt, dn): + """ + Returns in lowercase and code friendly names of doctype and name for certain types + """ + ndt, ndn = dt, dn + if dt.lower() in ('doctype', 'search criteria', 'page'): + ndt, ndn = scrub(dt), scrub(dn) + + return ndt, ndn +
+
[docs]def get_item_file(module, dt, dn): + """ + Returns the path of the item file + """ + import os + ndt, ndn = scrub_dt_and_dn(dt, dn) + + return os.path.join(get_module_path(module), ndt, ndn, ndn + '.txt') +
+
[docs]def get_item_timestamp(module, dt, dn): + """ + Return ths timestamp of the given item (if exists) + """ + return get_file_timestamp(get_item_file(module, dt, dn)) +
+
[docs]def get_file_timestamp(fn): + """ + Returns timestamp of the given file + """ + import os + from webnotes.utils import cint + + try: + return str(cint(os.stat(fn).st_mtime)) + except OSError, e: + if e.args[0]!=2: + raise e + else: + return None +
+
[docs]def get_module_path(module): + """ + Returns path of the given module (imports it and reads it from __file__) + """ + import webnotes.defs, os, os.path + + try: + exec ('import ' + scrub(module)) in locals() + modules_path = eval(scrub(module) + '.__file__') + + modules_path = os.path.sep.join(modules_path.split(os.path.sep)[:-1]) + except ImportError, e: + # get module path by importing the module + modules_path = os.path.join(webnotes.defs.modules_path, scrub(module)) + + return modules_path +
+
[docs]def switch_module(dt, dn, to, frm=None, export=None): + """ + Change the module of the given doctype, if export is true, then also export txt and copy + code files from src + """ + import os + webnotes.conn.sql("update `tab"+dt+"` set module=%s where name=%s", (to, dn)) + + if export: + export_doc(dt, dn) + + # copy code files + if dt in ('DocType', 'Page', 'Search Criteria'): + from_path = os.path.join(get_module_path(frm), scrub(dt), scrub(dn), scrub(dn)) + to_path = os.path.join(get_module_path(to), scrub(dt), scrub(dn), scrub(dn)) + + # make dire if exists + os.system('mkdir -p %s' % os.path.join(get_module_path(to), scrub(dt), scrub(dn))) + + for ext in ('py','js','html','css'): + os.system('cp %s %s') +
+ +
+
+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/modules/compress.html b/docs/_build/html/_modules/webnotes/modules/compress.html new file mode 100644 index 0000000000..07963a728c --- /dev/null +++ b/docs/_build/html/_modules/webnotes/modules/compress.html @@ -0,0 +1,440 @@ + + + + + + + + + webnotes.modules.compress — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.modules.compress

+"""
+Load compressed .js page scripts
+
+Will also replace $import(page) or $import(module.page) with the relevant js files
+"""
+
+
+# load "compressed" js code from modules
+#==============================================================================
+
+
[docs]def get_js_code(fn, extn='js'): + """ + Get js code from a file (uncompressed) + """ + import webnotes + from webnotes.modules import scrub, get_file_timestamp + + src_file_name = fn + '.' + extn + + # src_timestamp = get_file_timestamp(src_file_name) + + # if no source, return + #if not src_timestamp: + # return '' + + # if timestamps are not same, compress + #if src_timestamp != get_file_timestamp(comp_file_name): + # compress(src_file_name, comp_file_name) + + # get the code + try: + file = open(src_file_name, 'r') + except IOError, e: + return '' + + code = file.read() + file.close() + + # return + return code + +# get doctype client +#============================================================================== +
+
[docs]def sub_get_doctype_js(match): + name = match.group('name') + return get_doctype_js(name) +
+
[docs]def get_doctype_js(dt): + """ + Returns the client-side (js) code of the DocType. + Adds custom script + and replaces $import(dt) with the code of that DocType + """ + import webnotes, os + from webnotes.modules import scrub, get_module_path + from webnotes.model.code import get_custom_script + + module = scrub(webnotes.conn.get_value('DocType',dt,'module')) + + code = get_js_code(os.path.join(get_module_path(scrub(module)), 'doctype', scrub(dt), scrub(dt))) \ + + '\n' + (get_custom_script(dt, 'Client') or '') + + # compile for import + if code.strip(): + import re + p = re.compile('\$import\( (?P<name> [^)]*) \)', re.VERBOSE) + + code = p.sub(sub_get_doctype_js, code) + + return code + +# get page client +#============================================================================== +
+
[docs]def sub_get_page_js(match): + from webnotes.model.doc import Document + + name = match.group('name') + + if '.' in name: + name = name.split('.') + return get_page_js(name[1], name[0]) + + return get_page_js(Document('Page', name)) +
+
[docs]def get_page_js(page, module=None): + """ + Returns the js code of a page. Will replace $import (page) or $import(module.page) + with the code from the file + """ + import webnotes, os + from webnotes.modules import scrub, get_module_path + + if type(page)==str: + page_name = page + else: + page_name, module = page.name, page.module + + code = get_js_code(os.path.join(get_module_path(module), 'page', scrub(page_name), scrub(page_name))) + + if not code and type(page)!=str: + code = page.script + + # compile for import + if code and code.strip(): + import re + p = re.compile('\$import\( (?P<name> [^)]*) \)', re.VERBOSE) + + code = p.sub(sub_get_page_js, code) + + return code + + +# compress +#============================================================================== +
+
[docs]def compress(src, comp): + out = open(comp, 'w') + + jsm = JavascriptMinify() + jsm.minify(open(src,'r'), out) + + out.close() + + + + +#============================================================================== +#============================================================================== +# +# This code is original from jsmin by Douglas Crockford, it was translated to +# Python by Baruch Even. The original code had the following copyright and +# license. +# +# /* jsmin.c +# 2007-05-22 +# +# Copyright (c) 2002 Douglas Crockford (www.crockford.com) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# The Software shall be used for Good, not Evil. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# */ +
+from StringIO import StringIO + +
[docs]def jsmin(js): + ins = StringIO(js) + outs = StringIO() + JavascriptMinify().minify(ins, outs) + str = outs.getvalue() + if len(str) > 0 and str[0] == '\n': + str = str[1:] + return str +
+
[docs]def isAlphanum(c): + """return true if the character is a letter, digit, underscore, + dollar sign, or non-ASCII character. + """ + return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or + (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126)); +
+
[docs]class UnterminatedComment(Exception): + pass +
+
[docs]class UnterminatedStringLiteral(Exception): + pass +
+
[docs]class UnterminatedRegularExpression(Exception): + pass +
+
[docs]class JavascriptMinify(object): + + def _outA(self): + self.outstream.write(self.theA) + def _outB(self): + self.outstream.write(self.theB) + + def _get(self): + """return the next character from stdin. Watch out for lookahead. If + the character is a control character, translate it to a space or + linefeed. + """ + c = self.theLookahead + self.theLookahead = None + if c == None: + c = self.instream.read(1) + if c >= ' ' or c == '\n': + return c + if c == '': # EOF + return '\000' + if c == '\r': + return '\n' + return ' ' + + def _peek(self): + self.theLookahead = self._get() + return self.theLookahead + + def _next(self): + """get the next character, excluding comments. peek() is used to see + if an unescaped '/' is followed by a '/' or '*'. + """ + c = self._get() + if c == '/' and self.theA != '\\': + p = self._peek() + if p == '/': + c = self._get() + while c > '\n': + c = self._get() + return c + if p == '*': + c = self._get() + while 1: + c = self._get() + if c == '*': + if self._peek() == '/': + self._get() + return ' ' + if c == '\000': + raise UnterminatedComment() + + return c + + def _action(self, action): + """do something! What you do is determined by the argument: + 1 Output A. Copy B to A. Get the next B. + 2 Copy B to A. Get the next B. (Delete A). + 3 Get the next B. (Delete B). + action treats a string as a single character. Wow! + action recognizes a regular expression if it is preceded by ( or , or =. + """ + if action <= 1: + self._outA() + + if action <= 2: + self.theA = self.theB + if self.theA == "'" or self.theA == '"': + while 1: + self._outA() + self.theA = self._get() + if self.theA == self.theB: + break + if self.theA <= '\n': + raise UnterminatedStringLiteral() + if self.theA == '\\': + self._outA() + self.theA = self._get() + + + if action <= 3: + self.theB = self._next() + if self.theB == '/' and (self.theA == '(' or self.theA == ',' or + self.theA == '=' or self.theA == ':' or + self.theA == '[' or self.theA == '?' or + self.theA == '!' or self.theA == '&' or + self.theA == '|' or self.theA == ';' or + self.theA == '{' or self.theA == '}' or + self.theA == '\n'): + self._outA() + self._outB() + while 1: + self.theA = self._get() + if self.theA == '/': + break + elif self.theA == '\\': + self._outA() + self.theA = self._get() + elif self.theA <= '\n': + raise UnterminatedRegularExpression() + self._outA() + self.theB = self._next() + + + def _jsmin(self): + """Copy the input to the output, deleting the characters which are + insignificant to JavaScript. Comments will be removed. Tabs will be + replaced with spaces. Carriage returns will be replaced with linefeeds. + Most spaces and linefeeds will be removed. + """ + self.theA = '\n' + self._action(3) + + while self.theA != '\000': + if self.theA == ' ': + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + elif self.theA == '\n': + if self.theB in ['{', '[', '(', '+', '-']: + self._action(1) + elif self.theB == ' ': + self._action(3) + else: + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + else: + if self.theB == ' ': + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + elif self.theB == '\n': + if self.theA in ['}', ']', ')', '+', '-', '"', '\'']: + self._action(1) + else: + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + else: + self._action(1) + +
[docs] def minify(self, instream, outstream): + self.instream = instream + self.outstream = outstream + self.theA = '\n' + self.theB = None + self.theLookahead = None + + self._jsmin() + self.instream.close()
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/modules/export_module.html b/docs/_build/html/_modules/webnotes/modules/export_module.html new file mode 100644 index 0000000000..9c83482691 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/modules/export_module.html @@ -0,0 +1,189 @@ + + + + + + + + + webnotes.modules.export_module — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.modules.export_module

+from webnotes.modules import scrub, get_module_path
+
+
[docs]def export_to_files(record_list=[], record_module=None, verbose=0): + module_doclist =[] + if record_list: + for record in record_list: + doclist = [d.fields for d in webnotes.model.doc.get(record[0], record[1])] + write_document_file(doclist, record_module) + + return out +
+
[docs]def create_init_py(modules_path, module, dt, dn): + import os + from webnotes.modules import scrub + + def create_if_not_exists(path): + initpy = os.path.join(path, '__init__.py') + if not os.path.exists(initpy): + open(initpy, 'w').close() + + create_if_not_exists(os.path.join(modules_path, module)) + create_if_not_exists(os.path.join(modules_path, module, dt)) + create_if_not_exists(os.path.join(modules_path, module, dt, dn)) +
+
[docs]def create_folder(module, dt, dn): + import webnotes, os + + # get module path by importing the module + modules_path = get_module_path(module) + + code_type = dt in ['DocType', 'Page', 'Search Criteria'] + + # create folder + folder = os.path.join(modules_path, code_type and scrub(dt) or dt, code_type and scrub(dn) or dn) + + webnotes.create_folder(folder) + + # create init_py_files + if code_type: + create_init_py(modules_path, module, scrub(dt), scrub(dn)) + + return folder +
+
[docs]def get_module_name(doclist, record_module=None): + # module name + if doclist[0]['doctype'] == 'Module Def': + module = doclist[0]['name'] + elif doclist[0]['doctype']=='Control Panel': + module = 'Core' + elif record_module: + module = record_module + else: + module = doclist[0]['module'] + + return module +
+
[docs]def write_document_file(doclist, record_module=None): + import os + from webnotes.utils import pprint_dict + + module = get_module_name() + + # create the folder + code_type = doclist[0]['doctype'] in ['DocType','Page','Search Criteria'] + + # create folder + folder = create_folder(module, doclist[0]['doctype'], doclist[0]['name']) + + # separate code files + clear_code_fields(doclist, folder, code_type) + + # write the data file + fname = (code_type and scrub(doclist[0]['name'])) or doclist[0]['name'] + dict_list = [pprint_dict(d) for d in doclist] + + txtfile = open(os.path.join(folder, fname +'.txt'),'w+') + txtfile.write('[\n' + ',\n'.join(dict_list) + '\n]') + txtfile.close() +
+
[docs]def clear_code_fields(doclist, folder, code_type): + + import os + import webnotes + # code will be in the parent only + code_fields = webnotes.code_fields_dict.get(doclist[0]['doctype'], []) + + for code_field in code_fields: + if doclist[0].get(code_field[0]): + + doclist[0][code_field[0]] = None +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/modules/import_module.html b/docs/_build/html/_modules/webnotes/modules/import_module.html new file mode 100644 index 0000000000..aba011043a --- /dev/null +++ b/docs/_build/html/_modules/webnotes/modules/import_module.html @@ -0,0 +1,376 @@ + + + + + + + + + webnotes.modules.import_module — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.modules.import_module

+"""
+Imports Documents from modules (.txt) files in the filesystem
+"""
+
+import webnotes
+
+#
+# imports / updates all files in a module into the database
+#
+
[docs]def import_module(module, verbose=0): + "imports the all the records and files from the given module" + from webnotes.modules import get_module_path + import os + + not_module = ('startup', 'event_handlers', 'files', 'patches') + if module in not_module: + if verbose: webnotes.msgprint('%s is not a module' % module) + return + + path = get_module_path(module) + + doctypes = listfolders(path, 1) + if 'doctype' in doctypes: + doctypes.remove('doctype') + doctypes = ['doctype'] + doctypes + + for doctype in doctypes: + for docname in listfolders(os.path.join(path, doctype), 1): + import_file(module, doctype, docname, path) + if verbose: webnotes.msgprint('Imported %s/%s/%s' % (module, doctype, docname)) + + import_attachments(module) + +# +# get doclist from file +#
+
[docs]def get_doclist(path, doctype, docname): + "returns a doclist (list of dictionaries) of multiple records for the given parameters" + import os + do_not_import = ('control_panel') + + fname = os.path.join(path,doctype,docname,docname+'.txt') + if os.path.exists(fname) and (doctype not in do_not_import): + f = open(fname,'r') + dl = eval(f.read()) + f.close() + return dl + else: + return None + +# +# import a file into the database +#
+
[docs]def import_file(module, doctype, docname, path=None): + "imports a given file into the database" + + if not path: + from webnotes.modules import get_module_path + path = get_module_path(module) + + doclist = get_doclist(path, doctype, docname) + + if doclist: + from webnotes.utils.transfer import set_doc + set_doc(doclist, 1, 1, 1) + +# +# list folders in a dir +#
+
[docs]def listfolders(path, only_name=0): + """returns the list of folders (with paths) in the given path, + if only_name is set, it returns only the folder names""" + + import os + out = [] + for each in os.listdir(path): + dirname = each.split(os.path.sep)[-1] + fullpath = os.path.join(path, dirname) + + if os.path.isdir(fullpath) and not dirname.startswith('.'): + out.append(only_name and dirname or fullname) + return out + + + + + + + +# ============================================================================== +# Import from files +# =============================================================================
+
[docs]def import_from_files(modules = [], record_list = [], sync_cp = 0, target_db=None, target_ac=None): + + if target_db or target_ac: + init_db_login(target_ac, target_db) + + from webnotes.utils import transfer + # Get paths of folder which will be imported + folder_list = get_folder_paths(modules, record_list) + ret = [] + + if folder_list: + # get all doclist + all_doclist = get_all_doclist(folder_list) + + # import doclist + ret += accept_module(all_doclist) + + # import attachments + for m in modules: + import_attachments(m) + + # sync control panel + if sync_cp: + ret.append(sync_control_panel()) + else: + ret.append("Module/Record not found") + + return ret + + +# ============================================================================== +# Get list of folder path +# ============================================================================= +# record_list in format [[module,dt,dn], ..]
+
[docs]def get_folder_paths(modules, record_list): + import os + import webnotes + import fnmatch + import webnotes.defs + from webnotes.modules import transfer_types, get_module_path, scrub + + folder_list=[] + + # get the folder list + if record_list: + for record in record_list: + if scrub(record[1]) in ('doctype', 'page', 'search_criteria'): + record[1], record[2] = scrub(record[1]), scrub(record[2]) + + folder_list.append(os.path.join(get_module_path(scrub(record[0])), \ + record[1], record[2].replace('/','_'))) + + if modules: + # system modules will be transferred in a predefined order and before all other modules + sys_mod_ordered_list = ['roles', 'core','application_internal', 'mapper', 'settings'] + all_mod_ordered_list = [t for t in sys_mod_ordered_list if t in modules] + list(set(modules).difference(sys_mod_ordered_list)) + + for module in all_mod_ordered_list: + mod_path = get_module_path(module) + types_list = listfolders(mod_path, 1) + + # list of types + types_list = list(set(types_list).difference(['control_panel'])) + all_transfer_types =[t for t in transfer_types if t in types_list] + list(set(types_list).difference(transfer_types)) + + # build the folders + for d in all_transfer_types: + if d not in ('files', 'startup', 'patches'): + # get all folders inside type + folder_list+=listfolders(os.path.join(mod_path, d)) + + return folder_list + + +# ============================================================================== +# Get doclist for all folder +# ============================================================================= + +
+
[docs]def get_all_doclist(folder_list): + import fnmatch + import os + + doclist = [] + all_doclist = [] + + # build into doclist + for folder in folder_list: + # get the doclist + file_list = os.listdir(folder) + for each in file_list: + + if fnmatch.fnmatch(each,'*.txt'): + doclist = eval(open(os.path.join(folder,each),'r').read()) + # add code + all_doclist.append(doclist) + + return all_doclist + + +# ============================================================================== +# accept a module coming from a remote server +# ==============================================================================
+
[docs]def accept_module(super_doclist): + import webnotes + import webnotes.utils + from webnotes.utils import transfer + msg, i = [], 0 + + for dl in super_doclist: + if dl[0]['doctype']!='Control Panel': + msg.append(transfer.set_doc(dl, 1, 1, 1)) + + if dl[0]['doctype']=='Module Def': + update_module_timestamp(dl[0]['name']) + + if not webnotes.conn.in_transaction: + webnotes.conn.sql("START TRANSACTION") + + # clear cache + webnotes.conn.sql("DELETE from __DocTypeCache") + webnotes.conn.sql("COMMIT") + + return msg + +# ============================================================================= +# Update timestamp in Module Def table +# =============================================================================
+
[docs]def update_module_timestamp(mod): + import webnotes, webnotes.defs, os + + try: + file = open(os.path.join(webnotes.defs.modules_path, mod, 'module.info'), 'r') + except Exception, e: + if e.args[0]==2: + return # module.info + else: + raise e + + module_info = eval(file.read()) + file.close() + +# ============================================================================= +
+
[docs]def update_module_timestamp_query(mod, timestamp): + import webnotes + webnotes.conn.sql("start transaction") + webnotes.conn.sql("update `tabModule Def` set last_updated_date=%s where name=%s", (timestamp, mod)) + webnotes.conn.sql("commit") + + +# ============================================================================= +# Import Attachments +# ============================================================================= +
+
[docs]def import_attachments(m): + import os, webnotes.defs + import webnotes.utils.file_manager + from webnotes.modules import get_module_path + + out = [] + + # get list + try: + folder = os.path.join(get_module_path(m), 'files') + fl = os.listdir(folder) + except OSError, e: + if e.args[0]==2: + return + else: + raise e + + # import files + for f in fl: + if not os.path.isdir(os.path.join(folder, f)): + # delete + webnotes.utils.file_manager.delete_file(f) + + # import + file = open(os.path.join(folder, f),'r') + webnotes.utils.file_manager.save_file(f, file.read(), m) + file.close() + + out.append(f) + + return out
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/modules/module_manager.html b/docs/_build/html/_modules/webnotes/modules/module_manager.html new file mode 100644 index 0000000000..14fb3f1cc7 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/modules/module_manager.html @@ -0,0 +1,259 @@ + + + + + + + + + webnotes.modules.module_manager — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.modules.module_manager

+#==============================================================================
+# SYNC
+#==============================================================================
+def reload_doc(module, dt, dn):
+	"alias for webnotes.modules.import_module.import_file"
+
[docs] from webnotes.modules.import_module import import_file + + import_file(module, dt, dn) + +# +# get list of doctypes and their last update times +# +def get_doc_list(dt): + """
+
[docs] returns the list of records and their last update times from the table + if the column _last_update does not exist, it will add it to the table + """ + + import webnotes + module = dt=='Module Def' and 'name' or 'module' + q = "select %s, name, _last_update from `tab%s`" % (module, dt) + try: + return webnotes.conn.sql(q) + except Exception, e: + if e.args[0]==1054: + webnotes.conn.commit() + webnotes.conn.sql("alter table `tab%s` add column _last_update varchar(32)" % dt) + webnotes.conn.begin() + return webnotes.conn.sql(q) + elif e.args[0]==1146: + return [] + else: + raise e + +# +# sync dt +# +def sync_one_doc(d, dt, ts): + import webnotes
+
[docs] from webnotes.model.db_schema import updatedb + reload_doc(d[0], dt, d[1]) + + # update schema(s) + if dt=='DocType': + updatedb(d[1]) + webnotes.conn.sql("update `tab%s` set _last_update=%s where name=%s" % (dt, '%s', '%s'), (ts, d[1])) + +# +# sync doctypes, mappers and +# +def sync_meta(): + import webnotes, os
+
[docs] from webnotes.modules import scrub, get_module_path + from webnotes.utils import cint + + tl = ['DocType', 'DocType Mapper', 'Module Def'] + + for dt in tl: + dtl = get_doc_list(dt) + + for d in filter(lambda x: x[0], dtl): + try: + ndt, ndn = dt, d[1] + if dt == 'DocType': + ndt, ndn = scrub(dt), scrub(d[1]) + + mp = get_module_path(scrub(d[0])) + ts = cint(os.stat(os.path.join(mp, ndt, ndn, ndn + '.txt')).st_mtime) + + if d[2] != str(ts): + sync_one_doc(d, dt, ts) + except OSError, e: + pass + + + + + + +#============================================================================== + +def get_module_details(m): + from export_module import get_module_items
+
[docs] return {'in_files': get_module_items_from_files(m), \ + 'in_system':[[i[0], i[1], get_modified(i[0], i[1])] for i in get_module_items(m)]} + +#============================================================================== + +def get_modified(dt, dn): + import webnotes
+
[docs] try: + return str(webnotes.conn.sql("select modified from `tab%s` where replace(name,' ','_')=%s" % (dt,'%s'), dn)[0][0]) + except: + pass + +#============================================================================== + +def get_module_items_from_files(m): + import os, webnotes.defs
+
[docs] from import_module import listfolders + + items = [] + for item_type in listfolders(os.path.join(webnotes.defs.modules_path, m), 1): + for item_name in listfolders(os.path.join(webnotes.defs.modules_path, m, item_type), 1): + # read the file + file = open(os.path.join(webnotes.defs.modules_path, m, item_type, item_name, item_name)+'.txt','r') + doclist = eval(file.read()) + file.close() + + # append + items.append([item_type, item_name, doclist[0]['modified']]) + + return items + +#============================================================================== + +def get_last_update_for(mod): + import webnotes
+
[docs] try: + return webnotes.conn.sql("select last_updated_date from `tabModule Def` where name=%s", mod)[0][0] + except: + return '' + +#============================================================================== + +def init_db_login(ac_name, db_name): + import webnotes
+
[docs] import webnotes.db + import webnotes.profile + + if ac_name: + webnotes.conn = webnotes.db.Database(ac_name = ac_name) + webnotes.conn.use(webnotes.conn.user) + elif db_name: + webnotes.conn = webnotes.db.Database(user=db_name) + webnotes.conn.use(db_name) + else: + webnotes.conn = webnotes.db.Database(use_default=1) + + webnotes.session = {'user':'Administrator'} + webnotes.user = webnotes.profile.Profile() + +#============================================================================== +# Return module names present in File System +#============================================================================== +def get_modules_from_filesystem(): + import os, webnotes.defs
+
[docs] from import_module import listfolders + + modules = listfolders(webnotes.defs.modules_path, 1) + out = [] + modules.sort() + modules = filter(lambda x: x!='patches', modules) + + for m in modules: + file = open(os.path.join(webnotes.defs.modules_path, m, 'module.info'), 'r') + out.append([m, eval(file.read()), get_last_update_for(m), \ + webnotes.conn.exists('Module Def',m) and 'Installed' or 'Not Installed']) + file.close() + + return out +
+ +
+
+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/modules/patch.html b/docs/_build/html/_modules/webnotes/modules/patch.html new file mode 100644 index 0000000000..0bca338fe9 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/modules/patch.html @@ -0,0 +1,134 @@ + + + + + + + + + webnotes.modules.patch — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.modules.patch

+# patch manager
+
+
[docs]def run(log_exception=1): + import webnotes + from patches import patch + from webnotes.utils import cint + + next_patch = cint(webnotes.conn.get_global('next_patch')) + + if next_patch <= patch.last_patch: + for i in range(next_patch, patch.last_patch+1): + webnotes.conn.begin() + if log_exception: + try: + patch.execute(i) + except Exception, e: + write_log() + return + else: + patch.execute(i) + + webnotes.conn.set_global('next_patch', str(i+1)) + webnotes.conn.commit() +
+
[docs]def write_log(): + import os + import webnotes.defs + import webnotes + + patch_log = open(os.path.join(webnotes.defs.modules_path, 'patches', 'patch.log'), 'a') + patch_log.write(('\n\nError in %s:\n' % webnotes.conn.cur_db_name) + webnotes.getTraceback()) + patch_log.close() + + webnotes.msgprint("There were errors in running patches, please call the Administrator") + +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/multi_tenant/setup.html b/docs/_build/html/_modules/webnotes/multi_tenant/setup.html new file mode 100644 index 0000000000..35671a5632 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/multi_tenant/setup.html @@ -0,0 +1,115 @@ + + + + + + + + + webnotes.multi_tenant.setup — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.multi_tenant.setup

+import webnotes
+
+# setup all tables for multi-tenant
+# ---------------------------------
+
[docs]def setup_tables(): + import webnotes.multi_tenant + + tl = webnotes.conn.sql("show tables") + for t in tl: + add_tenant_id(t[0]) + change_primary_key(t[0]) +
+
[docs]def add_tenant_id(tname): + webnotes.conn.sql("alter table `%s` add column _tenant_id int(10) default 0 not null") +
+
[docs]def change_primary_key(tname): + webnotes.conn.sql("alter table `%s` drop primary key name") + webnotes.conn.sql("alter table `%s` add primary key (name, _tenant_id)") +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/profile.html b/docs/_build/html/_modules/webnotes/profile.html new file mode 100644 index 0000000000..f35509c160 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/profile.html @@ -0,0 +1,335 @@ + + + + + + + + + webnotes.profile — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.profile

+import webnotes
+
+
[docs]class Profile: + """ + A profile object is created at the beginning of every request with details of the use. + The global profile object is `webnotes.user` + """ + def __init__(self, name=''): + self.name = name or webnotes.session.get('user') + self.roles = [] + + self.can_create = [] + self.can_read = [] + self.can_write = [] + self.can_get_report = [] + + def _load_roles(self): + res = webnotes.conn.sql('select role from tabUserRole where parent = "%s"' % self.name) + self.roles = [] + for t in res: + if t[0]: self.roles.append(t[0]) + if webnotes.session.get('user') == 'Guest': + self.roles.append('Guest') + else: + self.roles.append('All') + + return self.roles + +
[docs] def get_roles(self): + """ + get list of roles + """ + if self.roles: + return self.roles + + return self._load_roles() +
+
[docs] def get_allow_list(self, key): + """ + Internal - get list of DocType where `key` is allowed. Key is either 'read', 'write' or 'create' + """ + conn = webnotes.conn + roles = self.get_roles() + return [r[0] for r in conn.sql('SELECT DISTINCT t1.parent FROM `tabDocPerm` t1, tabDocType t2 WHERE t1.`%s`=1 AND t1.parent not like "old_parent:%%" AND t1.parent = t2.name AND IFNULL(t2.istable,0) = 0 AND t1.role in ("%s") order by t1.parent' % (key, '", "'.join(roles)))] +
+
[docs] def get_create_list(self): + """ + Get list of DocTypes the user can create. Will filter DocTypes tagged with 'not_in_create' and table + """ + cl = self.get_allow_list('create') + conn = webnotes.conn + no_create_list = [r[0] for r in conn.sql('select name from tabDocType where ifnull(in_create,0)=1 or ifnull(istable,0)=1 or ifnull(issingle,0)=1')] + self.can_create = filter(lambda x: x not in no_create_list, cl) + return self.can_create +
+
[docs] def get_read_list(self): + """ + Get list of DocTypes the user can read + """ + self.can_read = list(set(self.get_allow_list('read') + self.get_allow_list('write'))) + return self.can_read +
+
[docs] def get_report_list(self): + + conn = webnotes.conn + + # get all tables list + res = conn.sql('SELECT parent, options from tabDocField where fieldtype="Table"') + table_types, all_tabletypes = {}, [] + + # make a dictionary fo all table types + for t in res: + all_tabletypes.append(t[1]) + if not table_types.has_key(t[0]): + table_types[t[0]] = [] + table_types[t[0]].append(t[1]) + + no_search_list = [r[0] for r in conn.sql('SELECT name FROM tabDocType WHERE read_only = 1 ORDER BY name')] + # make the lists + for f in self.can_read: + tl = table_types.get(f, None) + if tl: + for t in tl: + if t and (not t in self.can_get_report) and (not t in no_search_list): + self.can_get_report.append(t) + + if f and (not f in self.can_get_report) and (not f in no_search_list): + self.can_get_report.append(f) + + return self.can_get_report +
+
[docs] def get_write_list(self): + """ + Get list of DocTypes the user can write + """ + self.can_write = self.get_allow_list('write') + return self.can_write +
+
[docs] def get_home_page(self): + """ + Get the name of the user's home page from the `Control Panel` + """ + try: + hpl = webnotes.conn.sql("select role, home_page from `tabDefault Home Page` where parent='Control Panel' order by idx asc") + for h in hpl: + if h[0] in self.get_roles(): + return h[1] + except: + pass + return webnotes.conn.get_value('Control Panel',None,'home_page') +
+
[docs] def get_defaults(self): + """ + Get the user's default values based on user and role profile + """ + roles = self.get_roles() + [self.name] + res = webnotes.conn.sql('select defkey, defvalue from `tabDefaultValue` where parent in ("%s")' % '", "'.join(roles)) + + self.defaults = {'owner': [self.name,]} + + for rec in res: + if not self.defaults.has_key(rec[0]): + self.defaults[rec[0]] = [] + self.defaults[rec[0]].append(rec[1] or '') + + return self.defaults +
+
[docs] def get_hide_tips(self): + try: + return webnotes.conn.sql("select hide_tips from tabProfile where name=%s", self.name)[0][0] or 0 + except: + return 0 +
+
[docs] def get_random_password(self): + """ + Generate a random password + """ + import string + from random import choice + + size = 9 + pwd = ''.join([choice(string.letters + string.digits) for i in range(size)]) + return pwd +
+
[docs] def reset_password(self): + """ + Reset the user's password and send an email + """ + pwd = self.get_random_password() + + # get profile + profile = webnotes.conn.sql("SELECT name, email, first_name, last_name FROM tabProfile WHERE name=%s OR email=%s",(self.name, self.name)) + + if not profile: + raise Exception, "Profile %s not found" % self.name + + # update tab Profile + webnotes.conn.sql("UPDATE tabProfile SET password=password(%s) WHERE name=%s", (pwd, profile[0][0])) + + self.send_email("Password Reset", "<p>Dear %s%s,</p><p>your password has been changed to %s</p><p>[Automatically Generated]</p>" % (profile[0][2], (profile[0][3] and (' ' + profile[0][3]) or ''), pwd), profile[0][1]) +
+
[docs] def send_email(self, subj, mess, email): + import webnotes.utils.email_lib + + webnotes.utils.email_lib.sendmail(email, msg=mess, subject=subj) + + # update recent documents
+
[docs] def update_recent(self, dt, dn): + """ + Update the user's `Recent` list with the given `dt` and `dn` + """ + conn = webnotes.conn + + # get list of child tables, so we know what not to add in the recent list + child_tables = [t[0] for t in conn.sql('select name from tabDocType where istable = 1')] + if not (dt in ['Print Format', 'Start Page', 'Event', 'ToDo Item', 'Search Criteria']) and not webnotes.is_testing and not (dt in child_tables): + r = webnotes.conn.sql("select recent_documents from tabProfile where name=%s", self.name)[0][0] or '' + new_str = dt+'~~~'+dn + '\n' + if new_str in r: + r = r.replace(new_str, '') + + self.recent = new_str + r + + if len(self.recent.split('\n')) > 50: + self.recent = '\n'.join(self.recent.split('\n')[:50]) + + webnotes.conn.sql("update tabProfile set recent_documents=%s where name=%s", (self.recent, self.name)) +
+
[docs] def load_profile(self): + """ + Return a dictionary of user properites to be stored in the session + """ + t = webnotes.conn.sql('select email, first_name, last_name, recent_documents from tabProfile where name = %s', self.name)[0] + + d = {} + d['name'] = self.name + d['email'] = t[0] or '' + d['first_name'] = t[1] or '' + d['last_name'] = t[2] or '' + d['recent'] = t[3] or '' + + d['hide_tips'] = self.get_hide_tips() + + d['roles'] = self.get_roles() + d['defaults'] = self.get_defaults() + + d['can_create'] = self.get_create_list() + d['can_read'] = self.get_read_list() + d['can_write'] = self.get_write_list() + d['can_get_report'] = self.get_report_list() + + return d +
+
[docs] def load_from_session(self, d): + """ + Setup the user profile from the dictionary saved in the session (generated by `load_profile`) + """ + self.can_create = d['can_create'] + self.can_read = d['can_read'] + self.can_write = d['can_write'] + self.can_get_report = d['can_get_report'] + + self.roles = d['roles'] + self.defaults = d['defaults'] +
+
[docs]def get_user_img(): + if not webnotes.form.getvalue('username'): + webnotes.response['message'] = 'no_img_m' + return + + f = webnotes.conn.sql("select file_list from tabProfile where name=%s", webnotes.form.getvalue('username','')) + if f: + if f[0][0]: + lst = f[0][0].split('\n') + webnotes.response['message'] = lst[0].split(',')[1] + else: + webnotes.response['message'] = 'no_img_m' + else: + webnotes.response['message'] = 'no_img_m'
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/session_cache.html b/docs/_build/html/_modules/webnotes/session_cache.html new file mode 100644 index 0000000000..0aff5d4004 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/session_cache.html @@ -0,0 +1,279 @@ + + + + + + + + + webnotes.session_cache — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.session_cache

+# session_cache.py
+
+# clear cache
+# ==================================================
+
+
[docs]def clear(): + clear_cache() + + import webnotes + webnotes.response['message'] = "Cache Cleared" +
+
[docs]def clear_cache(user=''): + import webnotes + try: + if user: + webnotes.conn.sql("delete from __SessionCache where user=%s", user) + else: + webnotes.conn.sql("delete from __SessionCache") + except Exception, e: + if e.args[0]==1146: + make_cache_table() + else: + raise e + +# load cache +# ================================================== +
+
[docs]def get(): + import webnotes + import webnotes.defs + + + # get country + country = webnotes.session['data'].get('ipinfo', {}).get('countryName', 'Unknown Country') + + # run patches + try: + import webnotes.modules.patch + webnotes.modules.patch.run() + except ImportError, e: + pass # no patches - do nothing + + # check if cache exists + if not getattr(webnotes.defs,'auto_cache_clear',None): + cache = load(country) + if cache: + return cache + + # if not create it + sd = build() + dump(sd, country) + + # update profile from cache + webnotes.session['data']['profile'] = sd['profile'] + + return sd + +# load cache +# ================================================== +
+
[docs]def load(country): + import webnotes + + try: + sd = webnotes.conn.sql("select cache from __SessionCache where user='%s' %s" % (webnotes.session['user'], (country and (" and country='%s'" % country) or ''))) + if sd: + return eval(sd[0][0]) + else: + return None + except Exception, e: + if e.args[0]==1146: + make_cache_table() + else: + raise e + +# make the cache table +# ================================================== +
+
[docs]def make_cache_table(): + import webnotes + webnotes.conn.commit() + webnotes.conn.sql("create table `__SessionCache` (user VARCHAR(120), country VARCHAR(120), cache LONGTEXT)") + webnotes.conn.begin() + +# dump session to cache +# ================================================== +
+
[docs]def dump(sd, country): + import webnotes + import webnotes.model.doclist + + if sd.get('docs'): + sd['docs'] = webnotes.model.doclist.compress(sd['docs']) + + # delete earlier (?) + webnotes.conn.sql("delete from __SessionCache where user=%s and country=%s", (webnotes.session['user'], country)) + + # make new + webnotes.conn.sql("insert into `__SessionCache` (user, country, cache) VALUES (%s, %s, %s)", (webnotes.session['user'], country, str(sd))) + +# ================================================== +
+
[docs]def get_letter_heads(): + import webnotes + try: + lh = {} + ret = webnotes.conn.sql("select name, content from `tabLetter Head` where ifnull(disabled,0)=0") + for r in ret: + lh[r[0]] = r[1] + return lh + except Exception, e: + if e.args[0]==1146: + return {} + else: + raise Exception, e + +# ================================================== +# load startup.js and startup.css from the modules/startup folder +
+
[docs]def load_startup(cp): + from webnotes.modules import compress + + try: from webnotes.defs import modules_path + except ImportError: return + + import os + + try: + cp.startup_code = compress.get_js_code(os.path.join(modules_path, 'startup', 'startup')) + startup_css = open(os.path.join(modules_path, 'startup', 'startup.css'), 'r') + cp.startup_css = startup_css.read() + startup_css.close() + except IOError, e: + if e.args[0]!=2: # no startup module! + raise e + +# build it +# ================================================== +
+
[docs]def build(): + sd = {} + + import webnotes + import webnotes.model + import webnotes.model.doc + import webnotes.model.doctype + import webnotes.widgets.page + import webnotes.widgets.menus + import webnotes.profile + import webnotes.defs + + sql = webnotes.conn.sql + + webnotes.conn.begin() + sd['profile'] = webnotes.user.load_profile() + + doclist = [] + doclist += webnotes.model.doc.get('Control Panel') + cp = doclist[0] + load_startup(cp) + + doclist += webnotes.model.doctype.get('Event') + doclist += webnotes.model.doctype.get('Search Criteria') + home_page = webnotes.user.get_home_page() + + if home_page: + doclist += webnotes.widgets.page.get(home_page) + + sd['account_name'] = cp.account_id or '' + sd['sysdefaults'] = webnotes.utils.get_defaults() + sd['n_online'] = int(sql("SELECT COUNT(DISTINCT user) FROM tabSessions")[0][0] or 0) + sd['docs'] = doclist + sd['letter_heads'] = get_letter_heads() + sd['home_page'] = home_page or '' + sd['start_items'] = webnotes.widgets.menus.get_menu_items() + if webnotes.session['data'].get('ipinfo'): + sd['ipinfo'] = webnotes.session['data']['ipinfo'] + + webnotes.session['data']['profile'] = sd['profile'] + sd['dt_labels'] = webnotes.model.get_dt_labels() + webnotes.conn.commit() + + return sd
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/tests.html b/docs/_build/html/_modules/webnotes/tests.html new file mode 100644 index 0000000000..df64c2ede7 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/tests.html @@ -0,0 +1,160 @@ + + + + + + + + + webnotes.tests — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.tests

+"""
+Run tests from modules. Sets up database connection, modules path and session before running test
+
+Usage: from shell, run
+
+python tests.py [test modules]
+
+Options:
+	test modules: list of modules separated by space
+	
+if no modules are specified, it will run all "tests.py" files from all modules
+"""
+
+import sys, os
+import unittest
+
+# webnotes path
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+# modules path
+import webnotes
+import webnotes.defs
+
+if webnotes.defs.__dict__.get('modules_path'):
+	sys.path.append(webnotes.defs.modules_path)
+
+
[docs]def get_tests(): + """ + Returns list of test modules identified by "tests.py" + """ + ret = [] + for walk_tuple in os.walk(webnotes.defs.modules_path): + if 'tests.py' in walk_tuple[2]: + dir_path = os.path.relpath(walk_tuple[0], webnotes.defs.modules_path) + if dir_path=='.': + ret.append('tests') + else: + ret.append(dir_path.replace('/', '.') + '.tests') + + return ret +
+
[docs]def setup(): + """ + Sets up connection and session + """ + from webnotes.db import Database + webnotes.conn = Database() + webnotes.session = {'user':'Administrator'} +
+if __name__=='__main__': + setup() + + if len(sys.argv) > 1: + tests_list = sys.argv[1:] + + # for unittest.main + sys.argv = sys.argv[:1] + else: + tests_list = get_tests() + + for tests in tests_list: + exec 'from %s import *' % str(tests) + + unittest.main() +
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils.html b/docs/_build/html/_modules/webnotes/utils.html new file mode 100644 index 0000000000..18cfda7277 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils.html @@ -0,0 +1,646 @@ + + + + + + + + + webnotes.utils — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils

+# util __init__.py
+
+import webnotes
+
+user_time_zone = None
+month_name = ['','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
+month_name_full = ['','January','February','March','April','May','June','July','August','September','October','November','December']
+no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'FlexTable', 'Button', 'Image', 'Graph']
+default_fields = ['doctype','name','owner','creation','modified','modified_by','parent','parentfield','parenttype','idx','docstatus']
+
+
[docs]def getCSVelement(v): + """ + Returns the CSV value of `v`, For example: + + * apple becomes "apple" + * hi"there becomes "hi""there" + """ + v = cstr(v) + if not v: return '' + if (',' in v) or ('\n' in v) or ('"' in v): + if '"' in v: v = v.replace('"', '""') + return '"'+v+'"' + else: return v or '' +
+
[docs]def validate_email_add(email_str): + """ + Validates the email string + """ + s = email_str + if '<' in s: + s = s.split('<')[1].split('>')[0] + if s: s = s.strip().lower() + import re + #return re.match("^[a-zA-Z0-9._%-]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email_str) + return re.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", s) +
+
[docs]def sendmail(recipients, sender='', msg='', subject='[No Subject]', parts=[], cc=[], attach=[]): + """ + Send an email. For more details see :func:`email_lib.sendmail` + """ + import webnotes.utils.email_lib + return email_lib.sendmail(recipients, sender, msg, subject, parts, cc, attach) +
+
[docs]def generate_hash(): + """ + Generates reandom hash for session id + """ + import sha, time + return sha.new(str(time.time())).hexdigest() +
+
[docs]def db_exists(dt, dn): + return webnotes.conn.sql('select name from `tab%s` where name="%s"' % (dt, dn)) +
+
[docs]def load_json(arg): + + # already a dictionary? + if type(arg)!=str: + return arg + + try: import json + except: import simplejson as json + + #return json.loads(unicode(arg, 'iso-8859-15')) + return json.loads(arg) + +# Get Traceback +# ============================================================================== +
+
[docs]def getTraceback(): + """ + Returns the traceback of the Exception + """ + import sys, traceback, string + type, value, tb = sys.exc_info() + + body = "Traceback (innermost last):\n" + list = traceback.format_tb(tb, None) + traceback.format_exception_only(type, value) + body = body + "%-20s %s" % (string.join(list[:-1], ""), list[-1]) + + if webnotes.logger: + webnotes.logger.error('Db:'+(webnotes.conn and webnotes.conn.cur_db_name or '') + ' - ' + body) + + return body + +# Log +# ============================================================================== +
+
[docs]def log(event, details): + webnotes.logger.info(details) + +# Date and Time +# ============================================================================== + +
+
[docs]def getdate(string_date): + """ + Coverts string date (yyyy-mm-dd) to datetime.date object + """ + import datetime + + if type(string_date)==unicode: + string_date = str(string_date) + + if type(string_date) in (datetime.datetime, datetime.date): + return string_date + + if ' ' in string_date: + string_date = string_date.split(' ')[0] + t = string_date.split('-') + if len(t)==3: + return datetime.date(cint(t[0]), cint(t[1]), cint(t[2])) + else: + return '' +
+
[docs]def add_days(date, days): + """ + Adds `days` to the given `string_date` + """ + import datetime + if not date: + date = now_datetime() + + if type(date) not in (datetime.datetime, datetime.date): + date = getdate(date) + + return (date + datetime.timedelta(days)).strftime('%Y-%m-%d') +
+
[docs]def add_months(string_date, months): + import datetime + return webnotes.conn.sql("select DATE_ADD('%s',INTERVAL '%s' MONTH)" % (getdate(string_date),months))[0][0] +
+
[docs]def add_years(string_date, years): + import datetime + return webnotes.conn.sql("select DATE_ADD('%s',INTERVAL '%s' YEAR)" % (getdate(string_date),years))[0][0] +
+
[docs]def date_diff(string_ed_date, string_st_date=None): + import datetime + return webnotes.conn.sql("SELECT DATEDIFF('%s','%s')" %(getdate(string_ed_date), getdate(string_st_date)))[0][0] +
+
[docs]def now_datetime(): + global user_time_zone + from datetime import datetime + from pytz import timezone + + # get localtime + if not user_time_zone: + user_time_zone = webnotes.conn.get_value('Control Panel', None, 'time_zone') or 'Asia/Calcutta' + + # convert to UTC + utcnow = timezone('UTC').localize(datetime.utcnow()) + + # convert to user time zone + return utcnow.astimezone(timezone(user_time_zone)) +
+
[docs]def now(): + """ + Returns `time.strftime('%Y-%m-%d %H:%M:%S')` + """ + return now_datetime().strftime('%Y-%m-%d %H:%M:%S') +
+
[docs]def nowdate(): + """ + Returns time.strftime('%Y-%m-%d') + """ + return now_datetime().strftime('%Y-%m-%d') +
+
[docs]def get_first_day(dt, d_years=0, d_months=0): + """ + Returns the first day of the month for the date specified by date object + Also adds `d_years` and `d_months` if specified + """ + import datetime + # d_years, d_months are "deltas" to apply to dt + y, m = dt.year + d_years, dt.month + d_months + a, m = divmod(m-1, 12) + return datetime.date(y+a, m+1, 1) +
+
[docs]def get_last_day(dt): + """ + Returns last day of the month using: + `get_first_day(dt, 0, 1) + datetime.timedelta(-1)` + """ + import datetime + return get_first_day(dt, 0, 1) + datetime.timedelta(-1) +
+user_format = None +""" + User format specified in :term:`Control Panel` + + Examples: + + * dd-mm-yyyy + * mm-dd-yyyy + * dd/mm/yyyy +""" + +
[docs]def formatdate(string_date): + """ + Convers the given string date to :data:`user_format` + """ + global user_format + if not user_format: + user_format = webnotes.conn.get_value('Control Panel', None, 'date_format') + d = string_date.split('-'); + out = user_format + return out.replace('dd', ('%.2i' % cint(d[2]))).replace('mm', ('%.2i' % cint(d[1]))).replace('yyyy', d[0]) +
+
[docs]def dict_to_str(args, sep='&'): + """ + Converts a dictionary to URL + """ + import urllib + t = [] + for k in args.keys(): + t.append(str(k)+'='+urllib.quote(str(args[k] or ''))) + return sep.join(t) +
+
[docs]def timestamps_equal(t1, t2): + """Returns true if same the two string timestamps are same""" + scrub = lambda x: x.replace(':', ' ').replace('-',' ').split() + + t1, t2 = scrub(t1), scrub(t2) + + if len(t1) != len(t2): + return + + for i in range(len(t1)): + if t1[i]!=t2[i]: + return + return 1 +
+
[docs]def global_date_format(date): + import datetime + + if type(date) in (str, unicode): + date = getdate(date) + + return date.strftime('%d') + ' ' + month_name_full[int(date.strftime('%m'))] + ' ' + date.strftime('%Y') + + + + +# Datatype +# ============================================================================== +
+
[docs]def isNull(v): + """ + Returns true if v='' or v is `None` + """ + return (v=='' or v==None) +
+
[docs]def has_common(l1, l2): + """ + Returns true if there are common elements in lists l1 and l2 + """ + for l in l1: + if l in l2: + return 1 + return 0 +
+
[docs]def flt(s): + """ + Convert to float (ignore commas) + """ + if type(s)==str: # if string + s = s.replace(',','') + try: tmp = float(s) + except: tmp = 0 + return tmp +
+
[docs]def cint(s): + """ + Convert to integer + """ + try: tmp = int(float(s)) + except: tmp = 0 + return tmp +
+
[docs]def cstr(s): + """ + Convert to string + """ + if s==None: + return '' + else: + if hasattr(s, 'encode'): + try: + s = s.encode('utf-8', 'ignore') + except: + pass + return str(s) +
+
[docs]def str_esc_quote(s): + """ + Escape quotes + """ + if s==None:return '' + return s.replace("'","\'") +
+
[docs]def replace_newlines(s): + """ + Replace newlines by '<br>' + """ + if s==None:return '' + return s.replace("\n","<br>") + + +# ============================================================================== +
+
[docs]def parse_val(v): + """ + Converts to simple datatypes from SQL query results + """ + import datetime + + try: import decimal # for decimal Python 2.5 (?) + except: pass + + if type(v)==datetime.date: + v = str(v) + elif type(v)==datetime.timedelta: + v = ':'.join(str(v).split(':')[:2]) + elif type(v)==datetime.datetime: + v = str(v) + elif type(v)==long: v=int(v) + + try: + if type(v)==decimal.Decimal: v=float(v) + except: pass + + return v + +# ============================================================================== +
+
[docs]def fmt_money(amount, fmt = '%.2f'): + """ + Convert to string with commas for thousands, millions etc + """ + curr = webnotes.conn.get_value('Control Panel', None, 'currency_format') or 'Millions' + + val = 2 + if curr == 'Millions': val = 3 + + if cstr(amount).find('.') == -1: temp = '00' + else: temp = cstr(amount).split('.')[1] + + l = [] + minus = '' + if flt(amount) < 0: minus = '-' + + amount = ''.join(cstr(amount).split(',')) + amount = cstr(abs(flt(amount))).split('.')[0] + + # main logic + if len(cstr(amount)) > 3: + nn = amount[len(amount)-3:] + l.append(nn) + amount = amount[0:len(amount)-3] + while len(cstr(amount)) > val: + nn = amount[len(amount)-val:] + l.insert(0,nn) + amount = amount[0:len(amount)-val] + + if len(amount) > 0: l.insert(0,amount) + + amount = ','.join(l)+'.'+temp + amount = minus + amount + return amount + +# +# convet currency to words +#
+
[docs]def money_in_words(number, main_currency = None, fraction_currency=None): + """ + Returns string in words with currency and fraction currency. + """ + + d = get_defaults() + if not main_currency: + main_currency = d.get('currency', 'INR') + if not fraction_currency: + fraction_currency = d.get('fraction_currency', 'paise') + + n = str(flt(number)) + main, fraction = n.split('.') + if len(fraction)==1: fraction += '0' + + out = main_currency + ' ' + in_words(main).title() + if cint(fraction): + out = out + ' and ' + in_words(fraction).title() + ' ' + fraction_currency + + return out + ' only.' + +# +# convert number to words +#
+
[docs]def in_words(integer): + """ + Returns string in words for the given integer. + """ + + in_million = webnotes.conn.get_value('Control Panel',None,'currency_format')=='Millions' and 1 or 0 + + + n=int(integer) + known = {0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six', 7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten', + 11: 'eleven', 12: 'twelve', 13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen', 18: 'eighteen', + 19: 'nineteen', 20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty', 60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'} + + def psn(n, known, xpsn): + import sys; + if n in known: return known[n] + bestguess, remainder = str(n), 0 + + if n<=20: + print >>sys.stderr, n, "How did this happen?" + assert 0 + elif n < 100: + bestguess= xpsn((n//10)*10, known, xpsn) + '-' + xpsn(n%10, known, xpsn) + return bestguess + elif n < 1000: + bestguess= xpsn(n//100, known, xpsn) + ' ' + 'hundred' + remainder = n%100 + else: + if in_million: + if n < 1000000: + bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand' + remainder = n%1000 + elif n < 1000000000: + bestguess= xpsn(n//1000000, known, xpsn) + ' ' + 'million' + remainder = n%1000000 + else: + bestguess= xpsn(n//1000000000, known, xpsn) + ' ' + 'billion' + remainder = n%1000000000 + else: + if n < 100000: + bestguess= xpsn(n//1000, known, xpsn) + ' ' + 'thousand' + remainder = n%1000 + elif n < 10000000: + bestguess= xpsn(n//100000, known, xpsn) + ' ' + 'lakh' + remainder = n%100000 + else: + bestguess= xpsn(n//10000000, known, xpsn) + ' ' + 'crore' + remainder = n%10000000 + if remainder: + if remainder >= 100: + comma = ',' + else: + comma = '' + return bestguess + comma + ' ' + xpsn(remainder, known, xpsn) + else: + return bestguess + + return psn(n, known, psn) + + +# Get Defaults +# ============================================================================== +
+
[docs]def get_defaults(key=None): + """ + Get dictionary of default values from the :term:`Control Panel`, or a value if key is passed + """ + if key: + res = webnotes.conn.sql('select defvalue from `tabDefaultValue` where parent = "Control Panel" where defkey=%s', key) + return res and res[0][0] or None + else: + res = webnotes.conn.sql('select defkey, defvalue from `tabDefaultValue` where parent = "Control Panel"') + d = {} + for rec in res: + d[rec[0]] = rec[1] or '' + return d +
+
[docs]def set_default(key, val): + """ + Set / add a default value to :term:`Control Panel` + """ + res = webnotes.conn.sql('select defkey from `tabDefaultValue` where defkey="%s" and parent = "Control Panel"' % key) + if res: + webnotes.conn.sql('update `tabDefaultValue` set defvalue="%s" where parent = "Control Panel" and defkey="%s"' % (val, key)) + else: + from webnotes.model.doc import Document + d = Document('DefaultValue') + d.parent = 'Control Panel' + d.parenttype = 'Control Panel' + d.parentfield = 'system_defaults' + d.defkey = key + d.defvalue = val + d.save(1) + +# +# Clear recycle bin +#
+
[docs]def clear_recycle_bin(): + sql = webnotes.conn.sql + + tl = sql('show tables') + total_deleted = 0 + for t in tl: + fl = [i[0] for i in sql('desc `%s`' % t[0])] + + if 'name' in fl: + total_deleted += sql("select count(*) from `%s` where name like '__overwritten:%%'" % t[0])[0][0] + sql("delete from `%s` where name like '__overwritten:%%'" % t[0]) + + if 'parent' in fl: + total_deleted += sql("select count(*) from `%s` where parent like '__oldparent:%%'" % t[0])[0][0] + sql("delete from `%s` where parent like '__oldparent:%%'" % t[0]) + + total_deleted += sql("select count(*) from `%s` where parent like 'oldparent:%%'" % t[0])[0][0] + sql("delete from `%s` where parent like 'oldparent:%%'" % t[0]) + + total_deleted += sql("select count(*) from `%s` where parent like 'old_parent:%%'" % t[0])[0][0] + sql("delete from `%s` where parent like 'old_parent:%%'" % t[0]) + + return "%s records deleted" % str(int(total_deleted)) + + +# Send Error Report +# ============================================================================== +
+
[docs]def send_error_report(): + sql = webnotes.conn.sql + m = '' + acc_id = webnotes.conn.get_value('Control Panel',None,'account_id') or '' + if acc_id: m = 'Account Id : '+acc_id + form = webnotes.form + err_msg = ''' + %s <br> + Comment: %s + Err Msg : %s + ''' % (m, form.getvalue('msg') or '', form.getvalue('err_msg')) + sendmail([webnotes.conn.get_value('Control Panel',None,'support_email_id') or 'support@iwebnotes.com'], sender=webnotes.session['user'], msg=err_msg, subject='Error Report '+m) + +# pretty print a dict +# ============================================================================== +
+
[docs]def pprint_dict(d, level=1): + indent = '' + for i in range(0,level): + indent += '\t' + lines = [] + kl = d.keys() + kl.sort() + for key in kl: + tmp = {key: d[key]} + lines.append(indent + str(tmp)[1:-1] ) + return indent + '{\n' \ + + indent + ',\n\t'.join(lines) \ + + '\n' + indent + '}'
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/archive.html b/docs/_build/html/_modules/webnotes/utils/archive.html new file mode 100644 index 0000000000..b14424a668 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/archive.html @@ -0,0 +1,204 @@ + + + + + + + + + webnotes.utils.archive — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.archive

+import webnotes
+
+sql = webnotes.conn.sql
+
+# main function
+# -------------------------
+
+
[docs]def archive_doc(doctype, name, restore=0): + archive_record(doctype, name, restore) + + tables = sql("select options from tabDocField where parent=%s and fieldtype='Table'", doctype) + for t in tables: + try: + rec_list = sql("select name from `%s%s` where parent=%s" % ((restore and 'arc' or 'tab') ,t[0], '%s'), name) + except Exception,e: + if e.args[0]==1146: # no child table + rec_list = [] + else: + raise e + + for r in rec_list: + archive_record(t[0], r[0], restore) + +# archive individual record +# ------------------------- +
+
[docs]def archive_record(doctype, name, restore = 0): + src_tab = (restore and 'arc' or 'tab') + doctype + tar_tab = (restore and 'tab' or 'arc') + doctype + + # get the record + try: + rec = sql("select * from `%s` where name=%s for update" % (src_tab, '%s'), name, as_dict=1)[0] + except Exception, e: + if e.args[0]==1146: + return # source table does not exist + else: + raise e + + # insert the record + insert_record(doctype, tar_tab, name) + + # put it field by field (ignore missing columns) + for field in rec.keys(): + if rec.get(field): + update_value(src_tab, tar_tab, name, rec, field) + + # delete from main + try: + sql("delete from `%s` where name=%s limit 1" % (src_tab, '%s'), name) + except Exception, e: + if e.args[0]==1451: + webnotes.msgprint("Cannot archive %s '%s' as it is referenced in another record. You must delete the referred record first" % (doctype, name)) + + # delete from target, as it will create a double copy! + sql("delete from `%s` where name=%s limit 1" % (tar_tab, '%s'), name) + +# insert the record +# ------------------------- +
+
[docs]def insert_record_name(tab, name): + sql("insert ignore into `%s` (name) values (%s)" % (tab, '%s'), name) + +# insert record +# ------------------------- +
+
[docs]def insert_record(doctype, tar_tab, name): + try: + insert_record_name(tar_tab, name) + except Exception, e: + if e.args[0]==1146: + # missing table - create it + from webnotes.model.db_schema import updatedb + updatedb(doctype, 1) + + # again + insert_record_name(tar_tab, name) + else: + raise e + +# update single value +# ------------------------- +
+
[docs]def update_single_value(tab, field, value, name): + sql("update `%s` set `%s`=%s where name=%s" % (tab, field, '%s', '%s'), (value, name)) + + +# update value +# ------------------------- +
+
[docs]def update_value(src_tab, tar_tab, name, rec, field): + try: + update_single_value(tar_tab, field, rec[field], name) + except Exception, e: + if e.args[0]==1054: + # column missing.... add it? + ftype = sql("show columns from `%s` like '%s'" % (src_tab, field))[0][1] + + webnotes.conn.commit() # causes implict commit + sql("alter table `%s` add column `%s` %s" % (tar_tab, field, ftype)) + webnotes.conn.begin() + + # again + update_single_value(tar_tab, field, rec[field], name) + else: + raise e +
+ +
+
+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/cache.html b/docs/_build/html/_modules/webnotes/utils/cache.html new file mode 100644 index 0000000000..39531795d1 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/cache.html @@ -0,0 +1,155 @@ + + + + + + + + + webnotes.utils.cache — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.cache

+"""
+Simple Caching:
+
+Stores key-value pairs in database and enables simple caching
+
+get_item(key).get() returns the cached value if not expired (else returns null)
+get_item(key).set(interval = 60000) sets a value to cache, expiring after x seconds
+get_item(key).clear() clears an old value
+setup() sets up cache
+"""
+
+import webnotes
+
+
[docs]class CacheItem: + def __init__(self, key): + """create a new cache""" + self.key = key + +
[docs] def get(self): + """get value""" + try: + return webnotes.conn.sql("select `value` from __CacheItem where `key`=%s and expires_on > NOW()", self.key)[0][0] + except Exception: + return None +
+
[docs] def set(self, value, interval=6000): + """set a new value, with interval""" + try: + self.clear() + webnotes.conn.sql("""INSERT INTO + __CacheItem (`key`, `value`, expires_on) + VALUES + (%s, %s, addtime(now(), sec_to_time(%s))) + """, (self.key, str(value), interval)) + except Exception, e: + if e.args[0]==1146: + setup() + self.set(value, interval) + else: raise e +
+
[docs] def clear(self): + """clear the item""" + webnotes.conn.sql("delete from __CacheItem where `key`=%s", self.key) +
+
[docs]def setup(): + webnotes.conn.commit() + webnotes.conn.sql("""create table __CacheItem( + `key` VARCHAR(180) NOT NULL PRIMARY KEY, + `value` TEXT, + `expires_on` TIMESTAMP + )""") + webnotes.conn.begin() +
+
[docs]def get_item(key): + """returns get CacheItem object""" + return CacheItem(key) + pass
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/email_lib.html b/docs/_build/html/_modules/webnotes/utils/email_lib.html new file mode 100644 index 0000000000..5220d5bee7 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/email_lib.html @@ -0,0 +1,185 @@ + + + + + + + + + webnotes.utils.email_lib — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.email_lib

+import webnotes
+
+
[docs]def sendmail_html(sender, recipients, subject, html, text=None, template=None, send_now=1, reply_to=None): + """ + Send an html mail with alternative text and using Page Templates + """ + sendmail(recipients, sender, html, subject, send_now = send_now, reply_to = reply_to, template = template) +
+
[docs]def make_html_body(content, template = None): + """ + Generate html content from a Page Template object + """ + template_html = '%(content)s' + + if template: + from webnotes.model.code import get_code + template_html = get_code(webnotes.conn.get_value('Page Template', template, 'module'), 'Page Template', template, 'html', fieldname='template') + + return template_html % {'content': content} + +
+
[docs]def sendmail(recipients, sender='', msg='', subject='[No Subject]', parts=[], cc=[], attach=[], send_now=1, reply_to=None, template=None): + """ + send an html email as multipart with attachments and all + """ + + from webnotes.utils.email_lib.html2text import html2text + from webnotes.utils.email_lib.send import EMail + + email = EMail(sender, recipients, subject, reply_to=reply_to) + email.cc = cc + + if msg: + if template: + msg = make_html_body(msg, template) + else: + # if not html, then lets put some whitespace + if (not '<br>' in msg) or (not '<p>' in msg): + msg = msg.replace('\n','<br>') + + footer = get_footer() + msg = msg + (footer or '') + email.set_text(html2text(msg)) + email.set_html(msg) + for p in parts: + email.set_message(p[1]) + for a in attach: + email.attach(a) + + email.send(send_now) + +
+ +
[docs]def send_form(): + """ + Emails a print format (form) + Called from form UI + """ + + from webnotes.utils.email_lib.form_email import FormEmail + FormEmail().send() + +
+
[docs]def get_contact_list(): + """ + Returns contacts (from autosuggest) + """ + import webnotes + + cond = ['`%s` like "%s%%"' % (f, webnotes.form.getvalue('txt')) for f in webnotes.form.getvalue('where').split(',')] + cl = webnotes.conn.sql("select `%s` from `tab%s` where %s" % ( + webnotes.form.getvalue('select') + ,webnotes.form.getvalue('from') + ,' OR '.join(cond) + ) + ) + webnotes.response['cl'] = filter(None, [c[0] for c in cl]) + +
+ +
+
+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/email_lib/form_email.html b/docs/_build/html/_modules/webnotes/utils/email_lib/form_email.html new file mode 100644 index 0000000000..0cb2aff8f7 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/email_lib/form_email.html @@ -0,0 +1,262 @@ + + + + + + + + + webnotes.utils.email_lib.form_email — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.email_lib.form_email

+import webnotes
+from webnotes.utils import cint
+
+form = webnotes.form
+
+from webnotes.utils.email_lib import get_footer
+from webnotes.utils.email_lib.send import EMail
+
+
[docs]class FormEmail: + """ + Represents an email sent from a Form + """ + def __init__(self): + """ + Get paramteres from the cgi form object + """ + self.__dict__.update(webnotes.form_dict) + + self.recipients = None + if self.sendto: + self.recipients = self.sendto.replace(';', ',') + self.recipients = self.recipients.split(',') + +
[docs] def update_contacts(self): + """ + Add new email contact to database + """ + import webnotes + from webnotes.model.doc import Document + + for r in self.recipients: + r = r.strip() + try: + if not webnotes.conn.sql("select email_id from tabContact where email_id=%s", r): + d = Document('Contact') + d.email_id = r + d.save(1) + except Exception, e: + if e.args[0]==1146: pass # no table + else: raise e +
+ + +
[docs] def set_attachments(self): + """ + Set attachments to the email from the form + """ + al = [] + try: + al = webnotes.conn.sql('select file_list from `tab%s` where name="%s"' % (form.getvalue('dt'), form.getvalue('dn'))) + if al: + al = (al[0][0] or '').split('\n') + except Exception, e: + if e.args[0]==1146: + pass # no attachments in single types! + else: + raise Exception, e + return al +
+
[docs] def build_message(self): + """ + Builds the message object + """ + + self.email = EMail(self.sendfrom, self.recipients, self.subject, alternative = 1) + + from webnotes.utils.email_lib.html2text import html2text + + self.make_full_links() + + # message + if not self.__dict__.get('message'): + self.message = 'Please find attached %s: %s\n' % (self.dt, self.dn) + + html_message = text_message = self.message.replace('\n','<br>') + + # separator + html_message += '<div style="margin:17px 0px; border-bottom:1px solid #AAA"></div>' + + # form itself (only in the html message) + html_message += self.body + + # form link + html_message += self.get_form_link() + text_message += self.get_form_link() + + # footer + footer = get_footer() + if footer: + html_message += footer + text_message += footer + + # message as text + self.email.set_text(html2text(text_message)) + self.email.set_html(html_message) +
+
[docs] def send(self): + """ + Send the form with html attachment + """ + + if not self.recipients: + webnotes.msgprint('No one to send to!') + return + + self.build_message() + + # print format (as attachment also - for text-only clients) + self.email.add_attachment(self.dn.replace(' ','').replace('/','-') + '.html', self.body) + + # attachments + # self.with_attachments comes from http form variables + # i.e. with_attachments=1 + if cint(self.with_attachments): + for a in self.set_attachments(): + a and self.email.attach_file(a.split(',')[0]) + + # cc + if self.cc: + self.email.cc = [self.cc] + + self.email.send(send_now=1) + webnotes.msgprint('Sent')
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/email_lib/html2text.html b/docs/_build/html/_modules/webnotes/utils/email_lib/html2text.html new file mode 100644 index 0000000000..2c83d67aa2 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/email_lib/html2text.html @@ -0,0 +1,591 @@ + + + + + + + + + webnotes.utils.email_lib.html2text — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.email_lib.html2text

+#!/usr/bin/env python
+"""html2text: Turn HTML into equivalent Markdown-structured text."""
+__version__ = "3.02"
+__author__ = "Aaron Swartz (me@aaronsw.com)"
+__copyright__ = "(C) 2004-2008 Aaron Swartz. GNU GPL 3."
+__contributors__ = ["Martin 'Joey' Schulze", "Ricardo Reyes", "Kevin Jay North"]
+
+# TODO:
+#   Support decoded entities with unifiable.
+
+try:
+    True
+except NameError:
+    setattr(__builtins__, 'True', 1)
+    setattr(__builtins__, 'False', 0)
+
+
[docs]def has_key(x, y): + if hasattr(x, 'has_key'): return x.has_key(y) + else: return y in x +
+try: + import htmlentitydefs + import urlparse + import HTMLParser +except ImportError: #Python3 + import html.entities as htmlentitydefs + import urllib.parse as urlparse + import html.parser as HTMLParser +try: #Python3 + import urllib.request as urllib +except: + import urllib +import optparse, re, sys, codecs, types + +try: from textwrap import wrap +except: pass + +# Use Unicode characters instead of their ascii psuedo-replacements +UNICODE_SNOB = 0 + +# Put the links after each paragraph instead of at the end. +LINKS_EACH_PARAGRAPH = 0 + +# Wrap long lines at position. 0 for no wrapping. (Requires Python 2.3.) +BODY_WIDTH = 78 + +# Don't show internal links (href="#local-anchor") -- corresponding link targets +# won't be visible in the plain text file anyway. +SKIP_INTERNAL_LINKS = False + +### Entity Nonsense ### + +
[docs]def name2cp(k): + if k == 'apos': return ord("'") + if hasattr(htmlentitydefs, "name2codepoint"): # requires Python 2.3 + return htmlentitydefs.name2codepoint[k] + else: + k = htmlentitydefs.entitydefs[k] + if k.startswith("&#") and k.endswith(";"): return int(k[2:-1]) # not in latin-1 + return ord(codecs.latin_1_decode(k)[0]) +
+unifiable = {'rsquo':"'", 'lsquo':"'", 'rdquo':'"', 'ldquo':'"', +'copy':'(C)', 'mdash':'--', 'nbsp':' ', 'rarr':'->', 'larr':'<-', 'middot':'*', +'ndash':'-', 'oelig':'oe', 'aelig':'ae', +'agrave':'a', 'aacute':'a', 'acirc':'a', 'atilde':'a', 'auml':'a', 'aring':'a', +'egrave':'e', 'eacute':'e', 'ecirc':'e', 'euml':'e', +'igrave':'i', 'iacute':'i', 'icirc':'i', 'iuml':'i', +'ograve':'o', 'oacute':'o', 'ocirc':'o', 'otilde':'o', 'ouml':'o', +'ugrave':'u', 'uacute':'u', 'ucirc':'u', 'uuml':'u'} + +unifiable_n = {} + +for k in unifiable.keys(): + unifiable_n[name2cp(k)] = unifiable[k] + +
[docs]def charref(name): + if name[0] in ['x','X']: + c = int(name[1:], 16) + else: + c = int(name) + + if not UNICODE_SNOB and c in unifiable_n.keys(): + return unifiable_n[c] + else: + try: + return unichr(c) + except NameError: #Python3 + return chr(c) +
+
[docs]def entityref(c): + if not UNICODE_SNOB and c in unifiable.keys(): + return unifiable[c] + else: + try: name2cp(c) + except KeyError: return "&" + c + ';' + else: + try: + return unichr(name2cp(c)) + except NameError: #Python3 + return chr(name2cp(c)) +
+
[docs]def replaceEntities(s): + s = s.group(1) + if s[0] == "#": + return charref(s[1:]) + else: return entityref(s) +
+r_unescape = re.compile(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));") +
[docs]def unescape(s): + return r_unescape.sub(replaceEntities, s) + +### End Entity Nonsense ### +
+
[docs]def onlywhite(line): + """Return true if the line does only consist of whitespace characters.""" + for c in line: + if c is not ' ' and c is not ' ': + return c is ' ' + return line +
+
[docs]def optwrap(text): + """Wrap all paragraphs in the provided text.""" + if not BODY_WIDTH: + return text + + assert wrap, "Requires Python 2.3." + result = '' + newlines = 0 + for para in text.split("\n"): + if len(para) > 0: + if para[0] != ' ' and para[0] != '-' and para[0] != '*': + for line in wrap(para, BODY_WIDTH): + result += line + "\n" + result += "\n" + newlines = 2 + else: + if not onlywhite(para): + result += para + "\n" + newlines = 1 + else: + if newlines < 2: + result += "\n" + newlines += 1 + return result +
+
[docs]def hn(tag): + if tag[0] == 'h' and len(tag) == 2: + try: + n = int(tag[1]) + if n in range(1, 10): return n + except ValueError: return 0 +
+class _html2text(HTMLParser.HTMLParser): + def __init__(self, out=None, baseurl=''): + HTMLParser.HTMLParser.__init__(self) + + if out is None: self.out = self.outtextf + else: self.out = out + try: + self.outtext = unicode() + except NameError: # Python3 + self.outtext = str() + self.quiet = 0 + self.p_p = 0 + self.outcount = 0 + self.start = 1 + self.space = 0 + self.a = [] + self.astack = [] + self.acount = 0 + self.list = [] + self.blockquote = 0 + self.pre = 0 + self.startpre = 0 + self.lastWasNL = 0 + self.abbr_title = None # current abbreviation definition + self.abbr_data = None # last inner HTML (for abbr being defined) + self.abbr_list = {} # stack of abbreviations to write later + self.baseurl = baseurl + + def outtextf(self, s): + self.outtext += s + + def close(self): + HTMLParser.HTMLParser.close(self) + + self.pbr() + self.o('', 0, 'end') + + return self.outtext + + def handle_charref(self, c): + self.o(charref(c)) + + def handle_entityref(self, c): + self.o(entityref(c)) + + def handle_starttag(self, tag, attrs): + self.handle_tag(tag, attrs, 1) + + def handle_endtag(self, tag): + self.handle_tag(tag, None, 0) + + def previousIndex(self, attrs): + """ returns the index of certain set of attributes (of a link) in the + self.a list + + If the set of attributes is not found, returns None + """ + if not has_key(attrs, 'href'): return None + + i = -1 + for a in self.a: + i += 1 + match = 0 + + if has_key(a, 'href') and a['href'] == attrs['href']: + if has_key(a, 'title') or has_key(attrs, 'title'): + if (has_key(a, 'title') and has_key(attrs, 'title') and + a['title'] == attrs['title']): + match = True + else: + match = True + + if match: return i + + def handle_tag(self, tag, attrs, start): + #attrs = fixattrs(attrs) + + if hn(tag): + self.p() + if start: self.o(hn(tag)*"#" + ' ') + + if tag in ['p', 'div']: self.p() + + if tag == "br" and start: self.o(" \n") + + if tag == "hr" and start: + self.p() + self.o("* * *") + self.p() + + if tag in ["head", "style", 'script']: + if start: self.quiet += 1 + else: self.quiet -= 1 + + if tag in ["body"]: + self.quiet = 0 # sites like 9rules.com never close <head> + + if tag == "blockquote": + if start: + self.p(); self.o('> ', 0, 1); self.start = 1 + self.blockquote += 1 + else: + self.blockquote -= 1 + self.p() + + if tag in ['em', 'i', 'u']: self.o("_") + if tag in ['strong', 'b']: self.o("**") + if tag == "code" and not self.pre: self.o('`') #TODO: `` `this` `` + if tag == "abbr": + if start: + attrsD = {} + for (x, y) in attrs: attrsD[x] = y + attrs = attrsD + + self.abbr_title = None + self.abbr_data = '' + if has_key(attrs, 'title'): + self.abbr_title = attrs['title'] + else: + if self.abbr_title != None: + self.abbr_list[self.abbr_data] = self.abbr_title + self.abbr_title = None + self.abbr_data = '' + + if tag == "a": + if start: + attrsD = {} + for (x, y) in attrs: attrsD[x] = y + attrs = attrsD + if has_key(attrs, 'href') and not (SKIP_INTERNAL_LINKS and attrs['href'].startswith('#')): + self.astack.append(attrs) + self.o("[") + else: + self.astack.append(None) + else: + if self.astack: + a = self.astack.pop() + if a: + i = self.previousIndex(a) + if i is not None: + a = self.a[i] + else: + self.acount += 1 + a['count'] = self.acount + a['outcount'] = self.outcount + self.a.append(a) + self.o("][" + str(a['count']) + "]") + + if tag == "img" and start: + attrsD = {} + for (x, y) in attrs: attrsD[x] = y + attrs = attrsD + if has_key(attrs, 'src'): + attrs['href'] = attrs['src'] + alt = attrs.get('alt', '') + i = self.previousIndex(attrs) + if i is not None: + attrs = self.a[i] + else: + self.acount += 1 + attrs['count'] = self.acount + attrs['outcount'] = self.outcount + self.a.append(attrs) + self.o("![") + self.o(alt) + self.o("]["+ str(attrs['count']) +"]") + + if tag == 'dl' and start: self.p() + if tag == 'dt' and not start: self.pbr() + if tag == 'dd' and start: self.o(' ') + if tag == 'dd' and not start: self.pbr() + + if tag in ["ol", "ul"]: + if start: + self.list.append({'name':tag, 'num':0}) + else: + if self.list: self.list.pop() + + self.p() + + if tag == 'li': + if start: + self.pbr() + if self.list: li = self.list[-1] + else: li = {'name':'ul', 'num':0} + self.o(" "*len(self.list)) #TODO: line up <ol><li>s > 9 correctly. + if li['name'] == "ul": self.o("* ") + elif li['name'] == "ol": + li['num'] += 1 + self.o(str(li['num'])+". ") + self.start = 1 + else: + self.pbr() + + if tag in ["table", "tr"] and start: self.p() + if tag == 'td': self.pbr() + + if tag == "pre": + if start: + self.startpre = 1 + self.pre = 1 + else: + self.pre = 0 + self.p() + + def pbr(self): + if self.p_p == 0: self.p_p = 1 + + def p(self): self.p_p = 2 + + def o(self, data, puredata=0, force=0): + if self.abbr_data is not None: self.abbr_data += data + + if not self.quiet: + if puredata and not self.pre: + data = re.sub('\s+', ' ', data) + if data and data[0] == ' ': + self.space = 1 + data = data[1:] + if not data and not force: return + + if self.startpre: + #self.out(" :") #TODO: not output when already one there + self.startpre = 0 + + bq = (">" * self.blockquote) + if not (force and data and data[0] == ">") and self.blockquote: bq += " " + + if self.pre: + bq += " " + data = data.replace("\n", "\n"+bq) + + if self.start: + self.space = 0 + self.p_p = 0 + self.start = 0 + + if force == 'end': + # It's the end. + self.p_p = 0 + self.out("\n") + self.space = 0 + + + if self.p_p: + self.out(('\n'+bq)*self.p_p) + self.space = 0 + + if self.space: + if not self.lastWasNL: self.out(' ') + self.space = 0 + + if self.a and ((self.p_p == 2 and LINKS_EACH_PARAGRAPH) or force == "end"): + if force == "end": self.out("\n") + + newa = [] + for link in self.a: + if self.outcount > link['outcount']: + self.out(" ["+ str(link['count']) +"]: " + urlparse.urljoin(self.baseurl, link['href'])) + if has_key(link, 'title'): self.out(" ("+link['title']+")") + self.out("\n") + else: + newa.append(link) + + if self.a != newa: self.out("\n") # Don't need an extra line when nothing was done. + + self.a = newa + + if self.abbr_list and force == "end": + for abbr, definition in self.abbr_list.items(): + self.out(" *[" + abbr + "]: " + definition + "\n") + + self.p_p = 0 + self.out(data) + self.lastWasNL = data and data[-1] == '\n' + self.outcount += 1 + + def handle_data(self, data): + if r'\/script>' in data: self.quiet -= 1 + self.o(data, 1) + + def unknown_decl(self, data): pass + +
[docs]def wrapwrite(text): + text = text.encode('utf-8') + try: #Python3 + sys.stdout.buffer.write(text) + except AttributeError: + sys.stdout.write(text) +
+
[docs]def html2text_file(html, out=wrapwrite, baseurl=''): + h = _html2text(out, baseurl) + h.feed(html) + h.feed("") + return h.close() +
+
[docs]def html2text(html, baseurl=''): + return optwrap(html2text_file(html, None, baseurl)) +
+if __name__ == "__main__": + baseurl = '' + + p = optparse.OptionParser('%prog [(filename|url) [encoding]]', + version='%prog ' + __version__) + args = p.parse_args()[1] + if len(args) > 0: + file_ = args[0] + encoding = None + if len(args) == 2: + encoding = args[1] + if len(args) > 2: + p.error('Too many arguments') + + if file_.startswith('http://') or file_.startswith('https://'): + baseurl = file_ + j = urllib.urlopen(baseurl) + text = j.read() + if encoding is None: + try: + from feedparser import _getCharacterEncoding as enc + except ImportError: + enc = lambda x, y: ('utf-8', 1) + encoding = enc(j.headers, text)[0] + if encoding == 'us-ascii': + encoding = 'utf-8' + data = text.decode(encoding) + + else: + data = open(file_, 'rb').read() + if encoding is None: + try: + from chardet import detect + except ImportError: + detect = lambda x: {'encoding': 'utf-8'} + encoding = detect(data)['encoding'] + data = data.decode(encoding) + else: + data = sys.stdin.read() + wrapwrite(html2text(data, baseurl)) +
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/email_lib/receive.html b/docs/_build/html/_modules/webnotes/utils/email_lib/receive.html new file mode 100644 index 0000000000..6b49455551 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/email_lib/receive.html @@ -0,0 +1,242 @@ + + + + + + + + + webnotes.utils.email_lib.receive — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.email_lib.receive

+"""
+	This module contains classes for managing incoming emails
+"""
+
+
[docs]class IncomingMail: + """ + Single incoming email object. Extracts, text / html and attachments from the email + """ + def __init__(self, content): + """ + Parse the incoming mail content + """ + import email + + self.mail = email.message_from_string(content) + self.text_content = '' + self.html_content = '' + self.attachments = [] + self.parse() + +
[docs] def get_text_content(self): + """ + Returns the text parts of the email. If None, then HTML parts + """ + return self.text_content or self.html_content +
+
[docs] def get_charset(self, part): + """ + Guesses character set + """ + charset = part.get_content_charset() + if not charset: + import chardet + charset = chardet.detect(str(part))['encoding'] + + return charset +
+
[docs] def get_payload(self, part, charset): + """ + get utf-8 encoded part content + """ + return unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') +
+
[docs] def get_attachment(self, part, charset): + """ + Extracts an attachment + """ + self.attachments.append({ + 'content-type': part.get_content_type(), + 'filename': part.get_filename(), + 'content': self.get_payload(part, charset) + }) +
+
[docs] def parse(self): + """ + Extracts text, html and attachments from the mail + """ + for part in self.mail.walk(): + self.process_part(part) +
+
[docs] def get_thread_id(self): + """ + Extracts thread id of the message between first [] + from the subject + """ + subject = self.mail.get('Subject', '') + if '[' in subject and ']' in subject: + return subject.split('[')[1].split(']')[0] +
+
[docs] def process_part(self, part): + """ + Process a single part of an email + """ + charset = self.get_charset(part) + content_type = part.get_content_type() + + if content_type == 'text/plain': + self.text_content += self.get_payload(part, charset) + + if content_type == 'text/html': + self.html_content += self.get_payload(part, charset) + + if part.get_filename(): + self.get_attachment(part, charset) +
+
[docs]class POP3Mailbox: + """ + A simple pop3 mailbox, abstracts connection and mail extraction + To use, subclass it and override method process_message(from, subject, text, thread_id) + """ + + def __init__(self, settings_doc): + """ + settings_doc must contain + is_ssl, host, username, password + """ + from webnotes.model.doc import Document + self.settings = Document(settings_doc, settings_doc) + +
[docs] def connect(self): + """ + Connects to the mailbox + """ + import poplib + + if self.settings.use_ssl: + self.pop = poplib.POP3_SSL(self.settings.host) + else: + self.pop = poplib.POP3(self.settings.host) + self.pop.user(self.settings.username) + self.pop.pass_(self.settings.password) + +
+
[docs] def get_messages(self): + """ + Loads messages from the mailbox and calls + process_message for each message + """ + + if not self.check_mails(): + return # nothing to do + + self.connect() + num = len(self.pop.list()[1]) + for m in range(num): + msg = self.pop.retr(m+1) + self.process_message(IncomingMail('\n'.join(msg[1]))) + self.pop.dele(m+1) + self.pop.quit() +
+
[docs] def check_mails(self): + """ + To be overridden + If mailbox is to be scanned, returns true + """ + return true +
+
[docs] def process_message(self, mail): + """ + To be overriden + """ + pass
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/email_lib/send.html b/docs/_build/html/_modules/webnotes/utils/email_lib/send.html new file mode 100644 index 0000000000..aaaeffee8e --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/email_lib/send.html @@ -0,0 +1,392 @@ + + + + + + + + + webnotes.utils.email_lib.send — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.email_lib.send

+"""
+Sends email via outgoing server specified in "Control Panel"
+Allows easy adding of Attachments of "File" objects
+"""
+
+import webnotes	
+import webnotes.defs
+from webnotes import msgprint
+import email
+
+
[docs]class EMail: + """ + Wrapper on the email module. Email object represents emails to be sent to the client. + Also provides a clean way to add binary `FileData` attachments + Also sets all messages as multipart/alternative for cleaner reading in text-only clients + """ + def __init__(self, sender='', recipients=[], subject='', from_defs=0, alternative=0, reply_to=None): + from email.mime.multipart import MIMEMultipart + if type(recipients)==str: + recipients = recipients.replace(';', ',') + recipients = recipients.split(',') + + self.from_defs = from_defs + self.sender = sender + self.reply_to = reply_to or sender + self.recipients = recipients + self.subject = subject + + self.msg_root = MIMEMultipart('mixed') + self.msg_multipart = MIMEMultipart('alternative') + self.msg_root.attach(self.msg_multipart) + self.cc = [] + +
[docs] def set_text(self, message): + """ + Attach message in the text portion of multipart/alternative + """ + from email.mime.text import MIMEText + part = MIMEText(message, 'plain') + self.msg_multipart.attach(part) +
+
[docs] def set_html(self, message): + """ + Attach message in the html portion of multipart/alternative + """ + from email.mime.text import MIMEText + part = MIMEText(message, 'html') + self.msg_multipart.attach(part) +
+
[docs] def set_message(self, message, mime_type='text/html', as_attachment=0, filename='attachment.html'): + """ + Append the message with MIME content to the root node (as attachment) + """ + from email.mime.text import MIMEText + + maintype, subtype = mime_type.split('/') + part = MIMEText(message, _subtype = subtype) + + if as_attachment: + part.add_header('Content-Disposition', 'attachment', filename=filename) + + self.msg_root.attach(part) +
+
[docs] def attach_file(self, n): + """ + attach a file from the `FileData` table + """ + from webnotes.utils.file_manager import get_file + res = get_file(n) + if not res: + return + + self.add_attachment(res[0], res[1]) +
+
[docs] def add_attachment(self, fname, fcontent, content_type=None): + + from email.mime.audio import MIMEAudio + from email.mime.base import MIMEBase + from email.mime.image import MIMEImage + from email.mime.text import MIMEText + + import mimetypes + + if not content_type: + content_type, encoding = mimetypes.guess_type(fname) + + if content_type is None: + # No guess could be made, or the file is encoded (compressed), so + # use a generic bag-of-bits type. + content_type = 'application/octet-stream' + + maintype, subtype = content_type.split('/', 1) + if maintype == 'text': + # Note: we should handle calculating the charset + part = MIMEText(fcontent, _subtype=subtype) + elif maintype == 'image': + part = MIMEImage(fcontent, _subtype=subtype) + elif maintype == 'audio': + part = MIMEAudio(fcontent, _subtype=subtype) + else: + part = MIMEBase(maintype, subtype) + part.set_payload(fcontent) + # Encode the payload using Base64 + from email import encoders + encoders.encode_base64(part) + + # Set the filename parameter + if fname: + part.add_header('Content-Disposition', 'attachment', filename=fname) + + self.msg_root.attach(part) +
+
[docs] def validate(self): + """ + validate the email ids + """ + if not self.sender: + self.sender = webnotes.conn.get_value('Control Panel',None,'auto_email_id') + + from webnotes.utils import validate_email_add + # validate ids + if self.sender and (not validate_email_add(self.sender)): + webnotes.msgprint("%s is not a valid email id" % self.sender, raise_exception = 1) + + if self.reply_to and (not validate_email_add(self.reply_to)): + webnotes.msgprint("%s is not a valid email id" % self.reply_to, raise_exception = 1) + + for e in self.recipients: + if not validate_email_add(e): + webnotes.msgprint("%s is not a valid email id" % e, raise_exception = 1) +
+
[docs] def setup(self): + """ + setup the SMTP (outgoing) server from `Control Panel` or defs.py + """ + if self.from_defs: + self.server = getattr(webnotes.defs,'mail_server','') + self.login = getattr(webnotes.defs,'mail_login','') + self.port = getattr(webnotes.defs,'mail_port',None) + self.password = getattr(webnotes.defs,'mail_password','') + self.use_ssl = getattr(webnotes.defs,'use_ssl',0) + + else: + import webnotes.model.doc + from webnotes.utils import cint + + # get defaults from control panel + cp = webnotes.model.doc.Document('Control Panel','Control Panel') + self.server = cp.outgoing_mail_server or getattr(webnotes.defs,'mail_server','') + self.login = cp.mail_login or getattr(webnotes.defs,'mail_login','') + self.port = cp.mail_port or getattr(webnotes.defs,'mail_port',None) + self.password = cp.mail_password or getattr(webnotes.defs,'mail_password','') + self.use_ssl = cint(cp.use_ssl) +
+
[docs] def make_msg(self): + self.msg_root['Subject'] = self.subject + self.msg_root['From'] = self.sender + self.msg_root['To'] = ', '.join([r.strip() for r in self.recipients]) + if self.reply_to and self.reply_to != self.sender: + self.msg_root['Reply-To'] = self.reply_to + if self.cc: + self.msg_root['CC'] = ', '.join([r.strip() for r in self.cc]) +
+
[docs] def add_to_queue(self): + # write to a file called "email_queue" or as specified in email + q = EmailQueue() + q.push({ + 'server': self.server, + 'port': self.port, + 'use_ssl': self.use_ssl, + 'login': self.login, + 'password': self.password, + 'sender': self.sender, + 'recipients': self.recipients, + 'msg': self.msg_root.as_string() + }) + q.close() +
+
[docs] def send(self, send_now = 0): + """ + send the message + """ + from webnotes.utils import cint + + self.setup() + self.validate() + self.make_msg() + + if (not send_now) and getattr(webnotes.defs, 'batch_emails', 0): + self.add_to_queue() + return + + import smtplib + sess = smtplib.SMTP(self.server, self.port or None) + + if self.use_ssl: + sess.ehlo() + sess.starttls() + sess.ehlo() + + ret = sess.login(self.login, self.password) + + # check if logged correctly + if ret[0]!=235: + msgprint(ret[1]) + raise Exception + + sess.sendmail(self.sender, self.recipients, self.msg_root.as_string()) + + try: + sess.quit() + except: + pass + + + + +# =========================================== +# Email Queue +# Maintains a list of emails in a file +# Flushes them when called from cron +# Defs settings: +# email_queue: (filename) [default: email_queue.py] +# +# From the scheduler, call: flush(qty) +# =========================================== +
+
[docs]class EmailQueue: + def __init__(self): + self.server = self.login = self.sess = None + self.filename = getattr(webnotes.defs, 'email_queue', 'email_queue.py') + + try: + f = open(self.filename, 'r') + self.queue = eval(f.read() or '[]') + f.close() + except IOError, e: + if e.args[0]==2: + self.queue = [] + else: + raise e + +
[docs] def push(self, email): + self.queue.append(email) +
+
[docs] def close(self): + f = open(self.filename, 'w') + f.write(str(self.queue)) + f.close() +
+
[docs] def get_smtp_session(self, e): + if self.server==e['server'] and self.login==e['login'] and self.sess: + return self.sess + + webnotes.msgprint('getting server') + + import smtplib + + sess = smtplib.SMTP(e['server'], e['port'] or None) + + if self.use_ssl: + sess.ehlo() + sess.starttls() + sess.ehlo() + + ret = sess.login(e['login'], e['password']) + + # check if logged correctly + if ret[0]!=235: + webnotes.msgprint(ret[1]) + raise Exception + + self.sess = sess + self.server, self.login = e['server'], e['login'] + + return sess +
+
[docs] def flush(self, qty = 100): + f = open(self.filename, 'r') + + self.queue = eval(f.read() or '[]') + + if len(self.queue) < 100: + qty = len(self.queue) + + for i in range(qty): + e = self.queue[i] + sess = self.get_smtp_session(e) + sess.sendmail(e['sender'], e['recipients'], e['msg']) + + self.queue = self.queue[:(len(self.queue) - qty)] + self.close() +
+ +
+
+ +
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/encrypt.html b/docs/_build/html/_modules/webnotes/utils/encrypt.html new file mode 100644 index 0000000000..ea9e6f885b --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/encrypt.html @@ -0,0 +1,151 @@ + + + + + + + + + webnotes.utils.encrypt — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.encrypt

+"""
+XTEA Block Encryption Algorithm
+Author: Paul Chakravarti (paul_dot_chakravarti_at_gmail_dot_com)
+License: Public Domain
+""" 
+
+
[docs]def get_key(): + # Encryption key is datetime of creation of DocType, DocType" + import webnotes + return webnotes.conn.sql("select creation from tabDocType where name='DocType'")[0][0].strftime('%Y%m%d%H%M%s')[:16] +
+
[docs]def encrypt(data, encryption_key = None): + if not encryption_key: + encryption_key = get_key() + return crypt(encryption_key, data).encode('hex') +
+
[docs]def decrypt(data, encryption_key = None): + if not encryption_key: + encryption_key = get_key() + return crypt(encryption_key, data.decode('hex')) +
+
[docs]def crypt(key,data,iv='\00\00\00\00\00\00\00\00',n=32): + def keygen(key,iv,n): + while True: + iv = xtea_encrypt(key,iv,n) + for k in iv: + yield ord(k) + xor = [ chr(x^y) for (x,y) in zip(map(ord,data),keygen(key,iv,n)) ] + return "".join(xor) +
+
[docs]def xtea_encrypt(key,block,n=32,endian="!"): + import struct + v0,v1 = struct.unpack(endian+"2L",block) + k = struct.unpack(endian+"4L",key) + sum,delta,mask = 0L,0x9e3779b9L,0xffffffffL + for round in range(n): + v0 = (v0 + (((v1<<4 ^ v1>>5) + v1) ^ (sum + k[sum & 3]))) & mask + sum = (sum + delta) & mask + v1 = (v1 + (((v0<<4 ^ v0>>5) + v0) ^ (sum + k[sum>>11 & 3]))) & mask + return struct.pack(endian+"2L",v0,v1) +
+
[docs]def xtea_decrypt(key,block,n=32,endian="!"): + import struct + + v0,v1 = struct.unpack(endian+"2L",block) + k = struct.unpack(endian+"4L",key) + delta,mask = 0x9e3779b9L,0xffffffffL + sum = (delta * n) & mask + for round in range(n): + v1 = (v1 - (((v0<<4 ^ v0>>5) + v0) ^ (sum + k[sum>>11 & 3]))) & mask + sum = (sum - delta) & mask + v0 = (v0 - (((v1<<4 ^ v1>>5) + v1) ^ (sum + k[sum & 3]))) & mask + return struct.pack(endian+"2L",v0,v1) +
+ +
+
+
+
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/file_manager.html b/docs/_build/html/_modules/webnotes/utils/file_manager.html new file mode 100644 index 0000000000..19dc9e0c12 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/file_manager.html @@ -0,0 +1,300 @@ + + + + + + + + + webnotes.utils.file_manager — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.file_manager

+
[docs]def upload(): + import webnotes + form = webnotes.form + + # get record details + dt = form.getvalue('doctype') + dn = form.getvalue('docname') + at_id = form.getvalue('at_id') + + # save + fid, fname = save_uploaded() + + if fid: + # refesh the form! + webnotes.response['result'] = """ +<script type='text/javascript'> +window.parent.wn.widgets.form.file_upload_done('%s', '%s', '%s', '%s', '%s'); +window.parent.frms['%s'].show_doc('%s'); +</script> + """ % (dt, dn, fid, fname.replace("'", "\\'"), at_id, dt, dn) + +# ------------------------------------------------------- +
+
[docs]def make_thumbnail(blob, size): + from PIL import Image + import cStringIO + + fobj = cStringIO.StringIO(blob) + image = Image.open(fobj) + image.thumbnail((tn,tn*2), Image.ANTIALIAS) + outfile = cStringIO.StringIO() + image.save(outfile, 'JPEG') + outfile.seek(0) + fcontent = outfile.read() + + return fcontent + +
+
[docs]def save_uploaded(js_okay='window.parent.msgprint("File Upload Successful")', js_fail=''): + import webnotes + import webnotes.utils + + webnotes.response['type'] = 'iframe' + + form, fid, fname = webnotes.form, None, None + + try: + # has attachment? + if 'filedata' in form: + i = form['filedata'] + + fname, content = i.filename, i.file.read() + + # thumbnail + if webnotes.form_dict.get('thumbnail'): + try: + content = make_thumbnail(content, int(form.get('thumbnail'))) + # change extension to jpg + fname = '.'.join(fname.split('.')[:-1])+'.jpg' + except Exception, e: + pass + + # get the file id + fid = save_file(fname, content) + + # okay + webnotes.response['result'] = """<script type='text/javascript'>%s</script>""" % js_okay + else: + webnotes.response['result'] = """<script type='text/javascript'>window.parent.msgprint("No file"); %s</script>""" % js_fail + + except Exception, e: + webnotes.response['result'] = """<script type='text/javascript'>window.parent.msgprint("%s"); window.parent.errprint("%s"); %s</script>""" % (str(e), webnotes.utils.getTraceback().replace('\n','<br>').replace('"', '\\"'), js_fail) + + return fid, fname + +# ------------------------------------------------------- +
+
[docs]def save_file(fname, content, module=None): + import webnotes + from webnotes.model.doc import Document + + # some browsers return the full path + if '\\' in fname: + fname = fname.split('\\')[-1] + if '/' in fname: + fname = fname.split('/')[-1] + + # generate the ID (?) + f = Document('File Data') + f.file_name = fname + if module: + f.module = module + f.save(1) + + write_file(f.name, content) + + return f.name + +# ------------------------------------------------------- +
+
[docs]def write_file(fid, content): + import webnotes, os, webnotes.defs + + # test size + max_file_size = 1000000 + if hasattr(webnotes.defs, 'max_file_size'): + max_file_size = webnotes.defs.max_file_size + + if len(content) > max_file_size: + raise Exception, 'Maximum File Limit (%s MB) Crossed' % (int(max_file_size / 1000000)) + + # no slashes + fid = fid.replace('/','-') + + # save to a folder (not accessible to public) + folder = webnotes.get_files_path() + + # create account folder (if not exists) + webnotes.create_folder(folder) + + # write the file + file = open(os.path.join(folder, fid),'w+') + file.write(content) + file.close() + + +# -------------------------------------------------------
+
[docs]def get_file_system_name(fname): + # get system name from File Data table + import webnotes + return webnotes.conn.sql("select name, file_name from `tabFile Data` where name=%s or file_name=%s", (fname, fname)) + +# -------------------------------------------------------
+
[docs]def delete_file(fname, verbose=0): + import webnotes, os + + for f in get_file_system_name(fname): + webnotes.conn.sql("delete from `tabFile Data` where name=%s", f[0]) + + # delete file + file_id = f[0].replace('/','-') + try: + os.remove(os.path.join(webnotes.get_files_path(), file_id)) + except OSError, e: + if e.args[0]!=2: + raise e + + if verbose: webnotes.msgprint('File Deleted') + +# Get File +# ------------------------------------------------------- +
+
[docs]def get_file(fname): + import webnotes + in_fname = fname + + # from the "File" table + if webnotes.conn.exists('File',fname): + fname = webnotes.conn.sql("select file_list from tabFile where name=%s", fname) + fname = fname and fname[0][0] + fname = fname.split('\n')[0].split(',')[1] + + + if get_file_system_name(fname): + f = get_file_system_name(fname)[0] + else: + f = None + + + # read the file + import os + + file_id = f[0].replace('/','-') + file = open(os.path.join(webnotes.get_files_path(), file_id), 'r') + content = file.read() + file.close() + return [f[1], content] + +# Conversion Patch +# ------------------------------------------------------- +
+
[docs]def convert_to_files(verbose=0): + import webnotes + + # nfiles + fl = webnotes.conn.sql("select name from `tabFile Data`") + for f in fl: + # get the blob + blob = webnotes.conn.sql("select blob_content from `tabFile Data` where name=%s", f[0])[0][0] + + if blob: + + if hasattr(blob, 'tostring'): + blob = blob.tostring() + + # write the file + write_file(f[0], blob) + + if verbose: + webnotes.msgprint('%s updated' % f[0]) + +# -------------------------------------------------------
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/jsmin.html b/docs/_build/html/_modules/webnotes/utils/jsmin.html new file mode 100644 index 0000000000..a0dafec4b1 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/jsmin.html @@ -0,0 +1,311 @@ + + + + + + + + + webnotes.utils.jsmin — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.jsmin

+import os, os.path, shutil
+
+# This code is original from jsmin by Douglas Crockford, it was translated to
+# Python by Baruch Even. The original code had the following copyright and
+# license.
+#
+# /* jsmin.c
+#    2007-05-22
+#
+# Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is furnished to do
+# so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# The Software shall be used for Good, not Evil.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# */
+
+from StringIO import StringIO
+
+
[docs]def jsmin(js): + ins = StringIO(js) + outs = StringIO() + JavascriptMinify().minify(ins, outs) + str = outs.getvalue() + if len(str) > 0 and str[0] == '\n': + str = str[1:] + return str +
+
[docs]def isAlphanum(c): + """return true if the character is a letter, digit, underscore, + dollar sign, or non-ASCII character. + """ + return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or + (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126)); +
+
[docs]class UnterminatedComment(Exception): + pass +
+
[docs]class UnterminatedStringLiteral(Exception): + pass +
+
[docs]class UnterminatedRegularExpression(Exception): + pass +
+
[docs]class JavascriptMinify(object): + + def _outA(self): + self.outstream.write(self.theA) + def _outB(self): + self.outstream.write(self.theB) + + def _get(self): + """return the next character from stdin. Watch out for lookahead. If + the character is a control character, translate it to a space or + linefeed. + """ + c = self.theLookahead + self.theLookahead = None + if c == None: + c = self.instream.read(1) + if c >= ' ' or c == '\n': + return c + if c == '': # EOF + return '\000' + if c == '\r': + return '\n' + return ' ' + + def _peek(self): + self.theLookahead = self._get() + return self.theLookahead + + def _next(self): + """get the next character, excluding comments. peek() is used to see + if an unescaped '/' is followed by a '/' or '*'. + """ + c = self._get() + if c == '/' and self.theA != '\\': + p = self._peek() + if p == '/': + c = self._get() + while c > '\n': + c = self._get() + return c + if p == '*': + c = self._get() + while 1: + c = self._get() + if c == '*': + if self._peek() == '/': + self._get() + return ' ' + if c == '\000': + raise UnterminatedComment() + + return c + + def _action(self, action): + """do something! What you do is determined by the argument: + 1 Output A. Copy B to A. Get the next B. + 2 Copy B to A. Get the next B. (Delete A). + 3 Get the next B. (Delete B). + action treats a string as a single character. Wow! + action recognizes a regular expression if it is preceded by ( or , or =. + """ + if action <= 1: + self._outA() + + if action <= 2: + self.theA = self.theB + if self.theA == "'" or self.theA == '"': + while 1: + self._outA() + self.theA = self._get() + if self.theA == self.theB: + break + if self.theA <= '\n': + raise UnterminatedStringLiteral() + if self.theA == '\\': + self._outA() + self.theA = self._get() + + + if action <= 3: + self.theB = self._next() + if self.theB == '/' and (self.theA == '(' or self.theA == ',' or + self.theA == '=' or self.theA == ':' or + self.theA == '[' or self.theA == '?' or + self.theA == '!' or self.theA == '&' or + self.theA == '|' or self.theA == ';' or + self.theA == '{' or self.theA == '}' or + self.theA == '\n'): + self._outA() + self._outB() + while 1: + self.theA = self._get() + if self.theA == '/': + break + elif self.theA == '\\': + self._outA() + self.theA = self._get() + elif self.theA <= '\n': + raise UnterminatedRegularExpression() + self._outA() + self.theB = self._next() + + + def _jsmin(self): + """Copy the input to the output, deleting the characters which are + insignificant to JavaScript. Comments will be removed. Tabs will be + replaced with spaces. Carriage returns will be replaced with linefeeds. + Most spaces and linefeeds will be removed. + """ + self.theA = '\n' + self._action(3) + + while self.theA != '\000': + if self.theA == ' ': + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + elif self.theA == '\n': + if self.theB in ['{', '[', '(', '+', '-']: + self._action(1) + elif self.theB == ' ': + self._action(3) + else: + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + else: + if self.theB == ' ': + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + elif self.theB == '\n': + if self.theA in ['}', ']', ')', '+', '-', '"', '\'']: + self._action(1) + else: + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + else: + self._action(1) + +
[docs] def minify(self, instream, outstream): + self.instream = instream + self.outstream = outstream + self.theA = '\n' + self.theB = None + self.theLookahead = None + + self._jsmin() + self.instream.close()
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/nestedset.html b/docs/_build/html/_modules/webnotes/utils/nestedset.html new file mode 100644 index 0000000000..24a1ac5d39 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/nestedset.html @@ -0,0 +1,178 @@ + + + + + + + + + webnotes.utils.nestedset — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.nestedset

+# Tree (Hierarchical) Nested Set Model (nsm)
+# 
+# To use the nested set model,
+# use the following pattern
+# 1. name your parent field as "parent_node" if not have a property nsm_parent_field as your field name in the document class
+# 2. have a field called "old_parent" in your fields list - this identifies whether the parent has been changed
+# 3. call update_nsm(doc_obj) in the on_upate method
+
+# ------------------------------------------
+
+import webnotes
+
+# called in the on_update method
+
[docs]def update_nsm(doc_obj): + # get fields, data from the DocType + d = doc_obj.doc + pf, opf = 'parent_node', 'old_parent' + if hasattr(doc_obj,'nsm_parent_field'): + pf = doc_obj.nsm_parent_field + if hasattr(doc_obj,'nsm_oldparent_field'): + opf = doc_obj.nsm_oldparent_field + p, op = d.fields[pf], d.fields.get(opf, '') + + # has parent changed (?) or parent is None (root) + if not doc_obj.doc.lft and not doc_obj.doc.rgt: + update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf) + elif op != p: + update_remove_node(doc_obj.doc.doctype, doc_obj.doc.name) + update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf) + # set old parent + webnotes.conn.set(d, opf, p or '') +
+
[docs]def rebuild_tree(doctype, parent_field): + # get all roots + right = 1 + result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='' or `%s` IS NULL" % (doctype, parent_field, parent_field)) + for r in result: + right = rebuild_node(doctype, r[0], right, parent_field) +
+
[docs]def rebuild_node(doctype, parent, left, parent_field): + # the right value of this node is the left value + 1 + right = left+1 + + # get all children of this node + result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='%s'" % (doctype, parent_field, parent)) + for r in result: + right = rebuild_node(doctype, r[0], right, parent_field) + + # we've got the left value, and now that we've processed + # the children of this node we also know the right value + webnotes.conn.sql('UPDATE `tab%s` SET lft=%s, rgt=%s WHERE name="%s"' % (doctype,left,right,parent)) + + #return the right value of this node + 1 + return right+1 +
+
[docs]def update_add_node(doctype, name, parent, parent_field): + # get the last sibling of the parent + if parent: + right = webnotes.conn.sql("select rgt from `tab%s` where name='%s'" % (doctype, parent))[0][0] + else: # root + right = webnotes.conn.sql("select ifnull(max(rgt),0)+1 from `tab%s` where ifnull(`%s`,'') =''" % (doctype, parent_field))[0][0] + right = right or 1 + + # update all on the right + webnotes.conn.sql("update `tab%s` set rgt = rgt+2 where rgt >= %s" %(doctype,right)) + webnotes.conn.sql("update `tab%s` set lft = lft+2 where lft >= %s" %(doctype,right)) + + #$ update index of new node + webnotes.conn.sql("update `tab%s` set lft=%s, rgt=%s where name='%s'" % (doctype,right,right+1,name)) + return right +
+
[docs]def update_remove_node(doctype, name): + left = webnotes.conn.sql("select lft from `tab%s` where name='%s'" % (doctype,name)) + if left[0][0]: + # reset this node + webnotes.conn.sql("update `tab%s` set lft=0, rgt=0 where name='%s'" % (doctype,name)) + + # update all on the right + webnotes.conn.sql("update `tab%s` set rgt = rgt-2 where rgt > %s" %(doctype,left[0][0])) + webnotes.conn.sql("update `tab%s` set lft = lft-2 where lft > %s" %(doctype,left[0][0]))
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/scheduler.html b/docs/_build/html/_modules/webnotes/utils/scheduler.html new file mode 100644 index 0000000000..3d7e232878 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/scheduler.html @@ -0,0 +1,264 @@ + + + + + + + + + webnotes.utils.scheduler — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.scheduler

+"""
+Simple Scheduler
+
+This scheduler is used to fire events across multiple databases. A database
+master_scheduler is maintained with one event and one log table
+
+Events are added by different databases in the master scheduler using the
+`set_event` method and they are executed by the cron.
+
+__main__ will call run
+
+To install:
+-----------
+
+python install_lib.py [root] [password] master_scheduler
+
+In cron:
+--------
+
+python [path]webnotes/utils/scheduler.py
+
+"""
+
+
+
[docs]class Scheduler: +
[docs] def connect(self): + if hasattr(self,'conn'): return + + import webnotes.defs, webnotes.db + try: + self.conn = webnotes.db.Database(user='master_scheduler', password=webnotes.defs.db_password) + except Exception, e: + self.setup() + self.connect() +
+
[docs] def set(self, event, interval, recurring, db_name=None): + """ + Add an event to the Event table in the master scheduler + """ + self.connect() + + if not db_name: + import webnotes + db_name = webnotes.conn.cur_db_name + + self.clear(db_name, event) + self.conn.sql("""insert into + Event (`db_name`, `event`, `interval`, next_execution, recurring) + values (%s, %s, %s, ADDTIME(NOW(), SEC_TO_TIME(%s)), %s) + """, (webnotes.conn.cur_db_name, event, interval, interval, recurring)) +
+
[docs] def get_events(self, db_name=None): + """ + Returns list of upcoming events + """ + self.connect() + if not db_name: + import webnotes + db_name = webnotes.conn.cur_db_name + + return self.conn.sql("select * from Event where db_name=%s", db_name, as_dict=1) + +
+
[docs] def get_log(self, db_name=None): + """ + Returns log of events + """ + self.connect() + if not db_name: + import webnotes + db_name = webnotes.conn.cur_db_name + + return self.conn.sql("select * from EventLog where db_name=%s limit 50", db_name, as_dict=1) +
+
[docs] def clear(self, db_name, event): + """ + Clears the event + """ + self.connect() + self.conn.sql("delete from Event where `event`=%s and db_name=%s", (event, db_name)) +
+
[docs] def execute(self, db_name, event): + """ + Executes event in the specifed db + """ + import webnotes, webnotes.defs, webnotes.db + + try: + webnotes.conn = webnotes.db.Database(user=db_name, password=webnotes.defs.db_password) + webnotes.session = {'user':'Administrator'} + + module = '.'.join(event.split('.')[:-1]) + method = event.split('.')[-1] + + exec 'from %s import %s' % (module, method) + + webnotes.conn.begin() + ret = locals()[method]() + webnotes.conn.commit() + webnotes.conn.close() + + self.log(db_name, event, ret or 'Ok') + + except Exception, e: + self.log(db_name, event, webnotes.getTraceback()) +
+
[docs] def log(self, db_name, event, traceback): + """ + Log an event error + """ + self.conn.sql("insert into `EventLog`(db_name, event, log, executed_on) values (%s, %s, %s, now())", \ + (db_name, event, traceback)) + + # delete old logs + self.conn.sql("delete from EventLog where executed_on < subdate(curdate(), interval 30 day)") +
+
[docs] def run(self): + """ + Run scheduled (due) events and reset time for recurring events + """ + el = self.conn.sql("""select `db_name`, `event`, `recurring`, `interval` + from `Event` + where next_execution < NOW()""", as_dict=1) + + for e in el: + # execute the event + self.execute(e['db_name'], e['event']) + + # if recurring, update next_execution + if e['recurring']: + self.conn.sql("update Event set next_execution = addtime(now(), sec_to_time(%s))", e['interval']) + + # else clear + else: + self.clear(e['db_name'], e['event']) +
+
[docs]def set_event(event, interval=60*60*24, recurring=1): + """ + Adds an event to the master scheduler + """ + return Scheduler().set(event, interval, recurring) + +
+
[docs]def cancel_event(event): + """ + Cancels an event + """ + import webnotes + return Scheduler().clear(webnotes.conn.cur_db_name, event) + +# to be called from cron
+if __name__=='__main__': + import os,sys + + cgi_bin_path = os.path.sep.join(__file__.split(os.path.sep)[:-3]) + + sys.path.append(cgi_bin_path) + + import webnotes + import webnotes.defs + sys.path.append(getattr(webnotes.defs,'modules_path',None)) + + sch = Scheduler() + sch.connect() + sch.run() + +
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/sitemap.html b/docs/_build/html/_modules/webnotes/utils/sitemap.html new file mode 100644 index 0000000000..baa00ef274 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/sitemap.html @@ -0,0 +1,132 @@ + + + + + + + + + webnotes.utils.sitemap — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.sitemap

+# to generate sitemaps
+
+frame_xml = """<?xml version="1.0" encoding="UTF-8"?>
+<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">%s
+</urlset>"""
+
+link_xml = """\n<url><loc>%s</loc><lastmod>%s</lastmod></url>"""
+
+# generate the sitemap XML
+
[docs]def generate_xml(conn, site_prefix): + global frame_xml, link_xml + import urllib + + # settings + max_doctypes = 10 + max_items = 1000 + + site_map = '' + + if site_prefix: + # list of all Guest pages (static content) + for r in conn.sql("SELECT name, modified FROM tabPage WHERE ifnull(publish,0)=1 ORDER BY modified DESC"): + page_url = site_prefix + '#!' + urllib.quote(r[0]) + site_map += link_xml % (page_url, r[1].strftime('%Y-%m-%d')) + + # list of all Records that are viewable by guests (Blogs, Articles etc) + try: + from event_handlers import get_sitemap_items + for i in get_sitemap_items(site_prefix): + site_map += link_xml % (i[0], i[1]) + except ImportError, e: + pass + + return frame_xml % site_map
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/transfer.html b/docs/_build/html/_modules/webnotes/utils/transfer.html new file mode 100644 index 0000000000..d7f4e9ef9c --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/transfer.html @@ -0,0 +1,396 @@ + + + + + + + + + webnotes.utils.transfer — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.transfer

+import webnotes
+from webnotes.model.doc import Document
+
+
[docs]def set_doc(doclist, ovr=0, ignore=1, onupdate=1): + dt = doclist[0]['doctype'] + + if webnotes.conn.exists(doclist[0]['doctype'], doclist[0]['name']): + # exists, merge if possible + + if dt=='DocType': + ud = UpdateDocType(doclist) + elif dt == 'Module Def': + ud = UpdateModuleDef(doclist) + elif dt == 'DocType Mapper': + ud = UpdateDocTypeMapper(doclist) + else: + ud = UpdateDocument(doclist) + else: + ud = UpdateDocument(doclist) + + ud.sync() + return '\n'.join(ud.log) + + + + +# +# Class to sync incoming document +#
+
[docs]class UpdateDocument: + def __init__(self, in_doclist=[]): + self.in_doclist = in_doclist + self.doc = Document(fielddata = in_doclist[0]) + self.modified = self.doc.modified # make a copy + self.doclist = [] + + self.log = [] + self.exists = 0 + + # sync +
[docs] def sync(self): + is_mod = self.is_modified() + + if (not self.exists) or (is_mod): + webnotes.conn.begin() + if self.exists: + self.delete_existing() + self.save() + self.update_modified() + self.run_on_update() + webnotes.conn.commit() + + # check modified
+
[docs] def is_modified(self): + try: + timestamp = webnotes.conn.sql("select modified from `tab%s` where name=%s" % (self.doc.doctype, '%s'), self.doc.name) + except Exception ,e: + if(e.args[0]==1146): + return + else: + raise e + + if timestamp: + self.exists = 1 + if str(timestamp[0][0]) == self.doc.modified: + self.log.append('%s %s, No change' % (self.doc.doctype, self.doc.name)) + else: return 1 + + # delete existing
+
[docs] def delete_existing(self): + from webnotes.model import delete_doc + webnotes.conn.sql("set foreign_key_checks=0") + delete_doc(self.doc.doctype, self.doc.name) + webnotes.conn.sql("set foreign_key_checks=1") + + # update modified timestamp
+
[docs] def update_modified(self): + webnotes.conn.set(self.doc, 'modified', self.modified) +
+
[docs] def save(self): + # parent + self.doc.save(new = 1, ignore_fields = 1, check_links=0) + self.doclist = [self.doc] + self.save_children() +
+
[docs] def save_children(self): + for df in self.in_doclist[1:]: + self.save_one_doc(df) +
+
[docs] def save_one_doc(self, df, as_new=1): + d = Document(fielddata = df) + d.save(new = as_new, ignore_fields = 1, check_links=0) + self.doclist.append(d) +
+
[docs] def run_on_update(self): + from webnotes.model.code import get_server_obj + so = get_server_obj(self.doc, self.doclist) + if hasattr(so, 'on_update'): + so.on_update() + + + +# +# "Merge incoming doctype" +#
+
[docs]class UpdateDocumentMerge(UpdateDocument): + def __init__(self, in_doclist): + self.to_update_doctype = [] + UpdateDocument.__init__(self, in_doclist) + +
[docs] def delete_existing(self): + pass +
+
[docs] def get_id(self, d): + pass +
+
[docs] def to_update(self, d): + return 1 +
+
[docs] def child_exists(self, d): + return self.get_id(d) +
+
[docs] def on_save(self): + pass +
+
[docs] def save(self): + if self.exists: + # save main doc + self.keep_values(self.doc) + self.doc.save(ignore_fields = 1, check_links=0) + self.doclist.append(self.doc) + self.save_children() + self.on_save() + self.log.append('Updated %s' % self.doc.name) + else: + UpdateDocument.save(self) +
+
[docs] def save_children(self): + for df in self.in_doclist[1:]: + d = Document(fielddata = df) + + # update doctype? + if d.doctype in self.to_update_doctype: + + # update this record? + if self.to_update(d): + + # is it new? + if self.child_exists(d): + self.keep_values(d) + d.save(ignore_fields = 1, check_links=0) + self.log.append('updated %s, %s' % (d.doctype, d.name)) + else: + d.save(1, ignore_fields = 1, check_links=0) + self.log.append('new %s' % d.doctype) + self.doclist.append(d) +
+
[docs] def keep_values(self, d): + if hasattr(self, 'get_orignal_values'): + ov = self.get_orignal_values(d) + if ov: + d.fields.update(ov) + + + +# +# Class to sync incoming doctype +#
+
[docs]class UpdateDocType(UpdateDocumentMerge): + def __init__(self, in_doclist): + UpdateDocumentMerge.__init__(self, in_doclist) + self.to_update_doctype = ['DocType', 'DocField'] + +
[docs] def to_udpate(self, d): + if (d.fieldtype not in ['Section Break', 'Column Break', 'HTML']) and (d.fieldname or d.label): + return 1 +
+
[docs] def get_id(self, d): + key = d.fieldname and 'fieldname' or 'label' + return webnotes.conn.sql("""select name, options, permlevel, reqd, print_hide, hidden + from tabDocField where %s=%s and parent=%s""" % (key, '%s', '%s'), (d.fields[key], d.parent)) +
+
[docs] def on_save(self): + self.renum() +
+
[docs] def child_exists(self, d): + if d.doctype=='DocField': + return self.get_id(d) +
+
[docs] def get_orignal_values(self, d): + if d.doctype=='DocField': + t = self.get_id(d)[0] + return {'name': t[0], 'options': t[1], 'reqd':t[3], 'print_hide':t[4], 'hidden':t[5]} + + if d.doctype=='DocType': + return webnotes.conn.sql("select server_code, client_script from `tabDocType` where name=%s", d.name, as_dict = 1)[0] + + # renumber the indexes
+
[docs] def renum(self): + extra = self.get_extra_fields() + self.clear_section_breaks() + self.add_section_breaks_and_renum() + self.fix_extra_fields(extra) + + # get fields not in the incoming list (to preserve order)
+
[docs] def get_extra_fields(self): + prev_field, prev_field_key, extra = '', '', [] + + # get new fields and labels + fieldnames = [d.get('fieldname') for d in self.in_doclist] + labels = [d.get('label') for d in self.in_doclist] + + # check if all existing are present + for f in webnotes.conn.sql("select fieldname, label, idx from tabDocField where parent=%s and fieldtype not in ('Section Break', 'Column Break', 'HTML') order by idx asc", self.doc.name): + if f[0] and not f[0] in fieldnames: + extra.append([f[0], f[1], prev_field, prev_field_key]) + elif f[1] and not f[1] in labels: + extra.append([f[0], f[1], prev_field, prev_field_key]) + + prev_field, prev_field_key = f[0] or f[1], f[0] and 'fieldname' or 'label' + + return extra + + # clear section breaks
+
[docs] def clear_section_breaks(self): + webnotes.conn.sql("delete from tabDocField where fieldtype in ('Section Break', 'Column Break', 'HTML') and parent=%s and ifnull(options,'')!='Custom'", self.doc.name) + + # add section breaks
+
[docs] def add_section_breaks_and_renum(self): + for d in self.in_doclist: + if d.get('parentfield')=='fields': + if d.get('fieldtype') in ('Section Break', 'Column Break', 'HTML'): + tmp = Document(fielddata = d) + tmp.fieldname = '' + tmp.name = None + tmp.save(1, ignore_fields = 1, check_links=0) + else: + webnotes.conn.sql("update tabDocField set idx=%s where %s=%s and parent=%s" % \ + ('%s', d.get('fieldname') and 'fieldname' or 'label', '%s', '%s'), (d.get('idx'), d.get('fieldname') or d.get('label'), self.doc.name)) + + + # adjust the extra fields
+
[docs] def fix_extra_fields(self, extra): + # push fields down at new idx + for e in extra: + # get idx of the prev to extra field + idx = 0 + if e[2]: + idx = webnotes.conn.sql("select idx from tabDocField where %s=%s and parent=%s" % (e[3], '%s', '%s'), (e[2], self.doc.name)) + idx = idx and idx[0][0] or 0 + + if idx: + webnotes.conn.sql("update tabDocField set idx=idx+1 where idx>%s and parent=%s", (idx, self.doc.name)) + webnotes.conn.sql("update tabDocField set idx=%s where %s=%s and parent=%s" % \ + ('%s', e[0] and 'fieldname' or 'label', '%s', '%s'), (idx+1, e[0] or e[1], self.doc.name)) + + + + +# +# update module def +#
+
[docs]class UpdateModuleDef(UpdateDocumentMerge): + def __init__(self, in_doclist): + UpdateDocumentMerge.__init__(self, in_doclist) + self.to_update_doctype = ['Module Def', 'Module Def Item'] + +
[docs] def get_id(self, d): + return webnotes.conn.sql("select name from `tabModule Def Item` where doc_type=%s and doc_name=%s and display_name=%s and parent=%s", (d.doc_type, d.doc_name, d.display_name, d.parent)) +
+
[docs] def to_update(self, d): + if d.doctype=='Module Def Item': return 1 +
+
[docs] def get_orignal_values(self, d): + if d.doctype=='Module Def Item': + return {'name': self.get_id(d)[0][0]} + if d.doctype=='Module Def': + return webnotes.conn.sql("select module_seq, disabled, is_hidden from `tabModule Def` where name=%s", d.name, as_dict = 1)[0] + + + +# +# update module def +#
+
[docs]class UpdateDocTypeMapper(UpdateDocumentMerge): + def __init__(self, in_doclist): + UpdateDocumentMerge.__init__(self, in_doclist) + self.to_update_doctype = ['Field Mapper Detail', 'Table Mapper Detail'] + +
[docs] def get_id(self, d): + if d.doctype=='Field Mapper Detail': + return webnotes.conn.sql("select name from `tabField Mapper Detail` where from_field=%s and to_field=%s and match_id=%s and parent=%s", (d.from_field, d.to_field, d.match_id, d.parent)) + elif d.doctype=='Table Mapper Detail': + return webnotes.conn.sql("select name from `tabTable Mapper Detail` where from_table=%s and to_table = %s and match_id=%s and parent=%s", (d.from_table, d.to_table, d.match_id, d.parent)) +
+
[docs] def get_orignal_values(self, d): + if d.doctype in ['Field Mapper Detail', 'Table Mapper Detail']: + return {'name': self.get_id(d)[0][0]} +
+ +
+
+ +
+
+ + + +
+
+
+ + + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/utils/webservice.html b/docs/_build/html/_modules/webnotes/utils/webservice.html new file mode 100644 index 0000000000..015f7ab40b --- /dev/null +++ b/docs/_build/html/_modules/webnotes/utils/webservice.html @@ -0,0 +1,209 @@ + + + + + + + + + webnotes.utils.webservice — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.utils.webservice

+import webnotes
+import webnotes.utils
+
+
[docs]class FrameworkServer: + """ + Connect to a remote server via HTTP (webservice). + + * `remote_host` is the the address of the remote server + * `path` is the path of the Framework (excluding index.cgi) + """ + def __init__(self, remote_host, path, user='', password='', account='', cookies=None, opts=None, https = 0): + # validate + if not (remote_host and path): + raise Exception, "Server address and path necessary" + + if not ((user and password) or (cookies)): + raise Exception, "Either cookies or user/password necessary" + + self.remote_host = remote_host + self.path = path + self.cookies = cookies or {} + self.webservice_method='POST' + self.account = account + self.account_id = None + self.https = https + self.conn = None + + # login + if not cookies: + args = { 'usr': user, 'pwd': password, 'acx': account } + + if opts: + args.update(opts) + + res = self.http_get_response('login', args) + + ret = res.read() + try: + ret = eval(ret) + except Exception, e: + webnotes.msgprint(ret) + raise Exception, e + + if ret.get('message') and ret.get('message')!='Logged In': + raise Exception, ret.get('message') + + if ret.get('exc'): + raise Exception, ret.get('exc') + + self._extract_cookies(res) + + self.account_id = self.cookies.get('account_id') + self.sid = self.cookies.get('sid') + + self.login_response = res + self.login_return = ret + + # ----------------------------------------------------------------------------------------- + +
[docs] def http_get_response(self, method, args): + """ + Run a method on the remote server, with the given arguments + """ + # get response from remote server + + import urllib, urllib2, os + + args['cmd'] = method + if self.path.startswith('/'): self.path = self.path[1:] + + protocol = self.https and 'https://' or 'http://' + req = urllib2.Request(protocol + os.path.join(self.remote_host, self.path, 'index.cgi'), urllib.urlencode(args)) + for key in self.cookies: + req.add_header('cookie', '; '.join(['%s=%s' % (key, self.cookies[key]) for key in self.cookies])) + return urllib2.urlopen(req) + + # ----------------------------------------------------------------------------------------- +
+ def _extract_cookies(self, res): + import Cookie + cookies = Cookie.SimpleCookie() + cookies.load(res.headers.get('set-cookie')) + for c in cookies.values(): + self.cookies[c.key] = c.value.rstrip(',') + + # ----------------------------------------------------------------------------------------- + + +
[docs] def runserverobj(self, doctype, docname, method, arg=''): + """ + Returns the response of a remote method called on a system object specified by `doctype` and `docname` + """ + res = self.http_get_response('runserverobj', args = { + 'doctype':doctype + ,'docname':docname + ,'method':method + ,'arg':arg + }) + ret = eval(res.read()) + if ret.get('exc'): + raise Exception, ret.get('exc') + return ret + + # ----------------------------------------------------------------------------------------- +
+
[docs] def run_method(self, method, args): + res = self.http_get_response(method, args) + ret = eval(res.read()) + if ret.get('exc'): + raise Exception, ret.get('exc') + return ret
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/auto_master.html b/docs/_build/html/_modules/webnotes/widgets/auto_master.html new file mode 100644 index 0000000000..c4eebe53fc --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/auto_master.html @@ -0,0 +1,149 @@ + + + + + + + + + webnotes.widgets.auto_master — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.auto_master

+# auto masters
+# _ + fieldname is the table
+# 'value' is the column name, pkey
+
+import webnotes
+
+# create masters for a doctype
+
[docs]def create_auto_masters(dt): + fl = webnotes.conn.sql("select fieldname from tabDocField where fieldtype='Data' and options='Suggest' and parent=%s", dt) + for f in fl: + make_auto_master(f[0]) + +# create master table
+
[docs]def make_auto_master(fieldname): + try: + webnotes.conn.sql("select `value` from `__%s` limit 1" % fieldname) + except Exception, e: + if e.args[0]==1146: + webnotes.conn.commit() + webnotes.conn.sql("create table `__%s` (`value` varchar(220), primary key (`value`))" % fieldname) + webnotes.conn.begin() + +# get auto master fields
+
[docs]def get_master_fields(dt): + if not webnotes.session['data'].get('auto_masters'): + webnotes.session['data']['auto_masters'] = {} + + if webnotes.session['data']['auto_masters'].get(dt, None)==None: + fl = webnotes.conn.sql("select fieldname from tabDocField where fieldtype='Data' and options='Suggest' and parent=%s", dt) + webnotes.session['data']['auto_masters'][dt] = fl + + return webnotes.session['data']['auto_masters'][dt] + + +# update value
+
[docs]def update_auto_masters(doc): + if not doc.doctype: + return + + fl = get_master_fields(doc.doctype) + + # save masters in session cache + for f in fl: + if doc.fields.get(f[0]): + add_to_master(f[0], doc.fields.get(f[0])) + +# add to master
+
[docs]def add_to_master(fieldname, value): + try: + webnotes.conn.sql("insert into `__%s` (`value`) values (%s)" % (fieldname,'%s'), value) + except Exception, e: + # primary key + pass
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/event.html b/docs/_build/html/_modules/webnotes/widgets/event.html new file mode 100644 index 0000000000..c1f8edc930 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/event.html @@ -0,0 +1,144 @@ + + + + + + + + + webnotes.widgets.event — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.event

+# Event
+# -------------
+
+
[docs]def get_cal_events(m_st, m_end): + import webnotes + import webnotes.model.doc + + sql = webnotes.conn.sql + + # load owned events + res1 = sql("select name from `tabEvent` WHERE ifnull(event_date,'2000-01-01') between '%s' and '%s' and owner = '%s' and event_type != 'Public' and event_type != 'Cancel'" % (m_st, m_end, webnotes.user.name)) + + # load individual events + res2 = sql("select t1.name from `tabEvent` t1, `tabEvent User` t2 where ifnull(t1.event_date,'2000-01-01') between '%s' and '%s' and t2.person = '%s' and t1.name = t2.parent and t1.event_type != 'Cancel'" % (m_st, m_end, webnotes.user.name)) + + # load role events + roles = webnotes.user.get_roles() + myroles = ['t2.role = "%s"' % r for r in roles] + myroles = '(' + (' OR '.join(myroles)) + ')' + res3 = sql("select t1.name from `tabEvent` t1, `tabEvent Role` t2 where ifnull(t1.event_date,'2000-01-01') between '%s' and '%s' and t1.name = t2.parent and t1.event_type != 'Cancel' and %s" % (m_st, m_end, myroles)) + + # load public events + res4 = sql("select name from `tabEvent` where ifnull(event_date,'2000-01-01') between '%s' and '%s' and event_type='Public'" % (m_st, m_end)) + + doclist, rl = [], [] + for r in res1 + res2 + res3 + res4: + if not r in rl: + doclist += webnotes.model.doc.get('Event', r[0]) + rl.append(r) + + return doclist + + +# Load Month Events +# ----------------- +
+
[docs]def load_month_events(): + import webnotes + from webnotes.utils import cint + + form = webnotes.form + + mm = form.getvalue('month') + yy = form.getvalue('year') + m_st = str(yy) + '-%.2i' % cint(mm) + '-01' + m_end = str(yy) + '-%.2i' % cint(mm) + '-31' + + webnotes.response['docs'] = get_cal_events(m_st, m_end)
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/follow.html b/docs/_build/html/_modules/webnotes/widgets/follow.html new file mode 100644 index 0000000000..2a59cd6808 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/follow.html @@ -0,0 +1,230 @@ + + + + + + + + + webnotes.widgets.follow — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.follow

+"""
+Server side methods for the follower pattern (Follow button used in forms)
+"""
+
+import webnotes
+form = webnotes.form_dict
+
+#
+# Follow
+#
+
[docs]def follow(dt=None, dn=None, user=None, verbose=0): + "Add as follower to a particular record. If no parameteres, then take from the http request (form)" + + if not dt: + dt, dn, user = form.get('dt'), form.get('dn'), form.get('user') + verbose = 1 + + if not user: return + + if not is_follower(dt, dn, user): + make_follower(dt, dn, user, verbose) + else: + if verbose: webnotes.msgprint("%s is already a follower!" % user) + + return load_followers(dt, dn) +
+
[docs]def make_follower(dt, dn, user, verbose): + "Add the user as a follower" + if has_permission(dt, user): + from webnotes.model.doc import Document + d = Document('Follower') + d.doc_type = dt + d.doc_name = dn + d.owner = user + d.save(1) + else: + if verbose: webnotes.msgprint('%s does not have sufficient permission to follow' % user) +
+
[docs]def has_permission(dt, user): + "Check to see if the user has permission to follow" + + return webnotes.conn.sql("select name from tabDocPerm where parent=%s and ifnull(`read`,0)=1 and role in ('%s') limit 1" \ + % ('%s', ("', '".join(webnotes.user.get_roles()))), dt) +
+
[docs]def is_follower(dt, dn, user): + "returns true if given user is a follower" + + return webnotes.conn.sql(""" + select name from tabFollower + where ifnull(doc_type,'')=%s + and ifnull(doc_name,'')=%s + and owner=%s""", (dt, dn, user)) +# +# Unfollow +#
+
[docs]def unfollow(dt=None, dn=None, user=None): + "Unfollow a particular record. If no parameteres, then take from the http request (form)" + + if not dt: + dt, dn, user = form.get('dt'), form.get('dn'), form.get('user') + + webnotes.conn.sql("delete from tabFollower where doc_name=%s and doc_type=%s and owner=%s", (dn, dt, user)) + + return load_followers(dt, dn) + +# +# Load followers +#
+
[docs]def load_followers(dt=None, dn=None): + "returns list of followers (Full Names) for a particular object" + + if not dt: dt, dn = form.get('dt'), form.get('dn') + + try: + return [t[0] for t in webnotes.conn.sql(""" + SELECT IFNULL(CONCAT(t1.first_name, if(t1.first_name IS NULL, '', ' '), t1.last_name), t1.name) + FROM tabProfile t1, tabFollower t2 WHERE t2.doc_type=%s AND t2.doc_name=%s + AND t1.name = t2.owner""", (dt, dn))] + + except Exception, e: + if e.args[0] in (1146, 1054): + setup() + return [] + else: + raise e + +# +# Email followers +#
+
[docs]def email_followers(dt, dn, msg_html=None, msg_text=None): + "Send an email to all followers of this object" + pass + +# +# Update feed +#
+
[docs]def on_docsave(doc): + "Add the owner and all linked Profiles as followers" + follow(doc.doctype, doc.name, doc.owner) + for p in get_profile_fields(doc.doctype): + follow(doc.doctype, doc.name, doc.fields.get(p)) + + update_followers(doc = doc) + +# +# update the follower record timestamp and subject +#
+
[docs]def update_followers(dt=None, dn=None, subject=None, update_by=None, doc=None): + "Updates the timestamp and subject in follower table (for feed generation)" + from webnotes.utils import now + webnotes.conn.sql("update tabFollower set modified=%s, subject=%s, modified_by=%s where doc_type=%s and doc_name=%s", \ + (now(), + subject or doc.fields.get('subject'), \ + update_by or webnotes.session['user'],\ + dt or doc.doctype, + dn or doc.name)) + +# +# get type of "Profile" fields +#
+
[docs]def get_profile_fields(dt): + "returns a list of all profile link fields from the doctype" + return [f[0] for f in \ + webnotes.conn.sql("select fieldname from tabDocField where parent=%s and fieldtype='Link' and options='Profile'", dt)] + +# +# setup - make followers table +#
+
[docs]def setup(): + "Make table for followers - if missing" + webnotes.conn.commit() + from webnotes.modules.module_manager import reload_doc + reload_doc('core', 'doctype', 'follower') + webnotes.conn.begin()
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/form.html b/docs/_build/html/_modules/webnotes/widgets/form.html new file mode 100644 index 0000000000..4f3717fbe7 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/form.html @@ -0,0 +1,586 @@ + + + + + + + + + webnotes.widgets.form — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.form

+"""
+Server side handler for "Form" events
+"""
+
+import webnotes
+import webnotes.model.doc
+import webnotes.model.meta
+from webnotes.model.triggers import fire_event
+
+
[docs]def getdoc(): + """ + Loads a doclist for a given document. This method is called directly from the client. + Requries "doctype", "docname" as form variables. If "from_archive" is set, it will get from archive. + Will also call the "onload" method on the document. + """ + + import webnotes + from webnotes.utils import cint + + form = webnotes.form_dict + doctype, docname = form.get('doctype'), form.get('name') + prefix = cint(form.get('from_archive')) and 'arc' or 'tab' + + if not (doctype and docname): + raise Exception, 'doctype and name required!' + + doclist = [] + # single + doclist = load_single_doc(doctype, docname, (form.get('user') or webnotes.session['user']), prefix) + + # load doctype along with the doc + if form.get('getdoctype'): + import webnotes.model.doctype + doclist += webnotes.model.doctype.get(doctype) + + # tag as archived + if prefix == 'arc': + doclist[0].__archived=1 + + webnotes.response['docs'] = doclist + +#=========================================================================================== +
+
[docs]def get_comments(doctype=None, docname=None, limit=5): + nc, cl = 0, [] + + if not doctype: + doctype, docname, limit = webnotes.form_dict.get('dt'), webnotes.form_dict.get('dn'), webnotes.form_dict.get('limit') + + try: + nc = int(webnotes.conn.sql("select count(*) from `tabComment Widget Record` where comment_doctype=%s and comment_docname=%s", (doctype, docname))[0][0]) + if nc: + cl = webnotes.conn.sql("select comment, ifnull(comment_by_fullname, comment_by) AS 'comment_by_fullname', creation from `tabComment Widget Record` where comment_doctype=%s and comment_docname=%s order by creation desc limit %s" % ('%s','%s',limit), (doctype, docname), as_dict=1) + + except Exception, e: + if e.args[0]==1146: + # no table + make_comment_table() + else: + raise e + + webnotes.response['n_comments'], webnotes.response['comment_list'] = nc, cl + +# +# make comment table +#
+
[docs]def make_comment_table(): + "Make table for comments - if missing via import module" + webnotes.conn.commit() + from webnotes.modules import reload_doc + reload_doc('core', 'doctype', 'comment_widget_record') + webnotes.conn.begin() + +#=========================================================================================== +
+
[docs]def add_comment(): + import time + args = webnotes.form_dict + + if args.get('comment'): + from webnotes.model.doc import Document + from webnotes.utils import nowdate + + cmt = Document('Comment Widget Record') + for arg in ['comment', 'comment_by', 'comment_by_fullname', 'comment_doctype', 'comment_docname']: + cmt.fields[arg] = args[arg] + cmt.comment_date = nowdate() + cmt.comment_time = time.strftime('%H:%M') + cmt.save(1) + +#=========================================================================================== +
+
[docs]def remove_comment(): + args = webnotes.form_dict + webnotes.conn.sql("delete from `tabComment Widget Record` where name=%s",args.get('id')) + + try: + get_obj('Feed Control').upate_comment_in_feed(args['dt'], args['dn']) + except: pass + +#=========================================================================================== +
+
[docs]def getdoctype(): + # load parent doctype too + import webnotes.model.doctype + + form, doclist = webnotes.form, [] + + dt = form.getvalue('doctype') + with_parent = form.getvalue('with_parent') + + # with parent (called from report builder) + if with_parent: + parent_dt = webnotes.model.meta.get_parent_dt(dt) + if parent_dt: + doclist = webnotes.model.doctype.get(parent_dt) + webnotes.response['parent_dt'] = parent_dt + + if not doclist: + doclist = webnotes.model.doctype.get(dt) + + # if single, send the record too + if doclist[0].issingle: + doclist += webnotes.model.doc.get(dt) + + # load search criteria for reports (all) + doclist += webnotes.model.meta.get_search_criteria(dt) + + + webnotes.response['docs'] = doclist + +#=========================================================================================== +
+
[docs]def load_single_doc(dt, dn, user, prefix): + import webnotes.model.code + + if not dn: dn = dt + dl = webnotes.model.doc.get(dt, dn, prefix=prefix) + + # archive, done + if prefix=='arc': + return dl + + try: + so, r = webnotes.model.code.get_server_obj(dl[0], dl), None + if hasattr(so, 'onload'): + r = webnotes.model.code.run_server_obj(so, 'onload') + if hasattr(so, 'custom_onload'): + r = webnotes.model.code.run_server_obj(so, 'custom_onload') + if r: + webnotes.msgprint(r) + except Exception, e: + webnotes.errprint(webnotes.utils.getTraceback()) + webnotes.msgprint('Error in script while loading') + raise e + + if dl and not dn.startswith('_'): + webnotes.user.update_recent(dt, dn) + + # load search criteria ---- if doctype + if dt=='DocType': + dl += webnotes.model.meta.get_search_criteria(dt) + + return dl + +# Check Guest Access +#===========================================================================================
+
[docs]def check_guest_access(doc): + if webnotes.session['user']=='Guest' and not webnotes.conn.sql("select name from tabDocPerm where role='Guest' and parent=%s and ifnull(`read`,0)=1", doc.doctype): + webnotes.msgprint("Guest not allowed to call this object") + raise Exception + +# Runserverobj - run server calls from form +#=========================================================================================== +
+
[docs]def runserverobj(): + import webnotes.model.code + import webnotes.model.doclist + from webnotes.utils import cint + + form = webnotes.form + + + method = form.getvalue('method') + doclist, clientlist = [], [] + arg = form.getvalue('arg') + dt = form.getvalue('doctype') + dn = form.getvalue('docname') + + if dt: # not called from a doctype (from a page) + if not dn: dn = dt # single + so = webnotes.model.code.get_obj(dt, dn) + + else: + clientlist = webnotes.model.doclist.expand(form.getvalue('docs')) + + # find main doc + for d in clientlist: + if cint(d.get('docstatus')) != 2 and not d.get('parent'): + main_doc = webnotes.model.doc.Document(fielddata = d) + + # find child docs + for d in clientlist: + doc = webnotes.model.doc.Document(fielddata = d) + if doc.fields.get('parent'): + doclist.append(doc) + + so = webnotes.model.code.get_server_obj(main_doc, doclist) + + # check integrity + if not check_integrity(so.doc): + return + + check_guest_access(so.doc) + + if so: + r = webnotes.model.code.run_server_obj(so, method, arg) + doclist = so.doclist # reference back [in case of null] + if r: + try: + if r['doclist']: + clientlist += r['doclist'] + except: + pass + + #build output as csv + if cint(webnotes.form.getvalue('as_csv')): + make_csv_output(r, so.doc.doctype) + else: + webnotes.response['message'] = r + + if clientlist: + doclist.append(main_doc) + webnotes.response['docs'] = doclist +
+
[docs]def make_csv_output(res, dt): + import webnotes + from webnotes.utils import getCSVelement + + txt = [] + if type(res)==list: + for r in res: + txt.append(','.join([getCSVelement(i) for i in r])) + + txt = '\n'.join(txt) + + else: + txt = 'Output was not in list format\n' + r + + webnotes.response['result'] = txt + webnotes.response['type'] = 'csv' + webnotes.response['doctype'] = dt.replace(' ','') + + +# Document Save +#=========================================================================================== +
+def _get_doclist(clientlist): + # converts doc dictionaries into Document objects + + from webnotes.model.doc import Document + form = webnotes.form + + midx = 0 + for i in range(len(clientlist)): + if clientlist[i]['name'] == form.getvalue('docname'): + main_doc = Document(fielddata = clientlist[i]) + midx = i + else: + clientlist[i] = Document(fielddata = clientlist[i]) + + del clientlist[midx] + return main_doc, clientlist + +def _do_action(doc, doclist, so, method_name, docstatus=0): + + from webnotes.model.code import run_server_obj + set = webnotes.conn.set + + if so and hasattr(so, method_name): + errmethod = method_name + run_server_obj(so, method_name) + if hasattr(so, 'custom_'+method_name): + run_server_obj(so, 'custom_'+method_name) + errmethod = '' + + # fire triggers observers (if any) + fire_event(doc, method_name) + + # set docstatus for all children records + if docstatus: + for d in [doc] + doclist: + if int(d.docstatus or 0) != 2: + set(d, 'docstatus', docstatus) + +
[docs]def check_integrity(doc): + import webnotes + + if (not webnotes.model.meta.is_single(doc.doctype)) and (not doc.fields.get('__islocal')): + tmp = webnotes.conn.sql('SELECT modified FROM `tab%s` WHERE name="%s" for update' % (doc.doctype, doc.name)) + if tmp and str(tmp[0][0]) != str(doc.modified): + webnotes.msgprint('Document has been modified after you have opened it. To maintain the integrity of the data, you will not be able to save your changes. Please refresh this document. [%s/%s]' % (tmp[0][0], doc.modified)) + return 0 + + return 1 + +#=========================================================================================== +
+
[docs]def savedocs(): + import webnotes.model.doclist + + from webnotes.model.code import get_server_obj + from webnotes.model.code import run_server_obj + import webnotes.utils + from webnotes.widgets.auto_master import update_auto_masters + + from webnotes.utils import cint + + sql = webnotes.conn.sql + form = webnotes.form + + # action + action = form.getvalue('action') + + # get docs + doc, doclist = _get_doclist(webnotes.model.doclist.expand(form.getvalue('docs'))) + + # get server object + server_obj = get_server_obj(doc, doclist) + + # check integrity + if not check_integrity(doc): + return + + if not doc.check_perm(verbose=1): + webnotes.msgprint("Not enough permission to save %s" % doc.doctype) + return + + # validate links + ret = webnotes.model.doclist.validate_links_doclist([doc] + doclist) + if ret: + webnotes.msgprint("[Link Validation] Could not find the following values: %s. Please correct and resave. Document Not Saved." % ret) + return + + # saving & post-saving + try: + # validate befor saving and submitting + if action in ('Save', 'Submit') and server_obj: + if hasattr(server_obj, 'validate'): + t = run_server_obj(server_obj, 'validate') + if hasattr(server_obj, 'custom_validate'): + t = run_server_obj(server_obj, 'custom_validate') + + # set owner and modified times + is_new = cint(doc.fields.get('__islocal')) + if is_new and not doc.owner: + doc.owner = form.getvalue('user') + + doc.modified, doc.modified_by = webnotes.utils.now(), webnotes.session['user'] + + # save main doc + try: + t = doc.save(is_new) + update_auto_masters(doc) + except NameError, e: + webnotes.msgprint('%s "%s" already exists' % (doc.doctype, doc.name)) + if webnotes.conn.sql("select docstatus from `tab%s` where name=%s" % (doc.doctype, '%s'), doc.name)[0][0]==2: + webnotes.msgprint('[%s "%s" has been cancelled]' % (doc.doctype, doc.name)) + webnotes.errprint(webnotes.utils.getTraceback()) + raise e + + # save child docs + for d in doclist: + deleted, local = d.fields.get('__deleted',0), d.fields.get('__islocal',0) + + if cint(local) and cint(deleted): + pass + elif d.fields.has_key('parent'): + if d.parent and (not d.parent.startswith('old_parent:')): + d.parent = doc.name # rename if reqd + d.parenttype = doc.doctype + d.modified, d.modified_by = webnotes.utils.now(), webnotes.session['user'] + d.save(new = cint(local)) + update_auto_masters(d) + + # on_update + if action in ('Save','Submit') and server_obj: + if hasattr(server_obj, 'on_update'): + t = run_server_obj(server_obj, 'on_update') + if t: webnotes.msgprint(t) + + if hasattr(server_obj, 'custom_on_update'): + t = run_server_obj(server_obj, 'custom_on_update') + if t: webnotes.msgprint(t) + + fire_event(doc, 'on_update') + + # on_submit + if action == 'Submit': + _do_action(doc, doclist, server_obj, 'on_submit', 1) + + # for allow_on_submit type + if action == 'Update': + _do_action(doc, doclist, server_obj, 'on_update_after_submit', 0) + + # on_cancel + if action == 'Cancel': + _do_action(doc, doclist, server_obj, 'on_cancel', 2) + + # update recent documents + webnotes.user.update_recent(doc.doctype, doc.name) + + # send updated docs + webnotes.response['saved'] = '1' + webnotes.response['main_doc_name'] = doc.name + webnotes.response['docname'] = doc.name + webnotes.response['docs'] = [doc] + doclist + + except Exception, e: + webnotes.msgprint('Did not save') + webnotes.errprint(webnotes.utils.getTraceback()) + raise e + + +# Print Format +#===========================================================================================
+def _get_print_format(match): + name = match.group('name') + return webnotes.model.meta.get_print_format_html(name) + +
[docs]def get_print_format(): + import re + import webnotes + + html = webnotes.model.meta.get_print_format_html(webnotes.form.getvalue('name')) + + p = re.compile('\$import\( (?P<name> [^)]*) \)', re.VERBOSE) + out_html = '' + if html: + out_html = p.sub(_get_print_format, html) + + webnotes.response['message'] = out_html + +# remove attachment +#=========================================================================================== +
+
[docs]def remove_attach(): + import webnotes + import webnotes.utils.file_manager + + fid = webnotes.form.getvalue('fid') + webnotes.utils.file_manager.delete_file(fid, verbose=1) + +# Get Fields - Counterpart to $c_get_fields +#===========================================================================================
+
[docs]def get_fields(): + import webnotes + r = {} + args = { + 'select':webnotes.form.getvalue('select') + ,'from':webnotes.form.getvalue('from') + ,'where':webnotes.form.getvalue('where') + } + ret = webnotes.conn.sql("select %(select)s from `%(from)s` where %(where)s limit 1" % args) + if ret: + fl, i = webnotes.form.getvalue('fields').split(','), 0 + for f in fl: + r[f], i = ret[0][i], i+1 + webnotes.response['message']=r + +# validate link +#===========================================================================================
+ +
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/menus.html b/docs/_build/html/_modules/webnotes/widgets/menus.html new file mode 100644 index 0000000000..8dadbdcbf2 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/menus.html @@ -0,0 +1,277 @@ + + + + + + + + + webnotes.widgets.menus — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.menus

+"""
+Server side methods called from DocBrowser
+"""
+
+import webnotes
+from webnotes.utils import cint, cstr
+
+sql = webnotes.conn.sql
+
+
[docs]def get_menu_items(): + """ + Returns a list of items to show in `Options` of the Web Notes Toolbar + List contains Pages and Single DocTypes + """ + import webnotes.utils + + rl = webnotes.user.get_roles() + [webnotes.session['user']] + role_options = ["role = '"+r+"'" for r in rl] + + sql = webnotes.conn.sql + menuitems = [] + + # pages + pages = sql("select distinct parent from `tabPage Role` where docstatus!=2 and (%s)" % (' OR '.join(role_options))) + + for p in pages: + tmp = sql("select icon, parent_node, menu_index, show_in_menu from tabPage where name = '%s'" % p[0]) + if tmp and tmp[0][3]: + menuitems.append(['Page', p[0] or '', tmp[0][1] or '', tmp[0][0] or '', webnotes.utils.cint(tmp[0][2])]) + + # singles + tmp = sql("select smallicon, parent_node, menu_index, name from tabDocType where (show_in_menu = 1 and show_in_menu is not null)") + singles = {} + for t in tmp: singles[t[3]] = t + + for p in webnotes.user.can_read: + tmp = singles.get(p, None) + if tmp: menuitems.append([p, p, tmp[1] or '', tmp[0] or '', int(tmp[2] or 0)]) + + return menuitems + +# --------------------------------------------------------------
+
[docs]def has_result(): + return sql("select name from `tab%s` limit 1" % webnotes.form_dict.get('dt')) and 'Yes' or 'No' + +# -------------------------------------------------------------- +
+
[docs]def is_submittable(dt): + return sql("select name from tabDocPerm where parent=%s and ifnull(submit,0)=1 and docstatus<1 limit 1", dt) + +# -------------------------------------------------------------- +
+
[docs]def can_cancel(dt): + return sql('select name from tabDocPerm where parent="%s" and ifnull(cancel,0)=1 and docstatus<1 and role in ("%s") limit 1' % (dt, '", "'.join(webnotes.user.get_roles()))) + +# --------------------------------------------------------------
+
[docs]def get_dt_trend(dt): + ret = {} + for r in sql("select datediff(now(),modified), count(*) from `tab%s` where datediff(now(),modified) between 0 and 30 group by date(modified)" % dt): + ret[cint(r[0])] = cint(r[1]) + return ret + +# -------------------------------------------------------------- +
+
[docs]def get_columns(out, sf, fl, dt, tag_fields): + if not fl: + fl = sf + + # subject + subject = webnotes.conn.get_value('DocType', dt, 'subject') + if subject: + out['subject'] = subject + + # get fields from subject + import re + fl = re.findall('\%\( (?P<name> [^)]*) \)s', subject, re.VERBOSE) + + if tag_fields: + fl += [t.strip() for t in tag_fields.split(',')] + + res = [] + for f in tuple(set(fl)): + if f: + res += [[c or '' for c in r] for r in sql("select fieldname, label, fieldtype, options from tabDocField where parent='%s' and fieldname='%s'" % (dt, f))] + + + return res + + +# -------------------------------------------------------------- +# NOTE: THIS SHOULD BE CACHED IN DOCTYPE CACHE +# -------------------------------------------------------------- +
+
[docs]def get_dt_details(): + """ + Returns details called by DocBrowser this includes: + the filters, columns, subject and tag_fields + also if the doctype is of type "submittable" + """ + fl = eval(webnotes.form_dict.get('fl')) + dt = webnotes.form_dict.get('dt') + tag_fields, description = webnotes.conn.get_value('DocType', dt, ['tag_fields', 'description']) + + submittable = is_submittable(dt) and 1 or 0 + + out = { + 'submittable':(is_submittable(dt) and 1 or 0), + 'can_cancel':(can_cancel(dt) and 1 or 0) + } + + # filters + # ------- + + sf = sql("select search_fields from tabDocType where name=%s", dt)[0][0] or '' + + # get fields from in_filter (if not in search_fields) + if not sf.strip(): + res = sql("select fieldname, label, fieldtype, options from tabDocField where parent=%s and `in_filter` = 1 and ifnull(fieldname,'') != ''", dt) + sf = [s[0] for s in res] + else: + sf = [s.strip() for s in sf.split(',')] + res = sql("select fieldname, label, fieldtype, options from tabDocField where parent='%s' and fieldname in (%s)" % (dt, '"'+'","'.join(sf)+'"')) + + # select "link" options + res = [[c or '' for c in r] for r in res] + for r in res: + if r[2]=='Select' and r[3] and r[3].startswith('link:'): + tdt = r[3][5:] + ol = sql("select name from `tab%s` where docstatus!=2 order by name asc" % tdt) + r[3] = "\n".join([''] + [o[0] for o in ol]) + + if not res: + out['filters'] = [['name', 'ID', 'Data', '']] + else: + out['filters'] = [['name', 'ID', 'Data', '']] + res + + # columns + # ------- + res = get_columns(out, sf, fl, dt, tag_fields) + + from webnotes.widgets.tags import check_user_tags + check_user_tags(dt) + + out['columns'] = [['name', 'ID', 'Link', dt], ['modified', 'Modified', 'Data', ''], ['_user_tags', 'Tags', 'Data', '']] + res + out['tag_fields'] = tag_fields + out['description'] = description + + return out + + +# -------------------------------------------------------------- +
+
[docs]def get_trend(): + return {'trend': get_dt_trend(webnotes.form_dict.get('dt'))} + + + + + +# +# delete and archive in docbrowser +#
+
[docs]def delete_items(): + il = eval(webnotes.form_dict.get('items')) + from webnotes.model import delete_doc + from webnotes.model.code import get_obj + + for d in il: + dt_obj = get_obj(d[0], d[1]) + if hasattr(dt_obj, 'on_trash'): + dt_obj.on_trash() + delete_doc(d[0], d[1]) + +# -------------------------------------------------------------- +
+
[docs]def archive_items(): + il = eval(webnotes.form_dict.get('items')) + + from webnotes.utils.archive import archive_doc + for d in il: + archive_doc(d[0], d[1], webnotes.form_dict.get('action')=='Restore' and 1 or 0)
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/page.html b/docs/_build/html/_modules/webnotes/widgets/page.html new file mode 100644 index 0000000000..51af095625 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/page.html @@ -0,0 +1,183 @@ + + + + + + + + + webnotes.widgets.page — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.page

+import webnotes
+import webnotes.model.doc
+import webnotes.model.code
+
+conn = webnotes.conn
+
+
[docs]class Page: + """ + A page class helps in loading a Page in the system. On loading + + * Page will import Client Script from other pages where specified by `$import(page_name)` + * Execute dynamic HTML if the `content` starts with `#python` + """ + def __init__(self, name): + self.name = name + +
[docs] def load(self): + """ + Returns :term:`doclist` of the `Page` + """ + from webnotes.modules import compress + from webnotes.model.code import get_code + + doclist = webnotes.model.doc.get('Page', self.name) + doc = doclist[0] + + doc.fields['__script'] = compress.get_page_js(doc) + doc.script = None + + template = '%(content)s' + # load code from template + if doc.template: + template = get_code(webnotes.conn.get_value('Page Template', doc.template, 'module'), 'Page Template', doc.template, 'html', fieldname='template') + + doc.content = get_code(doc.module, 'page', doc.name, 'html') or doc.content + + # execute content + if doc.content and doc.content.startswith('#!python'): + doc.__content = template % {'content': webnotes.model.code.execute(doc.content).get('content')} + else: + doc.__content = template % {'content': doc.content or ''} + + # local stylesheet + css = get_code(doc.module, 'page', doc.name, 'css') + if css: doc.style = css + + # add stylesheet + if doc.stylesheet: + doclist += self.load_stylesheet(doc.stylesheet) + + return doclist +
+
[docs] def load_stylesheet(self, stylesheet): + import webnotes + # load stylesheet + loaded = eval(webnotes.form_dict.get('stylesheets') or '[]') + if not stylesheet in loaded: + import webnotes.model.doc + from webnotes.model.code import get_code + + # doclist + sslist = webnotes.model.doc.get('Stylesheet', stylesheet) + + # stylesheet from file + css = get_code(sslist[0].module, 'Stylesheet', stylesheet, 'css') + + if css: sslist[0].stylesheet = css + + return sslist + else: + return [] +
+
[docs]def get(name): + """ + Return the :term:`doclist` of the `Page` specified by `name` + """ + return Page(name).load() +
+
[docs]def getpage(): + """ + Load the page from `webnotes.form` and send it via `webnotes.response` + """ + doclist = get(webnotes.form.getvalue('name')) + + # send + webnotes.response['docs'] = doclist +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/page_body.html b/docs/_build/html/_modules/webnotes/widgets/page_body.html new file mode 100644 index 0000000000..b7c57260fc --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/page_body.html @@ -0,0 +1,336 @@ + + + + + + + + + webnotes.widgets.page_body — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.page_body

+#:    HTML Template of index.cgi
+index_template = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head id="head">
+<!-- Web Notes Framework : www.webnotesframework.org -->
+
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta name="robots" content="index, follow" />
+  <meta name="keywords" content="%(keywords)s" />
+  <meta name="description" content="%(site_description)s" />
+  <meta name="generator" content="Web Notes Framework Version v170 - Open Source Web Application Framework" />  
+  
+  <title>%(title)s</title>
+  <link type="text/css" rel="stylesheet" href="css/jquery-ui.css">
+  <link type="text/css" rel="stylesheet" href="css/default.css">
+  <link rel="Shortcut Icon" href="/favicon.ico">
+  
+  <script language="JavaScript" src="js/jquery/jquery.min.js"></script>
+  <script language="JavaScript" src="js/jquery/jquery-ui.min.js"></script>
+  <script type="text/javascript" src="js/tiny_mce_33/jquery.tinymce.js"></script>
+  <script language="JavaScript" src="js/wnf.compressed.js"></script>
+  %(import_form)s
+  <script language="JavaScript">var _startup_data = %(startup_data)s;</script>
+  <!--[if IE]><script language="javascript" type="text/javascript" src="js/jquery/excanvas.min.js"></script><![endif]-->
+  %(add_in_head)s
+  
+  <script type="text/javascript">
+    window.dhtmlHistory.create({ debugMode: false });
+  </script>
+</head>
+<body>
+
+<div id="dialog_back"></div>
+
+<div id="startup_div" style="padding: 8px; font-size: 14px;"></div>
+
+<!-- Main Starts -->
+<div id="body_div"> 
+
+	<!--static (no script) content-->
+	<div class="no_script">
+		%(content)s
+	</div>
+
+</div>
+
+%(add_in_body)s
+</body>
+</html>
+'''
+
+redirect_template = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>%s</title>
+<meta http-equiv="REFRESH" content="0; url=%s"></HEAD>
+<BODY style="font-family: Arial; padding: 8px; font-size: 14px; margin: 0px;">
+Redirecting...
+</BODY>
+</HTML>'''
+
+page_properties = {
+	'add_in_head':'',
+	'add_in_body':'',
+	'keywords':'',
+	'site_description':'',
+	'title':'',
+	'content':'',
+	'startup_data':'{}',
+	'import_form':'<script language="JavaScript" src="js/form.compressed.js"></script>'
+}
+
+
+import webnotes
+
+# remove 'id' attributes so they don't conflict
+# ---------------------------------------------
+
[docs]def replace_id(match): + #webnotes.msgprint(match.group('name')) + return '' +
+
[docs]def scrub_ids(content): + import re + + p = re.compile('id=\"(?P<name> [^\"]*)\"', re.VERBOSE) + content = p.sub(replace_id, content) + + p = re.compile('id=\'(?P<name> [^\']*)\'', re.VERBOSE) + content = p.sub(replace_id, content) + + return content + +# +# load the page content and meta tags +#
+
[docs]def get_page_content(page): + """ + Gets the HTML content from `static_content` or `content` property of a `Page` + """ + from webnotes.model.code import get_code + from webnotes.model.doc import Document + global page_properties + + if not page: return + if '/' in page: page = page.split('/')[0] + if page=='Form': return + + try: + doc = Document('Page', page) + + load_page_metatags(doc) + + template = '%(content)s' + # content + if doc.template: + template = get_code(webnotes.conn.get_value('Page Template', doc.template, 'module'), 'Page Template', doc.template, 'html', fieldname='template') + + page_properties['content'] = get_code(doc.module, 'page', doc.name, 'html', fieldname='content') + + # dynamic (scripted) content + if page_properties['content'] and page_properties['content'].startswith('#!python'): + page_properties.update(webnotes.model.code.execute(page_properties['content'])) + + page_properties['content'] = scrub_ids(template % {'content':page_properties['content']}) + except: + pass + +# +# load metatags +#
+
[docs]def load_page_metatags(doc): + global page_properties + + try: + import startup + except: + startup = '' + + # page meta-tags + page_properties['title'] = doc.page_title or doc.name + page_properties['keywords'] = doc.keywords or webnotes.conn.get_value('Control Panel',None,'keywords') or '' + page_properties['site_description'] = doc.site_description or webnotes.conn.get_value('Control Panel',None,'site_description') or '' + page_properties['add_in_head'] = getattr(startup, 'add_in_head', '') + page_properties['add_in_body'] = getattr(startup, 'add_in_body', '') + +# +# load the form as page (deprecated) +#
+
[docs]def get_doc_content(dt, dn): + """ + Gets the HTML content of a document record by using the overridden or standard :method: `doclist.to_html` + """ + import webnotes.model.code + + if dt in webnotes.user.get_read_list(): + # generate HTML + do = webnotes.model.code.get_obj(dt, dn, with_children = 1) + if hasattr(do, 'to_html'): + return dn, do.to_html() + else: + import webnotes.model.doclist + return dn, webnotes.model.doclist.to_html(do.doclist) + else: + return 'Forbidden - 404', '<h1>Forbidden - 404</h1>' + +# find the page to load as static +# ------------------------------- +
+
[docs]def load_properties(): + import webnotes.widgets.page + import urllib + + page_url = webnotes.form_dict.get('_escaped_fragment_', webnotes.form_dict.get('page', '')) + + if page_url: + if page_url.startswith('Page/'): + page_url = page_url[5:] + page_url = ['Page', urllib.unquote(page_url)] + else: + page_url = ['Page', webnotes.user.get_home_page()] + + # load content + # ----------------- + get_page_content(page_url[1]) + +# generate the page +# -----------------
+
[docs]def load_default_properties(): + if not page_properites['keywords']: + page_properites['keywords'] = webnotes.conn.get_value('Control Panel',None,'keywords') or '' + if not page_properites['site_description']: + page_properites['site_description'] = webnotes.conn.get_value('Control Panel',None,'site_description') or '' + +# generate the page +# -----------------
+
[docs]def get(): + """ + returns the full rendered index.cgi + Gets `keywords` and `site_description` from the `Control Panel` + """ + import webnotes + no_startup = webnotes.form.getvalue('no_startup') or None + + global index_template, redirect_template + import webnotes.session_cache + try: + import json + except: # python 2.4 + import simplejson as json + + page = webnotes.form_dict.get('page', '') + # sid in public display + # --------------------- + if webnotes.form_dict.get('sid'): + return redirect_template % ('Redirecting...', ('index.cgi' + (page and ('?page='+page) or ''))) + + if '%(content)s' in index_template: + load_properties() + + # load the session data + # --------------------- + try: + sd = webnotes.session_cache.get() + except: + import webnotes.utils + sd = {'exc':webnotes.utils.getTraceback()} + + # add debug messages + + sd['server_messages'] = '\n--------------\n'.join(webnotes.message_log) + + page_properties['startup_data'] = no_startup and '{}' or json.dumps(sd) + + # no form api required for guests + if webnotes.session['user']=='Guest': + page_properties['import_form'] = '' + + index_template = index_template % page_properties + + return index_template
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/query_builder.html b/docs/_build/html/_modules/webnotes/widgets/query_builder.html new file mode 100644 index 0000000000..cc01dcb047 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/query_builder.html @@ -0,0 +1,429 @@ + + + + + + + + + webnotes.widgets.query_builder — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.query_builder

+import webnotes
+
+form = webnotes.form
+session = webnotes.session
+sql = webnotes.conn.sql
+out = webnotes.response
+
+from webnotes.utils import cint
+
+
[docs]def get_search_criteria_list(dt): + sc_list = sql("select criteria_name, doc_type from `tabSearch Criteria` where doc_type = '%s' or parent_doc_type = '%s'" % (dt, dt)) + return [list(s) for s in sc_list] +
+
[docs]def load_report_list(): + webnotes.response['rep_list'] = get_search_criteria_list(form.getvalue('dt')) + + +# Get, scrub metadata +# ==================================================================== +
+
[docs]def get_sql_tables(q): + if q.find('WHERE') != -1: + tl = q.split('FROM')[1].split('WHERE')[0].split(',') + elif q.find('GROUP BY') != -1: + tl = q.split('FROM')[1].split('GROUP BY')[0].split(',') + else: + tl = q.split('FROM')[1].split('ORDER BY')[0].split(',') + return [t.strip().strip('`')[3:] for t in tl] + +
+
[docs]def get_parent_dt(dt): + pdt = '' + if sql('select name from `tabDocType` where istable=1 and name="%s"' % dt): + res = sql('select parent from `tabDocField` where fieldtype="Table" and options="%s"' % dt) + if res: pdt = res[0][0] + return pdt +
+
[docs]def get_sql_meta(tl): + std_columns = { + 'owner':('Owner', '', '', '100'), + 'creation':('Created on', 'Date', '', '100'), + 'modified':('Last modified on', 'Date', '', '100'), + 'modified_by':('Modified By', '', '', '100') + } + + meta = {} + + for dt in tl: + meta[dt] = std_columns.copy() + + # for table doctype, the ID is the parent id + pdt = get_parent_dt(dt) + if pdt: + meta[dt]['parent'] = ('ID', 'Link', pdt, '200') + + # get the field properties from DocField + res = sql("select fieldname, label, fieldtype, options, width from tabDocField where parent='%s'" % dt) + for r in res: + if r[0]: + meta[dt][r[0]] = (r[1], r[2], r[3], r[4]); + + # name + meta[dt]['name'] = ('ID', 'Link', dt, '200') + + return meta + +# Additional conditions to fulfill match permission rules +# ==================================================================== +
+
[docs]def getmatchcondition(dt, ud, ur): + res = sql("SELECT `role`, `match` FROM tabDocPerm WHERE parent = '%s' AND (`read`=1) AND permlevel = 0" % dt) + cond = [] + for r in res: + if r[0] in ur: # role applicable to user + if r[1]: + defvalues = ud.get(r[1],['_NA']) + for d in defvalues: + cond.append('`tab%s`.`%s`="%s"' % (dt, r[1], d)) + else: # nomatch i.e. full read rights + return '' + + return ' OR '.join(cond) +
+
[docs]def add_match_conditions(q, tl, ur, ud): + sl = [] + for dt in tl: + s = getmatchcondition(dt, ud, ur) + if s: + sl.append(s) + + # insert the conditions + if sl: + condition_st = q.find('WHERE')!=-1 and ' AND ' or ' WHERE ' + + condition_end = q.find('ORDER BY')!=-1 and 'ORDER BY' or 'LIMIT' + condition_end = q.find('GROUP BY')!=-1 and 'GROUP BY' or condition_end + + if q.find('ORDER BY')!=-1 or q.find('LIMIT')!=-1 or q.find('GROUP BY')!=-1: # if query continues beyond conditions + q = q.split(condition_end) + q = q[0] + condition_st + '(' + ' OR '.join(sl) + ') ' + condition_end + q[1] + else: + q = q + condition_st + '(' + ' OR '.join(sl) + ')' + + return q + +# execute server-side script from Search Criteria +# ==================================================================== +
+
[docs]def exec_report(code, res, colnames=[], colwidths=[], coltypes=[], coloptions=[], filter_values={}, query='', from_export=0): + col_idx, i, out, style, header_html, footer_html, page_template = {}, 0, None, [], '', '', '' + for c in colnames: + col_idx[c] = i + i+=1 + + # load globals (api) + from webnotes import * + from webnotes.utils import * + from webnotes.model.doc import * + from webnotes.model.doclist import getlist + from webnotes.model.db_schema import updatedb + from webnotes.model.code import get_obj + + set = webnotes.conn.set + sql = webnotes.conn.sql + get_value = webnotes.conn.get_value + convert_to_lists = webnotes.conn.convert_to_lists + NEWLINE = '\n' + + exec str(code) + + if out!=None: + res = out + + return res, style, header_html, footer_html, page_template + +# ==================================================================== +
+
[docs]def guess_type(m): + """ + Returns fieldtype depending on the MySQLdb Description + """ + import MySQLdb + if m in MySQLdb.NUMBER: + return 'Currency' + elif m in MySQLdb.DATE: + return 'Date' + else: + return 'Data' +
+
[docs]def build_description_simple(): + colnames, coltypes, coloptions, colwidths = [], [], [], [] + + for m in webnotes.conn.get_description(): + colnames.append(m[0]) + coltypes.append(guess_type[m[0]]) + coloptions.append('') + colwidths.append('100') + + return colnames, coltypes, coloptions, colwidths + +# ==================================================================== +
+
[docs]def build_description_standard(meta, tl): + + desc = webnotes.conn.get_description() + + colnames, coltypes, coloptions, colwidths = [], [], [], [] + + # merged metadata - used if we are unable to + # get both the table name and field name from + # the description - in case of joins + merged_meta = {} + for d in meta: + merged_meta.update(meta[d]) + + for f in desc: + fn, dt = f[0], '' + if '.' in fn: + dt, fn = fn.split('.') + + if (not dt) and merged_meta.get(fn): + # no "AS" given, find type from merged description + + desc = merged_meta[fn] + colnames.append(desc[0] or fn) + coltypes.append(desc[1] or '') + coloptions.append(desc[2] or '') + colwidths.append(desc[3] or '100') + + elif meta.get(dt,{}).has_key(fn): + # type specified for a multi-table join + # usually from Report Builder + + desc = meta[dt][fn] + colnames.append(desc[0] or fn) + coltypes.append(desc[1] or '') + coloptions.append(desc[2] or '') + colwidths.append(desc[3] or '100') + + else: + # nothing found + # guess + + colnames.append(fn) + coltypes.append(guess_type(f[1])) + coloptions.append('') + colwidths.append('100') + + return colnames, coltypes, coloptions, colwidths + +# Entry Point - Run the query +# ==================================================================== +
+
[docs]def runquery(q='', ret=0, from_export=0): + import webnotes.utils + + formatted = cint(form.getvalue('formatted')) + + # CASE A: Simple Query + # -------------------- + if form.getvalue('simple_query') or form.getvalue('is_simple'): + q = form.getvalue('simple_query') or form.getvalue('query') + if q.split()[0].lower() != 'select': + raise Exception, 'Query must be a SELECT' + + as_dict = cint(form.getvalue('as_dict')) + res = sql(q, as_dict = as_dict, as_list = not as_dict, formatted=formatted) + + # build colnames etc from metadata + colnames, coltypes, coloptions, colwidths = [], [], [], [] + + # CASE B: Standard Query + # ----------------------- + else: + if not q: q = form.getvalue('query') + + tl = get_sql_tables(q) + meta = get_sql_meta(tl) + + q = add_match_conditions(q, tl, webnotes.user.roles, webnotes.user.get_defaults()) + + # replace special variables + q = q.replace('__user', session['user']) + q = q.replace('__today', webnotes.utils.nowdate()) + + res = sql(q, as_list=1, formatted=formatted) + + colnames, coltypes, coloptions, colwidths = build_description_standard(meta, tl) + + # run server script + # ----------------- + style, header_html, footer_html, page_template = '', '', '', '' + if form.has_key('sc_id') and form.getvalue('sc_id'): + sc_id = form.getvalue('sc_id') + from webnotes.model.code import get_code + sc_details = webnotes.conn.sql("select module, standard, server_script from `tabSearch Criteria` where name=%s", sc_id)[0] + if sc_details[1]!='No': + code = get_code(sc_details[0], 'Search Criteria', sc_id, 'py') + else: + code = sc_details[2] + + if code: + filter_values = form.has_key('filter_values') and eval(form.getvalue('filter_values','')) or {} + res, style, header_html, footer_html, page_template = exec_report(code, res, colnames, colwidths, coltypes, coloptions, filter_values, q, from_export) + + out['colnames'] = colnames + out['coltypes'] = coltypes + out['coloptions'] = coloptions + out['colwidths'] = colwidths + out['header_html'] = header_html + out['footer_html'] = footer_html + out['page_template'] = page_template + + if style: + out['style'] = style + + # just the data - return + if ret==1: + return res + + out['values'] = res + + # return num of entries + qm = form.has_key('query_max') and form.getvalue('query_max') or '' + if qm and qm.strip(): + if qm.split()[0].lower() != 'select': + raise Exception, 'Query (Max) must be a SELECT' + if not form.has_key('simple_query'): + qm = add_match_conditions(qm, tl, webnotes.user.roles, webnotes.user.defaults) + + out['n_values'] = webnotes.utils.cint(sql(qm)[0][0]) + +# Export to CSV +# ==================================================================== +
+
[docs]def runquery_csv(): + from webnotes.utils import getCSVelement + + # run query + res = runquery(from_export = 1) + + q = form.getvalue('query') + + rep_name = form.getvalue('report_name') + if not form.has_key('simple_query'): + + # Report Name + if not rep_name: + rep_name = get_sql_tables(q)[0] + + if not rep_name: rep_name = 'DataExport' + + # Headings + heads = [] + for h in out['colnames']: + heads.append(getCSVelement(h)) + if form.has_key('colnames'): + for h in form.getvalue('colnames').split(','): + heads.append(getCSVelement(h)) + + # Output dataset + dset = [rep_name, ''] + if heads: + dset.append(','.join(heads)) + + # Data + for r in out['values']: + dset.append(','.join([getCSVelement(i) for i in r])) + + txt = '\n'.join(dset) + out['result'] = txt + out['type'] = 'csv' + out['doctype'] = rep_name
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/search.html b/docs/_build/html/_modules/webnotes/widgets/search.html new file mode 100644 index 0000000000..36ccb47666 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/search.html @@ -0,0 +1,197 @@ + + + + + + + + + webnotes.widgets.search — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.search

+# Search
+import webnotes
+
+# this is called when a new doctype is setup for search - to set the filters
+
[docs]def getsearchfields(): + + sf = webnotes.conn.sql("select search_fields from tabDocType where name=%s", webnotes.form.getvalue("doctype")) + sf = sf and sf[0][0] or '' + sf = [s.strip() for s in sf.split(',')] + if sf and sf[0]: + res = webnotes.conn.sql("select fieldname, label, fieldtype, options from tabDocField where parent='%s' and fieldname in (%s)" % (webnotes.form.getvalue("doctype","_NA"), '"'+'","'.join(sf)+'"')) + else: + res = [] + + res = [[c or '' for c in r] for r in res] + for r in res: + if r[2]=='Select' and r[3] and r[3].startswith('link:'): + dt = r[3][5:] + ol = webnotes.conn.sql("select name from `tab%s` where docstatus!=2 order by name asc" % dt) + r[3] = '\n'.join([''] + [o[0] for o in ol]) + + webnotes.response['searchfields'] = [['name', 'ID', 'Data', '']] + res +
+
[docs]def make_query(fields, dt, key, txt, start, length): + return """SELECT %(fields)s + FROM `tab%(dt)s` + WHERE `tab%(dt)s`.`%(key)s` LIKE '%(txt)s' AND `tab%(dt)s`.docstatus != 2 + ORDER BY `tab%(dt)s`.`%(key)s` + DESC LIMIT %(start)s, %(len)s """ % { + 'fields': fields, + 'dt': dt, + 'key': key, + 'txt': txt + '%', + 'start': start, + 'len': length + } +
+
[docs]def get_std_fields_list(dt, key): + # get additional search fields + sflist = webnotes.conn.sql("select search_fields from tabDocType where name = '%s'" % dt) + sflist = sflist and sflist[0][0] and sflist[0][0].split(',') or [] + + sflist = ['name'] + sflist + if not key in sflist: + sflist = sflist + [key] + + return ['`tab%s`.`%s`' % (dt, f.strip()) for f in sflist] +
+
[docs]def build_for_autosuggest(res): + from webnotes.utils import cstr + + results = [] + for r in res: + info = '' + if len(r) > 1: + info = ','.join([cstr(t) for t in r[1:]]) + if len(info) > 30: + info = info[:30] + '...' + + results.append({'id':r[0], 'value':r[0], 'info':info}) + return results +
+
[docs]def scrub_custom_query(query, key, txt): + if '%(key)s' in query: + query = query.replace('%(key)s', key) + if '%s' in query: + query = query.replace('%s', ((txt or '') + '%')) + return query + +# this is called by the Link Field
+ +
[docs]def search_widget(): + import webnotes.widgets.query_builder + + dt = webnotes.form.getvalue('doctype') + txt = webnotes.form.getvalue('txt') or '' + key = webnotes.form.getvalue('searchfield') or 'name' # key field + user_query = webnotes.form.getvalue('query') or '' + + if user_query: + query = scrub_custom_query(user_query, key, txt) + else: + query = make_query(', '.join(get_std_fields_list(dt, key)), dt, key, txt, webnotes.form.getvalue('start') or 0, webnotes.form.getvalue('page_len') or 50) + + webnotes.widgets.query_builder.runquery(query)
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/tags.html b/docs/_build/html/_modules/webnotes/widgets/tags.html new file mode 100644 index 0000000000..d0a0f3d8e5 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/tags.html @@ -0,0 +1,352 @@ + + + + + + + + + webnotes.widgets.tags — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.tags

+"""
+Server side functions for tagging.
+
+- Tags can be added to any record (doctype, name) in the system.
+- Items are filtered by tags
+- Top tags are shown in the sidebar (?)
+- Tags are also identified by the tag_fields property of the DocType
+
+Discussion:
+
+Tags are shown in the docbrowser and ideally where-ever items are searched.
+There should also be statistics available for tags (like top tags etc)
+
+
+Design:
+
+- free tags (user_tags) are stored in __user_tags
+- doctype tags are set in tag_fields property of the doctype
+- top tags merges the tags from both the lists (only refreshes once an hour (max))
+
+"""
+
+
+
[docs]def check_user_tags(dt): + "if the user does not have a tags column, then it creates one" + try: + webnotes.conn.sql("select `_user_tags` from `tab%s` limit 1" % dt) + except Exception, e: + if e.args[0] == 1054: + DocTags(dt).setup() + + +# +# Add a new tag +#
+
[docs]def add_tag(): + "adds a new tag to a record, and creates the Tag master" + + f = webnotes.form_dict + tag, color = f.get('tag'), f.get('color') + dt, dn = f.get('dt'), f.get('dn') + + DocTags(dt).add(dn, tag) + + return tag + +# +# remove tag +#
+
[docs]def remove_tag(): + "removes tag from the record" + f = webnotes.form_dict + tag, dt, dn = f.get('tag'), f.get('dt'), f.get('dn') + + DocTags(dt).remove(dn, tag) + + +
+import webnotes +from webnotes.utils import cint, cstr, load_json + +
[docs]class DocTags: + """Tags for a particular doctype""" + def __init__(self, dt): + self.dt = dt + +
[docs] def get_tag_fields(self): + """returns tag_fields property""" + return webnotes.conn.get_value('DocType', self.dt, 'tag_fields') +
+
[docs] def get_tags(self, dn): + """returns tag for a particular item""" + return webnotes.conn.get_value(self.dt, dn, '_user_tags') or '' +
+
[docs] def create(self, tag): + try: + webnotes.conn.sql("insert into tabTag(name) values (%s) on duplicate key ignore", tag) + except Exception, e: + if e.args[0]==1147: + self.setup_tag_master() + self.create(tag) +
+
[docs] def add(self, dn, tag): + """add a new user tag""" + self.create(tag) + tl = self.get_tags(dn).split(',') + if not tag in tl: + tl.append(tag) + self.update(dn, tl) + TagCounter(self.dt).update(tag, 1) +
+
[docs] def remove(self, dn, tag): + """remove a user tag""" + tl = self.get_tags(dn).split(',') + self.update(dn, filter(lambda x:x!=tag, tl)) + TagCounter(self.dt).update(tag, -1) +
+
[docs] def update(self, dn, tl): + """updates the _user_tag column in the table""" + + tl = list(set(filter(lambda x: x, tl))) + + try: + webnotes.conn.sql("update `tab%s` set _user_tags=%s where name=%s" % \ + (self.dt,'%s','%s'), (',' + ','.join(tl), dn)) + except Exception, e: + if e.args[0]==1054: + self.setup() + self.update(dn, tl) + else: raise e +
+
[docs] def setup_tags(self): + """creates the tabTag table if not exists""" + webnotes.conn.commit() + from webnotes.modules.module_manager import reload_doc + reload_doc('core','doctype','tag') + webnotes.conn.begin() +
+
[docs] def setup(self): + """adds the _user_tags column if not exists""" + webnotes.conn.commit() + webnotes.conn.sql("alter table `tab%s` add column `_user_tags` varchar(180)" % self.dt) + webnotes.conn.begin() + + + + + + + +
+
[docs]class TagCounter: + """ + Tag Counter stores tag count per doctype in table _tag_cnt + """ + def __init__(self, doctype): + self.doctype = doctype + + # setup / update tag cnt + # keeps tags in _tag_cnt (doctype, tag, cnt) + # if doctype cnt does not exist + # creates it for the first time +
[docs] def update(self, tag, diff): + "updates tag cnt for a doctype and tag" + cnt = webnotes.conn.sql("select cnt from `_tag_cnt` where doctype=%s and tag=%s", (self.doctype, tag)) + + if not cnt: + # first time? build a cnt and add + self.new_tag(tag, 1) + else: + webnotes.conn.sql("update `_tag_cnt` set cnt = ifnull(cnt,0) + (%s) where doctype=%s and tag=%s",\ + (diff, self.doctype, tag)) + +
+
[docs] def new_tag(self, tag, cnt=0, dt=None): + "Creates a new row for the tag and doctype" + webnotes.conn.sql("insert into `_tag_cnt`(doctype, tag, cnt) values (%s, %s, %s)", \ + (dt or self.doctype, tag, cnt)) +
+
[docs] def build(self, dt): + "Builds / rebuilds the counting" + webnotes.conn.sql("delete from _tag_cnt where doctype=%s", dt) + + # count + tags = {} + for ut in webnotes.conn.sql("select _user_tags from `tab%s`" % dt): + if ut[0]: + tag_list = ut[0].split(',') + for t in tag_list: + if t: + tags[t] = tags.get(t, 0) + 1 + + # insert + for t in tags: + self.new_tag(t, tags[t], dt) +
+
[docs] def load_top(self): + try: + return webnotes.conn.sql("select tag, cnt from `_tag_cnt` where doctype=%s and cnt>0 order by cnt desc limit 10", self.doctype, as_list = 1) + except Exception, e: + if e.args[0]==1146: + self.setup() + return self.load_top() + else: raise e +
+
[docs] def setup(self): + "creates the tag cnt table from the DocType" + webnotes.conn.commit() + webnotes.conn.sql(""" + create table `_tag_cnt` ( + doctype varchar(180), tag varchar(22), cnt int(10), + primary key (doctype, tag), index cnt(cnt)) ENGINE=InnoDB + """) + webnotes.conn.begin() + + # build all + for dt in webnotes.conn.sql("select name from tabDocType where ifnull(issingle,0)=0 and docstatus<2"): + try: + self.build(dt[0]) + except Exception, e: + if e.args[0]==1054: pass + else: raise e + + + +
+
[docs]def get_top_field_tags(dt): + tf = webnotes.conn.get_value('DocType', dt, 'tag_fields') + if not tf: return [] + + # restrict to only 2 fields + tf = tuple(set(tf.split(',')))[:2] + tl = [] + + for t in tf: + t = t.strip() + # disastrous query but lets try it! + tl += webnotes.conn.sql("""select `%s`, count(*), '%s' from `tab%s` + where docstatus!=2 + and ifnull(`%s`, '')!='' + group by `%s` + order by count(*) desc + limit 10""" % (t, t, dt, t, t), as_list=1) + + if tl: + tl.sort(lambda x, y: y[1]-x[1]) + + return tl[:10] + +# returns the top ranked 10 tags for the +# doctype. +# merges the top tags from fields and user tags
+
[docs]def get_top_tags(args=''): + "returns the top 10 tags for the doctype from fields (7) and users (3)" + tl = None + dt = webnotes.form_dict['doctype'] + + from webnotes.utils.cache import get_item + + # if not reload, try and load from cache + if not cint(webnotes.form_dict.get('refresh')): + tl = get_item('tags-' + dt).get() + + if tl: + return eval(tl) + else: + tl = TagCounter(dt).load_top() + get_top_field_tags(dt) + if tl: + tl.sort(lambda x, y: y[1]-x[1]) + tl = tl[:20] + + # set in cache and don't reload for an hour + get_item('tags-' + dt).set(tl, 60*60) + + return tl +
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/webnotes/widgets/todo.html b/docs/_build/html/_modules/webnotes/widgets/todo.html new file mode 100644 index 0000000000..3b2eae90b3 --- /dev/null +++ b/docs/_build/html/_modules/webnotes/widgets/todo.html @@ -0,0 +1,145 @@ + + + + + + + + + webnotes.widgets.todo — WNFramework v1.8 documentation + + + + + + + + + + + + +
+
+
+
+ +

Source code for webnotes.widgets.todo

+# ToDO and Reminder
+# -----------------
+
+
[docs]def add_todo(user, date, priority, desc, ref_type, ref_name): + nlist = [] + if type(user)==list: + for i in user: + nlist.append(add_todo_item(i, date, priority, desc, ref_type, ref_name)) + return nlist + else: + return add_todo_item(user, date, priority, desc, ref_type, ref_name) +
+
[docs]def add_todo_item(user, date, priority, desc, ref_type, ref_name): + if not date: + date = nowdate() + + d = Document('ToDo Item') + d.owner = user + d.date = date + d.priority = priority + d.description = desc + d.reference_type = ref_type + d.reference_name = ref_name + d.save(1) + return d.name +
+
[docs]def remove_todo(name): + if type(name)==list: + for i in name: + sql("delete from `tabToDo Item` where name='%s'" % i) + else: + sql("delete from `tabToDo Item` where name='%s'" % name) +
+
[docs]def get_todo_list(): + c = getcursor() + try: + role_options = ["role = '"+r+"'" for r in roles] + role_options = role_options and ' OR ' + ' OR '.join(role_options) or '' + c.execute("select * from `tabToDo Item` where owner='%s' %s" % (session['user'], role_options)) + except: # deprecated + c.execute("select * from `tabToDo Item` where owner='%s'" % session['user']) + dataset = c.fetchall() + l = [] + for i in range(len(dataset)): + d = Document('ToDo Item') + d.loadfields(dataset, i, c.description) + l.append(d) + + return l
+
+ +
+
+
+
+
+ + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_sources/backupall.txt b/docs/_build/html/_sources/backupall.txt new file mode 100644 index 0000000000..a6b6e223ee --- /dev/null +++ b/docs/_build/html/_sources/backupall.txt @@ -0,0 +1,10 @@ +backupall Module +================ + +:mod:`backupall` Module +----------------------- + +.. automodule:: backupall + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/core.doctype.control_panel.txt b/docs/_build/html/_sources/core.doctype.control_panel.txt new file mode 100644 index 0000000000..65ecc83b27 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.control_panel.txt @@ -0,0 +1,11 @@ +control_panel Package +===================== + +:mod:`control_panel` Module +--------------------------- + +.. automodule:: core.doctype.control_panel.control_panel + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.custom_field.txt b/docs/_build/html/_sources/core.doctype.custom_field.txt new file mode 100644 index 0000000000..d2e8527439 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.custom_field.txt @@ -0,0 +1,11 @@ +custom_field Package +==================== + +:mod:`custom_field` Module +-------------------------- + +.. automodule:: core.doctype.custom_field.custom_field + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.doctype.txt b/docs/_build/html/_sources/core.doctype.doctype.txt new file mode 100644 index 0000000000..5b52a80754 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.doctype.txt @@ -0,0 +1,11 @@ +doctype Package +=============== + +:mod:`doctype` Module +--------------------- + +.. automodule:: core.doctype.doctype.doctype + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.doctype_mapper.txt b/docs/_build/html/_sources/core.doctype.doctype_mapper.txt new file mode 100644 index 0000000000..ce66c3e082 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.doctype_mapper.txt @@ -0,0 +1,11 @@ +doctype_mapper Package +====================== + +:mod:`doctype_mapper` Module +---------------------------- + +.. automodule:: core.doctype.doctype_mapper.doctype_mapper + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.letter_head.txt b/docs/_build/html/_sources/core.doctype.letter_head.txt new file mode 100644 index 0000000000..c1db316a4e --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.letter_head.txt @@ -0,0 +1,11 @@ +letter_head Package +=================== + +:mod:`letter_head` Module +------------------------- + +.. automodule:: core.doctype.letter_head.letter_head + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.module_def.txt b/docs/_build/html/_sources/core.doctype.module_def.txt new file mode 100644 index 0000000000..1a421deba3 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.module_def.txt @@ -0,0 +1,11 @@ +module_def Package +================== + +:mod:`module_def` Module +------------------------ + +.. automodule:: core.doctype.module_def.module_def + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.page.txt b/docs/_build/html/_sources/core.doctype.page.txt new file mode 100644 index 0000000000..e714c12fcf --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.page.txt @@ -0,0 +1,11 @@ +page Package +============ + +:mod:`page` Module +------------------ + +.. automodule:: core.doctype.page.page + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.page_template.txt b/docs/_build/html/_sources/core.doctype.page_template.txt new file mode 100644 index 0000000000..5f4e374748 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.page_template.txt @@ -0,0 +1,11 @@ +page_template Package +===================== + +:mod:`page_template` Module +--------------------------- + +.. automodule:: core.doctype.page_template.page_template + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.profile.txt b/docs/_build/html/_sources/core.doctype.profile.txt new file mode 100644 index 0000000000..d4dec82a51 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.profile.txt @@ -0,0 +1,11 @@ +profile Package +=============== + +:mod:`profile` Module +--------------------- + +.. automodule:: core.doctype.profile.profile + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.property_setter.txt b/docs/_build/html/_sources/core.doctype.property_setter.txt new file mode 100644 index 0000000000..e3d26edd0d --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.property_setter.txt @@ -0,0 +1,11 @@ +property_setter Package +======================= + +:mod:`property_setter` Module +----------------------------- + +.. automodule:: core.doctype.property_setter.property_setter + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.search_criteria.txt b/docs/_build/html/_sources/core.doctype.search_criteria.txt new file mode 100644 index 0000000000..8dd6fe0fce --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.search_criteria.txt @@ -0,0 +1,11 @@ +search_criteria Package +======================= + +:mod:`search_criteria` Module +----------------------------- + +.. automodule:: core.doctype.search_criteria.search_criteria + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.stylesheet.txt b/docs/_build/html/_sources/core.doctype.stylesheet.txt new file mode 100644 index 0000000000..701827d360 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.stylesheet.txt @@ -0,0 +1,11 @@ +stylesheet Package +================== + +:mod:`stylesheet` Module +------------------------ + +.. automodule:: core.doctype.stylesheet.stylesheet + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.system_console.txt b/docs/_build/html/_sources/core.doctype.system_console.txt new file mode 100644 index 0000000000..14afcd5e83 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.system_console.txt @@ -0,0 +1,11 @@ +system_console Package +====================== + +:mod:`system_console` Module +---------------------------- + +.. automodule:: core.doctype.system_console.system_console + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/core.doctype.txt b/docs/_build/html/_sources/core.doctype.txt new file mode 100644 index 0000000000..681bdd2284 --- /dev/null +++ b/docs/_build/html/_sources/core.doctype.txt @@ -0,0 +1,44 @@ +doctype Package +=============== + +Subpackages +----------- + +.. toctree:: + + core.doctype.comment_widget_record + core.doctype.control_panel + core.doctype.custom_field + core.doctype.custom_script + core.doctype.default_home_page + core.doctype.defaultvalue + core.doctype.docfield + core.doctype.docformat + core.doctype.docperm + core.doctype.doctrigger + core.doctype.doctype + core.doctype.doctype_label + core.doctype.doctype_mapper + core.doctype.event + core.doctype.event_role + core.doctype.event_user + core.doctype.field_mapper_detail + core.doctype.file_data + core.doctype.letter_head + core.doctype.module_def + core.doctype.module_def_item + core.doctype.module_def_role + core.doctype.page + core.doctype.page_role + core.doctype.page_template + core.doctype.print_format + core.doctype.profile + core.doctype.property_setter + core.doctype.role + core.doctype.search_criteria + core.doctype.stylesheet + core.doctype.system_console + core.doctype.table_mapper_detail + core.doctype.tag + core.doctype.userrole + diff --git a/docs/_build/html/_sources/core.page.txt b/docs/_build/html/_sources/core.page.txt new file mode 100644 index 0000000000..a0deceb5dc --- /dev/null +++ b/docs/_build/html/_sources/core.page.txt @@ -0,0 +1,10 @@ +page Package +============ + +Subpackages +----------- + +.. toctree:: + + core.page.login_page + diff --git a/docs/_build/html/_sources/core.txt b/docs/_build/html/_sources/core.txt new file mode 100644 index 0000000000..d2e002a1f4 --- /dev/null +++ b/docs/_build/html/_sources/core.txt @@ -0,0 +1,11 @@ +core Package +============ + +Subpackages +----------- + +.. toctree:: + + core.doctype + core.page + diff --git a/docs/_build/html/_sources/index.txt b/docs/_build/html/_sources/index.txt new file mode 100644 index 0000000000..8944ca23f2 --- /dev/null +++ b/docs/_build/html/_sources/index.txt @@ -0,0 +1,23 @@ +.. WNFramework documentation master file, created by + sphinx-quickstart on Wed Jun 29 14:22:33 2011. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to WNFramework documentation! +===================================== + +Contents: + +.. toctree:: + :maxdepth: 8 + + core + webnotes + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/_build/html/_sources/modules.txt b/docs/_build/html/_sources/modules.txt new file mode 100644 index 0000000000..5ded42bb9e --- /dev/null +++ b/docs/_build/html/_sources/modules.txt @@ -0,0 +1,8 @@ +Project Modules +=============== + +.. toctree:: + :maxdepth: 8 + + core + webnotes diff --git a/docs/_build/html/_sources/pypi-setup.txt b/docs/_build/html/_sources/pypi-setup.txt new file mode 100644 index 0000000000..1dfe84d6f4 --- /dev/null +++ b/docs/_build/html/_sources/pypi-setup.txt @@ -0,0 +1,10 @@ +pypi-setup Module +================= + +:mod:`pypi-setup` Module +------------------------ + +.. automodule:: pypi-setup + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/webnotes.install_lib.txt b/docs/_build/html/_sources/webnotes.install_lib.txt new file mode 100644 index 0000000000..4d0e0d5b72 --- /dev/null +++ b/docs/_build/html/_sources/webnotes.install_lib.txt @@ -0,0 +1,19 @@ +install_lib Package +=================== + +:mod:`db_init` Module +--------------------- + +.. automodule:: webnotes.install_lib.db_init + :members: + :undoc-members: + :show-inheritance: + +:mod:`install` Module +--------------------- + +.. automodule:: webnotes.install_lib.install + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/webnotes.model.txt b/docs/_build/html/_sources/webnotes.model.txt new file mode 100644 index 0000000000..0da187f05a --- /dev/null +++ b/docs/_build/html/_sources/webnotes.model.txt @@ -0,0 +1,83 @@ +model Package +============= + +:mod:`model` Package +-------------------- + +.. automodule:: webnotes.model + :members: + :undoc-members: + :show-inheritance: + +:mod:`code` Module +------------------ + +.. automodule:: webnotes.model.code + :members: + :undoc-members: + :show-inheritance: + +:mod:`db_schema` Module +----------------------- + +.. automodule:: webnotes.model.db_schema + :members: + :undoc-members: + :show-inheritance: + +:mod:`doc` Module +----------------- + +.. automodule:: webnotes.model.doc + :members: + :undoc-members: + :show-inheritance: + +:mod:`doclist` Module +--------------------- + +.. automodule:: webnotes.model.doclist + :members: + :undoc-members: + :show-inheritance: + +:mod:`doctype` Module +--------------------- + +.. automodule:: webnotes.model.doctype + :members: + :undoc-members: + :show-inheritance: + +:mod:`import_docs` Module +------------------------- + +.. automodule:: webnotes.model.import_docs + :members: + :undoc-members: + :show-inheritance: + +:mod:`meta` Module +------------------ + +.. automodule:: webnotes.model.meta + :members: + :undoc-members: + :show-inheritance: + +:mod:`modules` Module +--------------------- + +.. automodule:: webnotes.model.modules + :members: + :undoc-members: + :show-inheritance: + +:mod:`triggers` Module +---------------------- + +.. automodule:: webnotes.model.triggers + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/webnotes.modules.txt b/docs/_build/html/_sources/webnotes.modules.txt new file mode 100644 index 0000000000..d461d333e9 --- /dev/null +++ b/docs/_build/html/_sources/webnotes.modules.txt @@ -0,0 +1,51 @@ +modules Package +=============== + +:mod:`modules` Package +---------------------- + +.. automodule:: webnotes.modules + :members: + :undoc-members: + :show-inheritance: + +:mod:`compress` Module +---------------------- + +.. automodule:: webnotes.modules.compress + :members: + :undoc-members: + :show-inheritance: + +:mod:`export_module` Module +--------------------------- + +.. automodule:: webnotes.modules.export_module + :members: + :undoc-members: + :show-inheritance: + +:mod:`import_module` Module +--------------------------- + +.. automodule:: webnotes.modules.import_module + :members: + :undoc-members: + :show-inheritance: + +:mod:`module_manager` Module +---------------------------- + +.. automodule:: webnotes.modules.module_manager + :members: + :undoc-members: + :show-inheritance: + +:mod:`patch` Module +------------------- + +.. automodule:: webnotes.modules.patch + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/webnotes.multi_tenant.txt b/docs/_build/html/_sources/webnotes.multi_tenant.txt new file mode 100644 index 0000000000..968c442794 --- /dev/null +++ b/docs/_build/html/_sources/webnotes.multi_tenant.txt @@ -0,0 +1,27 @@ +multi_tenant Package +==================== + +:mod:`multi_tenant` Package +--------------------------- + +.. automodule:: webnotes.multi_tenant + :members: + :undoc-members: + :show-inheritance: + +:mod:`query_parser` Module +-------------------------- + +.. automodule:: webnotes.multi_tenant.query_parser + :members: + :undoc-members: + :show-inheritance: + +:mod:`setup` Module +------------------- + +.. automodule:: webnotes.multi_tenant.setup + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/webnotes.txt b/docs/_build/html/_sources/webnotes.txt new file mode 100644 index 0000000000..a9235977bc --- /dev/null +++ b/docs/_build/html/_sources/webnotes.txt @@ -0,0 +1,87 @@ +webnotes Package +================ + +:mod:`webnotes` Package +----------------------- + +.. automodule:: webnotes + :members: + :undoc-members: + :show-inheritance: + +:mod:`auth` Module +------------------ + +.. automodule:: webnotes.auth + :members: + :undoc-members: + :show-inheritance: + +:mod:`db` Module +---------------- + +.. automodule:: webnotes.db + :members: + :undoc-members: + :show-inheritance: + +:mod:`defs` Module +------------------ + +.. automodule:: webnotes.defs + :members: + :undoc-members: + :show-inheritance: + +:mod:`defs_template` Module +--------------------------- + +.. automodule:: webnotes.defs_template + :members: + :undoc-members: + :show-inheritance: + +:mod:`handler` Module +--------------------- + +.. automodule:: webnotes.handler + :members: + :undoc-members: + :show-inheritance: + +:mod:`profile` Module +--------------------- + +.. automodule:: webnotes.profile + :members: + :undoc-members: + :show-inheritance: + +:mod:`session_cache` Module +--------------------------- + +.. automodule:: webnotes.session_cache + :members: + :undoc-members: + :show-inheritance: + +:mod:`tests` Module +------------------- + +.. automodule:: webnotes.tests + :members: + :undoc-members: + :show-inheritance: + +Subpackages +----------- + +.. toctree:: + + webnotes.install_lib + webnotes.model + webnotes.modules + webnotes.multi_tenant + webnotes.utils + webnotes.widgets + diff --git a/docs/_build/html/_sources/webnotes.utils.email_lib.txt b/docs/_build/html/_sources/webnotes.utils.email_lib.txt new file mode 100644 index 0000000000..60d70b4557 --- /dev/null +++ b/docs/_build/html/_sources/webnotes.utils.email_lib.txt @@ -0,0 +1,43 @@ +email_lib Package +================= + +:mod:`email_lib` Package +------------------------ + +.. automodule:: webnotes.utils.email_lib + :members: + :undoc-members: + :show-inheritance: + +:mod:`form_email` Module +------------------------ + +.. automodule:: webnotes.utils.email_lib.form_email + :members: + :undoc-members: + :show-inheritance: + +:mod:`html2text` Module +----------------------- + +.. automodule:: webnotes.utils.email_lib.html2text + :members: + :undoc-members: + :show-inheritance: + +:mod:`receive` Module +--------------------- + +.. automodule:: webnotes.utils.email_lib.receive + :members: + :undoc-members: + :show-inheritance: + +:mod:`send` Module +------------------ + +.. automodule:: webnotes.utils.email_lib.send + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_sources/webnotes.utils.txt b/docs/_build/html/_sources/webnotes.utils.txt new file mode 100644 index 0000000000..685ebc3259 --- /dev/null +++ b/docs/_build/html/_sources/webnotes.utils.txt @@ -0,0 +1,106 @@ +utils Package +============= + +:mod:`utils` Package +-------------------- + +.. automodule:: webnotes.utils + :members: + :undoc-members: + :show-inheritance: + +:mod:`archive` Module +--------------------- + +.. automodule:: webnotes.utils.archive + :members: + :undoc-members: + :show-inheritance: + +:mod:`backups` Module +--------------------- + +.. automodule:: webnotes.utils.backups + :members: + :undoc-members: + :show-inheritance: + +:mod:`cache` Module +------------------- + +.. automodule:: webnotes.utils.cache + :members: + :undoc-members: + :show-inheritance: + +:mod:`encrypt` Module +--------------------- + +.. automodule:: webnotes.utils.encrypt + :members: + :undoc-members: + :show-inheritance: + +:mod:`file_manager` Module +-------------------------- + +.. automodule:: webnotes.utils.file_manager + :members: + :undoc-members: + :show-inheritance: + +:mod:`jsmin` Module +------------------- + +.. automodule:: webnotes.utils.jsmin + :members: + :undoc-members: + :show-inheritance: + +:mod:`nestedset` Module +----------------------- + +.. automodule:: webnotes.utils.nestedset + :members: + :undoc-members: + :show-inheritance: + +:mod:`scheduler` Module +----------------------- + +.. automodule:: webnotes.utils.scheduler + :members: + :undoc-members: + :show-inheritance: + +:mod:`sitemap` Module +--------------------- + +.. automodule:: webnotes.utils.sitemap + :members: + :undoc-members: + :show-inheritance: + +:mod:`transfer` Module +---------------------- + +.. automodule:: webnotes.utils.transfer + :members: + :undoc-members: + :show-inheritance: + +:mod:`webservice` Module +------------------------ + +.. automodule:: webnotes.utils.webservice + :members: + :undoc-members: + :show-inheritance: + +Subpackages +----------- + +.. toctree:: + + webnotes.utils.email_lib + diff --git a/docs/_build/html/_sources/webnotes.widgets.txt b/docs/_build/html/_sources/webnotes.widgets.txt new file mode 100644 index 0000000000..73cec46443 --- /dev/null +++ b/docs/_build/html/_sources/webnotes.widgets.txt @@ -0,0 +1,91 @@ +widgets Package +=============== + +:mod:`auto_master` Module +------------------------- + +.. automodule:: webnotes.widgets.auto_master + :members: + :undoc-members: + :show-inheritance: + +:mod:`event` Module +------------------- + +.. automodule:: webnotes.widgets.event + :members: + :undoc-members: + :show-inheritance: + +:mod:`follow` Module +-------------------- + +.. automodule:: webnotes.widgets.follow + :members: + :undoc-members: + :show-inheritance: + +:mod:`form` Module +------------------ + +.. automodule:: webnotes.widgets.form + :members: + :undoc-members: + :show-inheritance: + +:mod:`menus` Module +------------------- + +.. automodule:: webnotes.widgets.menus + :members: + :undoc-members: + :show-inheritance: + +:mod:`page` Module +------------------ + +.. automodule:: webnotes.widgets.page + :members: + :undoc-members: + :show-inheritance: + +:mod:`page_body` Module +----------------------- + +.. automodule:: webnotes.widgets.page_body + :members: + :undoc-members: + :show-inheritance: + +:mod:`query_builder` Module +--------------------------- + +.. automodule:: webnotes.widgets.query_builder + :members: + :undoc-members: + :show-inheritance: + +:mod:`search` Module +-------------------- + +.. automodule:: webnotes.widgets.search + :members: + :undoc-members: + :show-inheritance: + +:mod:`tags` Module +------------------ + +.. automodule:: webnotes.widgets.tags + :members: + :undoc-members: + :show-inheritance: + +:mod:`todo` Module +------------------ + +.. automodule:: webnotes.widgets.todo + :members: + :undoc-members: + :show-inheritance: + diff --git a/docs/_build/html/_static/README b/docs/_build/html/_static/README new file mode 100644 index 0000000000..18281ac955 --- /dev/null +++ b/docs/_build/html/_static/README @@ -0,0 +1,33 @@ +Documentation Help: +=================== + +1. To rebuild documentation +--------------------------- + +(set webnotes path in conf.py in this folder) +make html + +2. Install +----------- + +easy_install sphinx + +3. Build modules again (if you have added new modules) +---------------------- + +python generate_modules.py ../ -d . -f + +help: + +python generate_modules.py [source] -d [destination] [-f to rebuild] + +4. General Sphinx Help +---------------------- + +1. install sphinx +2. create a docs folder +3. in the docs folder, do sphinx-quickstart (say yes to autodocs and viewcode) +4. generate module .txt files using generate_modules.py script by Thomas Waldmann +5. add cool css and icons in _static folder +6. update conf.py and add sys.path.append - change .rst to .txt +7. run "make html" diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css new file mode 100644 index 0000000000..32630d54c9 --- /dev/null +++ b/docs/_build/html/_static/basic.css @@ -0,0 +1,528 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +img { + border: 0; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + clear: both; + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.refcount { + color: #060; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} diff --git a/docs/_build/html/_static/default.css b/docs/_build/html/_static/default.css new file mode 100644 index 0000000000..51811361d3 --- /dev/null +++ b/docs/_build/html/_static/default.css @@ -0,0 +1,387 @@ +/* + * flasky.css_t + * ~~~~~~~~~~~~ + * + * :copyright: Copyright 2010 by Armin Ronacher. + * :license: Flask Design License, see LICENSE for details. + */ + + + + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'Georgia', serif; + font-size: 17px; + background-color: white; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #ffffff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +img.floatingflask { + padding: 0 0 10px 10px; + float: right; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +div.related { + display: none; +} + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebar { + font-size: 14px; + line-height: 1.5; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0 0 20px 0; + margin: 0; + text-align: center; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: 'Garamond', 'Georgia', serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar input { + border: 1px solid #ccc; + font-family: 'Georgia', serif; + font-size: 1em; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Garamond', 'Georgia', serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #ddd; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #eaeaea; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + background: #fafafa; + margin: 20px -30px; + padding: 10px 30px; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; +} + +div.admonition tt.xref, div.admonition a tt { + border-bottom: 1px solid #fafafa; +} + +dd div.admonition { + margin-left: -60px; + padding-left: 60px; +} + +div.admonition p.admonition-title { + font-family: 'Garamond', 'Georgia', serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: white; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt { + font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +img.screenshot { +} + +tt.descname, tt.descclassname { + font-size: 0.95em; +} + +tt.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #eee; + background: #fdfdfd; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.footnote td.label { + width: 0px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #eee; + padding: 7px 30px; + margin: 15px -30px; + line-height: 1.3em; +} + +dl pre, blockquote pre, li pre { + margin-left: -60px; + padding-left: 60px; +} + +dl dl pre { + margin-left: -90px; + padding-left: 90px; +} + +tt { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid white; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt { + background: #EEE; +} \ No newline at end of file diff --git a/docs/_build/html/_static/doctools.js b/docs/_build/html/_static/doctools.js new file mode 100644 index 0000000000..8b9bd2c0e9 --- /dev/null +++ b/docs/_build/html/_static/doctools.js @@ -0,0 +1,247 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilties for all documentation. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +} + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * small function to check if an array contains + * a given item. + */ +jQuery.contains = function(arr, item) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] == item) + return true; + } + return false; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('.sidebar .this-page-menu')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('.sidebar .this-page-menu li.highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/html/_static/file.png b/docs/_build/html/_static/file.png similarity index 100% rename from docs/html/_static/file.png rename to docs/_build/html/_static/file.png diff --git a/docs/_build/html/_static/jquery.js b/docs/_build/html/_static/jquery.js new file mode 100644 index 0000000000..7c24308023 --- /dev/null +++ b/docs/_build/html/_static/jquery.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/docs/html/_static/minus.png b/docs/_build/html/_static/minus.png similarity index 100% rename from docs/html/_static/minus.png rename to docs/_build/html/_static/minus.png diff --git a/docs/html/_static/plus.png b/docs/_build/html/_static/plus.png similarity index 100% rename from docs/html/_static/plus.png rename to docs/_build/html/_static/plus.png diff --git a/docs/_build/html/_static/pygments.css b/docs/_build/html/_static/pygments.css new file mode 100644 index 0000000000..ee96faeca2 --- /dev/null +++ b/docs/_build/html/_static/pygments.css @@ -0,0 +1,70 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #004461; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #582800 } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902 } /* Comment.Preproc */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #808080 } /* Generic.Output */ +.highlight .gp { color: #745334 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #990000 } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #004461 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #808080 } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */ +.highlight .mf { color: #990000 } /* Literal.Number.Float */ +.highlight .mh { color: #990000 } /* Literal.Number.Hex */ +.highlight .mi { color: #990000 } /* Literal.Number.Integer */ +.highlight .mo { color: #990000 } /* Literal.Number.Oct */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_build/html/_static/searchtools.js b/docs/_build/html/_static/searchtools.js new file mode 100644 index 0000000000..dae92b5e5a --- /dev/null +++ b/docs/_build/html/_static/searchtools.js @@ -0,0 +1,518 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilties for the full-text search. + * + * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words, hlwords is the list of normal, unstemmed + * words. the first one is used to find the occurance, the + * latter for highlighting it. + */ + +jQuery.makeSearchSummary = function(text, keywords, hlwords) { + var textLower = text.toLowerCase(); + var start = 0; + $.each(keywords, function() { + var i = textLower.indexOf(this.toLowerCase()); + if (i > -1) + start = i; + }); + start = Math.max(start - 120, 0); + var excerpt = ((start > 0) ? '...' : '') + + $.trim(text.substr(start, 240)) + + ((start + 240 - text.length) ? '...' : ''); + var rv = $('
').text(excerpt); + $.each(hlwords, function() { + rv = rv.highlightText(this, 'highlighted'); + }); + return rv; +} + +/** + * Porter Stemmer + */ +var PorterStemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + + +/** + * Search Module + */ +var Search = { + + _index : null, + _queued_query : null, + _pulse_status : -1, + + init : function() { + var params = $.getQueryParameters(); + if (params.q) { + var query = params.q[0]; + $('input[name="q"]')[0].value = query; + this.performSearch(query); + } + }, + + loadIndex : function(url) { + $.ajax({type: "GET", url: url, data: null, success: null, + dataType: "script", cache: true}); + }, + + setIndex : function(index) { + var q; + this._index = index; + if ((q = this._queued_query) !== null) { + this._queued_query = null; + Search.query(q); + } + }, + + hasIndex : function() { + return this._index !== null; + }, + + deferQuery : function(query) { + this._queued_query = query; + }, + + stopPulse : function() { + this._pulse_status = 0; + }, + + startPulse : function() { + if (this._pulse_status >= 0) + return; + function pulse() { + Search._pulse_status = (Search._pulse_status + 1) % 4; + var dotString = ''; + for (var i = 0; i < Search._pulse_status; i++) + dotString += '.'; + Search.dots.text(dotString); + if (Search._pulse_status > -1) + window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something + */ + performSearch : function(query) { + // create the required interface elements + this.out = $('#search-results'); + this.title = $('

' + _('Searching') + '

').appendTo(this.out); + this.dots = $('').appendTo(this.title); + this.status = $('

').appendTo(this.out); + this.output = $('