You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

101 lines
3.3 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals, print_function
  4. import frappe
  5. import os
  6. from frappe.utils.file_manager import get_content_hash, get_file, get_file_name
  7. from frappe.utils import get_files_path, get_site_path
  8. # The files missed by the previous patch might have been replaced with new files
  9. # with the same filename
  10. #
  11. # This patch does the following,
  12. # * Detect which files were replaced and rename them with name{hash:5}.extn and
  13. # update filedata record for the new file
  14. #
  15. # * make missing_files.txt in site dir with files that should be recovered from
  16. # a backup from a time before version 3 migration
  17. #
  18. # * Patch remaining unpatched File records.
  19. from six import iteritems
  20. def execute():
  21. frappe.db.auto_commit_on_many_writes = True
  22. rename_replacing_files()
  23. for name, file_name, file_url in frappe.db.sql(
  24. """select name, file_name, file_url from `tabFile`
  25. where ifnull(file_name, '')!='' and ifnull(content_hash, '')=''"""):
  26. b = frappe.get_doc('File', name)
  27. old_file_name = b.file_name
  28. b.file_name = os.path.basename(old_file_name)
  29. if old_file_name.startswith('files/') or old_file_name.startswith('/files/'):
  30. b.file_url = os.path.normpath('/' + old_file_name)
  31. else:
  32. b.file_url = os.path.normpath('/files/' + old_file_name)
  33. try:
  34. _file_name, content = get_file(name)
  35. b.content_hash = get_content_hash(content)
  36. except IOError:
  37. print('Warning: Error processing ', name)
  38. b.content_hash = None
  39. b.flags.ignore_duplicate_entry_error = True
  40. b.save()
  41. frappe.db.auto_commit_on_many_writes = False
  42. def get_replaced_files():
  43. ret = []
  44. new_files = dict(frappe.db.sql("select name, file_name from `tabFile` where file_name not like 'files/%'"))
  45. old_files = dict(frappe.db.sql("select name, file_name from `tabFile` where ifnull(content_hash, '')=''"))
  46. invfiles = invert_dict(new_files)
  47. for nname, nfilename in iteritems(new_files):
  48. if 'files/' + nfilename in old_files.values():
  49. ret.append((nfilename, invfiles[nfilename]))
  50. return ret
  51. def rename_replacing_files():
  52. replaced_files = get_replaced_files()
  53. if len(replaced_files):
  54. missing_files = [v[0] for v in replaced_files]
  55. with open(get_site_path('missing_files.txt'), 'w') as f:
  56. f.write(('\n'.join(missing_files) + '\n').encode('utf-8'))
  57. for file_name, file_datas in replaced_files:
  58. print ('processing ' + file_name)
  59. content_hash = frappe.db.get_value('File', file_datas[0], 'content_hash')
  60. if not content_hash:
  61. continue
  62. new_file_name = get_file_name(file_name, content_hash)
  63. if os.path.exists(get_files_path(new_file_name)):
  64. continue
  65. print('skipping ' + file_name)
  66. try:
  67. os.rename(get_files_path(file_name), get_files_path(new_file_name))
  68. except OSError:
  69. print('Error renaming ', file_name)
  70. for name in file_datas:
  71. f = frappe.get_doc('File', name)
  72. f.file_name = new_file_name
  73. f.file_url = '/files/' + new_file_name
  74. f.save()
  75. def invert_dict(ddict):
  76. ret = {}
  77. for k,v in iteritems(ddict):
  78. if not ret.get(v):
  79. ret[v] = [k]
  80. else:
  81. ret[v].append(k)
  82. return ret
  83. def get_file_name(fname, hash):
  84. if '.' in fname:
  85. partial, extn = fname.rsplit('.', 1)
  86. else:
  87. partial = fname
  88. extn = ''
  89. return '{partial}{suffix}.{extn}'.format(partial=partial, extn=extn, suffix=hash[:5])