Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

312 Zeilen
8.3 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe, re, os
  5. from six import iteritems
  6. def delete_page_cache(path):
  7. cache = frappe.cache()
  8. cache.delete_value('full_index')
  9. groups = ("website_page", "page_context")
  10. if path:
  11. for name in groups:
  12. cache.hdel(name, path)
  13. else:
  14. for name in groups:
  15. cache.delete_key(name)
  16. def find_first_image(html):
  17. m = re.finditer("""<img[^>]*src\s?=\s?['"]([^'"]*)['"]""", html)
  18. try:
  19. return m.next().groups()[0]
  20. except StopIteration:
  21. return None
  22. def can_cache(no_cache=False):
  23. if frappe.conf.disable_website_cache or frappe.conf.developer_mode:
  24. return False
  25. if getattr(frappe.local, "no_cache", False):
  26. return False
  27. return not no_cache
  28. def get_comment_list(doctype, name):
  29. return frappe.db.sql("""select
  30. content, sender_full_name, creation, sender
  31. from `tabCommunication`
  32. where
  33. communication_type='Comment'
  34. and reference_doctype=%s
  35. and reference_name=%s
  36. and (comment_type is null or comment_type in ('Comment', 'Communication'))
  37. and modified >= DATE_SUB(NOW(),INTERVAL 1 YEAR)
  38. order by creation""", (doctype, name), as_dict=1) or []
  39. def get_home_page():
  40. if frappe.local.flags.home_page:
  41. return frappe.local.flags.home_page
  42. def _get_home_page():
  43. home_page = None
  44. get_website_user_home_page = frappe.get_hooks('get_website_user_home_page')
  45. if get_website_user_home_page:
  46. home_page = frappe.get_attr(get_website_user_home_page[-1])(frappe.session.user)
  47. if not home_page:
  48. role_home_page = frappe.get_hooks("role_home_page")
  49. if role_home_page:
  50. for role in frappe.get_roles():
  51. if role in role_home_page:
  52. home_page = role_home_page[role][-1]
  53. break
  54. if not home_page:
  55. home_page = frappe.get_hooks("home_page")
  56. if home_page:
  57. home_page = home_page[-1]
  58. if not home_page:
  59. home_page = frappe.db.get_value("Website Settings", None, "home_page") or "login"
  60. home_page = home_page.strip('/')
  61. return home_page
  62. return frappe.cache().hget("home_page", frappe.session.user, _get_home_page)
  63. def is_signup_enabled():
  64. if getattr(frappe.local, "is_signup_enabled", None) is None:
  65. frappe.local.is_signup_enabled = True
  66. if frappe.utils.cint(frappe.db.get_value("Website Settings",
  67. "Website Settings", "disable_signup")):
  68. frappe.local.is_signup_enabled = False
  69. return frappe.local.is_signup_enabled
  70. def cleanup_page_name(title):
  71. """make page name from title"""
  72. if not title:
  73. return title
  74. name = title.lower()
  75. name = re.sub('[~!@#$%^&*+()<>,."\'\?]', '', name)
  76. name = re.sub('[:/]', '-', name)
  77. name = '-'.join(name.split())
  78. # replace repeating hyphens
  79. name = re.sub(r"(-)\1+", r"\1", name)
  80. return name[:140]
  81. def get_shade(color, percent):
  82. color, color_format = detect_color_format(color)
  83. r, g, b, a = color
  84. avg = (float(int(r) + int(g) + int(b)) / 3)
  85. # switch dark and light shades
  86. if avg > 128:
  87. percent = -percent
  88. # stronger diff for darker shades
  89. if percent < 25 and avg < 64:
  90. percent = percent * 2
  91. new_color = []
  92. for channel_value in (r, g, b):
  93. new_color.append(get_shade_for_channel(channel_value, percent))
  94. r, g, b = new_color
  95. return format_color(r, g, b, a, color_format)
  96. def detect_color_format(color):
  97. if color.startswith("rgba"):
  98. color_format = "rgba"
  99. color = [c.strip() for c in color[5:-1].split(",")]
  100. elif color.startswith("rgb"):
  101. color_format = "rgb"
  102. color = [c.strip() for c in color[4:-1].split(",")] + [1]
  103. else:
  104. # assume hex
  105. color_format = "hex"
  106. if color.startswith("#"):
  107. color = color[1:]
  108. if len(color) == 3:
  109. # hex in short form like #fff
  110. color = "{0}{0}{1}{1}{2}{2}".format(*tuple(color))
  111. color = [int(color[0:2], 16), int(color[2:4], 16), int(color[4:6], 16), 1]
  112. return color, color_format
  113. def get_shade_for_channel(channel_value, percent):
  114. v = int(channel_value) + int(int('ff', 16) * (float(percent)/100))
  115. if v < 0:
  116. v=0
  117. if v > 255:
  118. v=255
  119. return v
  120. def format_color(r, g, b, a, color_format):
  121. if color_format == "rgba":
  122. return "rgba({0}, {1}, {2}, {3})".format(r, g, b, a)
  123. elif color_format == "rgb":
  124. return "rgb({0}, {1}, {2})".format(r, g, b)
  125. else:
  126. # assume hex
  127. return "#{0}{1}{2}".format(convert_to_hex(r), convert_to_hex(g), convert_to_hex(b))
  128. def convert_to_hex(channel_value):
  129. h = hex(channel_value)[2:]
  130. if len(h) < 2:
  131. h = "0" + h
  132. return h
  133. def abs_url(path):
  134. """Deconstructs and Reconstructs a URL into an absolute URL or a URL relative from root '/'"""
  135. if not path:
  136. return
  137. if path.startswith('http://') or path.startswith('https://'):
  138. return path
  139. if not path.startswith("/"):
  140. path = "/" + path
  141. return path
  142. def get_toc(route, url_prefix=None, app=None):
  143. '''Insert full index (table of contents) for {index} tag'''
  144. from frappe.website.utils import get_full_index
  145. full_index = get_full_index(app=app)
  146. return frappe.get_template("templates/includes/full_index.html").render({
  147. "full_index": full_index,
  148. "url_prefix": url_prefix or "/",
  149. "route": route.rstrip('/')
  150. })
  151. def get_next_link(route, url_prefix=None, app=None):
  152. # insert next link
  153. next_item = None
  154. route = route.rstrip('/')
  155. children_map = get_full_index(app=app)
  156. parent_route = os.path.dirname(route)
  157. children = children_map[parent_route]
  158. if parent_route and children:
  159. for i, c in enumerate(children):
  160. if c.route == route and i < (len(children) - 1):
  161. next_item = children[i+1]
  162. next_item.url_prefix = url_prefix or "/"
  163. if next_item:
  164. if next_item.route and next_item.title:
  165. html = ('<p class="btn-next-wrapper">' + frappe._("Next")\
  166. +': <a class="btn-next" href="{url_prefix}{route}">{title}</a></p>').format(**next_item)
  167. return html
  168. return ''
  169. def get_full_index(route=None, app=None):
  170. """Returns full index of the website for www upto the n-th level"""
  171. from frappe.website.router import get_pages
  172. if not frappe.local.flags.children_map:
  173. def _build():
  174. children_map = {}
  175. added = []
  176. pages = get_pages(app=app)
  177. # make children map
  178. for route, page_info in iteritems(pages):
  179. parent_route = os.path.dirname(route)
  180. if parent_route not in added:
  181. children_map.setdefault(parent_route, []).append(page_info)
  182. # order as per index if present
  183. for route, children in children_map.items():
  184. if not route in pages:
  185. # no parent (?)
  186. continue
  187. page_info = pages[route]
  188. if page_info.index or ('index' in page_info.template):
  189. new_children = []
  190. page_info.extn = ''
  191. for name in (page_info.index or []):
  192. child_route = page_info.route + '/' + name
  193. if child_route in pages:
  194. if child_route not in added:
  195. new_children.append(pages[child_route])
  196. added.append(child_route)
  197. # add remaining pages not in index.txt
  198. _children = sorted(children, lambda a, b: cmp(
  199. os.path.basename(a.route), os.path.basename(b.route)))
  200. for child_route in _children:
  201. if child_route not in new_children:
  202. if child_route not in added:
  203. new_children.append(child_route)
  204. added.append(child_route)
  205. children_map[route] = new_children
  206. return children_map
  207. children_map = frappe.cache().get_value('website_full_index', _build)
  208. frappe.local.flags.children_map = children_map
  209. return frappe.local.flags.children_map
  210. def extract_title(source, path):
  211. '''Returns title from `&lt;!-- title --&gt;` or &lt;h1&gt; or path'''
  212. title = ''
  213. if "<!-- title:" in source:
  214. title = re.findall('<!-- title:([^>]*) -->', source)[0].strip()
  215. elif "<h1>" in source:
  216. match = re.findall('<h1>([^<]*)', source)
  217. title = match[0].strip()[:300]
  218. if not title:
  219. title = os.path.basename(path.rsplit('.', )[0].rstrip('/')).replace('_', ' ').replace('-', ' ').title()
  220. return title
  221. def add_missing_headers():
  222. '''Walk and add missing headers in docs (to be called from bench execute)'''
  223. path = frappe.get_app_path('erpnext', 'docs')
  224. for basepath, folders, files in os.walk(path):
  225. for fname in files:
  226. if fname.endswith('.md'):
  227. with open(os.path.join(basepath, fname), 'r') as f:
  228. content = frappe.as_unicode(f.read())
  229. if not content.startswith('# ') and not '<h1>' in content:
  230. with open(os.path.join(basepath, fname), 'w') as f:
  231. if fname=='index.md':
  232. fname = os.path.basename(basepath)
  233. else:
  234. fname = fname[:-3]
  235. h = fname.replace('_', ' ').replace('-', ' ').title()
  236. content = '# {0}\n\n'.format(h) + content
  237. f.write(content.encode('utf-8'))