diff --git a/frappe/cli.py b/frappe/cli.py index 86803365e5..01c3c48e36 100755 --- a/frappe/cli.py +++ b/frappe/cli.py @@ -362,13 +362,13 @@ def latest(verbose=True, rebuild_website_config=True, quiet=False): # sync frappe.model.sync.sync_all(verbose=verbose) + sync_fixtures() + statics.sync().start() # build website config if any changes in templates etc. if rebuild_website_config: rebuild_config() - statics.sync().start() - sync_fixtures() frappe.translate.clear_cache() diff --git a/frappe/core/page/data_import_tool/data_import_tool.py b/frappe/core/page/data_import_tool/data_import_tool.py index 674b226962..5105c15222 100644 --- a/frappe/core/page/data_import_tool/data_import_tool.py +++ b/frappe/core/page/data_import_tool/data_import_tool.py @@ -18,11 +18,11 @@ data_keys = frappe._dict({ @frappe.whitelist() def get_doctypes(): if "System Manager" in frappe.get_roles(): - return [r[0] for r in frappe.db.sql("""select name from `tabDocType` + return [r[0] for r in frappe.db.sql("""select name from `tabDocType` where allow_import = 1""")] else: return frappe.user._get("can_import") - + @frappe.whitelist() def get_doctype_options(): doctype = frappe.form_dict['doctype'] @@ -35,7 +35,7 @@ def import_file_by_path(path, ignore_links=False, overwrite=False, submit=False) from frappe.core.page.data_import_tool.importer import upload print "Importing " + path with open(path, "r") as infile: - upload(rows = read_csv_content(infile), ignore_links=ignore_links, overwrite=overwrite, submit_after_import=submit) + upload(rows = read_csv_content(infile.read()), ignore_links=ignore_links, overwrite=overwrite, submit_after_import=submit) def export_csv(doctype, path): from frappe.core.page.data_import_tool.exporter import get_template @@ -59,25 +59,30 @@ def export_json(doctype, name, path): def export_fixture(doctype, name, app): if frappe.session.user != "Administrator": raise frappe.PermissionError - + if not os.path.exists(frappe.get_app_path(app, "fixtures")): os.mkdir(frappe.get_app_path(app, "fixtures")) - + export_json(doctype, name, frappe.get_app_path(app, "fixtures", frappe.scrub(name) + ".json")) - + def import_doc(path, overwrite=False, ignore_links=False, ignore_insert=False, insert=False, submit=False): if os.path.isdir(path): files = [os.path.join(path, f) for f in os.listdir(path)] else: files = [path] - + def _import_doc(d): doc = frappe.get_doc(d) doc.ignore_links = ignore_links if insert: doc.set("__islocal", True) try: + if doc.name and overwrite: + if frappe.db.exists(doc.doctype, doc.name): + frappe.delete_doc(doc.doctype, doc.name, force=True) + doc.set("__islocal", True) + doc.ignore_links = ignore_links doc.save() except NameError: if ignore_insert: @@ -85,7 +90,7 @@ def import_doc(path, overwrite=False, ignore_links=False, ignore_insert=False, i else: raise print "Imported: " + doc.doctype + " / " + doc.name - + for f in files: if f.endswith(".json"): with open(f, "r") as infile: @@ -97,5 +102,5 @@ def import_doc(path, overwrite=False, ignore_links=False, ignore_insert=False, i _import_doc(data) frappe.db.commit() if f.endswith(".csv"): - import_file_by_path(f, ignore_links=True, overwrite=overwrite, submit=submit) + import_file_by_path(f, ignore_links=ignore_links, overwrite=overwrite, submit=submit) frappe.db.commit() diff --git a/frappe/core/page/data_import_tool/importer.py b/frappe/core/page/data_import_tool/importer.py index 5e2ed8ff9a..4a0a132232 100644 --- a/frappe/core/page/data_import_tool/importer.py +++ b/frappe/core/page/data_import_tool/importer.py @@ -17,7 +17,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, frappe.flags.mute_emails = True # extra input params params = json.loads(frappe.form_dict.get("params") or '{}') - + if params.get("_submit"): submit_after_import = True if params.get("ignore_encoding_errors"): @@ -54,7 +54,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, def filter_empty_columns(columns): empty_cols = filter(lambda x: x in ("", None), columns) - + if empty_cols: if columns[-1*len(empty_cols):] == empty_cols: # filter empty columns if they exist at the end @@ -69,7 +69,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, doctype_row, row_idx = get_header_row_and_idx(data_keys.doctype) if row_idx == -1: # old style return - + dt = None for i, d in enumerate(doctype_row[1:]): if d not in ("~", "-"): @@ -97,7 +97,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, try: fieldname = column_idx_to_fieldname[dt][column_idx] fieldtype = column_idx_to_fieldtype[dt][column_idx] - + d[fieldname] = rows[idx][column_idx] if fieldtype in ("Int", "Check"): d[fieldname] = cint(d[fieldname]) @@ -105,7 +105,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, d[fieldname] = flt(d[fieldname]) except IndexError, e: pass - + # scrub quotes from name and modified if d.get("name") and d["name"].startswith('"'): d["name"] = d["name"][1:-1] @@ -125,13 +125,13 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, return doc else: - d = frappe._dict(zip(columns, rows[start_idx][1:])) - d['doctype'] = doctype - return [d] + doc = frappe._dict(zip(columns, rows[start_idx][1:])) + doc['doctype'] = doctype + return doc def main_doc_empty(row): return not (row and ((len(row) > 1 and row[1]) or (len(row) > 2 and row[2]))) - + # header if not rows: rows = read_csv_content_from_uploaded_file(ignore_encoding_errors) @@ -144,13 +144,13 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, doctype_parentfield = {} column_idx_to_fieldname = {} column_idx_to_fieldtype = {} - - if submit_after_import and not cint(frappe.db.get_value("DocType", + + if submit_after_import and not cint(frappe.db.get_value("DocType", doctype, "is_submittable")): submit_after_import = False parenttype = get_header_row(data_keys.parent_table) - + if len(parenttype) > 1: parenttype = parenttype[1] parentfield = get_parent_field(doctype, parenttype) @@ -159,15 +159,15 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, if not frappe.permissions.can_import(parenttype or doctype): frappe.flags.mute_emails = False return {"messages": [_("Not allowed to Import") + ": " + _(doctype)], "error": True} - + # allow limit rows to be uploaded check_data_length() make_column_map() - + frappe.db.begin() if overwrite==None: overwrite = params.get('overwrite') - + # delete child rows (if parenttype) if parenttype and overwrite: delete_child_rows(data, doctype) @@ -179,10 +179,10 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, # bypass empty rows if main_doc_empty(row): continue - + row_idx = i + start_row doc = None - + doc = get_doc(row_idx) try: frappe.local.message_log = [] @@ -192,7 +192,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, parent.save() ret.append('Inserted row for %s at #%s' % (getlink(parenttype, doc.parent), unicode(doc.idx))) - + else: if overwrite and frappe.db.exists(doctype, doc["name"]): original = frappe.get_doc(doctype, doc["name"]) @@ -210,36 +210,36 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, except Exception, e: error = True if doc: - frappe.errprint(doc.as_dict()) + frappe.errprint(doc if isinstance(doc, dict) else doc.as_dict()) err_msg = frappe.local.message_log and "
".join(frappe.local.message_log) or cstr(e) - ret.append('Error for row (#%d) %s : %s' % (row_idx + 1, + ret.append('Error for row (#%d) %s : %s' % (row_idx + 1, len(row)>1 and row[1] or "", err_msg)) frappe.errprint(frappe.get_traceback()) - + if error: - frappe.db.rollback() + frappe.db.rollback() else: frappe.db.commit() - + frappe.flags.mute_emails = False - + return {"messages": ret, "error": error} - + def get_parent_field(doctype, parenttype): parentfield = None - + # get parentfield if parenttype: for d in frappe.get_meta(parenttype).get_table_fields(): if d.options==doctype: parentfield = d.fieldname break - + if not parentfield: frappe.msgprint("Did not find parentfield for %s (%s)" % \ (parenttype, doctype)) raise Exception - + return parentfield def delete_child_rows(rows, doctype): diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index bdab3baee2..4395809216 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -19,7 +19,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa if not doctype: doctype = frappe.form_dict.get('dt') name = frappe.form_dict.get('dn') - + if not doctype: frappe.msgprint('Nothing to delete!', raise_exception =1) @@ -28,16 +28,20 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa return doc = frappe.get_doc(doctype, name) - + if not for_reload: check_permission_and_not_submitted(doc, ignore_permissions) doc.run_method("on_trash") # check if links exist if not force: check_if_doc_is_linked(doc) - + try: - frappe.db.sql("delete from `tab%s` where name=%s" % (doctype, "%s"), (name,)) + if doctype==name: + frappe.db.sql("delete from `tabSingles` where doctype=%s", name) + else: + frappe.db.sql("delete from `tab%s` where name=%s" % (doctype, "%s"), (name,)) + for t in doc.meta.get_table_fields(): if t.options not in ignore_doctypes: frappe.db.sql("delete from `tab%s` where parent = %s" % (t.options, '%s'), (name,)) @@ -45,15 +49,15 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa except Exception, e: if e.args[0]==1451: frappe.msgprint("Cannot delete %s '%s' as it is referenced in another record. You must delete the referred record first" % (doctype, name)) - + raise - + # delete attachments remove_all(doctype, name) - + # delete restrictions frappe.defaults.clear_default(parenttype="Restriction", key=doctype, value=name) - + return 'okay' def check_permission_and_not_submitted(doc, ignore_permissions=False): @@ -78,12 +82,12 @@ def check_if_doc_is_linked(doc, method="Delete"): for link_dt, link_field, issingle in link_fields: if not issingle: - item = frappe.db.get_value(link_dt, {link_field:doc.name}, + item = frappe.db.get_value(link_dt, {link_field:doc.name}, ["name", "parent", "parenttype", "docstatus"], as_dict=True) - - if item and item.parent != doc.name and ((method=="Delete" and item.docstatus<2) or + + if item and item.parent != doc.name and ((method=="Delete" and item.docstatus<2) or (method=="Cancel" and item.docstatus==1)): frappe.msgprint(method + " " + _("Error") + ":"+\ - ("%s (%s) " % (doc.name, doc.doctype)) + _("is linked in") + (" %s (%s)") % + ("%s (%s) " % (doc.name, doc.doctype)) + _("is linked in") + (" %s (%s)") % (item.parent or item.name, item.parent and item.parenttype or link_dt), raise_exception=LinkExistsError) diff --git a/frappe/templates/generators/website_group.py b/frappe/templates/generators/website_group.py index 51e5a6a949..77ad3aeb3a 100644 --- a/frappe/templates/generators/website_group.py +++ b/frappe/templates/generators/website_group.py @@ -13,13 +13,13 @@ no_cache = 1 def get_context(context): group, view = guess_group_view(context) - + try: if not has_access(context.access, view): raise frappe.PermissionError - + return get_group_context(group, view, context) - + except frappe.DoesNotExistError: return { "content": '
' @@ -30,48 +30,48 @@ def get_context(context): "content": '
' 'You are not permitted to view this page.
' } - + def get_group_context(group, view, context): cache_key = "website_group_context:{}:{}".format(group, view) views = get_views(context.doc.group_type) view = frappe._dict(views.get(view)) - + if can_cache(view.no_cache): group_context = frappe.cache().get_value(cache_key) if group_context: return group_context - + group_context = build_group_context(group, view, views, context) - + if can_cache(view.get("no_cache")): frappe.cache().set_value(cache_key, group_context) - + return group_context - + def build_group_context(group, view, views, context): title = "{} - {}".format(context.doc.group_title, view.get("label")) - + group_context = frappe._dict({ - "group": context.doc.as_dict(), + "group": context.doc, "view": view, "views": [v[1] for v in sorted(views.iteritems(), key=lambda (k, v): v.get("idx"))], "title": title, "pathname": context.pathname }) group_context.update(build_view_context(group_context)) - + return group_context - + def build_view_context(context): from frappe.templates.website_group.post import get_post_context - + if context.view.name in ("popular", "feed", "open", "closed", "upcoming", "past"): context.post_list_html = get_post_list_html(context.group.name, context.view.name) - + elif context.view.name == "edit": context.post = frappe.get_doc("Post", frappe.form_dict.name).as_dict() - + if context.post.assigned_to: context.user = frappe.get_doc("User", context.post.assigned_to) @@ -79,22 +79,22 @@ def build_view_context(context): context.users = frappe.db.sql("""select p.*, wsp.`read`, wsp.`write`, wsp.`admin` from `tabUser` p, `tabWebsite Route Permission` wsp where wsp.website_route=%s and wsp.user=p.name""", context.pathname, as_dict=True) - + elif context.view.name == "post": context.update(get_post_context(context)) - + return context - + def guess_group_view(context): group = context.docname view = frappe.form_dict.view or get_default_view(context.doc.group_type) return group, view - + def get_default_view(group_type): for view, opts in get_views(group_type).iteritems(): if opts.get("default"): return view - + def get_views(group_type=None): if group_type: group_views = frappe._dict(views[group_type]) @@ -102,22 +102,22 @@ def get_views(group_type=None): group_views = {} for group_type in views: group_views.update(views[group_type].copy()) - + group_views.update(common_views) - + if group_type == "Forum": group_views["post"]["upvote"] = True - + return group_views - -def has_access(access, view): + +def has_access(access, view): if view=="settings": return access.get("admin") elif view in ("add", "edit"): return access.get("write") else: return access.get("read") - + def clear_cache(path=None, website_group=None): from frappe.templates.website_group.post import clear_post_cache if path: @@ -127,7 +127,7 @@ def clear_cache(path=None, website_group=None): else: clear_post_cache() website_groups = frappe.db.sql_list("""select name from `tabWebsite Group`""") - + cache = frappe.cache() all_views = get_views() for group in website_groups: @@ -137,10 +137,10 @@ def clear_cache(path=None, website_group=None): def clear_event_cache(): for group in frappe.db.sql_list("""select name from `tabWebsite Group` where group_type='Event'"""): clear_unit_views(website_group=group) - + def clear_cache_on_doc_event(doc, method, *args, **kwargs): clear_cache(path=doc.website_route, website_group=doc.website_group) - + def get_pathname(group): return frappe.db.get_value("Website Route", {"ref_doctype": "Website Group", "docname": group}) @@ -237,4 +237,4 @@ common_views = { "hidden": True, "idx": 6 } -} \ No newline at end of file +} diff --git a/frappe/templates/website_group/post.py b/frappe/templates/website_group/post.py index da450a715e..ebdc15283d 100644 --- a/frappe/templates/website_group/post.py +++ b/frappe/templates/website_group/post.py @@ -12,7 +12,7 @@ def get_post_context(context): post = frappe.get_doc("Post", frappe.form_dict.name) if post.parent_post: raise frappe.PermissionError - + def _get_post_context(): fullname = get_fullname(post.owner) return { @@ -21,42 +21,42 @@ def get_post_context(context): "post_list_html": get_child_posts_html(post, context), "parent_post": post.name } - + cache_key = "website_group_post:{}".format(post.name) return frappe.cache().get_value(cache_key, lambda: _get_post_context()) - + def get_parent_post_html(post, context): user = frappe.get_doc("User", post.owner) for fieldname in ("first_name", "last_name", "user_image", "location"): post.set(fieldname, user.get(fieldname)) - + return frappe.get_template("templates/includes/inline_post.html")\ - .render({"post": post.as_dict(), "view": context.view}) + .render({"post": post, "view": context.view}) def get_child_posts_html(post, context): posts = frappe.db.sql("""select p.*, pr.user_image, pr.first_name, pr.last_name from tabPost p, tabUser pr where p.parent_post=%s and pr.name = p.owner order by p.creation asc""", (post.name,), as_dict=True) - + return frappe.get_template("templates/includes/post_list.html")\ .render({ "posts": posts, "parent_post": post.name, "view": context.view }) - + def clear_post_cache(post=None): cache = frappe.cache() posts = [post] if post else frappe.db.sql_list("select name from `tabPost`") for post in posts: cache.delete_value("website_group_post:{}".format(post)) - + @frappe.whitelist(allow_guest=True) -def add_post(group, content, picture, picture_name, title=None, parent_post=None, +def add_post(group, content, picture, picture_name, title=None, parent_post=None, assigned_to=None, status=None, event_datetime=None): - + access = get_access(get_pathname(group)) if not access.get("write"): raise frappe.PermissionError @@ -64,8 +64,8 @@ def add_post(group, content, picture, picture_name, title=None, parent_post=None if parent_post: if frappe.db.get_value("Post", parent_post, "parent_post"): frappe.throw("Cannot reply to a reply") - - group = frappe.get_doc("Website Group", group) + + group = frappe.get_doc("Website Group", group) post = frappe.get_doc({ "doctype":"Post", "title": (title or "").title(), @@ -73,7 +73,7 @@ def add_post(group, content, picture, picture_name, title=None, parent_post=None "website_group": group.name, "parent_post": parent_post or None }) - + if not parent_post: if group.group_type == "Tasks": post.is_task = 1 @@ -81,38 +81,38 @@ def add_post(group, content, picture, picture_name, title=None, parent_post=None elif group.group_type == "Events": post.is_event = 1 post.event_datetime = event_datetime - + post.ignore_permissions = True post.insert() if picture_name and picture: process_picture(post, picture_name, picture) - + # send email if parent_post: post.run_method("send_email_on_reply") - + return post.parent_post or post.name - + @frappe.whitelist(allow_guest=True) def save_post(post, content, picture=None, picture_name=None, title=None, assigned_to=None, status=None, event_datetime=None): - + post = frappe.get_doc("Post", post) access = get_access(get_pathname(post.website_group)) - + if not access.get("write"): raise frappe.PermissionError - + # TODO improve error message if frappe.session.user != post.owner: for fieldname in ("title", "content"): if post.get(fieldname) != locals().get(fieldname): frappe.throw("You cannot change: {}".format(fieldname.title())) - + if picture and picture_name: frappe.throw("You cannot change: Picture") - + post.update({ "title": (title or "").title(), "content": content, @@ -122,34 +122,34 @@ def save_post(post, content, picture=None, picture_name=None, title=None, }) post.ignore_permissions = True post.save() - + if picture_name and picture: process_picture(post, picture_name, picture) - + return post.parent_post or post.name - + def process_picture(post, picture_name, picture): from frappe.templates.generators.website_group import clear_cache - + file_data = save_file(picture_name, picture, "Post", post.name, decode=True) post.picture_url = file_data.file_name or file_data.file_url frappe.db.set_value("Post", post.name, "picture_url", post.picture_url) clear_cache(website_group=post.website_group) - + @frappe.whitelist() def suggest_user(group, term): """suggest a user that has read permission in this group tree""" - users = frappe.db.sql("""select - pr.name, pr.first_name, pr.last_name, + users = frappe.db.sql("""select + pr.name, pr.first_name, pr.last_name, pr.user_image, pr.location from `tabUser` pr where (pr.first_name like %(term)s or pr.last_name like %(term)s) - and pr.user_type = 'Website User' and pr.enabled=1""", + and pr.user_type = 'Website User' and pr.enabled=1""", {"term": "%{}%".format(term), "group": group}, as_dict=True) - + template = frappe.get_template("templates/includes/user_display.html") return [{ - "value": "{} {}".format(pr.first_name or "", pr.last_name or "").strip(), + "value": "{} {}".format(pr.first_name or "", pr.last_name or "").strip(), "user_html": template.render({"user": pr}), "user": pr.name } for pr in users] diff --git a/frappe/utils/fixtures.py b/frappe/utils/fixtures.py index 9c544704e3..30284c8e1f 100644 --- a/frappe/utils/fixtures.py +++ b/frappe/utils/fixtures.py @@ -1,5 +1,5 @@ # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt +# MIT License. See license.txt from __future__ import unicode_literals