From 88b4876aedb993933cc3e73127c90036f8f27043 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 15 Jul 2013 16:33:23 +0530 Subject: [PATCH 1/4] [fix] [mapper] add rows only table is blank, allow multiple time pull and validation if same item pulled twice --- webnotes/model/mapper.py | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/webnotes/model/mapper.py b/webnotes/model/mapper.py index 53b02fdcc0..133bef2ee9 100644 --- a/webnotes/model/mapper.py +++ b/webnotes/model/mapper.py @@ -26,8 +26,8 @@ from webnotes import _ from webnotes.utils import cstr from webnotes.model import default_fields -def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[], postprocess=None, - ignore_permissions=False): +def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[], + postprocess=None, ignore_permissions=False): if isinstance(target_doclist, basestring): target_doclist = json.loads(target_doclist) @@ -38,7 +38,7 @@ def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[] source_meta = webnotes.get_doctype(from_doctype) target_meta = webnotes.get_doctype(table_maps[from_doctype]["doctype"]) - + # main if target_doclist: if isinstance(target_doclist[0], dict): @@ -49,8 +49,11 @@ def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[] target_doc = webnotes.new_doc(table_maps[from_doctype]["doctype"]) map_doc(source.doc, target_doc, table_maps[source.doc.doctype], source_meta, target_meta) - doclist = [target_doc] - + if target_doclist: + target_doclist[0] = target_doc + else: + target_doclist = [target_doc] + # children for source_d in source.doclist[1:]: table_map = table_maps.get(source_d.doctype) @@ -65,17 +68,20 @@ def get_mapped_doclist(from_doctype, from_docname, table_maps, target_doclist=[] "fieldtype": "Table", "options": target_doctype })[0].fieldname + + if table_map.get("add_if_empty") and row_exists_in_target(parentfield, target_doclist): + continue target_d = webnotes.new_doc(target_doctype, target_doc, parentfield) map_doc(source_d, target_d, table_map, source_meta, target_meta, source.doclist[0]) - doclist.append(target_d) + target_doclist.append(target_d) - doclist = webnotes.doclist(doclist) + target_doclist = webnotes.doclist(target_doclist) if postprocess: - postprocess(source, doclist) + postprocess(source, target_doclist) - return doclist + return target_doclist def map_doc(source_doc, target_doc, table_map, source_meta, target_meta, source_parent=None): no_copy_fields = set(\ @@ -122,3 +128,13 @@ def map_doc(source_doc, target_doc, table_map, source_meta, target_meta, source_ if "postprocess" in table_map: table_map["postprocess"](source_doc, target_doc, source_parent) + +row_exists_for_parentfield = {} +def row_exists_in_target(parentfield, target_doclist): + global row_exists_for_parentfield + + if parentfield not in row_exists_for_parentfield: + row_exists_for_parentfield[parentfield] = True if \ + webnotes.doclist(target_doclist).get({"parentfield": parentfield}) else False + + return row_exists_for_parentfield[parentfield] From a8c423361e564add83fa2b0e2795e6d85a768310 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 15 Jul 2013 17:14:38 +0530 Subject: [PATCH 2/4] [docs] [minor] update to docs, fixed bug in file_manager --- core/doctype/documentation_tool/docs.css | 46 +++++- .../documentation_tool/documentation_tool.js | 36 +---- .../documentation_tool/documentation_tool.py | 136 ++++-------------- public/js/wn/assets.js | 32 +---- public/js/wn/misc/tools.js | 31 ++++ public/js/wn/ui/dialog.js | 12 ++ webnotes/db.py | 2 - webnotes/utils/file_manager.py | 4 +- 8 files changed, 116 insertions(+), 183 deletions(-) diff --git a/core/doctype/documentation_tool/docs.css b/core/doctype/documentation_tool/docs.css index 6d494c2d69..bd9d2ebaea 100644 --- a/core/doctype/documentation_tool/docs.css +++ b/core/doctype/documentation_tool/docs.css @@ -6,19 +6,22 @@ body { line-height: 25px; } +img { + max-width: 100%; +} + .container { max-width: 767px; } -.navbar-inverse { - background-color: #2980b9; +.navbar { + background-color: #ffffff; + border-bottom: 1px solid #dddddd; } -.navbar-inverse .navbar-text, -.navbar-inverse .navbar-brand, -.navbar-inverse .navbar-nav > li > a +.navbar .navbar-nav > li > a:hover { - color: #eeeeee; + color: #444444; } h1 { @@ -61,3 +64,34 @@ blockquote p { .erpnext-logo rect { fill: #ffffff !important; } + +.btn-default { + color: #ffffff; + background-color: #a7a9aa; + border-color: #a7a9aa; +} + +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active { + background-color: #9a9c9d; + border-color: #8d9091; +} + +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #a7a9aa; + border-color: #a7a9aa; +} + diff --git a/core/doctype/documentation_tool/documentation_tool.js b/core/doctype/documentation_tool/documentation_tool.js index c4c3f537d1..f0cf3832c6 100644 --- a/core/doctype/documentation_tool/documentation_tool.js +++ b/core/doctype/documentation_tool/documentation_tool.js @@ -1,32 +1,3 @@ -/* - -Todo: -- make global toc -- static pages in markdown (in sources folder) - - web interface - - building an application - - customizing an application - - generating web pages - -- help / comments in markdown -- pages -- doctype - - links - - properties - - methods - - events (server, client) - -Documentation API - -Every module (namespace) / class will have a page -- _toc -- _path -- _label -- _intro -- _type (class, function, module, doctype etc) -- [list of functions / objects / classes] -*/ - wn.require("lib/public/js/lib/beautify-html.js"); cur_frm.cscript.onload = function(doc) { @@ -50,6 +21,7 @@ wn.docs.generate_all = function(logarea) { wn.docs.to_write = {}; var pages = [], body = $("
"), + original_cur_frm = cur_frm; doc = cur_frm.doc; make_page = function(name, links) { body.empty(); @@ -125,6 +97,7 @@ wn.docs.generate_all = function(logarea) { }, callback: function(r) { logarea.append("Wrote " + keys(wn.docs.to_write).length + " pages."); + cur_frm = original_cur_frm; } }); } @@ -316,6 +289,9 @@ wn.docs.DocsPage = Class.extend({ else page_icon = "file-text-alt"; } + + if(page_icon.substr(0,5)==="icon-") page_icon = page_icon.substr(5); + var icon = $('

') .appendTo(this.parent); @@ -615,7 +591,7 @@ wn.docs.DocsPage = Class.extend({ } wn.docs.to_write[this.namespace] = { - title: wn.app.name + ": " + this.obj._label || wn.docs.get_short_name(this.namespace), + title: wn.app.name + ": " + (this.obj._label || wn.docs.get_short_name(this.namespace)), content: html_beautify(this.parent.html()) } } diff --git a/core/doctype/documentation_tool/documentation_tool.py b/core/doctype/documentation_tool/documentation_tool.py index d0bdb8dd7d..52ec0bd769 100644 --- a/core/doctype/documentation_tool/documentation_tool.py +++ b/core/doctype/documentation_tool/documentation_tool.py @@ -104,7 +104,7 @@ def inspect_object_and_update_docs(mydocs, obj): if not mydocs.get("_intro"): mydocs["_intro"] = getattr(obj, "__doc__", "") - + for name in dir(obj): try: value = getattr(obj, name) @@ -112,13 +112,19 @@ def inspect_object_and_update_docs(mydocs, obj): value = None if value: - if inspect.ismethod(value) or (inspect.isfunction(value) and inspect.getmodule(value)==obj): - mydocs[name] = { - "_type": "function", - "_args": inspect.getargspec(value)[0], - "_help": getattr(value, "__doc__", ""), - "_source": inspect.getsource(value) - } + if (mydocs["_type"]=="module" and inspect.getmodule(value)==obj)\ + or (mydocs["_type"]=="class" and getattr(value, "im_class", None)==obj): + if inspect.ismethod(value) or inspect.isfunction(value): + mydocs[name] = { + "_type": "function", + "_args": inspect.getargspec(value)[0], + "_help": getattr(value, "__doc__", ""), + "_source": inspect.getsource(value) + } + elif inspect.isclass(value): + if not mydocs.get("_toc"): + mydocs["_toc"] = [] + mydocs["_toc"].append(obj.__name__ + "." + value.__name__) def get_gh_url(path): sep = "/lib/" if "/lib/" in path else "/app/" @@ -149,14 +155,13 @@ def get_modules(for_module=None): "_toc": [ prefix + ".doctype", prefix + ".page", - prefix + ".report", prefix + ".py_modules" ], "doctype": get_doctypes(m), "page": get_pages(m), #"report": {}, "py_modules": { - "_label": "Independant Python Modules for " + m, + "_label": "Independent Python Modules for " + m, "_toc": [] } } @@ -239,7 +244,7 @@ def get_doctypes(m): mydocs = docs[d] = { "_label": d, - "_icon": "sitemap", + "_icon": meta[0].icon, "_type": "doctype", "_gh_source": get_gh_url(doc_path), "_toc": [ @@ -273,7 +278,7 @@ def get_doctypes(m): # model modeldocs = mydocs["model"] = { "_label": d + " Model", - "_icon": "sitemap", + "_icon": meta[0].icon, "_type": "model", "_intro": "Properties and fields for " + d, "_gh_source": get_gh_url(os.path.join(doc_path, scrub(d) + ".txt")), @@ -291,7 +296,7 @@ def get_doctypes(m): permission_docs = mydocs["permissions"] = { "_label": d + " Permissions", "_type": "permissions", - "_icon": "shield", + "_icon": meta[0].icon, "_gh_source": get_gh_url(os.path.join(doc_path, scrub(d) + ".txt")), "_intro": "Standard Permissions for " + d + ". These can be changed by the user.", "_permissions": [p for p in doclist if p.doctype=="DocPerm"], @@ -314,12 +319,12 @@ def get_doctypes(m): # client controller if meta_p[0].fields.get("__js"): - mydocs["_toc"].append(prefix + d + ".controller_client") client_controller_path = os.path.join(doc_path, scrub(d) + ".js") if(os.path.exists(client_controller_path)): + mydocs["_toc"].append(prefix + d + ".controller_client") client_controller = mydocs["controller_client"] = { "_label": d + " Client Controller", - "_icon": "code", + "_icon": meta[0].icon, "_type": "controller_client", "_gh_source": get_gh_url(client_controller_path), "_modified": get_timestamp(client_controller_path), @@ -379,7 +384,10 @@ def prepare_docs(): def write_docs(data, build_sitemap=None, domain=None): if webnotes.session.user != "Administrator": raise webnotes.PermissionError - + + with open(os.path.join(os.path.dirname(__file__), "docs.html"), "r") as docshtml: + docs_template = docshtml.read() + data = json.loads(data) template = Template(docs_template) data["index"] = data["docs"] @@ -416,99 +424,3 @@ sitemap_frame_xml = """ """ sitemap_link_xml = """\n%s%s""" - - -docs_template = """ - - - - - - {{ title }} - - - - - - - - - - - -
- -
-
- -
-
- {{ content }} -
-
-
-
- -

 

-
- - - - -""" diff --git a/public/js/wn/assets.js b/public/js/wn/assets.js index e7b19737dc..efde25b5a2 100644 --- a/public/js/wn/assets.js +++ b/public/js/wn/assets.js @@ -111,34 +111,4 @@ wn.assets = { wn.dom.set_style(txt); } } -} - -wn.markdown = function(txt) { - if(!wn.md2html) { - wn.require('lib/js/lib/showdown.js'); - wn.md2html = new Showdown.converter(); - } - - while(txt.substr(0,1)==="\n") { - txt = txt.substr(1); - } - - // remove leading tab (if they exist in the first line) - var whitespace_len = 0, - first_line = txt.split("\n")[0]; - - while([" ", "\n", "\t"].indexOf(first_line.substr(0,1))!== -1) { - whitespace_len++; - first_line = first_line.substr(1); - } - - if(whitespace_len && whitespace_len != first_line.length) { - var txt1 = []; - $.each(txt.split("\n"), function(i, t) { - txt1.push(t.substr(whitespace_len)); - }) - txt = txt1.join("\n"); - } - - return wn.md2html.makeHtml(txt); -} +} \ No newline at end of file diff --git a/public/js/wn/misc/tools.js b/public/js/wn/misc/tools.js index de86361632..cccc5f6cd9 100644 --- a/public/js/wn/misc/tools.js +++ b/public/js/wn/misc/tools.js @@ -41,6 +41,37 @@ wn.tools.downloadify = function(data, roles, me) { } }; +wn.markdown = function(txt) { + if(!wn.md2html) { + wn.require('lib/js/lib/showdown.js'); + wn.md2html = new Showdown.converter(); + } + + while(txt.substr(0,1)==="\n") { + txt = txt.substr(1); + } + + // remove leading tab (if they exist in the first line) + var whitespace_len = 0, + first_line = txt.split("\n")[0]; + + while([" ", "\n", "\t"].indexOf(first_line.substr(0,1))!== -1) { + whitespace_len++; + first_line = first_line.substr(1); + } + + if(whitespace_len && whitespace_len != first_line.length) { + var txt1 = []; + $.each(txt.split("\n"), function(i, t) { + txt1.push(t.substr(whitespace_len)); + }) + txt = txt1.join("\n"); + } + + return wn.md2html.makeHtml(txt); +} + + wn.tools.to_csv = function(data) { var res = []; $.each(data, function(i, row) { diff --git a/public/js/wn/ui/dialog.js b/public/js/wn/ui/dialog.js index 3b8edcbc7b..e43043a503 100644 --- a/public/js/wn/ui/dialog.js +++ b/public/js/wn/ui/dialog.js @@ -26,6 +26,18 @@ var cur_dialog; wn.ui.open_dialogs = []; wn.ui.Dialog = wn.ui.FieldGroup.extend({ + _intro:' usage:\n\ + \n\ + var dialog = new wn.ui.Dialog({\n\ + title: "Dialog Title",\n\ + fields: [\n\ + {fieldname:"field1", fieldtype:"Data", reqd:1, label: "Test 1"},\n\ + {fieldname:"field2", fieldtype:"Link", reqd:1, label: "Test 1", options:"Some DocType"},\n\ + {fieldname:"mybutton", fieldtype:"Button", reqd:1, label: "Submit"},\n\ + ]\n\ + })\n\ + dialog.get_input("mybutton").click(function() { /* do something; */ dialog.hide(); });\n\ + dialog.show()', init: function(opts) { this.display = false; if(!opts.width) opts.width = 480; diff --git a/webnotes/db.py b/webnotes/db.py index 105e7bfa87..6909263e80 100644 --- a/webnotes/db.py +++ b/webnotes/db.py @@ -29,8 +29,6 @@ import webnotes import conf import datetime -_toc = ["webnotes.db.Database"] - class Database: """ Open a database connection with the given parmeters, if use_default is True, use the diff --git a/webnotes/utils/file_manager.py b/webnotes/utils/file_manager.py index 439169ff3a..52aac88ab4 100644 --- a/webnotes/utils/file_manager.py +++ b/webnotes/utils/file_manager.py @@ -23,7 +23,7 @@ from __future__ import unicode_literals import webnotes import os, conf -from webnotes.utils import cstr, get_path +from webnotes.utils import cstr, get_path, cint from webnotes import _ class MaxFileSizeReachedError(webnotes.ValidationError): pass @@ -123,7 +123,7 @@ def get_new_fname_based_on_version(files_path, fname): versions.sort() if "-" in versions[-1]: - version = int(versions[-1].split("-")[-1]) or 1 + version = cint(versions[-1].split("-")[-1]) or 1 else: version = 1 From 6a4b02c5906c049d5e28fd368c67cfc75afdbc44 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 15 Jul 2013 17:28:31 +0530 Subject: [PATCH 3/4] [fix] [minor] file manager versioning --- webnotes/utils/file_manager.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/webnotes/utils/file_manager.py b/webnotes/utils/file_manager.py index 52aac88ab4..0c4e5d48bc 100644 --- a/webnotes/utils/file_manager.py +++ b/webnotes/utils/file_manager.py @@ -118,8 +118,11 @@ def save_file(fname, content, dt, dn): return f.doc.name def get_new_fname_based_on_version(files_path, fname): - # new version of the file is being uploaded, add a revision number? - versions = filter(lambda f: f.startswith(fname), os.listdir(files_path)) + fname_parts = fname.split(".", -1) + fname = ".".join(fname_parts[:-1]) + extn = fname_parts[-1] + + versions = filter(lambda f: f.startswith(fname) and f.endswith(extn), os.listdir(files_path)) versions.sort() if "-" in versions[-1]: @@ -127,12 +130,12 @@ def get_new_fname_based_on_version(files_path, fname): else: version = 1 - new_fname = fname + "-" + str(version) + new_fname = fname + "-" + str(version) + "." + extn while os.path.exists(os.path.join(files_path, new_fname)): version += 1 - new_fname = fname + "-" + str(version) + new_fname = fname + "-" + str(version) + "." + extn if version > 100: - break # let there be an exception + webnotes.msgprint("Too many versions", raise_exception=True) return new_fname From 06e977579029d7d6b6d2b5e56e4f81c5e8e8548e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 15 Jul 2013 18:18:05 +0530 Subject: [PATCH 4/4] [minor] [file_manager] fixes to code and cleanup --- core/doctype/documentation_tool/docs.html | 92 +++++++++++++++++++++++ public/js/wn/upload.js | 7 +- webnotes/utils/file_manager.py | 54 +++++++------ webnotes/widgets/form/utils.py | 2 - 4 files changed, 126 insertions(+), 29 deletions(-) create mode 100644 core/doctype/documentation_tool/docs.html diff --git a/core/doctype/documentation_tool/docs.html b/core/doctype/documentation_tool/docs.html new file mode 100644 index 0000000000..772cb9c6b4 --- /dev/null +++ b/core/doctype/documentation_tool/docs.html @@ -0,0 +1,92 @@ + + + + + + {{ title }} + + + + + + + + + + + +
+ +
+
+ +
+
+ {{ content }} +
+
+
+
+ +

 

+
+ + + + diff --git a/public/js/wn/upload.js b/public/js/wn/upload.js index a0e37f6748..57468abe8a 100644 --- a/public/js/wn/upload.js +++ b/public/js/wn/upload.js @@ -56,14 +56,15 @@ wn.upload = { "method": "uploadfile", args: args, callback: function(r) { - msgbox.hide(); + if(!r._server_messages) + msgbox.hide(); if(r.exc) { onerror(r); return; } - callback(r.message, args.filename || args.file_url, r); + callback(r.message.fileid, r.message.filename, r); $(document).trigger("upload_complete", - [args.filename, args.file_url]); + [r.message.fileid, r.message.filename]); } }); } diff --git a/webnotes/utils/file_manager.py b/webnotes/utils/file_manager.py index 0c4e5d48bc..20dd9f516e 100644 --- a/webnotes/utils/file_manager.py +++ b/webnotes/utils/file_manager.py @@ -41,18 +41,16 @@ def upload(): # save if filename: - fid, fname = save_uploaded(dt, dn) + filedata = save_uploaded(dt, dn) elif file_url: - fid, fname = save_url(file_url, dt, dn) + filedata = save_url(file_url, dt, dn) + + return {"fid": filedata.name, "filename": filedata.file_name or filedata.file_url } - if fid: - return fid - -def save_uploaded(dt, dn): +def save_uploaded(dt, dn): fname, content = get_uploaded_content() if content: - fid = save_file(fname, content, dt, dn) - return fid, fname + return save_file(fname, content, dt, dn) else: raise Exception @@ -69,7 +67,7 @@ def save_url(file_url, dt, dn): }) f.ignore_permissions = True f.insert(); - return f.doc.name, file_url + return f.doc def get_uploaded_content(): # should not be unicode when reading a file, hence using webnotes.form @@ -90,14 +88,25 @@ def save_file(fname, content, dt, dn): temp_fname = write_file(content) fname = scrub_file_name(fname) fpath = os.path.join(files_path, fname) + + fname_parts = fname.split(".", -1) + main = ".".join(fname_parts[:-1]) + extn = fname_parts[-1] + versions = get_file_versions(files_path, main, extn) - if os.path.exists(fpath): - if cmp(fpath, temp_fname): - # remove new file, already exists! - os.remove(temp_fname) - else: + if versions: + found_match = False + for version in versions: + if cmp(os.path.join(files_path, version), temp_fname): + # remove new file, already exists! + os.remove(temp_fname) + fname = version + found_match = True + break + + if not found_match: # get_new_version name - fname = get_new_fname_based_on_version(files_path, fname) + fname = get_new_fname_based_on_version(files_path, main, extn, versions) # rename os.rename(temp_fname, os.path.join(files_path, fname)) @@ -115,25 +124,22 @@ def save_file(fname, content, dt, dn): f.ignore_permissions = True f.insert(); - return f.doc.name + return f.doc -def get_new_fname_based_on_version(files_path, fname): - fname_parts = fname.split(".", -1) - fname = ".".join(fname_parts[:-1]) - extn = fname_parts[-1] - - versions = filter(lambda f: f.startswith(fname) and f.endswith(extn), os.listdir(files_path)) +def get_file_versions(files_path, main, extn): + return filter(lambda f: f.startswith(main) and f.endswith(extn), os.listdir(files_path)) +def get_new_fname_based_on_version(files_path, main, extn, versions): versions.sort() if "-" in versions[-1]: version = cint(versions[-1].split("-")[-1]) or 1 else: version = 1 - new_fname = fname + "-" + str(version) + "." + extn + new_fname = main + "-" + str(version) + "." + extn while os.path.exists(os.path.join(files_path, new_fname)): version += 1 - new_fname = fname + "-" + str(version) + "." + extn + new_fname = main + "-" + str(version) + "." + extn if version > 100: webnotes.msgprint("Too many versions", raise_exception=True) diff --git a/webnotes/widgets/form/utils.py b/webnotes/widgets/form/utils.py index b3dbca2790..1b08b2b344 100644 --- a/webnotes/widgets/form/utils.py +++ b/webnotes/widgets/form/utils.py @@ -29,9 +29,7 @@ from webnotes import _ def remove_attach(): """remove attachment""" import webnotes.utils.file_manager - fid = webnotes.form_dict.get('fid') - webnotes.utils.file_manager.remove_file(fid) @webnotes.whitelist()