Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

236 linhas
6.6 KiB

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