diff --git a/frappe/patches/v4_0/__init__.py b/frappe/patches/v4_0/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/patches/v4_0/add_delete_permission.py b/frappe/patches/v4_0/add_delete_permission.py new file mode 100644 index 0000000000..7811217d97 --- /dev/null +++ b/frappe/patches/v4_0/add_delete_permission.py @@ -0,0 +1,12 @@ +import frappe + +def execute(): + frappe.reload_doc("core", "doctype", "docperm") + + # delete same as cancel (map old permissions) + frappe.db.sql("""update tabDocPerm set `delete`=ifnull(`cancel`,0)""") + + # can't cancel if can't submit + frappe.db.sql("""update tabDocPerm set `cancel`=0 where ifnull(`submit`,0)=0""") + + frappe.clear_cache() \ No newline at end of file diff --git a/frappe/patches/v4_0/change_varchar_length.py b/frappe/patches/v4_0/change_varchar_length.py new file mode 100644 index 0000000000..d9da8221e9 --- /dev/null +++ b/frappe/patches/v4_0/change_varchar_length.py @@ -0,0 +1,23 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for dt in frappe.db.sql_list("""select name from `tabDocType` where ifnull(issingle, 0)=0"""): + desc = dict((d["Field"], d) for d in frappe.db.sql("desc `tab{}`".format(dt), as_dict=True)) + alter_table = [] + + if desc["name"]["Type"] != "varchar(255)": + alter_table.append("change `name` `name` varchar(255) not null") + + for fieldname in ("modified_by", "owner", "parent", "parentfield", "parenttype"): + if desc[fieldname]["Type"] != "varchar(255)": + alter_table.append("change `{fieldname}` `{fieldname}` varchar(255)".format(fieldname=fieldname)) + + if alter_table: + alter_table_query = "alter table `tab{doctype}` {alter_table}".format(doctype=dt, alter_table=",\n".join(alter_table)) + # print alter_table_query + frappe.db.sql_ddl(alter_table_query) + diff --git a/frappe/patches/v4_0/create_custom_field_for_owner_match.py b/frappe/patches/v4_0/create_custom_field_for_owner_match.py new file mode 100644 index 0000000000..2ac51c18ef --- /dev/null +++ b/frappe/patches/v4_0/create_custom_field_for_owner_match.py @@ -0,0 +1,39 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.core.doctype.custom_field.custom_field import create_custom_field + +def execute(): + if "match" in frappe.db.get_table_columns("DocPerm"): + create_custom_field_for_owner_match() + +def create_custom_field_for_owner_match(): + frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1 where `match`='owner'""") + + for dt in frappe.db.sql_list("""select distinct parent from `tabDocPerm` + where `match`='owner' and permlevel=0 and parent != 'User'"""): + + # a link field pointing to User already exists + if (frappe.db.get_value("DocField", {"parent": dt, "fieldtype": "Link", "options": "User", "default": "__user"}) + or frappe.db.get_value("Custom Field", {"dt": dt, "fieldtype": "Link", "options": "User", "default": "__user"})): + print "User link field already exists for", dt + continue + + fieldname = "{}_owner".format(frappe.scrub(dt)) + + create_custom_field(dt, frappe._dict({ + "permlevel": 0, + "label": "{} Owner".format(dt), + "fieldname": fieldname, + "fieldtype": "Link", + "options": "User", + "default": "__user" + })) + + frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=owner""".format(doctype=dt, + fieldname=fieldname)) + + # commit is required so that we don't lose these changes because of an error in next loop's ddl + frappe.db.commit() diff --git a/frappe/patches/v4_0/deprecate_control_panel.py b/frappe/patches/v4_0/deprecate_control_panel.py new file mode 100644 index 0000000000..7bccf4bf2b --- /dev/null +++ b/frappe/patches/v4_0/deprecate_control_panel.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.db.sql("update `tabDefaultValue` set parenttype='__default' where parenttype='Control Panel'") + frappe.db.sql("update `tabDefaultValue` set parent='__default' where parent='Control Panel'") + frappe.clear_cache() diff --git a/frappe/patches/v4_0/deprecate_link_selects.py b/frappe/patches/v4_0/deprecate_link_selects.py new file mode 100644 index 0000000000..317333b019 --- /dev/null +++ b/frappe/patches/v4_0/deprecate_link_selects.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for name in frappe.db.sql_list("""select name from `tabCustom Field` + where fieldtype="Select" and options like "link:%" """): + custom_field = frappe.get_doc("Custom Field", name) + custom_field.fieldtype = "Link" + custom_field.options = custom_field.options[5:] + custom_field.save() diff --git a/frappe/patches/v4_0/enable_scheduler_in_system_settings.py b/frappe/patches/v4_0/enable_scheduler_in_system_settings.py new file mode 100644 index 0000000000..bc2f167ece --- /dev/null +++ b/frappe/patches/v4_0/enable_scheduler_in_system_settings.py @@ -0,0 +1,14 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils.scheduler import disable_scheduler, enable_scheduler +from frappe.utils import cint + +def execute(): + frappe.reload_doc("core", "doctype", "system_settings") + if cint(frappe.db.get_global("disable_scheduler")): + disable_scheduler() + else: + enable_scheduler() diff --git a/frappe/patches/v4_0/file_manager_hooks.py b/frappe/patches/v4_0/file_manager_hooks.py new file mode 100644 index 0000000000..ef043d4d31 --- /dev/null +++ b/frappe/patches/v4_0/file_manager_hooks.py @@ -0,0 +1,36 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals + +import frappe +import os +from frappe.utils import get_files_path +from frappe.utils.file_manager import get_content_hash, get_file + + +def execute(): + frappe.reload_doc('core', 'doctype', 'file_data') + for name, file_name, file_url in frappe.db.sql( + """select name, file_name, file_url from `tabFile Data` + where file_name is not null"""): + b = frappe.get_doc('File Data', name) + old_file_name = b.file_name + b.file_name = os.path.basename(old_file_name) + if old_file_name.startswith('files/') or old_file_name.startswith('/files/'): + b.file_url = os.path.normpath('/' + old_file_name) + else: + b.file_url = os.path.normpath('/files/' + old_file_name) + try: + _file_name, content = get_file(name) + b.content_hash = get_content_hash(content) + except IOError: + print 'Warning: Error processing ', name + _file_name = old_file_name + b.content_hash = None + + try: + b.save() + except frappe.DuplicateEntryError: + frappe.delete_doc(b.doctype, b.name) + diff --git a/frappe/patches/v4_0/fix_attach_field_file_url.py b/frappe/patches/v4_0/fix_attach_field_file_url.py new file mode 100644 index 0000000000..3c5a6aa03c --- /dev/null +++ b/frappe/patches/v4_0/fix_attach_field_file_url.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + attach_fields = (frappe.db.sql("""select parent, fieldname from `tabDocField` where fieldtype='Attach'""") + + frappe.db.sql("""select dt, fieldname from `tabCustom Field` where fieldtype='Attach'""")) + + for doctype, fieldname in attach_fields: + frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=concat("/", `{fieldname}`) + where `{fieldname}` like 'files/%'""".format(doctype=doctype, fieldname=fieldname)) diff --git a/frappe/patches/v4_0/private_backups.py b/frappe/patches/v4_0/private_backups.py new file mode 100644 index 0000000000..f82209c31e --- /dev/null +++ b/frappe/patches/v4_0/private_backups.py @@ -0,0 +1,11 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.installer import make_site_dirs + +def execute(): + make_site_dirs() + if frappe.local.conf.backup_path and frappe.local.conf.backup_path.startswith("public"): + raise Exception, "Backups path in conf set to public directory" diff --git a/frappe/patches/v4_0/remove_index_sitemap.py b/frappe/patches/v4_0/remove_index_sitemap.py new file mode 100644 index 0000000000..00d37eaf2e --- /dev/null +++ b/frappe/patches/v4_0/remove_index_sitemap.py @@ -0,0 +1,4 @@ +import frappe + +def execute(): + pass diff --git a/frappe/patches/v4_0/remove_old_parent.py b/frappe/patches/v4_0/remove_old_parent.py new file mode 100644 index 0000000000..588cda9121 --- /dev/null +++ b/frappe/patches/v4_0/remove_old_parent.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for doctype in frappe.db.sql_list("""select name from `tabDocType` where istable=1"""): + frappe.db.sql("""delete from `tab{0}` where parent like "old_par%:%" """.format(doctype)) + frappe.db.sql("""delete from `tabDocField` where parent="0" """) diff --git a/frappe/patches/v4_0/remove_user_owner_custom_field.py b/frappe/patches/v4_0/remove_user_owner_custom_field.py new file mode 100644 index 0000000000..4f3e478f98 --- /dev/null +++ b/frappe/patches/v4_0/remove_user_owner_custom_field.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + user_owner = frappe.db.get_value("Custom Field", {"fieldname": "user_owner"}) + if user_owner: + frappe.delete_doc("Custom Field", user_owner) diff --git a/frappe/patches/v4_0/rename_profile_to_user.py b/frappe/patches/v4_0/rename_profile_to_user.py new file mode 100644 index 0000000000..c7165961e7 --- /dev/null +++ b/frappe/patches/v4_0/rename_profile_to_user.py @@ -0,0 +1,14 @@ +import frappe + +from frappe.model import rename_field +from frappe.model.meta import get_table_columns + +def execute(): + tables = frappe.db.sql_list("show tables") + if "tabUser" not in tables: + frappe.rename_doc("DocType", "Profile", "User", force=True) + + frappe.reload_doc("website", "doctype", "blogger") + + if "profile" in get_table_columns("Blogger"): + rename_field("Blogger", "profile", "user") diff --git a/frappe/patches/v4_0/rename_sitemap_to_route.py b/frappe/patches/v4_0/rename_sitemap_to_route.py new file mode 100644 index 0000000000..9c7114fcb9 --- /dev/null +++ b/frappe/patches/v4_0/rename_sitemap_to_route.py @@ -0,0 +1,24 @@ +import frappe + +from frappe.model import rename_field + +def execute(): + tables = frappe.db.sql_list("show tables") + for doctype in ("Website Sitemap", "Website Sitemap Config"): + if "tab{}".format(doctype) in tables: + frappe.delete_doc("DocType", doctype, force=1) + frappe.db.sql("drop table `tab{}`".format(doctype)) + + for d in ("Blog Category", "Blog Post", "Web Page"): + frappe.reload_doc("website", "doctype", frappe.scrub(d)) + rename_field_if_exists(d, "parent_website_sitemap", "parent_website_route") + + for d in ("blog_category", "blog_post", "web_page", "post", "user_vote"): + frappe.reload_doc("website", "doctype", d) + +def rename_field_if_exists(doctype, old_fieldname, new_fieldname): + try: + rename_field(doctype, old_fieldname, new_fieldname) + except Exception, e: + if e.args[0] != 1054: + raise diff --git a/frappe/patches/v4_0/replace_deprecated_timezones.py b/frappe/patches/v4_0/replace_deprecated_timezones.py new file mode 100644 index 0000000000..4574dc19f8 --- /dev/null +++ b/frappe/patches/v4_0/replace_deprecated_timezones.py @@ -0,0 +1,21 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils.momentjs import data as momentjs_data + +def execute(): + frappe.reload_doc("core", "doctype", "user") + + ss = frappe.get_doc("System Settings", "System Settings") + if ss.time_zone in momentjs_data.get("links"): + ss.time_zone = momentjs_data["links"][ss.time_zone] + ss.ignore_mandatory = True + ss.save() + + for user, time_zone in frappe.db.sql("select name, time_zone from `tabUser` where ifnull(time_zone, '')!=''"): + if time_zone in momentjs_data.get("links"): + user = frappe.get_doc("User", user) + user.time_zone = momentjs_data["links"][user.time_zone] + user.save() diff --git a/frappe/patches/v4_0/set_module_in_report.py b/frappe/patches/v4_0/set_module_in_report.py new file mode 100644 index 0000000000..107d868eba --- /dev/null +++ b/frappe/patches/v4_0/set_module_in_report.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("core", "doctype", "report") + frappe.db.sql("""update `tabReport` r set r.module=(select d.module from `tabDocType` d + where d.name=r.ref_doctype) where ifnull(r.module, '')=''""") \ No newline at end of file diff --git a/frappe/patches/v4_0/set_todo_checked_as_closed.py b/frappe/patches/v4_0/set_todo_checked_as_closed.py new file mode 100644 index 0000000000..cc4b87a0bc --- /dev/null +++ b/frappe/patches/v4_0/set_todo_checked_as_closed.py @@ -0,0 +1,8 @@ +import frappe + +def execute(): + frappe.reload_doc("core", "doctype", "todo") + try: + frappe.db.sql("""update tabToDo set status = if(ifnull(checked,0)=0, 'Open', 'Closed')""") + except: + pass diff --git a/frappe/patches/v4_0/set_user_gravatar.py b/frappe/patches/v4_0/set_user_gravatar.py new file mode 100644 index 0000000000..78bd72f4dc --- /dev/null +++ b/frappe/patches/v4_0/set_user_gravatar.py @@ -0,0 +1,11 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for name in frappe.db.sql_list("select name from `tabUser` where ifnull(user_image, '')=''"): + user = frappe.get_doc("User", name) + user.update_gravatar() + user.db_set("user_image", user.user_image) diff --git a/frappe/patches/v4_0/set_user_permissions.py b/frappe/patches/v4_0/set_user_permissions.py new file mode 100644 index 0000000000..b25f68c09c --- /dev/null +++ b/frappe/patches/v4_0/set_user_permissions.py @@ -0,0 +1,24 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe +import frappe.permissions + +def execute(): + frappe.reload_doc("core", "doctype", "docperm") + table_columns = frappe.db.get_table_columns("DocPerm") + + if "restricted" in table_columns: + frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1 where ifnull(apply_user_permissions, 0)=0 + and restricted=1""") + + if "match" in table_columns: + frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1 + where ifnull(apply_user_permissions, 0)=0 and ifnull(`match`, '')!=''""") + + # change Restriction to User Permission in tabDefaultValue + frappe.db.sql("""update `tabDefaultValue` set parenttype='User Permission' where parenttype='Restriction'""") + + frappe.clear_cache() + diff --git a/frappe/patches/v4_0/set_website_route_idx.py b/frappe/patches/v4_0/set_website_route_idx.py new file mode 100644 index 0000000000..82f64756a4 --- /dev/null +++ b/frappe/patches/v4_0/set_website_route_idx.py @@ -0,0 +1,24 @@ +import frappe + +def execute(): + pass + # from frappe.website.doctype.website_template.website_template import \ + # get_pages_and_generators, get_template_controller + # + # frappe.reload_doc("website", "doctype", "website_template") + # frappe.reload_doc("website", "doctype", "website_route") + # + # for app in frappe.get_installed_apps(): + # pages, generators = get_pages_and_generators(app) + # for g in generators: + # doctype = frappe.get_attr(get_template_controller(app, g["path"], g["fname"]) + ".doctype") + # module = frappe.db.get_value("DocType", doctype, "module") + # frappe.reload_doc(frappe.scrub(module), "doctype", frappe.scrub(doctype)) + # + # frappe.db.sql("""update `tabBlog Category` set `title`=`name` where ifnull(`title`, '')=''""") + # frappe.db.sql("""update `tabWebsite Route` set idx=null""") + # for doctype in ["Blog Category", "Blog Post", "Web Page", "Website Group"]: + # frappe.db.sql("""update `tab{}` set idx=null""".format(doctype)) + # + # from frappe.website.doctype.website_template.website_template import rebuild_website_template + # rebuild_website_template() diff --git a/frappe/patches/v4_0/update_custom_field_insert_after.py b/frappe/patches/v4_0/update_custom_field_insert_after.py new file mode 100644 index 0000000000..0e820cd0e3 --- /dev/null +++ b/frappe/patches/v4_0/update_custom_field_insert_after.py @@ -0,0 +1,18 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for d in frappe.db.sql("""select name, dt, insert_after from `tabCustom Field` + where docstatus < 2""", as_dict=1): + dt_meta = frappe.get_meta(d.dt) + if not dt_meta.get_field(d.insert_after): + cf = frappe.get_doc("Custom Field", d.name) + df = dt_meta.get("fields", {"label": d.insert_after}) + if df: + cf.insert_after = df[0].fieldname + else: + cf.insert_after = None + cf.save() diff --git a/frappe/patches/v4_0/update_datetime.py b/frappe/patches/v4_0/update_datetime.py new file mode 100644 index 0000000000..672dd1940b --- /dev/null +++ b/frappe/patches/v4_0/update_datetime.py @@ -0,0 +1,11 @@ +import frappe + +def execute(): + for table in frappe.db.sql_list("show tables"): + for field in frappe.db.sql("desc `%s`" % table): + if field[1]=="datetime": + frappe.db.sql("alter table `%s` change `%s` `%s` datetime(6)" % \ + (table, field[0], field[0])) + elif field[1]=="time": + frappe.db.sql("alter table `%s` change `%s` `%s` time(6)" % \ + (table, field[0], field[0])) diff --git a/frappe/patches/v4_0/webnotes_to_frappe.py b/frappe/patches/v4_0/webnotes_to_frappe.py new file mode 100644 index 0000000000..c70b2fdbde --- /dev/null +++ b/frappe/patches/v4_0/webnotes_to_frappe.py @@ -0,0 +1,11 @@ +import frappe, json + +def execute(): + frappe.clear_cache() + installed = frappe.get_installed_apps() + if "webnotes" in installed: + installed.remove("webnotes") + if "frappe" not in installed: + installed = ["frappe"] + installed + frappe.db.set_global("installed_apps", json.dumps(installed)) + frappe.clear_cache() diff --git a/frappe/patches/v4_0/website_sitemap_hierarchy.py b/frappe/patches/v4_0/website_sitemap_hierarchy.py new file mode 100644 index 0000000000..324b13ea4a --- /dev/null +++ b/frappe/patches/v4_0/website_sitemap_hierarchy.py @@ -0,0 +1,21 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals + +import frappe + +def execute(): + # frappe.db.sql("""update `tabWebsite Route` ws set ref_doctype=(select wsc.ref_doctype + # from `tabWebsite Template` wsc where wsc.name=ws.website_template) + # where ifnull(page_or_generator, '')!='Page'""") + + frappe.reload_doc("website", "doctype", "website_settings") + + # original_home_page = frappe.db.get_value("Website Settings", "Website Settings", "home_page") + # + # home_page = frappe.db.sql("""select name from `tabWebsite Route` + # where (name=%s or docname=%s) and name!='index'""", (original_home_page, original_home_page)) + # home_page = home_page[0][0] if home_page else original_home_page + # + # frappe.db.set_value("Website Settings", "Website Settings", "home_page", home_page) diff --git a/frappe/patches/v4_1/__init__.py b/frappe/patches/v4_1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/patches/v4_1/enable_outgoing_email_settings.py b/frappe/patches/v4_1/enable_outgoing_email_settings.py new file mode 100644 index 0000000000..472a8109e3 --- /dev/null +++ b/frappe/patches/v4_1/enable_outgoing_email_settings.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("core", "doctype", "outgoing_email_settings") + if (frappe.db.get_value("Outgoing Email Settings", "Outgoing Email Settings", "mail_server") or "").strip(): + frappe.db.set_value("Outgoing Email Settings", "Outgoing Email Settings", "enabled", 1) diff --git a/frappe/patches/v4_1/enable_print_as_pdf.py b/frappe/patches/v4_1/enable_print_as_pdf.py new file mode 100644 index 0000000000..877a2b61f7 --- /dev/null +++ b/frappe/patches/v4_1/enable_print_as_pdf.py @@ -0,0 +1,26 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("core", "doctype", "print_settings") + print_settings = frappe.get_doc("Print Settings") + print_settings.print_style = "Modern" + + try: + import pdfkit + except ImportError: + pass + else: + # if someone has already configured in Outgoing Email Settings + outgoing_email_settings = frappe.db.get_singles_dict("Outgoing Email Settings") + if "send_print_as_pdf" in outgoing_email_settings: + print_settings.send_print_as_pdf = outgoing_email_settings.send_print_as_pdf + print_settings.pdf_page_size = outgoing_email_settings.pdf_page_size + + else: + print_settings.send_print_as_pdf = 1 + + print_settings.save() diff --git a/frappe/patches/v4_1/file_manager_fix.py b/frappe/patches/v4_1/file_manager_fix.py new file mode 100644 index 0000000000..5315284109 --- /dev/null +++ b/frappe/patches/v4_1/file_manager_fix.py @@ -0,0 +1,98 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals + +import frappe +import os +from frappe.utils.file_manager import get_content_hash, get_file, get_file_name +from frappe.utils import get_files_path, get_site_path + +# The files missed by the previous patch might have been replaced with new files +# with the same filename +# +# This patch does the following, +# * Detect which files were replaced and rename them with name{hash:5}.extn and +# update filedata record for the new file +# +# * make missing_files.txt in site dir with files that should be recovered from +# a backup from a time before version 3 migration +# +# * Patch remaining unpatched file data records. + +def execute(): + frappe.db.auto_commit_on_many_writes = True + rename_replacing_files() + for name, file_name, file_url in frappe.db.sql( + """select name, file_name, file_url from `tabFile Data` + where ifnull(file_name, '')!='' and ifnull(content_hash, '')=''"""): + b = frappe.get_doc('File Data', name) + old_file_name = b.file_name + b.file_name = os.path.basename(old_file_name) + if old_file_name.startswith('files/') or old_file_name.startswith('/files/'): + b.file_url = os.path.normpath('/' + old_file_name) + else: + b.file_url = os.path.normpath('/files/' + old_file_name) + try: + _file_name, content = get_file(name) + b.content_hash = get_content_hash(content) + except IOError: + print 'Warning: Error processing ', name + b.content_hash = None + b.ignore_duplicate_entry_error = True + b.save() + frappe.db.auto_commit_on_many_writes = False + +def get_replaced_files(): + ret = [] + new_files = dict(frappe.db.sql("select name, file_name from `tabFile Data` where file_name not like 'files/%'")) + old_files = dict(frappe.db.sql("select name, file_name from `tabFile Data` where ifnull(content_hash, '')=''")) + invfiles = invert_dict(new_files) + + for nname, nfilename in new_files.iteritems(): + if 'files/' + nfilename in old_files.values(): + ret.append((nfilename, invfiles[nfilename])) + return ret + +def rename_replacing_files(): + replaced_files = get_replaced_files() + if len(replaced_files): + missing_files = [v[0] for v in replaced_files] + with open(get_site_path('missing_files.txt'), 'w') as f: + f.write(('\n'.join(missing_files) + '\n').encode('utf-8')) + + for file_name, file_datas in replaced_files: + print 'processing ' + file_name + content_hash = frappe.db.get_value('File Data', file_datas[0], 'content_hash') + if not content_hash: + continue + new_file_name = get_file_name(file_name, content_hash) + if os.path.exists(get_files_path(new_file_name)): + continue + print 'skipping ' + file_name + try: + os.rename(get_files_path(file_name), get_files_path(new_file_name)) + except OSError: + print 'Error renaming ', file_name + for name in file_datas: + f = frappe.get_doc('File Data', name) + f.file_name = new_file_name + f.file_url = '/files/' + new_file_name + f.save() + +def invert_dict(ddict): + ret = {} + for k,v in ddict.iteritems(): + if not ret.get(v): + ret[v] = [k] + else: + ret[v].append(k) + return ret + +def get_file_name(fname, hash): + if '.' in fname: + partial, extn = fname.rsplit('.', 1) + else: + partial = fname + extn = '' + return '{partial}{suffix}.{extn}'.format(partial=partial, extn=extn, suffix=hash[:5]) diff --git a/frappe/patches/v4_2/__init__.py b/frappe/patches/v4_2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/patches/v4_2/print_with_letterhead.py b/frappe/patches/v4_2/print_with_letterhead.py new file mode 100644 index 0000000000..ad2a144d95 --- /dev/null +++ b/frappe/patches/v4_2/print_with_letterhead.py @@ -0,0 +1,11 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("core", "doctype", "print_settings") + print_settings = frappe.get_doc("Print Settings") + print_settings.with_letterhead = 1 + print_settings.save() diff --git a/frappe/patches/v4_2/refactor_website_routing.py b/frappe/patches/v4_2/refactor_website_routing.py new file mode 100644 index 0000000000..9cb39beaf0 --- /dev/null +++ b/frappe/patches/v4_2/refactor_website_routing.py @@ -0,0 +1,7 @@ +import frappe + +def execute(): + # clear all static web pages + frappe.delete_doc("DocType", "Website Route", force=1) + frappe.delete_doc("Page", "sitemap-browser", force=1) + frappe.db.sql("drop table if exists `tabWebsite Route`") diff --git a/frappe/patches/v4_2/set_assign_in_doc.py b/frappe/patches/v4_2/set_assign_in_doc.py new file mode 100644 index 0000000000..664c997eaf --- /dev/null +++ b/frappe/patches/v4_2/set_assign_in_doc.py @@ -0,0 +1,10 @@ +import frappe + +def execute(): + for name in frappe.db.sql_list("""select name from `tabToDo` + where ifnull(reference_type, '')!='' and ifnull(reference_name, '')!=''"""): + try: + frappe.get_doc("ToDo", name).on_update() + except Exception, e: + if e.args[0]!=1146: + raise