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): | def create_folder(path): | ||||
if not os.path.exists(path): os.makedirs(path) | if not os.path.exists(path): os.makedirs(path) | ||||
def connect(site=None, db_name=None): | def connect(site=None, db_name=None): | ||||
from db import Database | from db import Database | ||||
if site: | if site: | ||||
@@ -546,13 +546,14 @@ def get_jenv(): | |||||
return jenv | return jenv | ||||
def set_filters(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 markdown2 import markdown | ||||
from json import dumps | from json import dumps | ||||
jenv.filters["global_date_format"] = global_date_format | jenv.filters["global_date_format"] = global_date_format | ||||
jenv.filters["markdown"] = markdown | jenv.filters["markdown"] = markdown | ||||
jenv.filters["json"] = dumps | jenv.filters["json"] = dumps | ||||
jenv.filters["scrub_relative_url"] = scrub_relative_url | |||||
# load jenv_filters from hooks.txt | # load jenv_filters from hooks.txt | ||||
for app in get_all_apps(True): | for app in get_all_apps(True): | ||||
@@ -171,7 +171,7 @@ def print_json(): | |||||
make_logs() | make_logs() | ||||
cleanup_docs() | cleanup_docs() | ||||
webnotes._response.headers["Content-Type"] = "text/json; charset: utf-8" | |||||
webnotes._response.headers["Content-Type"] = "application/json; charset: utf-8" | |||||
import json | import json | ||||
@@ -8,11 +8,16 @@ app_color = #3498db | |||||
after_install = webnotes.utils.install.after_install | after_install = webnotes.utils.install.after_install | ||||
# website | |||||
app_include_js = assets/js/webnotes.min.js | app_include_js = assets/js/webnotes.min.js | ||||
app_include_css = assets/webnotes/css/splash.css | app_include_css = assets/webnotes/css/splash.css | ||||
app_include_css = assets/css/webnotes.css | app_include_css = assets/css/webnotes.css | ||||
web_include_js = assets/js/webnotes-web.min.js | web_include_js = assets/js/webnotes-web.min.js | ||||
web_include_css = assets/css/webnotes-web.css | 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 | get_desktop_icons = webnotes.manage.get_desktop_icons | ||||
notification_config = webnotes.core.notifications.get_notification_config | notification_config = webnotes.core.notifications.get_notification_config | ||||
@@ -26,7 +31,7 @@ on_session_creation = webnotes.auth.notify_administrator_login | |||||
# permissions | # permissions | ||||
permission_query_conditions:Event = webnotes.core.doctype.event.event.get_permission_query_conditions | 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 | 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> | <title>{{ title }}</title> | ||||
<meta name="generator" content="wnframework"> | <meta name="generator" content="wnframework"> | ||||
<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> | ||||
<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> | <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 }}"> | <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> | </head> | ||||
<body> | <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> | </div> | ||||
{% block footer %}{% include "templates/includes/footer.html" %}{% endblock %} | |||||
{% block script -%}{%- endblock %} | |||||
{%- block footer -%}{% include "templates/includes/footer.html" %}{%- endblock -%} | |||||
</body> | </body> | ||||
</html> | </html> |
@@ -1,5 +1,3 @@ | |||||
{% extends base_template %} | |||||
{% block content %} | {% block content %} | ||||
<div class="container content" itemscope itemtype="http://schema.org/BlogPost"> | <div class="container content" itemscope itemtype="http://schema.org/BlogPost"> | ||||
<h2 itemprop="name headline">{{ title }}</h2> | <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" | 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 %} | {% extends base_template %} | ||||
{% block content %} | {% block content %} | ||||
{{ content }} | |||||
{%- if access -%} | |||||
<script> | |||||
$(function() { | |||||
wn.provide("wn"); | |||||
wn.access = {{ access|json }}; | |||||
}) | |||||
</script> | |||||
{%- endif -%} | |||||
{% endblock %} | {% 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" | 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", | method: "GET", | ||||
url: "/", | url: "/", | ||||
data: { | data: { | ||||
cmd: "webnotes.website.doctype.blog_post.blog_post.get_blog_list", | |||||
cmd: "webnotes.templates.generators.blog_post.get_blog_list", | |||||
start: blog.start, | start: blog.start, | ||||
by: get_url_arg("by"), | by: get_url_arg("by"), | ||||
category: get_url_arg("category") | category: get_url_arg("category") | ||||
@@ -55,6 +55,7 @@ var blog = { | |||||
} | } | ||||
b.page_name = encodeURIComponent(b.page_name); | b.page_name = encodeURIComponent(b.page_name); | ||||
b.avatar = b.avatar || ""; | |||||
$(repl('<div class="row">\ | $(repl('<div class="row">\ | ||||
<div class="col-md-1">\ | <div class="col-md-1">\ | ||||
@@ -1,15 +1,17 @@ | |||||
<header> | <header> | ||||
<div class="navbar navbar-default"> | |||||
<nav class="navbar navbar-default" role="navigation"> | |||||
<div class="container"> | <div class="container"> | ||||
<div class="navbar-header"> | <div class="navbar-header"> | ||||
<button type="button" class="navbar-toggle" data-toggle="collapse" | <button type="button" class="navbar-toggle" data-toggle="collapse" | ||||
data-target=".navbar-responsive-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> | <span class="icon-bar"></span> | ||||
<span class="icon-bar"></span> | <span class="icon-bar"></span> | ||||
</button> | </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> | ||||
<div class="collapse navbar-collapse navbar-responsive-collapse"> | <div class="collapse navbar-collapse navbar-responsive-collapse"> | ||||
{% if top_bar_items -%} | {% if top_bar_items -%} | ||||
@@ -38,26 +40,41 @@ | |||||
{%- endfor %} | {%- endfor %} | ||||
</ul> | </ul> | ||||
{%- endif %} | {%- endif %} | ||||
<ul class="nav navbar-nav navbar-right"> | |||||
<ul class="logged-in nav navbar-nav navbar-right" style="display: none;"> | |||||
<!-- post login tools --> | <!-- 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> | </a> | ||||
<ul class="dropdown-menu"> | |||||
<ul class="dropdown-menu"> | |||||
{%- for child in post_login -%} | {%- 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> | </li> | ||||
{%- endfor -%} | {%- endfor -%} | ||||
</ul> | </ul> | ||||
</li> | </li> | ||||
</ul> | </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> | </div> | ||||
</div> | </div> | ||||
@@ -16,7 +16,7 @@ | |||||
{% for include in include_css -%} | {% for include in include_css -%} | ||||
<link type="text/css" rel="stylesheet" href="{{ include }}"> | <link type="text/css" rel="stylesheet" href="{{ include }}"> | ||||
{%- endfor -%} | {%- 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"> | <script type="text/javascript"> | ||||
window._version_number = "{{ build_version }}"; | window._version_number = "{{ build_version }}"; | ||||
// browser support | // browser support | ||||
@@ -3,12 +3,12 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
no_cache = 1 | |||||
no_sitemap = 1 | no_sitemap = 1 | ||||
base_template_path = "templates/pages/app.html" | |||||
import webnotes, os | import webnotes, os | ||||
def get_context(): | |||||
def get_context(context): | |||||
hooks = webnotes.get_hooks() | hooks = webnotes.get_hooks() | ||||
return { | return { | ||||
"build_version": str(os.path.getmtime(os.path.join(webnotes.local.sites_path, "assets", "js", | "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 %} | {% block content %} | ||||
<div class="container content"> | <div class="container content"> | ||||
<h2 id="blog-title">{{ blog_title }}</h2> | <h2 id="blog-title">{{ blog_title }}</h2> | ||||
@@ -34,4 +18,7 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
{% include 'templates/includes/blog_footer.html' %} | {% include 'templates/includes/blog_footer.html' %} | ||||
<script> | |||||
{% include "templates/includes/blog.js" %} | |||||
</script> | |||||
{% endblock %} | {% endblock %} |
@@ -3,6 +3,13 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import webnotes | 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 %} | {% block content %} | ||||
{% if not top_bar_items %} | |||||
<!--<style>body { background-color: #F5EFE6; }</style>--> | |||||
{% endif %} | |||||
<div class="container content" style="max-width: 800px;"> | <div class="container content" style="max-width: 800px;"> | ||||
<div class="row" style="margin-top: 70px; margin-bottom: 20px"> | <div class="row" style="margin-top: 70px; margin-bottom: 20px"> | ||||
<div class="col-sm-offset-1 col-sm-10"> | <div class="col-sm-offset-1 col-sm-10"> | ||||
@@ -44,7 +25,7 @@ | |||||
<div class="form-group"> | <div class="form-group"> | ||||
<button type="submit" id="login_btn" | <button type="submit" id="login_btn" | ||||
class="btn btn-primary">{{ _("Login") }}</button> | 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;"> | style="display: none;"> | ||||
</div> | </div> | ||||
<p id="forgot-link"></p> | <p id="forgot-link"></p> | ||||
@@ -60,6 +41,4 @@ | |||||
<script> | <script> | ||||
{% include "templates/includes/login.js" %} | {% include "templates/includes/login.js" %} | ||||
</script> | </script> | ||||
{% endblock %} | {% endblock %} |
@@ -1,6 +1,7 @@ | |||||
import webnotes | import webnotes | ||||
def get_context(): | |||||
def get_context(context): | |||||
return { | 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 | if not label: label = name | ||||
return """<a href="%(base_url)s/app.html#!Form/%(doctype)s/%(name)s">%(label)s</a>""" % locals() | 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"): | def encode_dict(d, encoding="utf-8"): | ||||
for key in d: | for key in d: | ||||
@@ -1,3 +1,9 @@ | |||||
@media (min-width: 992px) { | |||||
.login-wrapper { | |||||
border-right: 1px solid #f2f2f2; | |||||
} | |||||
} | |||||
h1, h2, h3, h4, h5 { | h1, h2, h3, h4, h5 { | ||||
font-weight: bold; | font-weight: bold; | ||||
} | } | ||||
@@ -4,8 +4,7 @@ | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
import webnotes | 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 import _ | ||||
from webnotes.utils import today | from webnotes.utils import today | ||||
@@ -30,74 +29,11 @@ class DocType(WebsiteGenerator): | |||||
def on_update(self): | def on_update(self): | ||||
WebsiteGenerator.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(): | def clear_blog_cache(): | ||||
for blog in webnotes.conn.sql_list("""select page_name from | for blog in webnotes.conn.sql_list("""select page_name from | ||||
`tabBlog Post` where ifnull(published,0)=1"""): | `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 | from __future__ import unicode_literals | ||||
import webnotes | import webnotes | ||||
from webnotes.webutils import WebsiteGenerator, cleanup_page_name | from webnotes.webutils import WebsiteGenerator, cleanup_page_name | ||||
from webnotes.templates.generators.website_group import get_context | |||||
class DocType(WebsiteGenerator): | class DocType(WebsiteGenerator): | ||||
def __init__(self, d, dl): | def __init__(self, d, dl): | ||||
@@ -26,3 +27,6 @@ class DocType(WebsiteGenerator): | |||||
if not self.doc.page_name: | if not self.doc.page_name: | ||||
webnotes.throw(_("Page Name is mandatory"), raise_exception=webnotes.MandatoryError) | 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", | "creation": "2013-11-18 15:38:40", | ||||
"docstatus": 0, | "docstatus": 0, | ||||
"modified": "2014-01-30 11:37:09", | |||||
"modified": "2014-01-30 16:50:49", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"owner": "Administrator" | "owner": "Administrator" | ||||
}, | }, | ||||
@@ -54,6 +54,13 @@ | |||||
"read_only": 1, | "read_only": 1, | ||||
"reqd": 1 | "reqd": 1 | ||||
}, | }, | ||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "page_title", | |||||
"fieldtype": "Data", | |||||
"label": "Page Title", | |||||
"read_only": 1 | |||||
}, | |||||
{ | { | ||||
"doctype": "DocField", | "doctype": "DocField", | ||||
"fieldname": "ref_doctype", | "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.ref_doctype = getattr(module, "doctype", None) | ||||
wsc.page_name_field = getattr(module, "page_name_field", "page_name") | wsc.page_name_field = getattr(module, "page_name_field", "page_name") | ||||
wsc.condition_field = getattr(module, "condition_field", None) | 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): | if webnotes.conn.exists("Website Sitemap Config", wsc.link_name): | ||||
# found by earlier app, override | # found by earlier app, override | ||||
@@ -2,7 +2,7 @@ | |||||
{ | { | ||||
"creation": "2013-11-18 15:35:00", | "creation": "2013-11-18 15:35:00", | ||||
"docstatus": 0, | "docstatus": 0, | ||||
"modified": "2014-01-29 18:05:09", | |||||
"modified": "2014-01-30 17:25:27", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"owner": "Administrator" | "owner": "Administrator" | ||||
}, | }, | ||||
@@ -62,6 +62,13 @@ | |||||
"label": "Link Name", | "label": "Link Name", | ||||
"read_only": 1 | "read_only": 1 | ||||
}, | }, | ||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "base_template_path", | |||||
"fieldtype": "Data", | |||||
"label": "Base Template Path", | |||||
"read_only": 1 | |||||
}, | |||||
{ | { | ||||
"doctype": "DocField", | "doctype": "DocField", | ||||
"fieldname": "template_path", | "fieldname": "template_path", | ||||
@@ -19,5 +19,58 @@ def remove_empty_permissions(): | |||||
webnotes.conn.sql("""delete from `tabWebsite Sitemap Permission` | webnotes.conn.sql("""delete from `tabWebsite Sitemap Permission` | ||||
where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") | 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 | # MIT License. See license.txt | ||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
from webnotes import conf | |||||
import webnotes | import webnotes | ||||
import json, os, time | import json, os, time | ||||
from webnotes import _ | from webnotes import _ | ||||
import webnotes.utils | 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 webnotes.model.controller import DocListController | ||||
from urllib import quote | |||||
import mimetypes | import mimetypes | ||||
from webnotes.website.doctype.website_sitemap.website_sitemap import add_to_sitemap, update_sitemap, remove_sitemap | 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 | class PageNotFoundError(Exception): pass | ||||
def render(page_name): | def render(page_name): | ||||
"""render html page""" | """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: | try: | ||||
html = render_page(page_name) | |||||
data = render_page(page_name) | |||||
except Exception: | 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): | def render_page(page_name): | ||||
"""get page html""" | """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: | if not webnotes.conn: | ||||
webnotes.connect() | webnotes.connect() | ||||
if page_name=="index": | |||||
page_name = get_home_page() | |||||
build_method = (build_json if is_ajax() else build_page) | |||||
try: | 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: | except webnotes.DoesNotExistError: | ||||
hooks = webnotes.get_hooks() | hooks = webnotes.get_hooks() | ||||
if hooks.website_catch_all: | if hooks.website_catch_all: | ||||
return build_page(hooks.website_catch_all[0]) | |||||
return build_method(hooks.website_catch_all[0]) | |||||
else: | 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()) | 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) | webnotes.cache().set_value("page:" + page_name, html) | ||||
return 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(): | def get_home_page(): | ||||
return webnotes.cache().get_value("home_page", \ | return webnotes.cache().get_value("home_page", \ | ||||
lambda: webnotes.conn.get_value("Website Settings", None, "home_page") or "login") | lambda: webnotes.conn.get_value("Website Settings", None, "home_page") or "login") | ||||
def get_website_settings(): | 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() | hooks = webnotes.get_hooks() | ||||
all_top_items = webnotes.conn.sql("""\ | all_top_items = webnotes.conn.sql("""\ | ||||
@@ -177,6 +209,43 @@ def get_website_settings(): | |||||
context.web_include_css = hooks.web_include_css or [] | context.web_include_css = hooks.web_include_css or [] | ||||
return context | 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): | def clear_cache(page_name=None): | ||||
if page_name: | if page_name: | ||||
@@ -321,3 +390,6 @@ def get_hex_shade(color, percent): | |||||
percent = percent * 2 | percent = percent * 2 | ||||
return p(r) + p(g) + p(b) | return p(r) + p(g) + p(b) | ||||
def get_access(sitemap): | |||||
pass |