@@ -160,7 +160,7 @@ def get_traceback(): | |||
def errprint(msg): | |||
from utils import cstr | |||
if not request: | |||
if not request or (not "cmd" in local.form_dict): | |||
print cstr(msg) | |||
error_log.append(cstr(msg)) | |||
@@ -51,3 +51,4 @@ execute:frappe.db.sql("""update `tabPrint Format` set print_format_type='Client' | |||
frappe.patches.v4_1.file_manager_fix | |||
frappe.patches.v4_2.print_with_letterhead | |||
execute:frappe.delete_doc("DocType", "Control Panel", force=1) | |||
execute:frappe.delete_doc("DocType", "Website Route", force=1) |
@@ -1,3 +1,4 @@ | |||
{% set parents = doc.get_parents() if doc else [] %} | |||
<ul class="breadcrumb"> | |||
{% if parents|length > 0 %} | |||
{% for parent in parents %} | |||
@@ -1,18 +1,10 @@ | |||
<div class="sidebar-exists"></div> | |||
{% set children = doc.get_children() if doc else (get_children() if get_children else []) %} | |||
{% if children -%} | |||
{%- for child in children -%} | |||
<div class="sidebar-item"> | |||
{% set is_parent = parents and child.name == parents[-1].name or (loop.first and child.name==pathname) %} | |||
{% set has_children = (child.lft != None) and (child.rgt - child.lft != 1) and (not loop.first) %} | |||
<i class="{% if has_children %} icon-chevron-right {% endif %} icon-fixed-width" | |||
style="color: #ddd; {% if is_parent %} margin-left: -30px; | |||
{% else %} margin-left: -18px; | |||
{% endif %}"></i> | |||
<a href="{{ child.name }}" class="no-decoration {% if child.name == pathname %}active{% endif %}"> | |||
{{ child.page_title or child.name.replace("_", " ").title() }} | |||
{% if not child.public_read %} | |||
(<i class="icon-fixed-width icon-lock"></i>) | |||
{% endif %} | |||
<a href="{{ child.name }}" class="no-decoration {% if pathname.startswith(child.name) %}active{% endif %}"> | |||
{{ child.title or child.page_title or child.name.replace("_", " ").title() }} | |||
</a> | |||
</div> | |||
{%- endfor -%} | |||
@@ -7,3 +7,8 @@ import frappe | |||
page_title = "Blog" | |||
def get_context(context): | |||
return frappe.get_doc("Blog Settings", "Blog Settings").as_dict() | |||
def get_children(): | |||
return frappe.db.sql("""select concat("blog/", page_name) as name, | |||
title from `tabBlog Category` | |||
where ifnull(published, 0) = 1 order by title asc""", as_dict=1) |
@@ -5,7 +5,6 @@ from __future__ import unicode_literals | |||
import frappe | |||
# frequently used imports (used by other modules) | |||
from frappe.website.permissions import get_access | |||
from frappe.website.doctype.website_settings.website_settings import get_website_settings | |||
from frappe.website.template import render_blocks | |||
@@ -30,7 +29,7 @@ def get_context(path): | |||
context = get_sitemap_options(path) | |||
# permission may be required for rendering | |||
context["access"] = get_access(context.pathname) | |||
context["access"] = frappe._dict({"public_read":1, "public_write":1}) | |||
context = build_context(context) | |||
add_data_path(context) | |||
@@ -39,7 +38,7 @@ def get_context(path): | |||
frappe.cache().set_value(cache_key, context) | |||
else: | |||
context["access"] = get_access(context.pathname) | |||
context["access"] = frappe._dict({"public_read":1, "public_write":1}) | |||
add_data_path(context) | |||
context.update(context.data or {}) | |||
@@ -52,18 +51,19 @@ def build_context(sitemap_options): | |||
context.update(get_website_settings()) | |||
# provide doc | |||
if context.doctype and context.docname: | |||
doc = frappe.get_doc(context.doctype, context.docname) | |||
context.doc = doc | |||
context.update(doc.as_dict()) | |||
if context.doc: | |||
context.update(context.doc.as_dict()) | |||
if hasattr(context.doc, "get_context"): | |||
context.update(context.doc.get_context(context) or {}) | |||
elif context.controller: | |||
module = frappe.get_module(context.controller) | |||
if module and hasattr(module, "get_context"): | |||
context.update(module.get_context(context) or {}) | |||
if module: | |||
if hasattr(module, "get_context"): | |||
context.update(module.get_context(context) or {}) | |||
if hasattr(module, "get_children"): | |||
context.get_children = module.get_children | |||
add_metatags(context) | |||
@@ -1,80 +1,80 @@ | |||
{ | |||
"allow_import": 1, | |||
"autoname": "field:category_name", | |||
"creation": "2013-03-08 09:41:11", | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Master", | |||
"allow_import": 1, | |||
"autoname": "field:category_name", | |||
"creation": "2013-03-08 09:41:11", | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Master", | |||
"fields": [ | |||
{ | |||
"fieldname": "category_name", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Category Name", | |||
"permlevel": 0, | |||
"fieldname": "category_name", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Category Name", | |||
"permlevel": 0, | |||
"reqd": 1 | |||
}, | |||
}, | |||
{ | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Title", | |||
"permlevel": 0, | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Title", | |||
"permlevel": 0, | |||
"reqd": 1 | |||
}, | |||
}, | |||
{ | |||
"fieldname": "published", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Published", | |||
"fieldname": "published", | |||
"fieldtype": "Check", | |||
"in_list_view": 1, | |||
"label": "Published", | |||
"permlevel": 0 | |||
}, | |||
}, | |||
{ | |||
"default": "blog", | |||
"fieldname": "parent_website_route", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Parent Website Route", | |||
"options": "Website Route", | |||
"permlevel": 0, | |||
"default": "blog", | |||
"fieldname": "parent_website_route", | |||
"fieldtype": "Read Only", | |||
"in_list_view": 1, | |||
"label": "Parent Website Route", | |||
"options": "", | |||
"permlevel": 0, | |||
"reqd": 1 | |||
}, | |||
}, | |||
{ | |||
"fieldname": "page_name", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Page Name", | |||
"fieldname": "page_name", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Page Name", | |||
"permlevel": 0 | |||
} | |||
], | |||
"icon": "icon-tag", | |||
"idx": 1, | |||
"modified": "2014-05-27 06:33:22.629900", | |||
"modified_by": "Administrator", | |||
"module": "Website", | |||
"name": "Blog Category", | |||
"owner": "Administrator", | |||
], | |||
"icon": "icon-tag", | |||
"idx": 1, | |||
"modified": "2014-08-18 06:07:54.923616", | |||
"modified_by": "Administrator", | |||
"module": "Website", | |||
"name": "Blog Category", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Website Manager", | |||
"set_user_permissions": 1, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Website Manager", | |||
"set_user_permissions": 1, | |||
"write": 1 | |||
}, | |||
}, | |||
{ | |||
"apply_user_permissions": 1, | |||
"delete": 0, | |||
"email": 1, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"apply_user_permissions": 1, | |||
"delete": 0, | |||
"email": 1, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"role": "Blogger" | |||
} | |||
] | |||
} | |||
} |
@@ -5,22 +5,23 @@ from __future__ import unicode_literals | |||
import frappe | |||
from frappe.website.website_generator import WebsiteGenerator | |||
from frappe.website.render import clear_cache | |||
template = "templates/generators/blog_category.html" | |||
no_cache = True | |||
from frappe.templates.pages.blog import get_children | |||
class BlogCategory(WebsiteGenerator): | |||
page_title_field = "title" | |||
template = "templates/generators/blog_category.html" | |||
no_cache = True | |||
def autoname(self): | |||
# to override autoname of WebsiteGenerator | |||
self.name = self.category_name | |||
def get_page_title(self): | |||
return self.title or self.name | |||
def on_update(self): | |||
WebsiteGenerator.on_update(self) | |||
clear_cache() | |||
def get_parent_website_route(self): | |||
parent_website_sitemap = super(BlogCategory, self).get_parent_website_route() | |||
return parent_website_sitemap or "blog" | |||
def get_children(self): | |||
return get_children() | |||
def validate(self): | |||
self.parent_website_route = "blog" | |||
super(BlogCategory, self).validate() |
@@ -50,10 +50,10 @@ | |||
}, | |||
{ | |||
"fieldname": "parent_website_route", | |||
"fieldtype": "Link", | |||
"fieldtype": "Read Only", | |||
"hidden": 1, | |||
"label": "Parent Website Route", | |||
"options": "Website Route", | |||
"options": "", | |||
"permlevel": 0, | |||
"read_only": 1 | |||
}, | |||
@@ -98,7 +98,7 @@ | |||
"icon": "icon-quote-left", | |||
"idx": 1, | |||
"max_attachments": 5, | |||
"modified": "2014-08-05 04:54:26.723053", | |||
"modified": "2014-08-18 07:08:56.343029", | |||
"modified_by": "Administrator", | |||
"module": "Website", | |||
"name": "Blog Post", | |||
@@ -9,15 +9,14 @@ from frappe.website.website_generator import WebsiteGenerator | |||
from frappe.website.render import clear_cache | |||
from frappe.utils import today, cint, global_date_format, get_fullname | |||
from frappe.website.utils import find_first_image, get_comment_list | |||
order_by = "published_on desc" | |||
condition_field = "published" | |||
template = "templates/generators/blog_post.html" | |||
from frappe.templates.pages.blog import get_children | |||
class BlogPost(WebsiteGenerator): | |||
condition_field = "published" | |||
template = "templates/generators/blog_post.html" | |||
save_versions = True | |||
def get_page_title(self): | |||
return self.title | |||
order_by = "published_on desc" | |||
parent_website_route_field = "blog_category" | |||
def validate(self): | |||
super(BlogPost, self).validate() | |||
@@ -32,12 +31,6 @@ class BlogPost(WebsiteGenerator): | |||
if self.published and not self.published_on: | |||
self.published_on = today() | |||
# make sure route for category exists | |||
self.parent_website_route = self.get_category_route() | |||
if not self.parent_website_route: | |||
frappe.get_doc("Blog Category", self.blog_category).save(ignore_permissions=True) | |||
self.parent_website_route = self.get_category_route() | |||
# update posts | |||
frappe.db.sql("""update tabBlogger set posts=(select count(*) from `tabBlog Post` | |||
where ifnull(blogger,'')=tabBlogger.name) | |||
@@ -81,6 +74,9 @@ class BlogPost(WebsiteGenerator): | |||
return context | |||
def get_children(self): | |||
return get_children() | |||
def clear_blog_cache(): | |||
for blog in frappe.db.sql_list("""select page_name from | |||
`tabBlog Post` where ifnull(published,0)=1"""): | |||
@@ -97,18 +93,18 @@ def get_blog_list(start=0, by=None, category=None): | |||
condition += " and t1.blog_category='%s'" % category.replace("'", "\'") | |||
query = """\ | |||
select | |||
t1.title, t1.name, t3.name as page_name, t1.published_on as creation, | |||
t1.title, t1.name, | |||
concat(t1.parent_website_route, "/", t1.page_name) as page_name, | |||
t1.published_on as creation, | |||
day(t1.published_on) as day, monthname(t1.published_on) as month, | |||
year(t1.published_on) as year, | |||
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, `tabWebsite Route` t3 | |||
from `tabBlog Post` t1, `tabBlogger` t2 | |||
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} | |||
@@ -30,8 +30,16 @@ | |||
"read_only": 0 | |||
}, | |||
{ | |||
"fieldname": "parent_website_route", | |||
"fieldname": "parent_web_page", | |||
"fieldtype": "Link", | |||
"label": "Parent Web Page", | |||
"options": "Web Page", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"fieldname": "parent_website_route", | |||
"fieldtype": "Read Only", | |||
"hidden": 1, | |||
"label": "Parent Website Page", | |||
"options": "Website Route", | |||
"permlevel": 0 | |||
@@ -157,7 +165,7 @@ | |||
"icon": "icon-file-alt", | |||
"idx": 1, | |||
"max_attachments": 20, | |||
"modified": "2014-08-05 04:54:49.018407", | |||
"modified": "2014-08-18 08:10:03.220821", | |||
"modified_by": "Administrator", | |||
"module": "Website", | |||
"name": "Web Page", | |||
@@ -8,11 +8,11 @@ from frappe.website.website_generator import WebsiteGenerator | |||
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow | |||
from frappe.website.utils import find_first_image, get_comment_list | |||
template = "templates/generators/web_page.html" | |||
condition_field = "published" | |||
class WebPage(WebsiteGenerator): | |||
save_versions = True | |||
template = "templates/generators/web_page.html" | |||
condition_field = "published" | |||
def get_context(self, context): | |||
# if static page, get static content | |||
if context.slideshow: | |||
@@ -7,13 +7,10 @@ from frappe.website.website_generator import WebsiteGenerator | |||
from frappe.website.render import can_cache | |||
from frappe.templates.website_group.forum import get_post_list_html | |||
no_cache = True | |||
template = "templates/generators/website_group.html" | |||
class WebsiteGroup(WebsiteGenerator): | |||
def get_page_title(self): | |||
return self.group_title | |||
page_title_field = "name" | |||
no_cache = True | |||
template = "templates/generators/website_group.html" | |||
def on_update(self): | |||
WebsiteGenerator.on_update(self) | |||
clear_cache(website_group=self.name) | |||
@@ -8,8 +8,9 @@ import mimetypes, json | |||
from werkzeug.wrappers import Response | |||
from frappe.website.context import get_context | |||
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache | |||
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache, delete_page_cache | |||
from frappe.website.permissions import clear_permissions | |||
from frappe.website.sitemap import clear_sitemap | |||
class PageNotFoundError(Exception): pass | |||
@@ -165,22 +166,11 @@ def clear_cache(path=None): | |||
if path: | |||
delete_page_cache(path) | |||
for p in frappe.db.sql_list('''select name from | |||
`tabWebsite Route` where name like "{0}/%"'''.format(path.replace('"', '\"'))): | |||
delete_page_cache(p) | |||
else: | |||
for p in frappe.db.sql_list("""select name from `tabWebsite Route`"""): | |||
if p is not None: | |||
delete_page_cache(p) | |||
clear_sitemap() | |||
frappe.clear_cache("Guest") | |||
clear_permissions() | |||
for method in frappe.get_hooks("website_clear_cache"): | |||
frappe.get_attr(method)(path) | |||
def delete_page_cache(path): | |||
cache = frappe.cache() | |||
cache.delete_value("page:" + path) | |||
cache.delete_value("page_context:" + path) | |||
cache.delete_value("sitemap_options:" + path) |
@@ -2,9 +2,10 @@ | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import frappe, os | |||
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache | |||
from frappe.website.utils import can_cache, delete_page_cache | |||
from frappe.model.document import get_controller | |||
def get_sitemap_options(path): | |||
sitemap_options = None | |||
@@ -18,11 +19,12 @@ def get_sitemap_options(path): | |||
if can_cache(sitemap_options.no_cache): | |||
frappe.cache().set_value(cache_key, sitemap_options) | |||
return frappe._dict(sitemap_options) | |||
return sitemap_options | |||
def build_sitemap_options(path): | |||
sitemap_options = frappe._dict(frappe.get_doc("Website Route", path).as_dict()) | |||
home_page = get_home_page() | |||
sitemap_options = resolve_route(path) | |||
if not sitemap_options: | |||
raise frappe.DoesNotExistError | |||
if sitemap_options.controller: | |||
module = frappe.get_module(sitemap_options.controller) | |||
@@ -35,20 +37,7 @@ def build_sitemap_options(path): | |||
sitemap_options.doctype = sitemap_options.ref_doctype | |||
sitemap_options.title = sitemap_options.page_title | |||
sitemap_options.pathname = sitemap_options.name | |||
# establish hierarchy | |||
sitemap_options.parents = frappe.db.sql("""select name, page_title from | |||
`tabWebsite Route` | |||
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: | |||
sitemap_options.children = get_route_children(sitemap_options.pathname, home_page) | |||
if not sitemap_options.children and sitemap_options.parent_website_route \ | |||
and sitemap_options.parent_website_route!=home_page: | |||
sitemap_options.children = get_route_children(sitemap_options.parent_website_route, home_page) | |||
sitemap_options.pathname = path | |||
# determine templates to be used | |||
if not sitemap_options.base_template_path: | |||
@@ -57,43 +46,102 @@ def build_sitemap_options(path): | |||
return sitemap_options | |||
def get_route_children(pathname, home_page=None): | |||
if not home_page: | |||
home_page = get_home_page() | |||
if pathname==home_page or not pathname: | |||
children = frappe.db.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: | |||
children = frappe.db.sql("""select * from `tabWebsite Route` | |||
where ifnull(parent_website_route,'')=%s | |||
and public_read=1 | |||
order by idx, page_title asc""", pathname, as_dict=True) | |||
if children: | |||
# if children are from generator and sort order is specified, then get that condition | |||
module = frappe.get_module(children[0].controller) | |||
if hasattr(module, "order_by"): | |||
children = frappe.db.sql("""select t1.* from | |||
`tabWebsite Route` t1, `tab{ref_doctype}` t2 | |||
where ifnull(t1.parent_website_route,'')=%s | |||
and t1.public_read=1 | |||
and t1.docname = t2.name | |||
order by {order_by}""".format( | |||
ref_doctype = children[0].ref_doctype, | |||
order_by = module.order_by), | |||
pathname, as_dict=True) | |||
children = [frappe.get_doc("Website Route", pathname)] + children | |||
return children | |||
def get_next(route): | |||
siblings = get_route_children(frappe.db.get_value("Website Route", | |||
route, "parent_website_route")) | |||
for i, r in enumerate(siblings): | |||
if i < len(siblings) - 1: | |||
if route==r.name: | |||
return siblings[i+1] | |||
def resolve_route(path): | |||
route = get_page_route(path) | |||
if route: | |||
return route | |||
return get_generator_route(path) | |||
def get_page_route(path): | |||
found = filter(lambda p: p.page_name==path, get_pages()) | |||
return found[0] if found else None | |||
def get_generator_route(path): | |||
def get_route(doctype, condition_field, order_by): | |||
condition = [] | |||
if condition_field: | |||
condition.append("ifnull({0}, 0)=1".format(condition_field)) | |||
meta = frappe.get_meta(doctype) | |||
if meta.get_field("parent_website_route"): | |||
condition.append("""concat(ifnull(parent_website_route, ""), | |||
if(ifnull(parent_website_route, "")="", "", "/"), page_name) = %s""") | |||
else: | |||
condition.append("page_name = %s") | |||
g = frappe.db.sql("""select name from `tab{0}` where {1} | |||
order by {2}""".format(doctype, " and ".join(condition), order_by), path) | |||
if g: | |||
return frappe.get_doc(doctype, g[0][0]).get_website_route() | |||
return process_generators(get_route) | |||
def clear_sitemap(): | |||
for p in get_pages(): | |||
delete_page_cache(p.name) | |||
def clear_generators(doctype, condition_field, order_by): | |||
meta = frappe.get_meta(doctype) | |||
query = "select page_name from `tab{0}`" | |||
if meta.get_field("parent_website_route"): | |||
query = """select concat(ifnull(parent_website_route, ""), | |||
if(ifnull(parent_website_route, "")="", "", "/"), page_name) from `tab{0}`""" | |||
for route in frappe.db.sql_list(query.format(doctype)): | |||
if route: | |||
delete_page_cache(route) | |||
process_generators(clear_generators) | |||
def process_generators(func): | |||
for app in frappe.get_installed_apps(): | |||
for doctype in frappe.get_hooks("website_generators", app_name = app): | |||
order_by = "name asc" | |||
condition_field = None | |||
controller = get_controller(doctype) | |||
if hasattr(controller, "condition_field"): | |||
condition_field = controller.condition_field | |||
if hasattr(controller, "order_by"): | |||
order_by = controller.order_by | |||
val = func(doctype, condition_field, order_by) | |||
if val: | |||
return val | |||
def get_pages(): | |||
pages = frappe.cache().get_value("_website_pages") | |||
if not pages: | |||
pages = [] | |||
for app in frappe.get_installed_apps(): | |||
app_path = frappe.get_app_path(app) | |||
path = os.path.join(app_path, "templates", "pages") | |||
if os.path.exists(path): | |||
for fname in os.listdir(path): | |||
fname = frappe.utils.cstr(fname) | |||
page_name, extn = fname.rsplit(".", 1) | |||
if extn in ("html", "xml", "js", "css"): | |||
route_page_name = page_name if extn=="html" else fname | |||
# add website route | |||
route = frappe._dict() | |||
route.page_or_generator = "Page" | |||
route.template = os.path.relpath(os.path.join(path, fname), app_path) | |||
route.name = route.page_name = route_page_name | |||
route.public_read = 1 | |||
controller_path = os.path.join(path, page_name + ".py") | |||
if os.path.exists(controller_path): | |||
controller = app + "." + os.path.relpath(controller_path, | |||
app_path).replace(os.path.sep, ".")[:-3] | |||
route.controller = controller | |||
try: | |||
route.page_title = frappe.get_attr(controller + "." + "page_title") | |||
except AttributeError: | |||
pass | |||
pages.append(route) | |||
frappe.cache().set_value("_website_pages", pages) | |||
return pages |
@@ -115,7 +115,7 @@ class sync(object): | |||
else: | |||
# Route does not exist, new page | |||
page = self.get_web_page_for_insert(route, fpath, page_name, | |||
priority, parent_website_route) | |||
priority, parent_web_page) | |||
self.to_insert.append(page) | |||
self.synced.append(route) | |||
@@ -149,7 +149,7 @@ class sync(object): | |||
"idx": priority, | |||
"page_name": page_name, | |||
"published": 1, | |||
"parent_website_route": parent_website_route | |||
"parent_web_page": parent_web_page | |||
}) | |||
page.fpath = fpath | |||
@@ -11,126 +11,98 @@ import statics, render | |||
all_routes = None | |||
def sync(app=None, verbose=False): | |||
global all_routes | |||
if app: | |||
apps = [app] | |||
else: | |||
apps = frappe.get_installed_apps() | |||
render.clear_cache() | |||
all_routes = frappe.db.sql_list("select name from `tabWebsite Route`") | |||
# pages | |||
pages = [] | |||
for app in apps: | |||
pages += get_sync_pages(app) | |||
sync_pages(pages) | |||
# sync statics (make generators) | |||
statics_sync = statics.sync(verbose=verbose) | |||
statics_sync.start() | |||
# generators | |||
generators = [] | |||
for app in apps: | |||
generators += get_sync_generators(app) | |||
sync_generators(generators) | |||
# delete remaining routes | |||
for r in all_routes: | |||
frappe.delete_doc("Website Route", r, force=True) | |||
def sync_pages(routes): | |||
global all_routes | |||
l = len(routes) | |||
if l: | |||
for i, r in enumerate(routes): | |||
r.autoname() | |||
if frappe.db.exists("Website Route", r.name): | |||
route = frappe.get_doc("Website Route", r.name) | |||
for key in ("page_title", "controller", "template"): | |||
route.set(key, r.get(key)) | |||
route.save(ignore_permissions=True) | |||
else: | |||
r.insert(ignore_permissions=True) | |||
if r.name in all_routes: | |||
all_routes.remove(r.name) | |||
update_progress_bar("Updating Pages", i, l) | |||
print "" | |||
def sync_generators(generators): | |||
global all_routes | |||
l = len(generators) | |||
if l: | |||
frappe.flags.in_sync_website = True | |||
for i, g in enumerate(generators): | |||
doc = frappe.get_doc(g[0], g[1]) | |||
doc.update_sitemap() | |||
route = doc.get_route() | |||
if route in all_routes: | |||
all_routes.remove(route) | |||
update_progress_bar("Updating Generators", i, l) | |||
sys.stdout.flush() | |||
frappe.flags.in_sync_website = False | |||
rebuild_tree("Website Route", "parent_website_route") | |||
# HACK! update public_read, public_write | |||
for name in frappe.db.sql_list("""select name from `tabWebsite Route` where ifnull(parent_website_route, '')!='' | |||
order by lft"""): | |||
route = frappe.get_doc("Website Route", name) | |||
route.make_private_if_parent_is_private() | |||
route.db_update() | |||
print "" | |||
def get_sync_pages(app): | |||
app_path = frappe.get_app_path(app) | |||
pages = [] | |||
path = os.path.join(app_path, "templates", "pages") | |||
if os.path.exists(path): | |||
for fname in os.listdir(path): | |||
fname = frappe.utils.cstr(fname) | |||
page_name, extn = fname.rsplit(".", 1) | |||
if extn in ("html", "xml", "js", "css"): | |||
route_page_name = page_name if extn=="html" else fname | |||
# add website route | |||
route = frappe.new_doc("Website Route") | |||
route.page_or_generator = "Page" | |||
route.template = os.path.relpath(os.path.join(path, fname), app_path) | |||
route.page_name = route_page_name | |||
route.public_read = 1 | |||
controller_path = os.path.join(path, page_name + ".py") | |||
if os.path.exists(controller_path): | |||
controller = app + "." + os.path.relpath(controller_path, | |||
app_path).replace(os.path.sep, ".")[:-3] | |||
route.controller = controller | |||
try: | |||
route.page_title = frappe.get_attr(controller + "." + "page_title") | |||
except AttributeError: | |||
pass | |||
pages.append(route) | |||
return pages | |||
def get_sync_generators(app): | |||
generators = [] | |||
for doctype in frappe.get_hooks("website_generators", app_name = app): | |||
condition, order_by = "", "name asc" | |||
module = load_doctype_module(doctype) | |||
if hasattr(module, "condition_field"): | |||
condition = " where ifnull({0}, 0)=1 ".format(module.condition_field) | |||
if hasattr(module, "order_by"): | |||
order_by = module.order_by | |||
for name in frappe.db.sql_list("select name from `tab{0}` {1} order by {2}".format(doctype, | |||
condition, order_by)): | |||
generators.append((doctype, name)) | |||
return generators | |||
# def sync_pages(routes): | |||
# global all_routes | |||
# l = len(routes) | |||
# if l: | |||
# for i, r in enumerate(routes): | |||
# r.autoname() | |||
# if frappe.db.exists("Website Route", r.name): | |||
# route = frappe.get_doc("Website Route", r.name) | |||
# for key in ("page_title", "controller", "template"): | |||
# route.set(key, r.get(key)) | |||
# route.save(ignore_permissions=True) | |||
# else: | |||
# r.insert(ignore_permissions=True) | |||
# | |||
# if r.name in all_routes: | |||
# all_routes.remove(r.name) | |||
# update_progress_bar("Updating Pages", i, l) | |||
# | |||
# print "" | |||
# | |||
# def sync_generators(generators): | |||
# global all_routes | |||
# l = len(generators) | |||
# if l: | |||
# frappe.flags.in_sync_website = True | |||
# for i, g in enumerate(generators): | |||
# doc = frappe.get_doc(g[0], g[1]) | |||
# doc.update_sitemap() | |||
# route = doc.get_route() | |||
# if route in all_routes: | |||
# all_routes.remove(route) | |||
# update_progress_bar("Updating Generators", i, l) | |||
# sys.stdout.flush() | |||
# | |||
# frappe.flags.in_sync_website = False | |||
# rebuild_tree("Website Route", "parent_website_route") | |||
# | |||
# # HACK! update public_read, public_write | |||
# for name in frappe.db.sql_list("""select name from `tabWebsite Route` where ifnull(parent_website_route, '')!='' | |||
# order by lft"""): | |||
# route = frappe.get_doc("Website Route", name) | |||
# route.make_private_if_parent_is_private() | |||
# route.db_update() | |||
# | |||
# print "" | |||
# | |||
# def get_sync_pages(app): | |||
# app_path = frappe.get_app_path(app) | |||
# pages = [] | |||
# | |||
# path = os.path.join(app_path, "templates", "pages") | |||
# if os.path.exists(path): | |||
# for fname in os.listdir(path): | |||
# fname = frappe.utils.cstr(fname) | |||
# page_name, extn = fname.rsplit(".", 1) | |||
# if extn in ("html", "xml", "js", "css"): | |||
# route_page_name = page_name if extn=="html" else fname | |||
# | |||
# # add website route | |||
# route = frappe.new_doc("Website Route") | |||
# route.page_or_generator = "Page" | |||
# route.template = os.path.relpath(os.path.join(path, fname), app_path) | |||
# route.page_name = route_page_name | |||
# route.public_read = 1 | |||
# controller_path = os.path.join(path, page_name + ".py") | |||
# | |||
# if os.path.exists(controller_path): | |||
# controller = app + "." + os.path.relpath(controller_path, | |||
# app_path).replace(os.path.sep, ".")[:-3] | |||
# route.controller = controller | |||
# try: | |||
# route.page_title = frappe.get_attr(controller + "." + "page_title") | |||
# except AttributeError: | |||
# pass | |||
# | |||
# pages.append(route) | |||
# | |||
# return pages | |||
# | |||
# def get_sync_generators(app): | |||
# generators = [] | |||
# for doctype in frappe.get_hooks("website_generators", app_name = app): | |||
# condition, order_by = "", "name asc" | |||
# module = load_doctype_module(doctype) | |||
# if hasattr(module, "condition_field"): | |||
# condition = " where ifnull({0}, 0)=1 ".format(module.condition_field) | |||
# if hasattr(module, "order_by"): | |||
# order_by = module.order_by | |||
# for name in frappe.db.sql_list("select name from `tab{0}` {1} order by {2}".format(doctype, | |||
# condition, order_by)): | |||
# generators.append((doctype, name)) | |||
# | |||
# return generators |
@@ -10,8 +10,6 @@ from jinja2.utils import concat | |||
from jinja2 import meta | |||
import re | |||
from sitemap import get_next | |||
def render_blocks(context): | |||
"""returns a dict of block name and its rendered content""" | |||
@@ -66,7 +64,7 @@ def render_blocks(context): | |||
out["content"] = out["content"].replace("{index}", html) | |||
if "{next}" in out.get("content", ""): | |||
next_item = get_next(context["pathname"]) | |||
next_item = context.get_next() | |||
if next_item: | |||
if next_item.name[0]!="/": next_item.name = "/" + next_item.name | |||
html = '''<p><br><a href="{name}" class="btn btn-primary"> | |||
@@ -4,6 +4,14 @@ | |||
from __future__ import unicode_literals | |||
import frappe, re | |||
def delete_page_cache(path): | |||
if not path: | |||
path = "" | |||
cache = frappe.cache() | |||
cache.delete_value("page:" + path) | |||
cache.delete_value("page_context:" + path) | |||
cache.delete_value("sitemap_options:" + path) | |||
def scrub_relative_urls(html): | |||
"""prepend a slash before a relative url""" | |||
html = re.sub("""(src|href)[^\w'"]*['"](?!http|ftp|/|#|%|{)([^'" >]+)['"]""", '\g<1> = "/\g<2>"', html) | |||
@@ -5,13 +5,14 @@ from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
from frappe.model.naming import append_number_if_name_exists | |||
from frappe.website.utils import cleanup_page_name | |||
from frappe.website.utils import cleanup_page_name, get_home_page | |||
from frappe.website.render import clear_cache | |||
from frappe.utils import now | |||
from frappe.modules import get_module_name, load_doctype_module | |||
from frappe.website.doctype.website_route.website_route import remove_sitemap | |||
from frappe.modules import get_module_name | |||
from frappe.website.sitemap import get_page_route | |||
class WebsiteGenerator(Document): | |||
page_title_field = "name" | |||
def autoname(self): | |||
self.name = self.get_page_name() | |||
append_number_if_name_exists(self) | |||
@@ -19,100 +20,95 @@ class WebsiteGenerator(Document): | |||
def onload(self): | |||
self.get("__onload").website_route = self.get_route() | |||
def get_parent_website_route(self): | |||
return self.get("parent_website_route", "") | |||
def validate(self): | |||
if self.is_condition_field_enabled() and self.meta.get_field("page_name") and not self.page_name: | |||
self.set_parent_website_route() | |||
if self.website_published() and self.meta.get_field("page_name") and not self.page_name: | |||
self.page_name = self.get_page_name() | |||
self.update_routes_of_descendants() | |||
def on_update(self): | |||
self.update_sitemap() | |||
clear_cache(self.get_route()) | |||
if getattr(self, "save_versions", False): | |||
frappe.add_version(self) | |||
def get_route(self): | |||
parent = self.get_parent_website_route() | |||
return ((parent + "/") if parent else "") + self.get_page_name() | |||
def get_route(self, doc = None): | |||
if not self.website_published(): | |||
return None | |||
self.get_page_name() | |||
return make_route(self) | |||
def get_page_name(self): | |||
return self.get_or_make_page_name() | |||
def get_or_make_page_name(self): | |||
page_name = self.get("page_name") | |||
if not page_name: | |||
page_name = cleanup_page_name(self.get(self.page_title_field)) | |||
if self.is_new(): | |||
self.set("page_name", page_name) | |||
def get_route_docname(self, name=None): | |||
return frappe.db.get_value("Website Route", | |||
{"ref_doctype":self.doctype, "docname": name or self.name}) | |||
return page_name | |||
def before_rename(self, oldname, name, merge): | |||
self.old_route = self.get_route() | |||
clear_cache(self.get_route()) | |||
def after_rename(self, olddn, newdn, merge): | |||
if self.is_condition_field_enabled(): | |||
self.update_route(self.get_route_docname()) | |||
self.update_routes_of_descendants(self.old_route) | |||
clear_cache(self.get_route()) | |||
def on_trash(self): | |||
remove_sitemap(ref_doctype=self.doctype, docname=self.name) | |||
clear_cache(self.get_route()) | |||
def is_condition_field_enabled(self): | |||
self.controller_module = load_doctype_module(self.doctype) | |||
if hasattr(self.controller_module, "condition_field"): | |||
return self.get(self.controller_module.condition_field) and True or False | |||
def website_published(self): | |||
if hasattr(self, "condition_field"): | |||
return self.get(self.condition_field) and True or False | |||
else: | |||
return True | |||
def update_sitemap(self): | |||
# update route of all descendants | |||
route_docname = self.get_route_docname() | |||
if not self.is_condition_field_enabled(): | |||
frappe.delete_doc("Website Route", route_docname, ignore_permissions=True) | |||
return | |||
if route_docname: | |||
self.update_route(route_docname) | |||
else: | |||
self.insert_route() | |||
def update_route(self, route_docname): | |||
route = frappe.get_doc("Website Route", route_docname) | |||
if self.get_route() != route_docname: | |||
route.rename(self.get_page_name(), self.get_parent_website_route()) | |||
if self.is_changed(route): | |||
route.idx = self.idx | |||
route.page_title = self.get_page_title() | |||
self.update_permissions(route) | |||
route.save(ignore_permissions=True) | |||
else: | |||
route.clear_cache() | |||
def set_parent_website_route(self): | |||
if hasattr(self, "parent_website_route_field"): | |||
field = self.meta.get_field(self.parent_website_route_field) | |||
self.parent_website_route = frappe.get_doc(field.options, | |||
self.get(self.parent_website_route_field)).get_route() | |||
def is_changed(self, route): | |||
if route.idx != self.idx or route.page_title != self.get_page_title(): | |||
return True | |||
if self.meta.get_field("public_read"): | |||
if route.public_read != self.public_read \ | |||
or route.public_write != self.public_write: | |||
return True | |||
def update_routes_of_descendants(self, old_route = None): | |||
if not self.is_new(): | |||
if not old_route: | |||
old_route = frappe.get_doc(self.doctype, self.name).get_route() | |||
return False | |||
if old_route != self.get_route(): | |||
frappe.db.sql("""update `tab{0}` set | |||
parent_website_route = replace(parent_website_route, %s, %s) | |||
where parent_website_route like %s""".format(self.doctype), | |||
(old_route, self.get_route(), old_route + "%")) | |||
def insert_route(self): | |||
def get_website_route(self): | |||
if self.modified: | |||
# for sitemap.xml | |||
lastmod = frappe.utils.get_datetime(self.modified).strftime("%Y-%m-%d") | |||
else: | |||
lastmod = now() | |||
route = frappe.new_doc("Website Route") | |||
route = frappe._dict() | |||
route.update({ | |||
"doc": self, | |||
"page_or_generator": "Generator", | |||
"ref_doctype":self.doctype, | |||
"idx": self.idx, | |||
"docname": self.name, | |||
"page_name": self.get_page_name(), | |||
"controller": get_module_name(self.doctype, self.meta.module), | |||
"template": self.controller_module.template, | |||
"template": self.template, | |||
"lastmod": lastmod, | |||
"parent_website_route": self.get_parent_website_route(), | |||
"page_title": self.get_page_title() | |||
"parent_website_route": self.get("parent_website_route", ""), | |||
"page_title": self.get(self.page_title_field) | |||
}) | |||
self.update_permissions(route) | |||
route.ignore_links = True | |||
route.insert(ignore_permissions=True) | |||
return route | |||
def update_permissions(self, route): | |||
if self.meta.get_field("public_read"): | |||
@@ -121,20 +117,78 @@ class WebsiteGenerator(Document): | |||
else: | |||
route.public_read = 1 | |||
def get_page_name(self): | |||
return self.get_or_make_page_name() | |||
def get_page_name_field(self): | |||
return self.page_name_field if hasattr(self, "page_name_field") else "page_name" | |||
def get_parents(self): | |||
parents = [] | |||
parent = self | |||
while parent: | |||
_parent_field = getattr(parent, "parent_website_route_field", None) | |||
_parent_val = parent.get(_parent_field) if _parent_field else None | |||
if _parent_val: | |||
df = parent.meta.get_field(_parent_field) | |||
parent_doc = frappe.get_doc(df.options, _parent_val) | |||
if not parent_doc.website_published(): | |||
break | |||
if parent_doc: | |||
parent_info = frappe._dict(name = parent_doc.get_route(), | |||
title= parent_doc.get(getattr(parent_doc, "page_title_field", "name"))) | |||
else: | |||
parent_info = frappe._dict(name=self.parent_website_route, | |||
title=self.parent_website_route.replace("_", " ").title()) | |||
if parent_info.name in [p.name for p in parents]: | |||
raise frappe.ValidationError, "Recursion in parent link" | |||
parents.append(parent_info) | |||
parent = parent_doc | |||
else: | |||
# parent route is a page e.g. "blog" | |||
if parent.get("parent_website_route"): | |||
page_route = get_page_route(parent.parent_website_route) | |||
if page_route: | |||
parents.append(frappe._dict(name = page_route.name, | |||
title=page_route.page_title)) | |||
parent = None | |||
parents.reverse() | |||
return parents | |||
def get_children(self): | |||
if self.get_route()==get_home_page(): | |||
return frappe.db.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) | |||
if self.meta.get_field("parent_website_route"): | |||
children = frappe.db.sql("""select name, page_name, | |||
parent_website_route, {title_field} as title from `tab{doctype}` | |||
where ifnull(parent_website_route,'')=%s | |||
order by {order_by}""".format( | |||
doctype = self.doctype, | |||
title_field = getattr(self, "page_title_field", "name"), | |||
order_by = getattr(self, "order_by", "page_name asc")), | |||
self.get_route(), as_dict=True, debug=1) | |||
for c in children: | |||
c.name = make_route(c.name) | |||
else: | |||
return [] | |||
def get_next(self): | |||
if self.meta.get_field("parent_website_route") and self.parent_website_route: | |||
route = self.get_route() | |||
siblings = frappe.get_doc(self.doctype, | |||
self.parent_website_route).get_children() | |||
for i, r in enumerate(siblings): | |||
if i < len(siblings) - 1: | |||
if route==r.name: | |||
return siblings[i+1] | |||
else: | |||
return frappe._dict() | |||
def get_or_make_page_name(self): | |||
page_name = self.get(self.get_page_name_field()) | |||
if not page_name: | |||
page_name = cleanup_page_name(self.get_page_title()) | |||
if self.is_new(): | |||
self.set(self.get_page_name_field(), page_name) | |||
def make_route(doc): | |||
parent = doc.get("parent_website_route", "") | |||
return ((parent + "/") if parent else "") + doc.page_name | |||
return page_name | |||
def get_page_title(self): | |||
return self.get("title") or (self.name.replace("-", " ").replace("_", " ").title()) |