diff --git a/webnotes/__init__.py b/webnotes/__init__.py index b18ba60829..e6a3e54408 100644 --- a/webnotes/__init__.py +++ b/webnotes/__init__.py @@ -588,7 +588,7 @@ def get_jloader(): def set_filters(jenv): from webnotes.utils import global_date_format - from webnotes.webutils import get_hex_shade + from webnotes.website.utils import get_hex_shade from markdown2 import markdown from json import dumps diff --git a/webnotes/app.py b/webnotes/app.py index ca1a355077..0a8be9bcd4 100644 --- a/webnotes/app.py +++ b/webnotes/app.py @@ -15,7 +15,7 @@ import webnotes import webnotes.handler import webnotes.auth import webnotes.api -import webnotes.webutils +import webnotes.website.render from webnotes.utils import get_site_name local_manager = LocalManager([webnotes.local]) @@ -58,7 +58,7 @@ def application(request): elif webnotes.request.path.startswith("/api/"): webnotes.api.handle() elif webnotes.local.request.method in ('GET', 'HEAD'): - webnotes.webutils.render(webnotes.request.path[1:]) + webnotes.website.render.render(webnotes.request.path[1:]) else: raise NotFound diff --git a/webnotes/boot.py b/webnotes/boot.py index 10779c7ee4..d0e3e9b769 100644 --- a/webnotes/boot.py +++ b/webnotes/boot.py @@ -11,7 +11,6 @@ import webnotes.defaults import webnotes.model.doc import webnotes.widgets.page import json -import webnotes.webutils def get_bootinfo(): """build and return boot info""" diff --git a/webnotes/cli.py b/webnotes/cli.py index a2c2fb9f43..b0c2e5e99e 100755 --- a/webnotes/cli.py +++ b/webnotes/cli.py @@ -430,9 +430,9 @@ def clear_cache(): @cmd def clear_web(): - import webnotes.webutils + import webnotes.website.render webnotes.connect() - webnotes.webutils.clear_cache() + webnotes.website.render.clear_cache() webnotes.destroy() @cmd diff --git a/webnotes/core/doctype/communication/communication.py b/webnotes/core/doctype/communication/communication.py index 80a6c20207..c033f6d43d 100644 --- a/webnotes/core/doctype/communication/communication.py +++ b/webnotes/core/doctype/communication/communication.py @@ -6,7 +6,7 @@ import webnotes import json import urllib from email.utils import formataddr -from webnotes.webutils import is_signup_enabled +from webnotes.website.utils import is_signup_enabled from webnotes.utils import get_url, cstr from webnotes.utils.email_lib.email_body import get_email from webnotes.utils.email_lib.smtp import send diff --git a/webnotes/templates/base.html b/webnotes/templates/base.html index c64588a451..71a52c3cb1 100644 --- a/webnotes/templates/base.html +++ b/webnotes/templates/base.html @@ -29,6 +29,11 @@ {%- endblock %} + {% block script -%} + + {%- endblock %} {%- endblock %} @@ -80,10 +85,5 @@ - {% block script -%} - - {%- endblock %} \ No newline at end of file diff --git a/webnotes/templates/generators/blog_category.html b/webnotes/templates/generators/blog_category.html index ee562e4750..e8736adc07 100644 --- a/webnotes/templates/generators/blog_category.html +++ b/webnotes/templates/generators/blog_category.html @@ -5,7 +5,5 @@ {% block header %}

{{ title }}

{% endblock %} {% block script %} -$(function() { - window.category = "{{ docname }}"; -}); +window.category = "{{ docname }}"; {% endblock %} \ No newline at end of file diff --git a/webnotes/templates/generators/blog_post.py b/webnotes/templates/generators/blog_post.py index 8d0fe2e554..1e6d168045 100644 --- a/webnotes/templates/generators/blog_post.py +++ b/webnotes/templates/generators/blog_post.py @@ -46,14 +46,16 @@ def get_blog_list(start=0, by=None, category=None): condition += " and t1.blog_category='%s'" % category.replace("'", "\'") query = """\ select - t1.title, t1.name, t1.page_name, t1.published_on as creation, + t1.title, t1.name, t3.name as page_name, t1.published_on as creation, ifnull(t1.blog_intro, t1.content) as content, t2.full_name, t2.avatar, t1.blogger, (select count(name) from `tabComment` where comment_doctype='Blog Post' and comment_docname=t1.name) as comments - from `tabBlog Post` t1, `tabBlogger` t2 + from `tabBlog Post` t1, `tabBlogger` t2, `tabWebsite Sitemap` t3 where ifnull(t1.published,0)=1 and t1.blogger = t2.name + and t3.docname = t1.name + and t3.ref_doctype = "Blog Post" %(condition)s order by published_on desc, name asc limit %(start)s, 20""" % {"start": start, "condition": condition} @@ -63,8 +65,6 @@ def get_blog_list(start=0, by=None, category=None): # strip html tags from content for res in result: res['published'] = global_date_format(res['creation']) - if not res['content']: - res['content'] = webnotes.webutils.get_html(res['page_name']) res['content'] = res['content'][:140] return result diff --git a/webnotes/templates/generators/website_group.py b/webnotes/templates/generators/website_group.py index da3e2f3261..7eb8f334b9 100644 --- a/webnotes/templates/generators/website_group.py +++ b/webnotes/templates/generators/website_group.py @@ -2,7 +2,8 @@ # MIT License. See license.txt import webnotes -from webnotes.webutils import get_access, can_cache +from webnotes.website.permissions import get_access +from webnotes.website.render import can_cache from webnotes.templates.website_group.forum import get_post_list_html doctype = "Website Group" diff --git a/webnotes/templates/includes/blog.js b/webnotes/templates/includes/blog.js index 898dacdc40..9ad5c4a652 100644 --- a/webnotes/templates/includes/blog.js +++ b/webnotes/templates/includes/blog.js @@ -36,7 +36,9 @@ var blog = { b.comment_text = b.comments + ' comments.' } - b.page_name = encodeURIComponent(b.page_name); + b.page_name = $.map(b.page_name.split("/"), function(p) + { return encodeURIComponent(p); }).join("/"); + b.avatar = b.avatar || ""; $(repl('
\ @@ -71,7 +73,7 @@ var blog = { $(document).ready(function() { // make list of blogs - blog.get_list(); + setTimeout(blog.get_list, 100); $("#next-page").click(function() { blog.get_list(); diff --git a/webnotes/templates/includes/comments.py b/webnotes/templates/includes/comments.py index 00a47afe9e..59f7232e6d 100644 --- a/webnotes/templates/includes/comments.py +++ b/webnotes/templates/includes/comments.py @@ -3,6 +3,7 @@ import webnotes import webnotes.utils, markdown2 +from webnotes.website.render import clear_cache from webnotes import _ @@ -34,7 +35,7 @@ def add_comment(args=None): comment.insert() # since comments are embedded in the page, clear the web cache - webnotes.webutils.clear_cache(page_name) + clear_cache(page_name) # notify commentors commentors = [d[0] for d in webnotes.conn.sql("""select comment_by from tabComment where diff --git a/webnotes/templates/pages/sitemap.py b/webnotes/templates/pages/sitemap.py index 3ee637c833..349cb70ec6 100644 --- a/webnotes/templates/pages/sitemap.py +++ b/webnotes/templates/pages/sitemap.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import urllib import webnotes -import webnotes.webutils from webnotes.utils import get_request_site_address no_cache = 1 diff --git a/webnotes/templates/website_group/forum.py b/webnotes/templates/website_group/forum.py index 8e7c6d330a..5a1169541d 100644 --- a/webnotes/templates/website_group/forum.py +++ b/webnotes/templates/website_group/forum.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import now_datetime, get_datetime_str -from webnotes.webutils import get_access +from webnotes.website.permissions import get_access @webnotes.whitelist(allow_guest=True) def get_post_list_html(group, view, limit_start=0, limit_length=20): diff --git a/webnotes/templates/website_group/post.py b/webnotes/templates/website_group/post.py index 564353d0a2..56d4bc4ce7 100644 --- a/webnotes/templates/website_group/post.py +++ b/webnotes/templates/website_group/post.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import get_fullname -from webnotes.webutils import get_access +from webnotes.website.permissions import get_access from webnotes.utils.file_manager import save_file from webnotes.templates.generators.website_group import get_pathname diff --git a/webnotes/templates/website_group/settings.py b/webnotes/templates/website_group/settings.py index 20b9d7b50d..5b40b083c1 100644 --- a/webnotes/templates/website_group/settings.py +++ b/webnotes/templates/website_group/settings.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.webutils import get_access, clear_permissions +from webnotes.website.permissions import get_access, clear_permissions from webnotes.templates.generators.website_group import get_pathname from webnotes.utils.email_lib.bulk import send diff --git a/webnotes/utils/response.py b/webnotes/utils/response.py index 75f4bb2c0b..19156e4cb7 100644 --- a/webnotes/utils/response.py +++ b/webnotes/utils/response.py @@ -30,7 +30,7 @@ def build_response(): def print_page(): """print web page""" - from webnotes.webutils import render + from webnotes.website.render import render render(webnotes.response['page_name']) def print_json(): diff --git a/webnotes/website/README.md b/webnotes/website/README.md deleted file mode 100644 index 8ad39038f4..0000000000 --- a/webnotes/website/README.md +++ /dev/null @@ -1,8 +0,0 @@ -Module for website management. - -Contains: - -- DocTypes for Web Page, Blogs -- Templates -- Settings -- Generators for Item, Blog Post, Item Group \ No newline at end of file diff --git a/webnotes/website/context.py b/webnotes/website/context.py new file mode 100644 index 0000000000..59764571bf --- /dev/null +++ b/webnotes/website/context.py @@ -0,0 +1,64 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes + +# frequently used imports (used by other modules) +from webnotes.website.permissions import get_access + +from webnotes.website.doctype.website_settings.website_settings import get_website_settings +from webnotes.website.template import render_blocks +from webnotes.website.sitemap import get_sitemap_options +from webnotes.website.utils import can_cache + +def get_context(path): + context = None + cache_key = "page_context:{}".format(path) + + # try from memcache + if can_cache(): + context = webnotes.cache().get_value(cache_key) + + if not context: + context = get_sitemap_options(path) + + # permission may be required for rendering + context["access"] = get_access(context.pathname) + + context = build_context(context) + + if can_cache(context.no_cache): + webnotes.cache().set_value(cache_key, context) + + else: + context["access"] = get_access(context.pathname) + + context.update(context.data or {}) + + # TODO private pages + + return context + +def build_context(sitemap_options): + """get_context method of bean or module is supposed to render content templates and push it into context""" + context = webnotes._dict(sitemap_options) + context.update(get_website_settings()) + + # provide bean + if context.doctype and context.docname: + context.bean = webnotes.bean(context.doctype, context.docname) + + if context.controller: + module = webnotes.get_module(context.controller) + if module and hasattr(module, "get_context"): + context.update(module.get_context(context) or {}) + + if context.get("base_template_path") != context.get("template_path") and not context.get("rendered"): + context.data = render_blocks(context) + + # remove bean, as it is not pickle friendly and its purpose is over + if context.bean: + del context["bean"] + + return context diff --git a/webnotes/website/doctype/about_us_settings/about_us_settings.py b/webnotes/website/doctype/about_us_settings/about_us_settings.py index 81eb5186a4..a9ba8b3355 100644 --- a/webnotes/website/doctype/about_us_settings/about_us_settings.py +++ b/webnotes/website/doctype/about_us_settings/about_us_settings.py @@ -11,7 +11,7 @@ class DocType: self.doc, self.doclist = d, dl def on_update(self): - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache("about") def get_args(): diff --git a/webnotes/website/doctype/blog_category/blog_category.py b/webnotes/website/doctype/blog_category/blog_category.py index fc6000ea0f..a917ad3a30 100644 --- a/webnotes/website/doctype/blog_category/blog_category.py +++ b/webnotes/website/doctype/blog_category/blog_category.py @@ -3,7 +3,8 @@ from __future__ import unicode_literals import webnotes -from webnotes.webutils import WebsiteGenerator, cleanup_page_name, clear_cache +from webnotes.website.website_generator import WebsiteGenerator +from webnotes.website.render import clear_cache class DocType(WebsiteGenerator): def __init__(self, d, dl): @@ -18,7 +19,4 @@ class DocType(WebsiteGenerator): def on_update(self): WebsiteGenerator.on_update(self) - - from webnotes.webutils import clear_cache clear_cache() - \ No newline at end of file diff --git a/webnotes/website/doctype/blog_post/blog_post.py b/webnotes/website/doctype/blog_post/blog_post.py index 3cc1816bb0..0f38b6414a 100644 --- a/webnotes/website/doctype/blog_post/blog_post.py +++ b/webnotes/website/doctype/blog_post/blog_post.py @@ -4,16 +4,21 @@ from __future__ import unicode_literals import webnotes -from webnotes.webutils import WebsiteGenerator, cleanup_page_name, clear_cache + +from webnotes.website.website_generator import WebsiteGenerator +from webnotes.website.render import clear_cache from webnotes import _ from webnotes.utils import today class DocType(WebsiteGenerator): def __init__(self, d, dl): self.doc, self.doclist = d, dl - - def autoname(self): - self.doc.name = cleanup_page_name(self.doc.title) + + def get_page_title(self): + return self.doc.title + + def get_parent_website_sitemap(self): + return webnotes.conn.get_value("Website Sitemap", {"ref_doctype": "Blog Category", "docname": self.doc.blog_category}) def validate(self): if self.doc.blog_intro: diff --git a/webnotes/website/doctype/blog_settings/blog_settings.py b/webnotes/website/doctype/blog_settings/blog_settings.py index 22a3b5e6ac..d861efea93 100644 --- a/webnotes/website/doctype/blog_settings/blog_settings.py +++ b/webnotes/website/doctype/blog_settings/blog_settings.py @@ -11,6 +11,6 @@ class DocType: self.doc, self.doclist = d, dl def on_update(self): - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache("blog") clear_cache("writers") \ No newline at end of file diff --git a/webnotes/website/doctype/contact_us_settings/contact_us_settings.py b/webnotes/website/doctype/contact_us_settings/contact_us_settings.py index 14b4a850f0..717e8f92b1 100644 --- a/webnotes/website/doctype/contact_us_settings/contact_us_settings.py +++ b/webnotes/website/doctype/contact_us_settings/contact_us_settings.py @@ -11,5 +11,5 @@ class DocType: self.doc, self.doclist = d, dl def on_update(self): - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache("contact") \ No newline at end of file diff --git a/webnotes/website/doctype/style_settings/style_settings.py b/webnotes/website/doctype/style_settings/style_settings.py index 014341f102..460c42b6e7 100644 --- a/webnotes/website/doctype/style_settings/style_settings.py +++ b/webnotes/website/doctype/style_settings/style_settings.py @@ -31,5 +31,5 @@ class DocType: from webnotes.sessions import clear_cache clear_cache('Guest') - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache() diff --git a/webnotes/website/doctype/user_vote/user_vote.py b/webnotes/website/doctype/user_vote/user_vote.py index fc35fa18dd..911973c13e 100644 --- a/webnotes/website/doctype/user_vote/user_vote.py +++ b/webnotes/website/doctype/user_vote/user_vote.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.webutils import get_access +from webnotes.website.permissions import get_access class DocType: def __init__(self, d, dl): diff --git a/webnotes/website/doctype/web_page/web_page.py b/webnotes/website/doctype/web_page/web_page.py index 68105b507d..92b5d1c068 100644 --- a/webnotes/website/doctype/web_page/web_page.py +++ b/webnotes/website/doctype/web_page/web_page.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes, os, time -from webnotes.webutils import WebsiteGenerator +from webnotes.website.website_generator import WebsiteGenerator from webnotes import _ from webnotes.utils import cint from markdown2 import markdown @@ -21,7 +21,7 @@ class DocType(WebsiteGenerator): # clear all cache if it has toc if self.doclist.get({"parentfield": "toc"}): - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache() def on_trash(self): @@ -33,7 +33,7 @@ class DocType(WebsiteGenerator): # clear all cache if it has toc if self.doclist.get({"parentfield": "toc"}): - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache() def sync_statics(): diff --git a/webnotes/website/doctype/website_group/website_group.py b/webnotes/website/doctype/website_group/website_group.py index 0b04c64fb5..9ca6737149 100644 --- a/webnotes/website/doctype/website_group/website_group.py +++ b/webnotes/website/doctype/website_group/website_group.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.webutils import WebsiteGenerator +from webnotes.website.website_generator import WebsiteGenerator from webnotes.templates.generators.website_group import clear_cache from webnotes.model.doc import make_autoname diff --git a/webnotes/website/doctype/website_script/website_script.py b/webnotes/website/doctype/website_script/website_script.py index dff9225dcd..2403749fd0 100644 --- a/webnotes/website/doctype/website_script/website_script.py +++ b/webnotes/website/doctype/website_script/website_script.py @@ -15,5 +15,5 @@ class DocType: from webnotes.sessions import clear_cache clear_cache('Guest') - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache() \ No newline at end of file diff --git a/webnotes/website/doctype/website_settings/website_settings.py b/webnotes/website/doctype/website_settings/website_settings.py index 20bb77b7fd..45f558ba16 100644 --- a/webnotes/website/doctype/website_settings/website_settings.py +++ b/webnotes/website/doctype/website_settings/website_settings.py @@ -4,7 +4,9 @@ from __future__ import unicode_literals import webnotes from webnotes import _, msgprint +from webnotes.utils import get_request_site_address, encode from webnotes.model.controller import DocListController +from urllib import quote class DocType(DocListController): def validate(self): @@ -43,6 +45,62 @@ class DocType(DocListController): # make js and css # clear web cache (for menus!) - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache() - \ No newline at end of file + +def get_website_settings(): + hooks = webnotes.get_hooks() + + all_top_items = webnotes.conn.sql("""\ + select * from `tabTop Bar Item` + where parent='Website Settings' and parentfield='top_bar_items' + order by idx asc""", as_dict=1) + + top_items = [d for d in all_top_items if not d['parent_label']] + + # attach child items to top bar + for d in all_top_items: + if d['parent_label']: + for t in top_items: + if t['label']==d['parent_label']: + if not 'child_items' in t: + t['child_items'] = [] + t['child_items'].append(d) + break + + context = webnotes._dict({ + 'top_bar_items': top_items, + 'footer_items': webnotes.conn.sql("""\ + select * from `tabTop Bar Item` + where parent='Website Settings' and parentfield='footer_items' + order by idx asc""", as_dict=1), + "post_login": [ + {"label": "Reset Password", "url": "update-password", "icon": "icon-key"}, + {"label": "Logout", "url": "?cmd=web_logout", "icon": "icon-signout"} + ] + }) + + settings = webnotes.doc("Website Settings", "Website Settings") + for k in ["banner_html", "brand_html", "copyright", "twitter_share_via", + "favicon", "facebook_share", "google_plus_one", "twitter_share", "linked_in_share", + "disable_signup"]: + if k in settings.fields: + context[k] = settings.fields.get(k) + + if settings.address: + context["footer_address"] = settings.address + + for k in ["facebook_share", "google_plus_one", "twitter_share", "linked_in_share", + "disable_signup"]: + context[k] = int(context.get(k) or 0) + + context.url = quote(str(get_request_site_address(full_address=True)), safe="/:") + context.encoded_title = quote(encode(context.title or ""), str("")) + + for update_website_context in hooks.update_website_context or []: + webnotes.get_attr(update_website_context)(context) + + context.web_include_js = hooks.web_include_js or [] + context.web_include_css = hooks.web_include_css or [] + + return context diff --git a/webnotes/website/doctype/website_sitemap/website_sitemap.py b/webnotes/website/doctype/website_sitemap/website_sitemap.py index 9a7d55cf34..b334f88f6d 100644 --- a/webnotes/website/doctype/website_sitemap/website_sitemap.py +++ b/webnotes/website/doctype/website_sitemap/website_sitemap.py @@ -1,8 +1,6 @@ # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt -# For license information, please see license.txt - from __future__ import unicode_literals import webnotes from webnotes import _ @@ -20,12 +18,16 @@ class DocType(DocTypeNestedSet): self.doc.name = self.get_url() def get_url(self): + parent_website_sitemap = self.get_parent_website_sitemap() url = self.doc.page_name - if self.doc.parent_website_sitemap: - url = self.doc.parent_website_sitemap + "/" + url + if parent_website_sitemap: + url = parent_website_sitemap + "/" + url return url - + + def get_parent_website_sitemap(self): + return self.doc.parent_website_sitemap + def validate(self): if self.get_url() != self.doc.name: self.rename() @@ -33,7 +35,7 @@ class DocType(DocTypeNestedSet): self.make_private_if_parent_is_private() def rename(self): - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache self.old_name = self.doc.name self.doc.name = self.get_url() webnotes.conn.sql("""update `tabWebsite Sitemap` set name=%s where name=%s""", @@ -86,7 +88,7 @@ class DocType(DocTypeNestedSet): self.doc.public_read = self.doc.public_write = 0 def on_trash(self): - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache # remove website sitemap permissions to_remove = webnotes.conn.sql_list("""select name from `tabWebsite Sitemap Permission` where website_sitemap=%s""", (self.doc.name,)) diff --git a/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.py b/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.py index 88ec0d604f..10c0ee863f 100644 --- a/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.py +++ b/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import webnotes import webnotes.utils import os - +from webnotes import _ from webnotes.website.doctype.website_sitemap.website_sitemap import add_to_sitemap, update_sitemap, cleanup_sitemap from webnotes.utils.nestedset import rebuild_tree @@ -95,6 +95,7 @@ def add_website_sitemap_config(page_or_generator, app, path, fname, basepath): wsc.page_name_field = getattr(module, "page_name_field", "page_name") wsc.condition_field = getattr(module, "condition_field", None) wsc.base_template_path = getattr(module, "base_template_path", None) + wsc.page_title = getattr(module, "page_title", _(name.title())) if webnotes.conn.exists("Website Sitemap Config", wsc.link_name): # found by earlier app, override diff --git a/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.txt b/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.txt index b604200b2f..74e913755c 100644 --- a/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.txt +++ b/webnotes/website/doctype/website_sitemap_config/website_sitemap_config.txt @@ -2,7 +2,7 @@ { "creation": "2013-11-18 15:35:00", "docstatus": 0, - "modified": "2014-02-13 15:48:16", + "modified": "2014-02-14 12:48:54", "modified_by": "Administrator", "owner": "Administrator" }, @@ -62,6 +62,12 @@ "label": "Link Name", "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "page_title", + "fieldtype": "Data", + "label": "Page Title" + }, { "doctype": "DocField", "fieldname": "base_template_path", diff --git a/webnotes/website/doctype/website_sitemap_permission/website_sitemap_permission.py b/webnotes/website/doctype/website_sitemap_permission/website_sitemap_permission.py index 299f82fcea..d83a50ab74 100644 --- a/webnotes/website/doctype/website_sitemap_permission/website_sitemap_permission.py +++ b/webnotes/website/doctype/website_sitemap_permission/website_sitemap_permission.py @@ -4,6 +4,8 @@ from __future__ import unicode_literals import webnotes +from webnotes.website.permissions import remove_empty_permissions, clear_permissions + class DocType: def __init__(self, d, dl): self.doc, self.doclist = d, dl @@ -12,68 +14,3 @@ class DocType: remove_empty_permissions() clear_permissions(self.doc.profile) -def remove_empty_permissions(): - permissions_cache_to_be_cleared = webnotes.conn.sql_list("""select distinct profile - from `tabWebsite Sitemap Permission` - where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") - - webnotes.conn.sql("""delete from `tabWebsite Sitemap Permission` - where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") - - clear_permissions(permissions_cache_to_be_cleared) - -def get_access(sitemap_page, profile=None): - profile = profile or webnotes.session.user - key = "website_sitemap_permissions:{}".format(profile) - - cache = webnotes.cache() - permissions = cache.get_value(key) or {} - if not permissions.get(sitemap_page): - permissions[sitemap_page] = _get_access(sitemap_page, profile) - cache.set_value(key, permissions) - - return permissions.get(sitemap_page) - -def _get_access(sitemap_page, profile): - lft, rgt, public_read, public_write = webnotes.conn.get_value("Website Sitemap", sitemap_page, - ["lft", "rgt", "public_read", "public_write"]) - - if not (lft and rgt): - raise webnotes.ValidationError("Please rebuild Website Sitemap Tree") - - if profile == "Guest": - return { "read": public_read, "write": 0, "admin": 0 } - - read = write = admin = private_read = 0 - - if public_write: - read = write = 1 - elif public_read: - read = 1 - - for perm in webnotes.conn.sql("""select wsp.`read`, wsp.`write`, wsp.`admin`, - ws.lft, ws.rgt, ws.name - from `tabWebsite Sitemap Permission` wsp, `tabWebsite Sitemap` ws - where wsp.profile = %s and wsp.website_sitemap = ws.name - order by lft asc""", (profile,), as_dict=True): - if perm.lft <= lft and perm.rgt >= rgt: - if not (public_read or private_read): private_read = perm.read - if not read: read = perm.read - if not write: write = perm.write - if not admin: admin = perm.admin - if write: read = write - - if read and write and admin: - break - - return { "read": read, "write": write, "admin": admin, "private_read": private_read } - -def clear_permissions(profiles=None): - if isinstance(profiles, basestring): - profiles = [profiles] - elif profiles is None: - profiles = webnotes.conn.sql_list("""select name from `tabProfile`""") - - cache = webnotes.cache() - for profile in profiles: - cache.delete_value("website_sitemap_permissions:{}".format(profile)) diff --git a/webnotes/website/doctype/website_slideshow/website_slideshow.py b/webnotes/website/doctype/website_slideshow/website_slideshow.py index d02bce5f86..ca9e945bd4 100644 --- a/webnotes/website/doctype/website_slideshow/website_slideshow.py +++ b/webnotes/website/doctype/website_slideshow/website_slideshow.py @@ -12,7 +12,7 @@ class DocType: def on_update(self): # a slide show can be in use and any change in it should get reflected - from webnotes.webutils import clear_cache + from webnotes.website.render import clear_cache clear_cache() def get_slideshow(bean): diff --git a/webnotes/website/permissions.py b/webnotes/website/permissions.py new file mode 100644 index 0000000000..5b4ed954ea --- /dev/null +++ b/webnotes/website/permissions.py @@ -0,0 +1,72 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes + + +def remove_empty_permissions(): + permissions_cache_to_be_cleared = webnotes.conn.sql_list("""select distinct profile + from `tabWebsite Sitemap Permission` + where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") + + webnotes.conn.sql("""delete from `tabWebsite Sitemap Permission` + where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") + + clear_permissions(permissions_cache_to_be_cleared) + +def get_access(sitemap_page, profile=None): + profile = profile or webnotes.session.user + key = "website_sitemap_permissions:{}".format(profile) + + cache = webnotes.cache() + permissions = cache.get_value(key) or {} + if not permissions.get(sitemap_page): + permissions[sitemap_page] = _get_access(sitemap_page, profile) + cache.set_value(key, permissions) + + return permissions.get(sitemap_page) + +def _get_access(sitemap_page, profile): + lft, rgt, public_read, public_write = webnotes.conn.get_value("Website Sitemap", sitemap_page, + ["lft", "rgt", "public_read", "public_write"]) + + if not (lft and rgt): + raise webnotes.ValidationError("Please rebuild Website Sitemap Tree") + + if profile == "Guest": + return { "read": public_read, "write": 0, "admin": 0 } + + read = write = admin = private_read = 0 + + if public_write: + read = write = 1 + elif public_read: + read = 1 + + for perm in webnotes.conn.sql("""select wsp.`read`, wsp.`write`, wsp.`admin`, + ws.lft, ws.rgt, ws.name + from `tabWebsite Sitemap Permission` wsp, `tabWebsite Sitemap` ws + where wsp.profile = %s and wsp.website_sitemap = ws.name + order by lft asc""", (profile,), as_dict=True): + if perm.lft <= lft and perm.rgt >= rgt: + if not (public_read or private_read): private_read = perm.read + if not read: read = perm.read + if not write: write = perm.write + if not admin: admin = perm.admin + if write: read = write + + if read and write and admin: + break + + return { "read": read, "write": write, "admin": admin, "private_read": private_read } + +def clear_permissions(profiles=None): + if isinstance(profiles, basestring): + profiles = [profiles] + elif profiles is None: + profiles = webnotes.conn.sql_list("""select name from `tabProfile`""") + + cache = webnotes.cache() + for profile in profiles: + cache.delete_value("website_sitemap_permissions:{}".format(profile)) diff --git a/webnotes/website/render.py b/webnotes/website/render.py new file mode 100644 index 0000000000..0a763ebdb0 --- /dev/null +++ b/webnotes/website/render.py @@ -0,0 +1,128 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes +import mimetypes, json + +from webnotes.website.context import get_context +from webnotes.website.utils import scrub_relative_urls, get_home_page, can_cache + +from webnotes.website.permissions import get_access, clear_permissions + +class PageNotFoundError(Exception): pass + +def render(path): + """render html page""" + path = resolve_path(path) + + try: + data = render_page(path) + except Exception: + path = "error" + data = render_page(path) + + data = set_content_type(data, path) + webnotes._response.data = data + webnotes._response.headers[b"Page Name"] = path.encode("utf-8") + +def render_page(path): + """get page html""" + cache_key = ("page_context:{}" if is_ajax() else "page:{}").format(path) + + out = None + + # try memcache + if can_cache(): + out = webnotes.cache().get_value(cache_key) + if out and is_ajax(): + out = out.get("data") + + if out: + if hasattr(webnotes, "_response"): + webnotes._response.headers[b"From Cache"] = True + + return out + + return build(path) + +def build(path): + if not webnotes.conn: + webnotes.connect() + + build_method = (build_json if is_ajax() else build_page) + try: + return build_method(path) + + except webnotes.DoesNotExistError: + hooks = webnotes.get_hooks() + if hooks.website_catch_all: + return build_method(hooks.website_catch_all[0]) + else: + return build_method("404") + +def build_json(path): + return get_context(path).data + +def build_page(path): + context = get_context(path) + + html = webnotes.get_template(context.base_template_path).render(context) + html = scrub_relative_urls(html) + + if can_cache(context.no_cache): + webnotes.cache().set_value("page:" + path, html) + + return html + +def is_ajax(): + return webnotes.get_request_header("X-Requested-With")=="XMLHttpRequest" + +def resolve_path(path): + if not path: + path = "index" + + if path.endswith('.html'): + path = path[:-5] + + if path == "index": + path = get_home_page() + + return path + +def set_content_type(data, path): + if isinstance(data, dict): + webnotes._response.headers[b"Content-Type"] = b"application/json; charset: utf-8" + data = json.dumps(data) + return data + + webnotes._response.headers[b"Content-Type"] = b"text/html; charset: utf-8" + + if "." in path and not path.endswith(".html"): + content_type, encoding = mimetypes.guess_type(path) + webnotes._response.headers[b"Content-Type"] = content_type.encode("utf-8") + + return data + +def clear_cache(path=None): + cache = webnotes.cache() + + if path: + delete_page_cache(path) + + else: + for p in webnotes.conn.sql_list("""select name from `tabWebsite Sitemap`"""): + if p is not None: + delete_page_cache(p) + + cache.delete_value("home_page") + clear_permissions() + + for method in webnotes.get_hooks("website_clear_cache"): + webnotes.get_attr(method)(path) + +def delete_page_cache(path): + cache = webnotes.cache() + cache.delete_value("page:" + path) + cache.delete_value("page_context:" + path) + cache.delete_value("sitemap_options:" + path) diff --git a/webnotes/website/sitemap.py b/webnotes/website/sitemap.py new file mode 100644 index 0000000000..102fd09409 --- /dev/null +++ b/webnotes/website/sitemap.py @@ -0,0 +1,61 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes + +from webnotes.website.utils import scrub_relative_urls, get_home_page, can_cache + +def get_sitemap_options(path): + sitemap_options = None + cache_key = "sitemap_options:{}".format(path) + + if can_cache(): + sitemap_options = webnotes.cache().get_value(cache_key) + + if not sitemap_options: + sitemap_options = build_sitemap_options(path) + if can_cache(sitemap_options.no_cache): + webnotes.cache().set_value(cache_key, sitemap_options) + + return webnotes._dict(sitemap_options) + +def build_sitemap_options(path): + sitemap_options = webnotes.doc("Website Sitemap", path).fields + home_page = get_home_page() + + sitemap_config = webnotes.doc("Website Sitemap Config", + sitemap_options.get("website_sitemap_config")).fields + + # get sitemap config fields too + for fieldname in ("base_template_path", "template_path", "controller", "no_cache", "no_sitemap", + "page_name_field", "condition_field"): + sitemap_options[fieldname] = sitemap_config.get(fieldname) + + sitemap_options.doctype = sitemap_options.ref_doctype + sitemap_options.title = sitemap_options.page_title + sitemap_options.pathname = sitemap_options.name + + def set_sidebar_items(pathname): + if pathname==home_page or not pathname: + sitemap_options.children = webnotes.conn.sql("""select url as name, label as page_title, + 1 as public_read from `tabTop Bar Item` where parentfield='sidebar_items' order by idx""", as_dict=True) + else: + sitemap_options.children = webnotes.conn.sql("""select * from `tabWebsite Sitemap` + where ifnull(parent_website_sitemap,'')=%s + and public_read=1 order by -idx desc, page_title asc""", pathname, as_dict=True) + + # establish hierarchy + sitemap_options.parents = webnotes.conn.sql("""select name, page_title from `tabWebsite Sitemap` + where lft < %s and rgt > %s order by lft asc""", (sitemap_options.lft, sitemap_options.rgt), as_dict=True) + + if not sitemap_options.no_sidebar: + set_sidebar_items(sitemap_options.pathname) + if not sitemap_options.children: + set_sidebar_items(sitemap_options.parent_website_sitemap) + + # determine templates to be used + if not sitemap_options.base_template_path: + sitemap_options.base_template_path = "templates/base.html" + + return sitemap_options diff --git a/webnotes/website/template.py b/webnotes/website/template.py new file mode 100644 index 0000000000..3bc21fded5 --- /dev/null +++ b/webnotes/website/template.py @@ -0,0 +1,48 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes + +from webnotes.website.utils import scrub_relative_urls +from jinja2.utils import concat +from jinja2 import meta + +def render_blocks(context): + """returns a dict of block name and its rendered content""" + + out = {} + + env = webnotes.get_jenv() + + def _render_blocks(template_path): + source = webnotes.local.jloader.get_source(webnotes.local.jenv, template_path)[0] + for referenced_template_path in meta.find_referenced_templates(env.parse(source)): + if referenced_template_path: + _render_blocks(referenced_template_path) + + template = webnotes.get_template(template_path) + for block, render in template.blocks.items(): + out[block] = scrub_relative_urls(concat(render(template.new_context(context)))) + + _render_blocks(context["template_path"]) + + # default blocks if not found + if "title" not in out: + out["title"] = context.get("title") + + if "header" not in out: + out["header"] = out["title"] + + if not out["header"].startswith("" + + if "breadcrumbs" not in out: + out["breadcrumbs"] = scrub_relative_urls( + webnotes.get_template("templates/includes/breadcrumbs.html").render(context)) + + if "sidebar" not in out: + out["sidebar"] = scrub_relative_urls( + webnotes.get_template("templates/includes/sidebar.html").render(context)) + + return out diff --git a/webnotes/website/utils.py b/webnotes/website/utils.py new file mode 100644 index 0000000000..ffa37f4006 --- /dev/null +++ b/webnotes/website/utils.py @@ -0,0 +1,67 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes, re + +def scrub_relative_urls(html): + """prepend a slash before a relative url""" + return re.sub("""(src|href)[^\w'"]*['"](?!http|ftp|/|#)([^'" >]+)['"]""", '\g<1> = "/\g<2>"', html) + +def can_cache(no_cache=False): + return not (webnotes.conf.disable_website_cache or no_cache) + +def get_home_page(): + home_page = webnotes.cache().get_value("home_page", \ + lambda: (webnotes.get_hooks("home_page") \ + or [webnotes.conn.get_value("Website Settings", None, "home_page") \ + or "login"])[0]) + + return home_page + +def is_signup_enabled(): + if getattr(webnotes.local, "is_signup_enabled", None) is None: + webnotes.local.is_signup_enabled = True + if webnotes.utils.cint(webnotes.conn.get_value("Website Settings", + "Website Settings", "disable_signup")): + webnotes.local.is_signup_enabled = False + + return webnotes.local.is_signup_enabled + +def cleanup_page_name(title): + """make page name from title""" + name = title.lower() + name = re.sub('[~!@#$%^&*+()<>,."\'\?]', '', name) + name = re.sub('[:/]', '-', name) + + name = '-'.join(name.split()) + + # replace repeating hyphens + name = re.sub(r"(-)\1+", r"\1", name) + + return name + +def get_hex_shade(color, percent): + def p(c): + v = int(c, 16) + int(int('ff', 16) * (float(percent)/100)) + if v < 0: + v=0 + if v > 255: + v=255 + h = hex(v)[2:] + if len(h) < 2: + h = "0" + h + return h + + r, g, b = color[0:2], color[2:4], color[4:6] + + avg = (float(int(r, 16) + int(g, 16) + int(b, 16)) / 3) + # switch dark and light shades + if avg > 128: + percent = -percent + + # stronger diff for darker shades + if percent < 25 and avg < 64: + percent = percent * 2 + + return p(r) + p(g) + p(b) diff --git a/webnotes/website/website_generator.py b/webnotes/website/website_generator.py new file mode 100644 index 0000000000..7095a2f9e0 --- /dev/null +++ b/webnotes/website/website_generator.py @@ -0,0 +1,99 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes.model.controller import DocListController + +from webnotes.website.doctype.website_sitemap.website_sitemap import add_to_sitemap, update_sitemap, remove_sitemap + +class WebsiteGenerator(DocListController): + def autoname(self): + from webnotes.website.utils import cleanup_page_name + self.doc.name = cleanup_page_name(self.get_page_title()) + + def set_page_name(self): + """set page name based on parent page_name and title""" + page_name = cleanup_page_name(self.get_page_title()) + + if self.doc.is_new(): + self.doc.fields[self._website_config.page_name_field] = page_name + else: + webnotes.conn.set(self.doc, self._website_config.page_name_field, page_name) + + def get_parent_website_sitemap(self): + return self.doc.parent_website_sitemap + + def setup_generator(self): + self._website_config = webnotes.conn.get_values("Website Sitemap Config", + {"ref_doctype": self.doc.doctype}, "*")[0] + + def on_update(self): + self.update_sitemap() + + def after_rename(self, olddn, newdn, merge): + webnotes.conn.sql("""update `tabWebsite Sitemap` + set docname=%s where ref_doctype=%s and docname=%s""", (newdn, self.doc.doctype, olddn)) + + if merge: + self.setup_generator() + remove_sitemap(ref_doctype=self.doc.doctype, docname=olddn) + + def on_trash(self): + self.setup_generator() + remove_sitemap(ref_doctype=self.doc.doctype, docname=self.doc.name) + + def update_sitemap(self): + self.setup_generator() + + if self._website_config.condition_field and \ + not self.doc.fields.get(self._website_config.condition_field): + # condition field failed, remove and return! + remove_sitemap(ref_doctype=self.doc.doctype, docname=self.doc.name) + return + + self.add_or_update_sitemap() + + def add_or_update_sitemap(self): + page_name = self.get_page_name() + + existing_site_map = webnotes.conn.get_value("Website Sitemap", {"ref_doctype": self.doc.doctype, + "docname": self.doc.name}) + + opts = webnotes._dict({ + "page_or_generator": "Generator", + "ref_doctype":self.doc.doctype, + "docname": self.doc.name, + "page_name": page_name, + "link_name": self._website_config.name, + "lastmod": webnotes.utils.get_datetime(self.doc.modified).strftime("%Y-%m-%d"), + "parent_website_sitemap": self.get_parent_website_sitemap(), + "page_title": self.get_page_title(), + "public_read": 1 if not self._website_config.no_sidebar else 0 + }) + + self.update_permissions(opts) + + if existing_site_map: + update_sitemap(existing_site_map, opts) + else: + add_to_sitemap(opts) + + def update_permissions(self, opts): + if self.meta.get_field("public_read"): + opts.public_read = self.doc.public_read + opts.public_write = self.doc.public_write + else: + opts.public_read = 1 + + def get_page_name(self): + if not self._get_page_name(): + self.set_page_name() + + return self._get_page_name() + + def _get_page_name(self): + return self.doc.fields.get(self._website_config.page_name_field) + + def get_page_title(self): + return self.doc.title or (self.doc.name.replace("-", " ").replace("_", " ").title()) diff --git a/webnotes/webutils.py b/webnotes/webutils.py deleted file mode 100644 index 910472454d..0000000000 --- a/webnotes/webutils.py +++ /dev/null @@ -1,496 +0,0 @@ -# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors -# MIT License. See license.txt - -from __future__ import unicode_literals -import webnotes -import json, os, time, re -from webnotes import _ -import webnotes.utils -from webnotes.utils import get_request_site_address, encode, cint -from webnotes.model import default_fields -from webnotes.model.controller import DocListController -from urllib import quote - -import mimetypes -from webnotes.website.doctype.website_sitemap.website_sitemap import add_to_sitemap, update_sitemap, remove_sitemap - -# frequently used imports (used by other modules) -from webnotes.website.doctype.website_sitemap_permission.website_sitemap_permission \ - import get_access, clear_permissions - -class PageNotFoundError(Exception): pass - -def render(path): - """render html page""" - path = resolve_path(path) - - try: - data = render_page(path) - except Exception: - path = "error" - data = render_page(path) - - data = set_content_type(data, path) - webnotes._response.data = data - webnotes._response.headers[b"Page Name"] = path.encode("utf-8") - -def render_page(path): - """get page html""" - cache_key = ("page_context:{}" if is_ajax() else "page:{}").format(path) - - out = None - - # try memcache - if can_cache(): - out = webnotes.cache().get_value(cache_key) - if out and is_ajax(): - out = out.get("data") - - if out: - if hasattr(webnotes, "_response"): - webnotes._response.headers[b"From Cache"] = True - - return out - - return build(path) - -def build(path): - if not webnotes.conn: - webnotes.connect() - - build_method = (build_json if is_ajax() else build_page) - try: - return build_method(path) - - except webnotes.DoesNotExistError: - hooks = webnotes.get_hooks() - if hooks.website_catch_all: - return build_method(hooks.website_catch_all[0]) - else: - return build_method("404") - -def build_json(path): - return get_context(path).data - -def build_page(path): - context = get_context(path) - - html = webnotes.get_template(context.base_template_path).render(context) - html = scrub_relative_urls(html) - - if can_cache(context.no_cache): - webnotes.cache().set_value("page:" + path, html) - - return html - -def get_context(path): - context = None - cache_key = "page_context:{}".format(path) - from pickle import dump - from StringIO import StringIO - - # try from memcache - if can_cache(): - context = webnotes.cache().get_value(cache_key) - - if not context: - context = get_sitemap_options(path) - - # permission may be required for rendering - context["access"] = get_access(context.pathname) - - context = build_context(context) - - if can_cache(context.no_cache): - webnotes.cache().set_value(cache_key, context) - - else: - context["access"] = get_access(context.pathname) - - context.update(context.data or {}) - - # TODO private pages - - return context - -def get_sitemap_options(path): - sitemap_options = None - cache_key = "sitemap_options:{}".format(path) - - if can_cache(): - sitemap_options = webnotes.cache().get_value(cache_key) - - if not sitemap_options: - sitemap_options = build_sitemap_options(path) - if can_cache(sitemap_options.no_cache): - webnotes.cache().set_value(cache_key, sitemap_options) - - return webnotes._dict(sitemap_options) - -def build_sitemap_options(path): - sitemap_options = webnotes.doc("Website Sitemap", path).fields - home_page = get_home_page() - - sitemap_config = webnotes.doc("Website Sitemap Config", - sitemap_options.get("website_sitemap_config")).fields - - # get sitemap config fields too - for fieldname in ("base_template_path", "template_path", "controller", "no_cache", "no_sitemap", - "page_name_field", "condition_field"): - sitemap_options[fieldname] = sitemap_config.get(fieldname) - - sitemap_options.doctype = sitemap_options.ref_doctype - sitemap_options.title = sitemap_options.page_title - sitemap_options.pathname = sitemap_options.name - - def set_sidebar_items(pathname): - if pathname==home_page or not pathname: - sitemap_options.children = webnotes.conn.sql("""select url as name, label as page_title, - 1 as public_read from `tabTop Bar Item` where parentfield='sidebar_items' order by idx""", as_dict=True) - else: - sitemap_options.children = webnotes.conn.sql("""select * from `tabWebsite Sitemap` - where ifnull(parent_website_sitemap,'')=%s - and public_read=1 order by -idx desc, page_title asc""", pathname, as_dict=True) - - # establish hierarchy - sitemap_options.parents = webnotes.conn.sql("""select name, page_title from `tabWebsite Sitemap` - where lft < %s and rgt > %s order by lft asc""", (sitemap_options.lft, sitemap_options.rgt), as_dict=True) - - if not sitemap_options.no_sidebar: - set_sidebar_items(sitemap_options.pathname) - if not sitemap_options.children: - set_sidebar_items(sitemap_options.parent_website_sitemap) - - # determine templates to be used - if not sitemap_options.base_template_path: - sitemap_options.base_template_path = "templates/base.html" - - return sitemap_options - -def build_context(sitemap_options): - """get_context method of bean or module is supposed to render content templates and push it into context""" - context = webnotes._dict(sitemap_options) - context.update(get_website_settings()) - - # provide bean - if context.doctype and context.docname: - context.bean = webnotes.bean(context.doctype, context.docname) - - if context.controller: - module = webnotes.get_module(context.controller) - if module and hasattr(module, "get_context"): - context.update(module.get_context(context) or {}) - - if context.get("base_template_path") != context.get("template_path") and not context.get("rendered"): - context.data = render_blocks(context) - - # remove bean, as it is not pickle friendly and its purpose is over - if context.bean: - del context["bean"] - - return context - -def can_cache(no_cache=False): - return not (webnotes.conf.disable_website_cache or no_cache) - -def get_home_page(): - home_page = webnotes.cache().get_value("home_page", \ - lambda: (webnotes.get_hooks("home_page") \ - or [webnotes.conn.get_value("Website Settings", None, "home_page") \ - or "login"])[0]) - - return home_page - -def get_website_settings(): - # TODO Cache this - hooks = webnotes.get_hooks() - - all_top_items = webnotes.conn.sql("""\ - select * from `tabTop Bar Item` - where parent='Website Settings' and parentfield='top_bar_items' - order by idx asc""", as_dict=1) - - top_items = [d for d in all_top_items if not d['parent_label']] - - # attach child items to top bar - for d in all_top_items: - if d['parent_label']: - for t in top_items: - if t['label']==d['parent_label']: - if not 'child_items' in t: - t['child_items'] = [] - t['child_items'].append(d) - break - - context = webnotes._dict({ - 'top_bar_items': top_items, - 'footer_items': webnotes.conn.sql("""\ - select * from `tabTop Bar Item` - where parent='Website Settings' and parentfield='footer_items' - order by idx asc""", as_dict=1), - "post_login": [ - {"label": "Reset Password", "url": "update-password", "icon": "icon-key"}, - {"label": "Logout", "url": "?cmd=web_logout", "icon": "icon-signout"} - ] - }) - - settings = webnotes.doc("Website Settings", "Website Settings") - for k in ["banner_html", "brand_html", "copyright", "twitter_share_via", - "favicon", "facebook_share", "google_plus_one", "twitter_share", "linked_in_share", - "disable_signup"]: - if k in settings.fields: - context[k] = settings.fields.get(k) - - if settings.address: - context["footer_address"] = settings.address - - for k in ["facebook_share", "google_plus_one", "twitter_share", "linked_in_share", - "disable_signup"]: - context[k] = cint(context.get(k) or 0) - - context.url = quote(str(get_request_site_address(full_address=True)), safe="/:") - context.encoded_title = quote(encode(context.title or ""), str("")) - - for update_website_context in hooks.update_website_context or []: - webnotes.get_attr(update_website_context)(context) - - context.web_include_js = hooks.web_include_js or [] - context.web_include_css = hooks.web_include_css or [] - - return context - -def is_ajax(): - return webnotes.get_request_header("X-Requested-With")=="XMLHttpRequest" - -def resolve_path(path): - if not path: - path = "index" - - if path.endswith('.html'): - path = path[:-5] - - if path == "index": - path = get_home_page() - - return path - -def set_content_type(data, path): - if isinstance(data, dict): - webnotes._response.headers[b"Content-Type"] = b"application/json; charset: utf-8" - data = json.dumps(data) - return data - - webnotes._response.headers[b"Content-Type"] = b"text/html; charset: utf-8" - - if "." in path and not path.endswith(".html"): - content_type, encoding = mimetypes.guess_type(path) - webnotes._response.headers[b"Content-Type"] = content_type.encode("utf-8") - - return data - -def clear_cache(path=None): - cache = webnotes.cache() - - if path: - delete_page_cache(path) - - else: - for p in webnotes.conn.sql_list("""select name from `tabWebsite Sitemap`"""): - if p is not None: - delete_page_cache(p) - - cache.delete_value("home_page") - clear_permissions() - - for method in webnotes.get_hooks("website_clear_cache"): - webnotes.get_attr(method)(path) - -def delete_page_cache(path): - cache = webnotes.cache() - cache.delete_value("page:" + path) - cache.delete_value("page_context:" + path) - cache.delete_value("sitemap_options:" + path) - -def is_signup_enabled(): - if getattr(webnotes.local, "is_signup_enabled", None) is None: - webnotes.local.is_signup_enabled = True - if webnotes.utils.cint(webnotes.conn.get_value("Website Settings", - "Website Settings", "disable_signup")): - webnotes.local.is_signup_enabled = False - - return webnotes.local.is_signup_enabled - -def call_website_generator(bean, method, *args, **kwargs): - getattr(WebsiteGenerator(bean.doc, bean.doclist), method)(*args, **kwargs) - -class WebsiteGenerator(DocListController): - def autoname(self): - from webnotes.webutils import cleanup_page_name - self.doc.name = cleanup_page_name(self.get_page_title()) - - def set_page_name(self): - """set page name based on parent page_name and title""" - page_name = cleanup_page_name(self.get_page_title()) - - if self.doc.is_new(): - self.doc.fields[self._website_config.page_name_field] = page_name - else: - webnotes.conn.set(self.doc, self._website_config.page_name_field, page_name) - - def setup_generator(self): - self._website_config = webnotes.conn.get_values("Website Sitemap Config", - {"ref_doctype": self.doc.doctype}, "*")[0] - - def on_update(self): - self.update_sitemap() - - def after_rename(self, olddn, newdn, merge): - webnotes.conn.sql("""update `tabWebsite Sitemap` - set docname=%s where ref_doctype=%s and docname=%s""", (newdn, self.doc.doctype, olddn)) - - if merge: - self.setup_generator() - remove_sitemap(ref_doctype=self.doc.doctype, docname=olddn) - - def on_trash(self): - self.setup_generator() - remove_sitemap(ref_doctype=self.doc.doctype, docname=self.doc.name) - - def update_sitemap(self): - self.setup_generator() - - if self._website_config.condition_field and \ - not self.doc.fields.get(self._website_config.condition_field): - # condition field failed, remove and return! - remove_sitemap(ref_doctype=self.doc.doctype, docname=self.doc.name) - return - - self.add_or_update_sitemap() - - def add_or_update_sitemap(self): - page_name = self.get_page_name() - - existing_site_map = webnotes.conn.get_value("Website Sitemap", {"ref_doctype": self.doc.doctype, - "docname": self.doc.name}) - - opts = webnotes._dict({ - "page_or_generator": "Generator", - "ref_doctype":self.doc.doctype, - "docname": self.doc.name, - "page_name": page_name, - "link_name": self._website_config.name, - "lastmod": webnotes.utils.get_datetime(self.doc.modified).strftime("%Y-%m-%d"), - "parent_website_sitemap": self.doc.parent_website_sitemap, - "page_title": self.get_page_title(), - "public_read": 1 if not self._website_config.no_sidebar else 0 - }) - - self.update_permissions(opts) - - if existing_site_map: - update_sitemap(existing_site_map, opts) - else: - add_to_sitemap(opts) - - def update_permissions(self, opts): - if self.meta.get_field("public_read"): - opts.public_read = self.doc.public_read - opts.public_write = self.doc.public_write - else: - opts.public_read = 1 - - def get_page_name(self): - if not self._get_page_name(): - self.set_page_name() - - return self._get_page_name() - - def _get_page_name(self): - return self.doc.fields.get(self._website_config.page_name_field) - - def get_page_title(self): - return self.doc.title or (self.doc.name.replace("-", " ").replace("_", " ").title()) - -def cleanup_page_name(title): - """make page name from title""" - import re - name = title.lower() - name = re.sub('[~!@#$%^&*+()<>,."\'\?]', '', name) - name = re.sub('[:/]', '-', name) - - name = '-'.join(name.split()) - - # replace repeating hyphens - name = re.sub(r"(-)\1+", r"\1", name) - - return name - -def get_hex_shade(color, percent): - def p(c): - v = int(c, 16) + int(int('ff', 16) * (float(percent)/100)) - if v < 0: - v=0 - if v > 255: - v=255 - h = hex(v)[2:] - if len(h) < 2: - h = "0" + h - return h - - r, g, b = color[0:2], color[2:4], color[4:6] - - avg = (float(int(r, 16) + int(g, 16) + int(b, 16)) / 3) - # switch dark and light shades - if avg > 128: - percent = -percent - - # stronger diff for darker shades - if percent < 25 and avg < 64: - percent = percent * 2 - - return p(r) + p(g) + p(b) - -def render_blocks(context): - """returns a dict of block name and its rendered content""" - from jinja2.utils import concat - from jinja2 import meta - - out = {} - - env = webnotes.get_jenv() - - def _render_blocks(template_path): - source = webnotes.local.jloader.get_source(webnotes.local.jenv, template_path)[0] - for referenced_template_path in meta.find_referenced_templates(env.parse(source)): - if referenced_template_path: - _render_blocks(referenced_template_path) - - template = webnotes.get_template(template_path) - for block, render in template.blocks.items(): - out[block] = scrub_relative_urls(concat(render(template.new_context(context)))) - - _render_blocks(context["template_path"]) - - # default blocks if not found - if "title" not in out: - out["title"] = context.get("title") - - if "header" not in out: - out["header"] = out["title"] - - if not out["header"].startswith("" - - if "breadcrumbs" not in out: - out["breadcrumbs"] = scrub_relative_urls( - webnotes.get_template("templates/includes/breadcrumbs.html").render(context)) - - if "sidebar" not in out: - out["sidebar"] = scrub_relative_urls( - webnotes.get_template("templates/includes/sidebar.html").render(context)) - - return out - -def scrub_relative_urls(html): - """prepend a slash before a relative url""" - return re.sub("""(src|href)[^\w'"]*['"](?!http|ftp|/|#)([^'" >]+)['"]""", '\g<1> = "/\g<2>"', html)