Related to (#421): Fixed base template Blog, Blog Post, Login, App pages Started with porting Unit Template to Website Group Templateversion-14
@@ -199,7 +199,7 @@ def throw(msg, exc=ValidationError): | |||
def create_folder(path): | |||
if not os.path.exists(path): os.makedirs(path) | |||
def connect(site=None, db_name=None): | |||
from db import Database | |||
if site: | |||
@@ -546,13 +546,14 @@ def get_jenv(): | |||
return jenv | |||
def set_filters(jenv): | |||
from webnotes.utils import global_date_format | |||
from webnotes.utils import global_date_format, scrub_relative_url | |||
from markdown2 import markdown | |||
from json import dumps | |||
jenv.filters["global_date_format"] = global_date_format | |||
jenv.filters["markdown"] = markdown | |||
jenv.filters["json"] = dumps | |||
jenv.filters["scrub_relative_url"] = scrub_relative_url | |||
# load jenv_filters from hooks.txt | |||
for app in get_all_apps(True): | |||
@@ -171,7 +171,7 @@ def print_json(): | |||
make_logs() | |||
cleanup_docs() | |||
webnotes._response.headers["Content-Type"] = "text/json; charset: utf-8" | |||
webnotes._response.headers["Content-Type"] = "application/json; charset: utf-8" | |||
import json | |||
@@ -8,11 +8,16 @@ app_color = #3498db | |||
after_install = webnotes.utils.install.after_install | |||
# website | |||
app_include_js = assets/js/webnotes.min.js | |||
app_include_css = assets/webnotes/css/splash.css | |||
app_include_css = assets/css/webnotes.css | |||
web_include_js = assets/js/webnotes-web.min.js | |||
web_include_css = assets/css/webnotes-web.css | |||
website_group_views:Forum = webnotes.templates.website_group.forum.get_views | |||
website_group_views:Events = webnotes.templates.website_group.events.get_views | |||
website_group_views:Tasks = webnotes.templates.website_group.tasks.get_views | |||
get_desktop_icons = webnotes.manage.get_desktop_icons | |||
notification_config = webnotes.core.notifications.get_notification_config | |||
@@ -26,7 +31,7 @@ on_session_creation = webnotes.auth.notify_administrator_login | |||
# permissions | |||
permission_query_conditions:Event = webnotes.core.doctype.event.event.get_permission_query_conditions | |||
has_permission:Event = webnotes.core.doctype.event.event.has_permission | |||
has_permission:Event = webnotes.core.doctype.event.event.has_permission | |||
permission_query_conditions:ToDo = webnotes.core.doctype.todo.todo.get_permission_query_conditions | |||
has_permission:ToDo = webnotes.core.doctype.todo.todo.has_permission | |||
has_permission:ToDo = webnotes.core.doctype.todo.todo.has_permission |
@@ -6,37 +6,51 @@ | |||
<title>{{ title }}</title> | |||
<meta name="generator" content="wnframework"> | |||
<script type="text/javascript" src="/assets/webnotes/js/lib/jquery/jquery.min.js"></script> | |||
<link rel="shortcut icon" href="{{ favicon }}" type="image/x-icon"> | |||
<link rel="icon" href="{{ favicon }}" type="image/x-icon"> | |||
{% block head %} | |||
{% if meta_description -%} | |||
<meta name="description" content="{{ meta_description }}">{%- endif %} | |||
{% for link in web_include_js -%} | |||
<link rel="shortcut icon" href="{{ favicon | scrub_relative_url }}" type="image/x-icon"> | |||
<link rel="icon" href="{{ favicon | scrub_relative_url }}" type="image/x-icon"> | |||
{%- block head -%} | |||
{%- if meta_description -%} | |||
<meta name="description" content="{{ meta_description }}"> | |||
{%- endif -%} | |||
{%- for link in web_include_js -%} | |||
<script type="text/javascript" src="/{{ link }}"></script> | |||
{%- endfor %} | |||
{% for link in web_include_css -%} | |||
{%- endfor -%} | |||
{%- for link in web_include_css -%} | |||
<link type="text/css" rel="stylesheet" href="/{{ link }}"> | |||
{%- endfor %} | |||
{% endblock %} | |||
{% block javascript -%} | |||
{% if javascript %}<script>{{ javascript }}</script>{% endif %} | |||
{%- endblock %} | |||
{% block css -%} | |||
{% if css %}<style>{{ css }}</style>{% endif %} | |||
{%- endblock %} | |||
{% block style -%}{%- endblock %} | |||
{%- endfor -%} | |||
{%- endblock -%} | |||
{%- block javascript -%} | |||
{%- if javascript -%} | |||
<script>{{ javascript }}</script> | |||
{%- endif -%} | |||
{%- endblock -%} | |||
{%- block css -%} | |||
{%- if css -%} | |||
<style>{{ css }}</style> | |||
{%- endif -%} | |||
{%- endblock -%} | |||
{%- block style -%}{%- endblock -%} | |||
</head> | |||
<body> | |||
{% block banner %} | |||
{% if banner_html -%} | |||
<header class="container">{{ banner_html or "" }}</header> | |||
{%- endif %} | |||
{% endblock %} | |||
{% block navbar %}{% include "templates/includes/navbar.html" %}{% endblock %} | |||
<div class="page-container" id="page-{{ name }}"> | |||
{% block content %}{% endblock %} | |||
{%- block banner -%} | |||
{% if banner_html -%} | |||
<header class="container">{{ banner_html or "" }}</header> | |||
{%- endif %} | |||
{%- endblock -%} | |||
{%- block navbar -%}{% include "templates/includes/navbar.html" %}{%- endblock -%} | |||
<div class="page-container" id="page-{{ name or page_name }}"> | |||
{%- block content -%}{{ content }}{%- endblock -%} | |||
</div> | |||
{% block footer %}{% include "templates/includes/footer.html" %}{% endblock %} | |||
{% block script -%}{%- endblock %} | |||
{%- block footer -%}{% include "templates/includes/footer.html" %}{%- endblock -%} | |||
</body> | |||
</html> |
@@ -1,5 +1,3 @@ | |||
{% extends base_template %} | |||
{% block content %} | |||
<div class="container content" itemscope itemtype="http://schema.org/BlogPost"> | |||
<h2 itemprop="name headline">{{ title }}</h2> | |||
@@ -1,2 +1,71 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import markdown2 | |||
import webnotes | |||
from webnotes.utils import global_date_format, get_fullname, cint | |||
doctype = "Blog Post" | |||
condition_field = "published" | |||
condition_field = "published" | |||
def get_context(context): | |||
blog_post = webnotes.doc(context.ref_doctype, context.docname) | |||
# this is for double precaution. usually it wont reach this code if not published | |||
if not cint(blog_post.published): | |||
raise Exception, "This blog has not been published yet!" | |||
# temp fields | |||
blog_post.full_name = get_fullname(blog_post.owner) | |||
blog_post.updated = global_date_format(blog_post.published_on) | |||
if blog_post.blogger: | |||
blog_post.blogger_info = webnotes.doc("Blogger", blog_post.blogger).fields | |||
blog_post.description = blog_post.blog_intro or blog_post.content[:140] | |||
blog_post.meta_description = blog_post.description | |||
blog_post.categories = webnotes.conn.sql_list("select name from `tabBlog Category` order by name") | |||
blog_post.comment_list = webnotes.conn.sql("""\ | |||
select comment, comment_by_fullname, creation | |||
from `tabComment` where comment_doctype="Blog Post" | |||
and comment_docname=%s order by creation""", (blog_post.name,), as_dict=1) or [] | |||
blog_post.fields.update(context) | |||
return { "title": blog_post.title, "content": context.template.render(blog_post.fields) } | |||
@webnotes.whitelist(allow_guest=True) | |||
def get_blog_list(start=0, by=None, category=None): | |||
condition = "" | |||
if by: | |||
condition = " and t1.blogger='%s'" % by.replace("'", "\'") | |||
if category: | |||
condition += " and t1.blog_category='%s'" % category.replace("'", "\'") | |||
query = """\ | |||
select | |||
t1.title, t1.name, t1.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 | |||
where ifnull(t1.published,0)=1 | |||
and t1.blogger = t2.name | |||
%(condition)s | |||
order by published_on desc, name asc | |||
limit %(start)s, 20""" % {"start": start, "condition": condition} | |||
result = webnotes.conn.sql(query, as_dict=1) | |||
# 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 |
@@ -1,4 +1,15 @@ | |||
{% extends base_template %} | |||
{% block content %} | |||
{{ content }} | |||
{%- if access -%} | |||
<script> | |||
$(function() { | |||
wn.provide("wn"); | |||
wn.access = {{ access|json }}; | |||
}) | |||
</script> | |||
{%- endif -%} | |||
{% endblock %} |
@@ -1 +1,105 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
import webnotes | |||
from webnotes.webutils import get_access | |||
doctype = "Website Group" | |||
no_cache = 1 | |||
def get_context(controller, page_options): | |||
group, view = guess_group_view(controller, page_options) | |||
try: | |||
if not has_access(group, view): | |||
raise webnotes.PermissionError | |||
context = get_initial_context(group, view, controller) | |||
context["access"] = get_access(group) | |||
context["content"] = get_content(context) | |||
return context | |||
except webnotes.DoesNotExistError: | |||
return { | |||
"content": '<div class="alert alert-danger full-page">' | |||
'The page you are looking for does not exist.</div>' | |||
} | |||
except webnotes.PermissionError: | |||
return { | |||
"content": '<div class="alert alert-danger full-page">' | |||
'You are not permitted to view this page.</div>' | |||
} | |||
def get_initial_context(group, view, controller): | |||
def _get_initial_context(): | |||
if controller: | |||
group = controller.doc | |||
else: | |||
group = webnotes.doc("Website Group", group) | |||
# move all this to webutils | |||
parents = webnotes.conn.sql("""select name, unit_title from tabUnit | |||
where lft < %s and rgt > %s order by lft asc""", (unit.lft, unit.rgt), as_dict=1) | |||
# update title | |||
title = unit.unit_title | |||
views = get_views(unit) | |||
view_options = views.get(view, {}) | |||
if view_options: | |||
title += " - " + view_options["label"] | |||
views = sorted([opts for v, opts in views.items()], key=lambda d: d.get("idx")) | |||
context = { | |||
"name": unit.name, | |||
"public_read": unit.public_read, | |||
"title": "Aam Aadmi Party: " + title, | |||
"unit_title": title, | |||
"public_write": unit.public_write, | |||
"parents": parents, | |||
"children": get_child_unit_items(unit.name, public_read=1), | |||
"unit": unit.fields, | |||
"view": view, | |||
"views": views, | |||
"view_options": view_options | |||
} | |||
return context | |||
if webnotes.conf.get("disable_website_cache"): | |||
return _get_unit_context(unit, view) | |||
return webnotes.cache().get_value("unit_context:{unit}:{view}".format(unit=unit.lower(), view=view), | |||
lambda:_get_unit_context(unit, view)) | |||
def get_content(context): | |||
pass | |||
def guess_group_view(controller, page_options): | |||
group = page_options.docname | |||
view = None | |||
pathname = webnotes.request.path[1:] | |||
if "/" in pathname: | |||
view = pathname.split("/", 1)[1] | |||
if not view: | |||
get_views = webnotes.get_hooks("website_group_views:{}".controller.doc.group_type) | |||
if get_views: | |||
for v, opts in webnotes.get_attr(get_views)(group).items(): | |||
if opts.get("default"): | |||
view = v | |||
break | |||
return group, view | |||
def has_access(group, view): | |||
access = get_access(group) | |||
if view=="settings": | |||
return access.get("admin") | |||
elif view in ("add", "edit"): | |||
return access.get("write") | |||
else: | |||
return access.get("read") |
@@ -1,7 +0,0 @@ | |||
<style> | |||
h2 > a, h2 > a:link, h2 > a:visited, h2 > a:active, | |||
h2 > a:hover, h2 > a:focus { | |||
text-decoration: none; | |||
color: inherit; | |||
} | |||
</style> |
@@ -28,7 +28,7 @@ var blog = { | |||
method: "GET", | |||
url: "/", | |||
data: { | |||
cmd: "webnotes.website.doctype.blog_post.blog_post.get_blog_list", | |||
cmd: "webnotes.templates.generators.blog_post.get_blog_list", | |||
start: blog.start, | |||
by: get_url_arg("by"), | |||
category: get_url_arg("category") | |||
@@ -55,6 +55,7 @@ var blog = { | |||
} | |||
b.page_name = encodeURIComponent(b.page_name); | |||
b.avatar = b.avatar || ""; | |||
$(repl('<div class="row">\ | |||
<div class="col-md-1">\ | |||
@@ -1,15 +1,17 @@ | |||
<header> | |||
<div class="navbar navbar-default"> | |||
<nav class="navbar navbar-default" role="navigation"> | |||
<div class="container"> | |||
<div class="navbar-header"> | |||
<button type="button" class="navbar-toggle" data-toggle="collapse" | |||
data-target=".navbar-responsive-collapse"> | |||
<span class="sr-only">Toggle navigation</span> | |||
<span class="icon-bar"></span> | |||
<span class="icon-bar"></span> | |||
<span class="icon-bar"></span> | |||
</button> | |||
<a class="navbar-brand ellipsis" href="index"><span>{{ brand_html or "<i class='icon-home'></i>"}}</span></a> | |||
<span class="clearfix"></span> | |||
<a class="navbar-brand ellipsis" href="/index"> | |||
<span>{{ brand_html or "<i class='icon-home'></i>"}}</span> | |||
</a> | |||
</div> | |||
<div class="collapse navbar-collapse navbar-responsive-collapse"> | |||
{% if top_bar_items -%} | |||
@@ -38,26 +40,41 @@ | |||
{%- endfor %} | |||
</ul> | |||
{%- endif %} | |||
<ul class="nav navbar-nav navbar-right"> | |||
<ul class="logged-in nav navbar-nav navbar-right" style="display: none;"> | |||
<!-- post login tools --> | |||
<li id="website-post-login" data-label="website-post-login" class="dropdown"> | |||
<a href="#" class="dropdown-toggle" onclick="return false;" data-toggle="dropdown"> | |||
<i class="icon-cog"></i><span class="visible-xs-inline"><span class="caret"></span></span> | |||
<li class="dropdown" id="website-post-login" data-label="website-post-login"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"> | |||
<img class="user-picture" style="min-width: 20px; max-height: 20px; border-radius: 4px"/> | |||
<b class="full-name"></b><b class="caret"></b> | |||
</a> | |||
<ul class="dropdown-menu"> | |||
<ul class="dropdown-menu"> | |||
{%- for child in post_login -%} | |||
<li data-label="{{ child.label }}" {% if child.class %}class="{{ child.class }}"{% endif %}> | |||
{% if child.url -%} | |||
<a href="{{ child.url }}" {{ child.target or '' }}> | |||
{% if child.icon %}<i class="icon-fixed-width {{ child.icon }}"></i> {% endif %} | |||
{{ child.label }} | |||
</a> | |||
{%- endif %} | |||
<li data-label="{{ child.label }}" | |||
{% if child.class %} class="{{ child.class }}" {% endif %}> | |||
{%- if child.url -%} | |||
<a href="{{ child.url }}" {{ child.target or '' }}> | |||
{%- if child.icon -%} | |||
<i class="icon-fixed-width {{ child.icon }}"></i> | |||
{%- endif -%} | |||
{{ child.label }} | |||
</a> | |||
{%- endif -%} | |||
</li> | |||
{%- endfor -%} | |||
</ul> | |||
</li> | |||
</ul> | |||
<ul class="btn-login-area nav navbar-nav navbar-right"> | |||
<li class="dropdown"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Login <b class="caret"></b></a> | |||
<ul class="dropdown-menu"> | |||
<li><a href="#" class="btn-login" disabled=disabled>Login via Facebook</a></li> | |||
<li><a href="/login">Sign Up / Login</a></li> | |||
</ul> | |||
</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
@@ -16,7 +16,7 @@ | |||
{% for include in include_css -%} | |||
<link type="text/css" rel="stylesheet" href="{{ include }}"> | |||
{%- endfor -%} | |||
<script type="text/javascript" src="assets/webnotes/js/lib/jquery/jquery.min.js"></script> | |||
<script type="text/javascript" src="/assets/webnotes/js/lib/jquery/jquery.min.js"></script> | |||
<script type="text/javascript"> | |||
window._version_number = "{{ build_version }}"; | |||
// browser support | |||
@@ -3,12 +3,12 @@ | |||
from __future__ import unicode_literals | |||
no_cache = 1 | |||
no_sitemap = 1 | |||
base_template_path = "templates/pages/app.html" | |||
import webnotes, os | |||
def get_context(): | |||
def get_context(context): | |||
hooks = webnotes.get_hooks() | |||
return { | |||
"build_version": str(os.path.getmtime(os.path.join(webnotes.local.sites_path, "assets", "js", | |||
@@ -1,19 +1,3 @@ | |||
{% extends base_template %} | |||
{% block javascript %} | |||
<script> | |||
{% include "templates/includes/blog.js" %} | |||
</script> | |||
{% endblock %} | |||
{% block css %} | |||
<style> | |||
{% include "templates/includes/blog.css" %} | |||
</style> | |||
{% endblock %} | |||
{% set title="Blog" %} | |||
{% block content %} | |||
<div class="container content"> | |||
<h2 id="blog-title">{{ blog_title }}</h2> | |||
@@ -34,4 +18,7 @@ | |||
</div> | |||
</div> | |||
{% include 'templates/includes/blog_footer.html' %} | |||
<script> | |||
{% include "templates/includes/blog.js" %} | |||
</script> | |||
{% endblock %} |
@@ -3,6 +3,13 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes import _ | |||
def get_context(): | |||
return webnotes.doc("Blog Settings", "Blog Settings").fields | |||
def get_context(context): | |||
extended_context = webnotes.doc("Blog Settings", "Blog Settings").fields | |||
extended_context.update(context) | |||
return { | |||
"title": extended_context.blog_title or "Blog", | |||
"content": context.template.render(extended_context) | |||
} |
@@ -1,23 +1,4 @@ | |||
{% extends base_template %} | |||
{% block css %} | |||
<style> | |||
@media (min-width: 992px) { | |||
.login-wrapper { | |||
border-right: 1px solid #f2f2f2; | |||
} | |||
} | |||
</style> | |||
{% endblock %} | |||
{% set title=_("Login") %} | |||
{% block content %} | |||
{% if not top_bar_items %} | |||
<!--<style>body { background-color: #F5EFE6; }</style>--> | |||
{% endif %} | |||
<div class="container content" style="max-width: 800px;"> | |||
<div class="row" style="margin-top: 70px; margin-bottom: 20px"> | |||
<div class="col-sm-offset-1 col-sm-10"> | |||
@@ -44,7 +25,7 @@ | |||
<div class="form-group"> | |||
<button type="submit" id="login_btn" | |||
class="btn btn-primary">{{ _("Login") }}</button> | |||
<img src="assets/webnotes/images/ui/button-load.gif" id="login-spinner" | |||
<img src="/assets/webnotes/images/ui/button-load.gif" id="login-spinner" | |||
style="display: none;"> | |||
</div> | |||
<p id="forgot-link"></p> | |||
@@ -60,6 +41,4 @@ | |||
<script> | |||
{% include "templates/includes/login.js" %} | |||
</script> | |||
{% endblock %} |
@@ -1,6 +1,7 @@ | |||
import webnotes | |||
def get_context(): | |||
def get_context(context): | |||
return { | |||
"title": webnotes._("Login") | |||
"title": webnotes._("Login"), | |||
"content": context.template.render(context) | |||
} |
@@ -841,6 +841,11 @@ def get_url_to_form(doctype, name, base_url=None, label=None): | |||
if not label: label = name | |||
return """<a href="%(base_url)s/app.html#!Form/%(doctype)s/%(name)s">%(label)s</a>""" % locals() | |||
def scrub_relative_url(url): | |||
if not url or url.startswith("http"): | |||
return url | |||
return "/" + url | |||
def encode_dict(d, encoding="utf-8"): | |||
for key in d: | |||
@@ -1,3 +1,9 @@ | |||
@media (min-width: 992px) { | |||
.login-wrapper { | |||
border-right: 1px solid #f2f2f2; | |||
} | |||
} | |||
h1, h2, h3, h4, h5 { | |||
font-weight: bold; | |||
} | |||
@@ -4,8 +4,7 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
import webnotes.webutils | |||
from webnotes.webutils import WebsiteGenerator, cleanup_page_name | |||
from webnotes.webutils import WebsiteGenerator, cleanup_page_name, delete_page_cache | |||
from webnotes import _ | |||
from webnotes.utils import today | |||
@@ -30,74 +29,11 @@ class DocType(WebsiteGenerator): | |||
def on_update(self): | |||
WebsiteGenerator.on_update(self) | |||
webnotes.webutils.delete_page_cache("writers") | |||
delete_page_cache("writers") | |||
def get_context(self): | |||
import webnotes.utils | |||
import markdown2 | |||
# this is for double precaution. usually it wont reach this code if not published | |||
if not webnotes.utils.cint(self.doc.published): | |||
raise Exception, "This blog has not been published yet!" | |||
# temp fields | |||
from webnotes.utils import global_date_format, get_fullname | |||
self.doc.full_name = get_fullname(self.doc.owner) | |||
self.doc.updated = global_date_format(self.doc.published_on) | |||
if self.doc.blogger: | |||
self.doc.blogger_info = webnotes.doc("Blogger", self.doc.blogger).fields | |||
self.doc.description = self.doc.blog_intro or self.doc.content[:140] | |||
self.doc.meta_description = self.doc.description | |||
self.doc.categories = webnotes.conn.sql_list("select name from `tabBlog Category` order by name") | |||
self.doc.comment_list = webnotes.conn.sql("""\ | |||
select comment, comment_by_fullname, creation | |||
from `tabComment` where comment_doctype="Blog Post" | |||
and comment_docname=%s order by creation""", (self.doc.name,), as_dict=1) or [] | |||
def clear_blog_cache(): | |||
for blog in webnotes.conn.sql_list("""select page_name from | |||
`tabBlog Post` where ifnull(published,0)=1"""): | |||
webnotes.webutils.delete_page_cache(blog) | |||
webnotes.webutils.delete_page_cache("writers") | |||
@webnotes.whitelist(allow_guest=True) | |||
def get_blog_list(start=0, by=None, category=None): | |||
import webnotes | |||
condition = "" | |||
if by: | |||
condition = " and t1.blogger='%s'" % by.replace("'", "\'") | |||
if category: | |||
condition += " and t1.blog_category='%s'" % category.replace("'", "\'") | |||
query = """\ | |||
select | |||
t1.title, t1.name, t1.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 | |||
where ifnull(t1.published,0)=1 | |||
and t1.blogger = t2.name | |||
%(condition)s | |||
order by published_on desc, name asc | |||
limit %(start)s, 20""" % {"start": start, "condition": condition} | |||
result = webnotes.conn.sql(query, as_dict=1) | |||
# strip html tags from content | |||
import webnotes.utils | |||
delete_page_cache(blog) | |||
for res in result: | |||
from webnotes.utils import global_date_format | |||
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 | |||
delete_page_cache("writers") |
@@ -4,6 +4,7 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import WebsiteGenerator, cleanup_page_name | |||
from webnotes.templates.generators.website_group import get_context | |||
class DocType(WebsiteGenerator): | |||
def __init__(self, d, dl): | |||
@@ -26,3 +27,6 @@ class DocType(WebsiteGenerator): | |||
if not self.doc.page_name: | |||
webnotes.throw(_("Page Name is mandatory"), raise_exception=webnotes.MandatoryError) | |||
def get_context(self, page_options): | |||
return get_context(self, page_options) |
@@ -2,7 +2,7 @@ | |||
{ | |||
"creation": "2013-11-18 15:38:40", | |||
"docstatus": 0, | |||
"modified": "2014-01-30 11:37:09", | |||
"modified": "2014-01-30 16:50:49", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
@@ -54,6 +54,13 @@ | |||
"read_only": 1, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "page_title", | |||
"fieldtype": "Data", | |||
"label": "Page Title", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "ref_doctype", | |||
@@ -90,6 +90,7 @@ def add_website_sitemap_config(page_or_generator, app, path, fname, basepath): | |||
wsc.ref_doctype = getattr(module, "doctype", None) | |||
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) | |||
if webnotes.conn.exists("Website Sitemap Config", wsc.link_name): | |||
# found by earlier app, override | |||
@@ -2,7 +2,7 @@ | |||
{ | |||
"creation": "2013-11-18 15:35:00", | |||
"docstatus": 0, | |||
"modified": "2014-01-29 18:05:09", | |||
"modified": "2014-01-30 17:25:27", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
@@ -62,6 +62,13 @@ | |||
"label": "Link Name", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "base_template_path", | |||
"fieldtype": "Data", | |||
"label": "Base Template Path", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "template_path", | |||
@@ -19,5 +19,58 @@ def remove_empty_permissions(): | |||
webnotes.conn.sql("""delete from `tabWebsite Sitemap Permission` | |||
where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") | |||
# TODO clear permissions cache for permissions_cache_to_be_cleared | |||
clear_permissions(permissions_cache_to_be_cleared) | |||
def get_access(website_node, 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(website_node): | |||
permissions[website_node] = _get_access(website_node, profile) | |||
cache.set_value(key, permissions) | |||
return permissions.get(website_node) | |||
def _get_access(website_node, profile): | |||
lft, rgt, public_read, public_write = webnotes.conn.get_value("Website Sitemap", website_node, | |||
["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` up, `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): | |||
if isinstance(profiles, basestring): | |||
profiles = [profiles] | |||
cache = webnotes.cache() | |||
for profile in profiles: | |||
cache.delete_value("website_sitemap_permissions:{}".format(profile)) |
@@ -2,124 +2,156 @@ | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
from webnotes import conf | |||
import webnotes | |||
import json, os, time | |||
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 | |||
# for access as webnotes.webutils.fn | |||
from webnotes.website.doctype.website_sitemap_permission.website_sitemap_permission \ | |||
import get_access | |||
class PageNotFoundError(Exception): pass | |||
def render(page_name): | |||
"""render html page""" | |||
if not page_name: | |||
page_name = "index" | |||
page_name = scrub_page_name(page_name) | |||
if "/" in page_name: | |||
page_name = page_name.split("/")[0] | |||
try: | |||
html = render_page(page_name) | |||
data = render_page(page_name) | |||
except Exception: | |||
html = render_page("error") | |||
page_name = "error" | |||
data = render_page(page_name) | |||
data = insert_traceback(data) | |||
webnotes._response.data = html | |||
data = set_content_type(data, page_name) | |||
webnotes._response.data = data | |||
webnotes._response.headers["Page Name"] = page_name | |||
def render_page(page_name): | |||
"""get page html""" | |||
set_content_type(page_name) | |||
cache_key = ("page_context:{}" if is_ajax() else "page:{}").format(page_name) | |||
out = None | |||
if page_name.endswith('.html'): | |||
page_name = page_name[:-5] | |||
html = '' | |||
# try memcache | |||
if can_cache(): | |||
out = webnotes.cache().get_value(cache_key) | |||
if is_ajax(): | |||
out = out.get("data") | |||
if not conf.disable_website_cache: | |||
html = webnotes.cache().get_value("page:" + page_name) | |||
from_cache = True | |||
if not html: | |||
html = build_page(page_name) | |||
from_cache = False | |||
if page_name=="error": | |||
html = html.replace("%(error)s", webnotes.get_traceback()) | |||
elif "text/html" in webnotes._response.headers["Content-Type"]: | |||
comments = "\npage:"+page_name+\ | |||
"\nload status: " + (from_cache and "cache" or "fresh") | |||
html += """\n<!-- %s -->""" % webnotes.utils.cstr(comments) | |||
return html | |||
if out: | |||
webnotes._response.headers["From Cache"] = True | |||
return out | |||
def set_content_type(page_name): | |||
webnotes._response.headers["Content-Type"] = "text/html; charset: utf-8" | |||
return build(page_name) | |||
if "." in page_name and not page_name.endswith(".html"): | |||
content_type, encoding = mimetypes.guess_type(page_name) | |||
webnotes._response.headers["Content-Type"] = content_type | |||
def build_page(page_name): | |||
def build(page_name): | |||
if not webnotes.conn: | |||
webnotes.connect() | |||
if page_name=="index": | |||
page_name = get_home_page() | |||
build_method = (build_json if is_ajax() else build_page) | |||
try: | |||
sitemap_options = webnotes.doc("Website Sitemap", page_name).fields | |||
page_options = webnotes.doc("Website Sitemap Config", | |||
sitemap_options.get("website_sitemap_config")).fields.update({ | |||
"page_name":sitemap_options.page_name, | |||
"docname":sitemap_options.docname | |||
}) | |||
return build_method(page_name) | |||
except webnotes.DoesNotExistError: | |||
hooks = webnotes.get_hooks() | |||
if hooks.website_catch_all: | |||
return build_page(hooks.website_catch_all[0]) | |||
return build_method(hooks.website_catch_all[0]) | |||
else: | |||
return build_page("404") | |||
page_options["page_name"] = page_name | |||
return build_method("404") | |||
no_cache = page_options.get("no_cache") | |||
# if generator, then load bean, pass arguments | |||
if page_options.get("page_or_generator")=="Generator": | |||
bean = webnotes.bean(page_options.get("ref_doctype"), page_options["docname"]) | |||
bean.run_method("get_context") | |||
context = webnotes._dict(bean.doc.fields) | |||
context["obj"] = bean.get_controller() | |||
else: | |||
# page | |||
context = webnotes._dict({ 'name': page_name }) | |||
if page_options.get("controller"): | |||
module = webnotes.get_module(page_options.get("controller")) | |||
if module and hasattr(module, "get_context"): | |||
context.update(module.get_context()) | |||
def build_json(page_name): | |||
return get_context(page_name).data | |||
def build_page(page_name): | |||
context = get_context(page_name) | |||
context.update(get_website_settings()) | |||
jenv = webnotes.get_jenv() | |||
context["base_template"] = jenv.get_template("templates/base.html") | |||
template_name = page_options['template_path'] | |||
context["_"] = webnotes._ | |||
html = jenv.get_template(template_name).render(context) | |||
jenv = webnotes.get_jenv() | |||
html = jenv.get_template(context.base_template_path).render(context) | |||
if not no_cache: | |||
if can_cache(context.no_cache): | |||
webnotes.cache().set_value("page:" + page_name, html) | |||
return html | |||
def get_context(page_name): | |||
context = None | |||
cache_key = "page_context:{}".format(page_name) | |||
# try from memcache | |||
if can_cache(): | |||
context = webnotes.cache().get_value(cache_key) | |||
if not context: | |||
sitemap_options = build_sitemap_options(page_name) | |||
context = build_context(sitemap_options) | |||
if can_cache(context.no_cache): | |||
webnotes.cache().set_value(cache_key, context) | |||
context.update(context.data or {}) | |||
return context | |||
def build_sitemap_options(page_name): | |||
sitemap_options = webnotes.doc("Website Sitemap", page_name).fields | |||
# only non default fields | |||
for fieldname in default_fields: | |||
if fieldname in sitemap_options: | |||
del sitemap_options[fieldname] | |||
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) | |||
# 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) | |||
sitemap_options.children = webnotes.conn.sql("""select * from `tabWebsite Sitemap` | |||
where parent_website_sitemap=%s""", (sitemap_options.page_name,)) | |||
# determine templates to be used | |||
if not sitemap_options.base_template_path: | |||
sitemap_options.base_template_path = "templates/base.html" | |||
sitemap_options.template = webnotes.get_jenv().get_template(sitemap_options.template_path) | |||
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({ "_": webnotes._ }) | |||
context.update(sitemap_options) | |||
if sitemap_options.get("controller"): | |||
module = webnotes.get_module(sitemap_options.get("controller")) | |||
if module and hasattr(module, "get_context"): | |||
context.data = module.get_context(context) or {} | |||
return context | |||
def can_cache(no_cache=False): | |||
return not (webnotes.conf.disable_website_cache or no_cache) | |||
def get_home_page(): | |||
return webnotes.cache().get_value("home_page", \ | |||
lambda: webnotes.conn.get_value("Website Settings", None, "home_page") or "login") | |||
def get_website_settings(): | |||
from webnotes.utils import get_request_site_address, encode, cint | |||
from urllib import quote | |||
# TODO Cache this | |||
hooks = webnotes.get_hooks() | |||
all_top_items = webnotes.conn.sql("""\ | |||
@@ -177,6 +209,43 @@ def get_website_settings(): | |||
context.web_include_css = hooks.web_include_css or [] | |||
return context | |||
def is_ajax(): | |||
return webnotes.get_request_header("X-Requested-With")=="XMLHttpRequest" | |||
def scrub_page_name(page_name): | |||
if not page_name: | |||
page_name = "index" | |||
if "/" in page_name: | |||
page_name = page_name.split("/")[0] | |||
if page_name.endswith('.html'): | |||
page_name = page_name[:-5] | |||
return page_name | |||
def insert_traceback(data): | |||
if isinstance(data, dict): | |||
data["error"] = webnotes.get_traceback() | |||
else: | |||
data = data.replace("%(error)s", webnotes.get_traceback()) | |||
return data | |||
def set_content_type(data, page_name): | |||
if isinstance(data, dict): | |||
webnotes._response.headers["Content-Type"] = "application/json; charset: utf-8" | |||
data = json.dumps(data) | |||
return data | |||
webnotes._response.headers["Content-Type"] = "text/html; charset: utf-8" | |||
if "." in page_name and not page_name.endswith(".html"): | |||
content_type, encoding = mimetypes.guess_type(page_name) | |||
webnotes._response.headers["Content-Type"] = content_type | |||
return data | |||
def clear_cache(page_name=None): | |||
if page_name: | |||
@@ -321,3 +390,6 @@ def get_hex_shade(color, percent): | |||
percent = percent * 2 | |||
return p(r) + p(g) + p(b) | |||
def get_access(sitemap): | |||
pass |