Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

pirms 8 gadiem
pirms 11 gadiem
pirms 11 gadiem
pirms 11 gadiem
pirms 11 gadiem
pirms 11 gadiem
pirms 11 gadiem
pirms 10 gadiem
pirms 11 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 8 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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'))