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.

file_manager.py 6.5 KiB

13 vuotta sitten
11 vuotta sitten
13 vuotta sitten
13 vuotta sitten
13 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
12 vuotta sitten
12 vuotta sitten
12 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
12 vuotta sitten
12 vuotta sitten
13 vuotta sitten
12 vuotta sitten
13 vuotta sitten
12 vuotta sitten
13 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
13 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import webnotes
  5. import os, base64, re
  6. from webnotes.utils import cstr, cint, get_site_path
  7. from webnotes import _
  8. from webnotes import conf
  9. class MaxFileSizeReachedError(webnotes.ValidationError): pass
  10. def upload():
  11. # get record details
  12. dt = webnotes.form_dict.doctype
  13. dn = webnotes.form_dict.docname
  14. file_url = webnotes.form_dict.file_url
  15. filename = webnotes.form_dict.filename
  16. if not filename and not file_url:
  17. webnotes.msgprint(_("Please select a file or url"),
  18. raise_exception=True)
  19. # save
  20. if filename:
  21. filedata = save_uploaded(dt, dn)
  22. elif file_url:
  23. filedata = save_url(file_url, dt, dn)
  24. return {"fid": filedata.name, "filename": filedata.file_name or filedata.file_url }
  25. def save_uploaded(dt, dn):
  26. fname, content = get_uploaded_content()
  27. if content:
  28. return save_file(fname, content, dt, dn)
  29. else:
  30. raise Exception
  31. def save_url(file_url, dt, dn):
  32. if not (file_url.startswith("http://") or file_url.startswith("https://")):
  33. webnotes.msgprint("URL must start with 'http://' or 'https://'")
  34. return None, None
  35. f = webnotes.bean({
  36. "doctype": "File Data",
  37. "file_url": file_url,
  38. "attached_to_doctype": dt,
  39. "attached_to_name": dn
  40. })
  41. f.ignore_permissions = True
  42. f.insert();
  43. return f.doc
  44. def get_uploaded_content():
  45. # should not be unicode when reading a file, hence using webnotes.form
  46. if 'filedata' in webnotes.form_dict:
  47. webnotes.uploaded_content = base64.b64decode(webnotes.form_dict.filedata)
  48. webnotes.uploaded_filename = webnotes.form_dict.filename
  49. return webnotes.uploaded_filename, webnotes.uploaded_content
  50. else:
  51. webnotes.msgprint('No File')
  52. return None, None
  53. def extract_images_from_html(doc, fieldname):
  54. content = doc.get(fieldname)
  55. webnotes.flags.has_dataurl = False
  56. def _save_file(match):
  57. data = match.group(1)
  58. headers, content = data.split(",")
  59. filename = headers.split("filename=")[-1]
  60. filename = save_file(filename, content, doc.doctype, doc.name, decode=True).get("file_name")
  61. if not webnotes.flags.has_dataurl:
  62. webnotes.flags.has_dataurl = True
  63. return '<img src="{filename}"'.format(filename = filename)
  64. if content:
  65. content = re.sub('<img\s*src=\s*["\'](data:[^"\']*)["\']', _save_file, content)
  66. if webnotes.flags.has_dataurl:
  67. doc.fields[fieldname] = content
  68. def save_file(fname, content, dt, dn, decode=False):
  69. if decode:
  70. if isinstance(content, unicode):
  71. content = content.encode("utf-8")
  72. content = base64.b64decode(content)
  73. import filecmp
  74. from webnotes.model.code import load_doctype_module
  75. files_path = get_site_path(conf.files_path)
  76. module = load_doctype_module(dt, webnotes.conn.get_value("DocType", dt, "module"))
  77. if hasattr(module, "attachments_folder"):
  78. files_path = os.path.join(files_path, module.attachments_folder)
  79. file_size = check_max_file_size(content)
  80. temp_fname = write_file(content, files_path)
  81. fname = scrub_file_name(fname)
  82. fname_parts = fname.split(".", -1)
  83. main = ".".join(fname_parts[:-1])
  84. extn = fname_parts[-1]
  85. versions = get_file_versions(files_path, main, extn)
  86. if versions:
  87. found_match = False
  88. for version in versions:
  89. if filecmp.cmp(os.path.join(files_path, version), temp_fname):
  90. # remove new file, already exists!
  91. os.remove(temp_fname)
  92. fname = version
  93. fpath = os.path.join(files_path, fname)
  94. found_match = True
  95. break
  96. if not found_match:
  97. # get_new_version name
  98. fname = get_new_fname_based_on_version(files_path, main, extn, versions)
  99. fpath = os.path.join(files_path, fname)
  100. # rename
  101. if os.path.exists(fpath.encode("utf-8")):
  102. webnotes.throw("File already exists: " + fname)
  103. os.rename(temp_fname, fpath.encode("utf-8"))
  104. else:
  105. fpath = os.path.join(files_path, fname)
  106. # rename new file
  107. if os.path.exists(fpath.encode("utf-8")):
  108. webnotes.throw("File already exists: " + fname)
  109. os.rename(temp_fname, fpath.encode("utf-8"))
  110. f = webnotes.bean({
  111. "doctype": "File Data",
  112. "file_name": os.path.relpath(os.path.join(files_path, fname),
  113. get_site_path(conf.get("public_path", "public"))),
  114. "attached_to_doctype": dt,
  115. "attached_to_name": dn,
  116. "file_size": file_size
  117. })
  118. f.ignore_permissions = True
  119. try:
  120. f.insert();
  121. except webnotes.DuplicateEntryError:
  122. return {"file_name": f.doc.file_name}
  123. return f.doc
  124. def get_file_versions(files_path, main, extn):
  125. out = []
  126. for f in os.listdir(files_path):
  127. f = cstr(f)
  128. if f.startswith(main) and f.endswith(extn):
  129. out.append(f)
  130. return out
  131. def get_new_fname_based_on_version(files_path, main, extn, versions):
  132. versions.sort()
  133. if "-" in versions[-1]:
  134. version = cint(versions[-1].split("-")[-1]) or 1
  135. else:
  136. version = 1
  137. new_fname = main + "-" + str(version) + "." + extn
  138. while os.path.exists(os.path.join(files_path, new_fname).encode("utf-8")):
  139. version += 1
  140. new_fname = main + "-" + str(version) + "." + extn
  141. if version > 100:
  142. webnotes.msgprint("Too many versions", raise_exception=True)
  143. return new_fname
  144. def scrub_file_name(fname):
  145. if '\\' in fname:
  146. fname = fname.split('\\')[-1]
  147. if '/' in fname:
  148. fname = fname.split('/')[-1]
  149. return fname
  150. def check_max_file_size(content):
  151. max_file_size = conf.get('max_file_size') or 1000000
  152. file_size = len(content)
  153. if file_size > max_file_size:
  154. webnotes.msgprint(_("File size exceeded the maximum allowed size"),
  155. raise_exception=MaxFileSizeReachedError)
  156. return file_size
  157. def write_file(content, files_path):
  158. """write file to disk with a random name (to compare)"""
  159. # create account folder (if not exists)
  160. webnotes.create_folder(files_path)
  161. fname = os.path.join(files_path, webnotes.generate_hash())
  162. # write the file
  163. with open(fname, 'w+') as f:
  164. f.write(content)
  165. return fname
  166. def remove_all(dt, dn):
  167. """remove all files in a transaction"""
  168. try:
  169. for fid in webnotes.conn.sql_list("""select name from `tabFile Data` where
  170. attached_to_doctype=%s and attached_to_name=%s""", (dt, dn)):
  171. remove_file(fid)
  172. except Exception, e:
  173. if e.args[0]!=1054: raise # (temp till for patched)
  174. def remove_file(fid):
  175. """Remove file and File Data entry"""
  176. webnotes.delete_doc("File Data", fid)
  177. def get_file(fname):
  178. f = webnotes.conn.sql("""select file_name from `tabFile Data`
  179. where name=%s or file_name=%s""", (fname, fname))
  180. if f:
  181. file_name = f[0][0]
  182. else:
  183. file_name = fname
  184. if not "/" in file_name:
  185. file_name = "files/" + file_name
  186. # read the file
  187. with open(get_site_path("public", file_name), 'r') as f:
  188. content = f.read()
  189. return [file_name, content]