diff --git a/frappe/core/doctype/file_data/file_data.json b/frappe/core/doctype/file_data/file_data.json
index d416ebbb3f..cb42e57ad1 100644
--- a/frappe/core/doctype/file_data/file_data.json
+++ b/frappe/core/doctype/file_data/file_data.json
@@ -1,72 +1,255 @@
{
+ "_last_update": null,
+ "_user_tags": null,
+ "allow_attach": null,
+ "allow_copy": null,
+ "allow_email": null,
+ "allow_import": null,
+ "allow_print": null,
+ "allow_rename": null,
+ "allow_trash": null,
"autoname": "File.######",
- "creation": "2012-12-12 11:19:22.000000",
+ "change_log": null,
+ "client_script": null,
+ "client_script_core": null,
+ "client_string": null,
+ "colour": null,
+ "creation": "2012-12-12 11:19:22",
+ "custom": null,
+ "default_print_format": null,
+ "description": null,
"docstatus": 0,
"doctype": "DocType",
+ "document_type": null,
+ "dt_template": null,
"fields": [
{
+ "allow_on_submit": null,
+ "default": null,
+ "depends_on": null,
+ "description": null,
"fieldname": "file_name",
"fieldtype": "Data",
+ "hidden": null,
+ "ignore_restrictions": null,
+ "in_filter": null,
+ "in_list_view": 1,
"label": "File Name",
+ "no_column": null,
+ "no_copy": null,
"oldfieldname": "file_name",
"oldfieldtype": "Data",
+ "options": null,
"permlevel": 0,
- "read_only": 1
+ "print_hide": null,
+ "print_width": null,
+ "read_only": 1,
+ "report_hide": null,
+ "reqd": null,
+ "search_index": null,
+ "set_only_once": null,
+ "trigger": null,
+ "width": null
},
{
+ "allow_on_submit": null,
+ "default": null,
+ "depends_on": null,
+ "description": null,
"fieldname": "file_url",
"fieldtype": "Data",
+ "hidden": null,
+ "ignore_restrictions": null,
+ "in_filter": null,
"in_list_view": 1,
"label": "File URL",
+ "no_column": null,
+ "no_copy": null,
+ "oldfieldname": null,
+ "oldfieldtype": null,
+ "options": null,
"permlevel": 0,
- "read_only": 1
+ "print_hide": null,
+ "print_width": null,
+ "read_only": 1,
+ "report_hide": null,
+ "reqd": null,
+ "search_index": null,
+ "set_only_once": null,
+ "trigger": null,
+ "width": null
},
{
+ "allow_on_submit": null,
+ "default": null,
+ "depends_on": null,
+ "description": null,
"fieldname": "attached_to_doctype",
"fieldtype": "Link",
+ "hidden": null,
+ "ignore_restrictions": null,
+ "in_filter": null,
"in_list_view": 1,
"label": "Attached To DocType",
+ "no_column": null,
+ "no_copy": null,
+ "oldfieldname": null,
+ "oldfieldtype": null,
"options": "DocType",
"permlevel": 0,
+ "print_hide": null,
+ "print_width": null,
"read_only": 1,
- "search_index": 1
+ "report_hide": null,
+ "reqd": null,
+ "search_index": 1,
+ "set_only_once": null,
+ "trigger": null,
+ "width": null
},
{
+ "allow_on_submit": null,
+ "default": null,
+ "depends_on": null,
+ "description": null,
"fieldname": "attached_to_name",
"fieldtype": "Data",
+ "hidden": null,
+ "ignore_restrictions": null,
+ "in_filter": null,
"in_list_view": 1,
"label": "Attached To Name",
+ "no_column": null,
+ "no_copy": null,
+ "oldfieldname": null,
+ "oldfieldtype": null,
+ "options": null,
"permlevel": 0,
+ "print_hide": null,
+ "print_width": null,
"read_only": 1,
- "search_index": 1
+ "report_hide": null,
+ "reqd": null,
+ "search_index": 1,
+ "set_only_once": null,
+ "trigger": null,
+ "width": null
},
{
+ "allow_on_submit": null,
+ "default": null,
+ "depends_on": null,
+ "description": null,
"fieldname": "file_size",
"fieldtype": "Int",
+ "hidden": null,
+ "ignore_restrictions": null,
+ "in_filter": null,
"in_list_view": 1,
"label": "File Size",
+ "no_column": null,
+ "no_copy": null,
+ "oldfieldname": null,
+ "oldfieldtype": null,
+ "options": null,
"permlevel": 0,
- "read_only": 1
+ "print_hide": null,
+ "print_width": null,
+ "read_only": 1,
+ "report_hide": null,
+ "reqd": null,
+ "search_index": null,
+ "set_only_once": null,
+ "trigger": null,
+ "width": null
+ },
+ {
+ "allow_on_submit": null,
+ "default": null,
+ "depends_on": null,
+ "description": null,
+ "fieldname": "content_hash",
+ "fieldtype": "Data",
+ "hidden": null,
+ "ignore_restrictions": null,
+ "in_filter": null,
+ "in_list_view": null,
+ "label": "Content Hash",
+ "no_column": null,
+ "no_copy": null,
+ "oldfieldname": null,
+ "oldfieldtype": null,
+ "options": null,
+ "permlevel": 0,
+ "print_hide": null,
+ "print_width": null,
+ "read_only": null,
+ "report_hide": null,
+ "reqd": null,
+ "search_index": 1,
+ "set_only_once": null,
+ "trigger": null,
+ "width": null
}
],
+ "hide_heading": null,
+ "hide_toolbar": null,
"icon": "icon-file",
"idx": 1,
- "modified": "2014-01-20 17:48:46.000000",
+ "in_create": null,
+ "in_dialog": null,
+ "is_submittable": null,
+ "is_transaction_doc": null,
+ "issingle": null,
+ "istable": null,
+ "max_attachments": null,
+ "menu_index": null,
+ "modified": "2014-04-07 17:01:13.295614",
"modified_by": "Administrator",
"module": "Core",
"name": "File Data",
+ "name_case": null,
"owner": "Administrator",
+ "parent": null,
+ "parent_node": null,
+ "parentfield": null,
+ "parenttype": null,
"permissions": [
{
- "cancel": 1,
+ "amend": null,
+ "cancel": 0,
+ "create": null,
"delete": 1,
"email": 1,
+ "export": null,
+ "import": null,
+ "match": null,
"permlevel": 0,
"print": 1,
"read": 1,
+ "report": null,
+ "restrict": null,
+ "restricted": null,
"role": "System Manager",
+ "submit": null,
"write": 1
}
],
- "read_only": 0
+ "plugin": null,
+ "print_outline": null,
+ "read_only": 0,
+ "read_only_onload": null,
+ "search_fields": null,
+ "section_style": null,
+ "server_code": null,
+ "server_code_compiled": null,
+ "server_code_core": null,
+ "server_code_error": null,
+ "show_in_menu": null,
+ "smallicon": null,
+ "subject": null,
+ "tag_fields": null,
+ "title_field": null,
+ "use_template": null,
+ "version": null
}
\ No newline at end of file
diff --git a/frappe/core/doctype/file_data/file_data.py b/frappe/core/doctype/file_data/file_data.py
index 7b58f9e905..a457a3da5b 100644
--- a/frappe/core/doctype/file_data/file_data.py
+++ b/frappe/core/doctype/file_data/file_data.py
@@ -11,6 +11,7 @@ naming for same name files: file.gif, file-1.gif, file-2.gif etc
import frappe, frappe.utils, os
from frappe import conf
from frappe.model.document import Document
+from frappe.utils.file_manager import delete_file_data_content
class FileData(Document):
def before_insert(self):
@@ -19,10 +20,10 @@ class FileData(Document):
def on_update(self):
# check duplicate assignement
n_records = frappe.db.sql("""select name from `tabFile Data`
- where file_name=%s
+ where content_hash=%s
and name!=%s
and attached_to_doctype=%s
- and attached_to_name=%s""", (self.file_name, self.name, self.attached_to_doctype,
+ and attached_to_name=%s""", (self.content_hash, self.name, self.attached_to_doctype,
self.attached_to_name))
if len(n_records) > 0:
self.duplicate_entry = n_records[0][0]
@@ -34,7 +35,7 @@ class FileData(Document):
if self.attached_to_name:
# check persmission
try:
- if not self.ignore_permissions and \
+ if not getattr(self, 'ignore_permissions', False) and \
not frappe.has_permission(self.attached_to_doctype, "write", self.attached_to_name):
frappe.msgprint(frappe._("No permission to write / remove."), raise_exception=True)
@@ -44,13 +45,8 @@ class FileData(Document):
# if file not attached to any other record, delete it
if self.file_name and not frappe.db.count("File Data",
- {"file_name": self.file_name, "name": ["!=", self.name]}):
- if self.file_name.startswith("files/"):
- path = frappe.utils.get_site_path("public", self.file_name)
- else:
- path = frappe.utils.get_site_path("public", "files", self.file_name)
- if os.path.exists(path):
- os.remove(path)
+ {"content_hash": self.content_hash, "name": ["!=", self.name]}):
+ delete_file_data_content(self)
def on_rollback(self):
- self.on_trash()
\ No newline at end of file
+ self.on_trash()
diff --git a/frappe/hooks.txt b/frappe/hooks.txt
index c3aff8d520..5feb017e48 100644
--- a/frappe/hooks.txt
+++ b/frappe/hooks.txt
@@ -48,3 +48,6 @@ doc_event:Website Route Permission:on_update = frappe.templates.generators.websi
doc_event:*:on_update = frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications
doc_event:*:on_cancel = frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications
doc_event:*:on_trash = frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications
+
+write_file_keys = file_url
+write_file_keys = file_name
diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py
index 22763351f9..b177708681 100644
--- a/frappe/model/rename_doc.py
+++ b/frappe/model/rename_doc.py
@@ -114,21 +114,14 @@ def update_child_docs(old, new, meta):
% (df.options, '%s', '%s'), (new, old))
def update_link_field_values(link_fields, old, new, doctype):
- update_list = []
-
- # update values
for field in link_fields:
- # if already updated, do not do it again
- if [field['parent'], field['fieldname']] in update_list:
- continue
- update_list.append([field['parent'], field['fieldname']])
if field['issingle']:
frappe.db.sql("""\
update `tabSingles` set value=%s
where doctype=%s and field=%s and value=%s""",
(new, field['parent'], field['fieldname'], old))
else:
- if doctype!='DocType' and field['parent']!=new:
+ if field['parent']!=new:
frappe.db.sql("""\
update `tab%s` set `%s`=%s
where `%s`=%s""" \
diff --git a/frappe/patches.txt b/frappe/patches.txt
index bcb5b9efa3..b1ac2d88f6 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -16,11 +16,12 @@ frappe.patches.4_0.website_sitemap_hierarchy
frappe.patches.4_0.webnotes_to_frappe
execute:frappe.reset_perms("Module Def")
frappe.patches.4_0.rename_sitemap_to_route
+frappe.patches.4_0.rename_profile_to_user
frappe.patches.4_0.set_website_route_idx
execute:import frappe.installer;frappe.installer.make_site_dirs() #2014-02-19
frappe.patches.4_0.private_backups
frappe.patches.4_0.set_module_in_report
frappe.patches.4_0.remove_old_parent
-frappe.patches.4_0.rename_profile_to_user
frappe.patches.4_0.update_datetime
frappe.patches.4_0.deprecate_control_panel
+frappe.patches.4_0.file_manager_hooks
diff --git a/frappe/patches/4_0/file_manager_hooks.py b/frappe/patches/4_0/file_manager_hooks.py
new file mode 100644
index 0000000000..5c72e62da3
--- /dev/null
+++ b/frappe/patches/4_0/file_manager_hooks.py
@@ -0,0 +1,27 @@
+# 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)
+ _file_name, content = get_file(name)
+ b.content_hash = get_content_hash(content)
+ b.save()
+
diff --git a/frappe/patches/4_0/rename_profile_to_user.py b/frappe/patches/4_0/rename_profile_to_user.py
index 6c2b984429..66b8752da6 100644
--- a/frappe/patches/4_0/rename_profile_to_user.py
+++ b/frappe/patches/4_0/rename_profile_to_user.py
@@ -1,6 +1,7 @@
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")
@@ -9,6 +10,7 @@ def execute():
if frappe.db.exists("DocType", "Website Route Permission"):
frappe.reload_doc("website", "doctype", "website_route_permission")
- rename_field("Website Route Permission", "profile", "user")
+ if "profile" in get_table_columns("Website Route Permission"):
+ rename_field("Website Route Permission", "profile", "user")
frappe.reload_doc("website", "doctype", "blogger")
rename_field("Blogger", "profile", "user")
diff --git a/frappe/public/js/frappe/form/attachments.js b/frappe/public/js/frappe/form/attachments.js
index cbde3e16f5..1d9f7248ec 100644
--- a/frappe/public/js/frappe/form/attachments.js
+++ b/frappe/public/js/frappe/form/attachments.js
@@ -41,13 +41,14 @@ frappe.ui.form.Attachments = Class.extend({
this.$list.empty();
var attachments = this.get_attachments();
- var file_names = keys(attachments).sort();
+ var that = this;
+
// add attachment objects
- if(file_names.length) {
- for(var i=0; i