From 72c945b7c681690089c51d550ea4e66d9d99e663 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 22 Jun 2012 20:01:07 +0530 Subject: [PATCH] template based web page loading using web.py --- erpnext/patches/june_2012/cms2.py | 39 ++++- erpnext/website/doctype/blog/blog.py | 49 +----- erpnext/website/doctype/blog/blog.txt | 29 ++-- erpnext/website/doctype/blog/template.html | 24 --- erpnext/website/doctype/web_cache/__init__.py | 0 .../website/doctype/web_cache/web_cache.txt | 99 +++++++++++ .../website/doctype/web_page/template.html | 20 --- erpnext/website/doctype/web_page/web_page.py | 47 +----- erpnext/website/doctype/web_page/web_page.txt | 25 ++- erpnext/website/templates/blog-old.html | 58 +++++++ erpnext/website/templates/blog.html | 79 +++------ .../blog/blog_page.js => templates/blog.js} | 22 ++- erpnext/website/templates/page.html | 2 + erpnext/website/templates/web_page.html | 23 +++ erpnext/website/utils.py | 43 +---- erpnext/website/web_cache.py | 154 ++++++++++++++++++ erpnext/website/web_page.py | 78 +++++++++ public/js/all-app.js | 6 +- public/js/all-web.js | 6 +- public/web.py | 82 +++------- 20 files changed, 566 insertions(+), 319 deletions(-) delete mode 100644 erpnext/website/doctype/blog/template.html create mode 100644 erpnext/website/doctype/web_cache/__init__.py create mode 100644 erpnext/website/doctype/web_cache/web_cache.txt delete mode 100644 erpnext/website/doctype/web_page/template.html create mode 100644 erpnext/website/templates/blog-old.html rename erpnext/website/{doctype/blog/blog_page.js => templates/blog.js} (89%) create mode 100644 erpnext/website/templates/web_page.html create mode 100644 erpnext/website/web_cache.py create mode 100644 erpnext/website/web_page.py diff --git a/erpnext/patches/june_2012/cms2.py b/erpnext/patches/june_2012/cms2.py index fb9c72cf55..88e70496ed 100644 --- a/erpnext/patches/june_2012/cms2.py +++ b/erpnext/patches/june_2012/cms2.py @@ -1,11 +1,40 @@ def execute(): import webnotes - from webnotes.model.doclist import DocList import webnotes.model.sync - # sync web page doctype + # sync web page, blog doctype webnotes.model.sync.sync('website', 'web_page') + webnotes.model.sync.sync('website', 'blog') + + cleanup() + + save_pages() - # save all web pages to create content - for p in webnotes.conn.sql("""select name from `tabWeb Page` where docstatus=0"""): - DocList('Web Page', p[0]).save() \ No newline at end of file +def cleanup(): + import webnotes + + # delete pages from `tabPage` of module Website or of type Webpage + webnotes.conn.sql("""\ + delete from `tabPage` + where module='Website' and ifnull(web_page, 'No') = 'Yes'""") + +def save_pages(): + """save all web pages, blogs to create content""" + import webnotes + from webnotes.model.doclist import DocList + save_list = [ + { + 'doctype': 'Web Page', + 'query': """select name from `tabWeb Page` where docstatus=0""" + }, + { + 'doctype': 'Blog', + 'query': """\ + select name from `tabBlog` + where docstatus = 0 and ifnull(published, 0) = 1""" + }, + ] + + for s in save_list: + for p in webnotes.conn.sql(s['query'], as_dict=1): + DocList(s['doctype'], p['name']).save() \ No newline at end of file diff --git a/erpnext/website/doctype/blog/blog.py b/erpnext/website/doctype/blog/blog.py index 919b830399..0dfecc0a81 100644 --- a/erpnext/website/doctype/blog/blog.py +++ b/erpnext/website/doctype/blog/blog.py @@ -22,52 +22,17 @@ naming for same name files: file.gif, file-1.gif, file-2.gif etc import webnotes import website.utils +import website.web_page -class DocType(): +class DocType(website.web_page.Page): def __init__(self, d, dl): + super(DocType, self).__init__('Blog') self.doc, self.doclist = d, dl - - def autoname(self): - """save file by its name""" - self.doc.name = website.utils.page_name(self.doc.title) - - def validate(self): - """write/update 'Page' with the blog""" - # we need the name for the templates - if not self.doc.name: - self.autoname() - - if self.doc.page_name: - webnotes.conn.sql("""delete from tabPage where name=%s""", self.doc.page_name) - - p = website.utils.add_page(self.doc.title) - - from jinja2 import Template - import markdown2 - import os + + def get_html(self): + # temp fields from webnotes.utils import global_date_format, get_fullname - from webnotes.model.code import get_obj - - self.doc.content_html = unicode(markdown2.markdown(self.doc.content or '')) self.doc.full_name = get_fullname(self.doc.owner) self.doc.updated = global_date_format(self.doc.modified) - - with open(os.path.join(os.path.dirname(__file__), 'template.html'), 'r') as f: - p.content = Template(f.read()).render(doc=self.doc) - - with open(os.path.join(os.path.dirname(__file__), 'blog_page.js'), 'r') as f: - p.script = Template(f.read()).render(doc=self.doc) - - p.web_page = 'Yes' - p.save() - get_obj(doc=p).write_cms_page() - - website.utils.add_guest_access_to_page(p.name) - self.doc.page_name = p.name - - # cleanup - for f in ['full_name', 'updated', 'content_html']: - if f in self.doc.fields: - del self.doc.fields[f] - \ No newline at end of file + self.markdown_to_html(['content']) \ No newline at end of file diff --git a/erpnext/website/doctype/blog/blog.txt b/erpnext/website/doctype/blog/blog.txt index ad44d13d96..24187e3bf3 100644 --- a/erpnext/website/doctype/blog/blog.txt +++ b/erpnext/website/doctype/blog/blog.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-04-02 16:02:43', + 'creation': '2012-05-28 19:22:38', 'docstatus': 0, - 'modified': '2012-04-26 16:58:27', + 'modified': '2012-06-22 18:56:16', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -21,7 +21,7 @@ 'name': '__common__', 'section_style': u'Simple', 'show_in_menu': 0, - 'version': 5 + 'version': 1 }, # These values are common for all DocField @@ -51,6 +51,7 @@ # DocPerm { + 'cancel': 1, 'create': 1, 'doctype': u'DocPerm', 'permlevel': 0, @@ -71,7 +72,14 @@ { 'doctype': u'DocPerm', 'permlevel': 1, - 'role': u'All' + 'role': u'Website Manager' + }, + + # DocPerm + { + 'doctype': u'DocPerm', + 'permlevel': 1, + 'role': u'Blogger' }, # DocField @@ -99,26 +107,19 @@ 'fieldname': u'content', 'fieldtype': u'Code', 'label': u'Content', + 'options': u'Markdown', 'permlevel': 0, 'reqd': 0 }, - # DocField - { - 'doctype': u'DocField', - 'fieldname': u'content_html', - 'fieldtype': u'Text', - 'label': u'Content HTML', - 'permlevel': 1 - }, - # DocField { 'doctype': u'DocField', 'fieldname': u'page_name', 'fieldtype': u'Data', + 'hidden': 1, 'label': u'Page Name', - 'permlevel': 0 + 'permlevel': 1 }, # DocField diff --git a/erpnext/website/doctype/blog/template.html b/erpnext/website/doctype/blog/template.html deleted file mode 100644 index 510f1bed5f..0000000000 --- a/erpnext/website/doctype/blog/template.html +++ /dev/null @@ -1,24 +0,0 @@ -
-
-
-

{{ doc.title }}

-
By {{ doc.full_name }} on {{ doc.updated }}
-
- {{ doc.content_html }} -

Comments

-
-
-
-
-

All Blogs

-

Recent Posts

-
-

Subscribe

-

- - RSS Feed -

-
-
-
-
\ No newline at end of file diff --git a/erpnext/website/doctype/web_cache/__init__.py b/erpnext/website/doctype/web_cache/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/website/doctype/web_cache/web_cache.txt b/erpnext/website/doctype/web_cache/web_cache.txt new file mode 100644 index 0000000000..98a48918a7 --- /dev/null +++ b/erpnext/website/doctype/web_cache/web_cache.txt @@ -0,0 +1,99 @@ +# DocType, Web Cache +[ + + # These values are common in all dictionaries + { + 'creation': '2012-06-21 12:01:17', + 'docstatus': 0, + 'modified': '2012-06-21 17:25:52', + 'modified_by': u'Administrator', + 'owner': u'Administrator' + }, + + # These values are common for all DocType + { + 'doctype': 'DocType', + 'document_type': u'System', + 'module': u'Website', + 'name': '__common__', + 'version': 1 + }, + + # These values are common for all DocField + { + 'doctype': u'DocField', + 'name': '__common__', + 'parent': u'Web Cache', + 'parentfield': u'fields', + 'parenttype': u'DocType', + 'permlevel': 0 + }, + + # These values are common for all DocPerm + { + 'doctype': u'DocPerm', + 'name': '__common__', + 'parent': u'Web Cache', + 'parentfield': u'permissions', + 'parenttype': u'DocType', + 'permlevel': 0, + 'read': 1, + 'write': 1 + }, + + # DocType, Web Cache + { + 'doctype': 'DocType', + 'name': u'Web Cache' + }, + + # DocPerm + { + 'create': 0, + 'doctype': u'DocPerm', + 'role': u'All' + }, + + # DocPerm + { + 'create': 1, + 'doctype': u'DocPerm', + 'role': u'Website Manager' + }, + + # DocPerm + { + 'create': 1, + 'doctype': u'DocPerm', + 'role': u'Blogger' + }, + + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'doc_type', + 'fieldtype': u'Link', + 'in_filter': 1, + 'label': u'DocType', + 'options': u'DocType', + 'reqd': 1 + }, + + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'doc_name', + 'fieldtype': u'Data', + 'in_filter': 0, + 'label': u'DocName', + 'reqd': 1 + }, + + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'html', + 'fieldtype': u'Long Text', + 'label': u'HTML' + } +] \ No newline at end of file diff --git a/erpnext/website/doctype/web_page/template.html b/erpnext/website/doctype/web_page/template.html deleted file mode 100644 index f46113c0b2..0000000000 --- a/erpnext/website/doctype/web_page/template.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
- - {% if doc.layout and doc.layout.startswith('Two column') %} -
- {% else %} -
- {% endif %} - {{ doc.main_section_html }} -
- - {% if doc.layout and doc.layout.startswith('Two column') %} -
- {{ doc.side_section_html }} -
- {% endif %} -
-
-
diff --git a/erpnext/website/doctype/web_page/web_page.py b/erpnext/website/doctype/web_page/web_page.py index 3f4a39c0a9..37e0cee18b 100644 --- a/erpnext/website/doctype/web_page/web_page.py +++ b/erpnext/website/doctype/web_page/web_page.py @@ -16,51 +16,22 @@ import webnotes import website.utils +import website.web_page -class DocType: +class DocType(website.web_page.Page): def __init__(self, d, dl): + super(DocType, self).__init__('Web Page') self.doc, self.doclist = d, dl - - def autoname(self): - """name from title""" - self.doc.name = website.utils.page_name(self.doc.title) def on_update(self): - """make page for this product""" - from jinja2 import Template - import os - - # we need the name for the templates - if self.doc.name.startswith('New Web Page'): - self.autoname() - - # page name updates with the title - self.doc.page_name = website.utils.page_name(self.doc.title) - - # markdown - website.utils.markdown(self.doc, ['head_section','main_section', 'side_section']) - - # make page layout - with open(os.path.join(os.path.dirname(__file__), 'template.html'), 'r') as f: - self.doc.content = Template(f.read()).render(doc=self.doc) - - self.cleanup_temp() - - self.doc.save() - + super(DocType, self).on_update() self.if_home_clear_cache() - - def cleanup_temp(self): - """cleanup temp fields""" - fl = ['main_section_html', 'side_section_html', \ - 'head_section_html'] - for f in fl: - if f in self.doc.fields: - del self.doc.fields[f] - + def if_home_clear_cache(self): """if home page, clear cache""" if webnotes.conn.get_value("Website Settings", None, "home_page")==self.doc.name: from webnotes.session_cache import clear_cache - clear_cache('Guest') - \ No newline at end of file + clear_cache('Guest') + + def get_html(self): + self.markdown_to_html(['head_section','main_section', 'side_section']) \ No newline at end of file diff --git a/erpnext/website/doctype/web_page/web_page.txt b/erpnext/website/doctype/web_page/web_page.txt index 9fba41a2c5..a1fd8949f9 100644 --- a/erpnext/website/doctype/web_page/web_page.txt +++ b/erpnext/website/doctype/web_page/web_page.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-04-02 16:02:43', + 'creation': '2012-06-19 15:02:20', 'docstatus': 0, - 'modified': '2012-06-15 17:18:59', + 'modified': '2012-06-22 18:49:02', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -36,13 +36,15 @@ # These values are common for all DocPerm { + 'amend': 0, 'doctype': u'DocPerm', 'name': '__common__', 'parent': u'Web Page', 'parentfield': u'permissions', 'parenttype': u'DocType', 'read': 1, - 'role': u'Website Manager' + 'role': u'Website Manager', + 'submit': 0 }, # DocType, Web Page @@ -53,6 +55,7 @@ # DocPerm { + 'cancel': 1, 'create': 1, 'doctype': u'DocPerm', 'permlevel': 0, @@ -61,8 +64,11 @@ # DocPerm { + 'cancel': 0, + 'create': 0, 'doctype': u'DocPerm', - 'permlevel': 1 + 'permlevel': 1, + 'write': 0 }, # DocField @@ -163,17 +169,6 @@ 'permlevel': 0 }, - # DocField - { - 'colour': u'White:FFF', - 'doctype': u'DocField', - 'fieldname': u'content', - 'fieldtype': u'Code', - 'hidden': 1, - 'label': u'Content', - 'permlevel': 0 - }, - # DocField { 'colour': u'White:FFF', diff --git a/erpnext/website/templates/blog-old.html b/erpnext/website/templates/blog-old.html new file mode 100644 index 0000000000..d0b9a1362b --- /dev/null +++ b/erpnext/website/templates/blog-old.html @@ -0,0 +1,58 @@ +{% extends "outer.html" %} + +{% block title %}{{ title }}{% endblock %} + + +{% block content %} +
+
+
+

Blog

+
+
+ +
+
+
+ +

Subscribe

+

+ + RSS Feed +

+
+
+
+
+ + \ No newline at end of file diff --git a/erpnext/website/templates/blog.html b/erpnext/website/templates/blog.html index d0b9a1362b..e188edf921 100644 --- a/erpnext/website/templates/blog.html +++ b/erpnext/website/templates/blog.html @@ -1,58 +1,31 @@ -{% extends "outer.html" %} - -{% block title %}{{ title }}{% endblock %} - +{% extends "blog.js" %} {% block content %} -
-
-
-

Blog

-
-
- +
+
+ +
+

{{ title }}

+
By {{ full_name }} on {{ updated }}
+
+ {{ content_html }} +

Comments

+
+
+ +
+

All Blogs

+

Recent Posts

+
+

Subscribe

+

+ + RSS Feed +

+
+ +
-
- -

Subscribe

-

- - RSS Feed -

-
-
-
- - \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/erpnext/website/doctype/blog/blog_page.js b/erpnext/website/templates/blog.js similarity index 89% rename from erpnext/website/doctype/blog/blog_page.js rename to erpnext/website/templates/blog.js index 4b283920fa..80cb813f95 100644 --- a/erpnext/website/doctype/blog/blog_page.js +++ b/erpnext/website/templates/blog.js @@ -1,3 +1,6 @@ +{% extends "page.html" %} + +{% block javascript %} // ERPNext - web based ERP (http://erpnext.com) // Copyright (C) 2012 Web Notes Technologies Pvt Ltd // @@ -15,14 +18,13 @@ // along with this program. If not, see . // js inside blog page - -pscript['onload_{{ doc.name }}'] = function(wrapper) { +wn.pages['{{ name }}'].onload = function(wrapper) { // sidebar wrapper.recent_list = new wn.ui.Listing({ parent: $(wrapper).find('.recent-posts'), no_toolbar: true, query: 'select name, title, left(content, 100) as content from tabBlog\ - where ifnull(published,0)=1 and name!="{{ doc.name }}" order by creation desc', + where ifnull(published,0)=1 and name!="{{ name }}" order by creation desc', hide_refresh: true, render_row: function(parent, data) { //console.log(data); @@ -33,13 +35,13 @@ pscript['onload_{{ doc.name }}'] = function(wrapper) { page_length: 5, }); wrapper.recent_list.run(); - + wrapper.comment_list = new wn.ui.Listing({ parent: $(wrapper).find('.blog-comments').get(0), no_toolbar: true, query: 'select comment, comment_by_fullname, creation\ from `tabComment` where comment_doctype="Page"\ - and comment_docname="{{ doc.name }}" order by creation desc', + and comment_docname="{{ name }}" order by creation desc', no_result_message: 'Be the first one to comment', render_row: function(parent, data) { data.comment_date = prettyDate(data.creation); @@ -48,10 +50,10 @@ pscript['onload_{{ doc.name }}'] = function(wrapper) {
\

%(comment)s


", data)) }, - hide_refresh: true + hide_refresh: true, }); wrapper.comment_list.run(); - + // add comment $(wrapper).find('.layout-main-section').append('
'); @@ -70,7 +72,7 @@ pscript['onload_{{ doc.name }}'] = function(wrapper) { var args = d.get_values(); if(!args) return; args.comment_doctype = 'Page'; - args.comment_docname = '{{ doc.name }}'; + args.comment_docname = '{{ name }}'; $(btn).set_working(); $c('webnotes.widgets.form.comments.add_comment', args, function(r) { $(btn).done_working(); @@ -80,4 +82,6 @@ pscript['onload_{{ doc.name }}'] = function(wrapper) { } d.show(); }) -} \ No newline at end of file +} + +{% endblock %} diff --git a/erpnext/website/templates/page.html b/erpnext/website/templates/page.html index 97a309ab73..a8e20f67f2 100644 --- a/erpnext/website/templates/page.html +++ b/erpnext/website/templates/page.html @@ -12,7 +12,9 @@ var _page = new wn.views.Page(window.page_name); // page script + {% block javascript %} {{ javascript }} + {% endblock %} // trigger onload _page.trigger('onload'); diff --git a/erpnext/website/templates/web_page.html b/erpnext/website/templates/web_page.html new file mode 100644 index 0000000000..8188e71373 --- /dev/null +++ b/erpnext/website/templates/web_page.html @@ -0,0 +1,23 @@ +{% extends "page.html" %} + +{% block content %} +
+
+ + {% if layout and layout.startswith('Two column') %} +
+ {% else %} +
+ {% endif %} + {{ main_section_html }} +
+ + {% if layout and layout.startswith('Two column') %} +
+ {{ side_section_html }} +
+ {% endif %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/erpnext/website/utils.py b/erpnext/website/utils.py index 57e940a755..06bb60d94b 100644 --- a/erpnext/website/utils.py +++ b/erpnext/website/utils.py @@ -29,43 +29,12 @@ def make_template(doc, path, convert_fields = ['main_section', 'side_section']): return temp.render(doc = doc.fields) -def markdown(doc, fields): - """convert fields to markdown""" - import markdown2 - # markdown - for f in fields: - doc.fields[f + '_html'] = markdown2.markdown(doc.fields[f] or '', \ - extras=["wiki-tables"]) - - def page_name(title): - """make page name from title, and check that there is no duplicate""" - import webnotes.cms - return webnotes.cms.page_name(title) - -def add_page(title): - """add a custom page with title""" - name = page_name(title) - if webnotes.conn.sql("""select name from tabPage where name=%s""", name): - p = Document('Page', name) - else: - p = Document('Page') - - p.title = title - p.name = p.page_name = name - p.module = 'Website' - p.standard = 'No' - - return p - -def add_guest_access_to_page(page): - """add Guest in Page Role""" - if not webnotes.conn.sql("""select parent from `tabPage Role` - where role='Guest' and parent=%s""", page): - d = Document('Page Role') - d.parent = page - d.role = 'Guest' - d.save() + """make page name from title""" + import re + name = title.lower() + name = re.sub('[~!@#$%^&*()<>,."\']', '', name) + return '-'.join(name.split()[:4]) def get_header(page_name): """get page header""" @@ -144,4 +113,4 @@ def get_footer(page_name): {% endfor %}
""").render(website_settings.fields) +
""").render(website_settings.fields) \ No newline at end of file diff --git a/erpnext/website/web_cache.py b/erpnext/website/web_cache.py new file mode 100644 index 0000000000..30e3f0015d --- /dev/null +++ b/erpnext/website/web_cache.py @@ -0,0 +1,154 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# used by web.py +def load_from_web_cache(page_name, comments, template): + """ + * search for page in cache + * if html exists, return + * if not, build html, store it in cache, return + """ + import webnotes + import conf + + if page_name == 'index': + page_name = get_index_page()[0] + + res = webnotes.conn.sql("""\ + select html, doc_type, doc_name from `tabWeb Cache` + where name = %s""", page_name) + + # if page doesn't exist, raise exception + if not res and page_name not in ['404', 'index']: + raise Exception, "Page %s not found" % page_name + + html, doc_type, doc_name = res and res[0] or (None, None, None) + auto_cache_clear = hasattr(conf, 'auto_cache_clear') and conf.auto_cache_clear or 0 + if not html or auto_cache_clear: + comments += "\n\npage load status: fresh" + html = load_into_web_cache(page_name, template, doc_type, doc_name) + else: + comments += "\n\npage load status: cached" + + from webnotes.utils import cstr + html += """\n""" % cstr(comments) + return html + +def load_into_web_cache(page_name, template, doc_type, doc_name): + """build html and store it in web cache""" + import webnotes + outer_env_dict = get_outer_env() + + if page_name == '404': + args = outer_env_dict + else: + if page_name == 'index': + page_name, doc_type, doc_name = get_index_page() + + from webnotes.model.code import get_obj + obj = get_obj(doc_type, doc_name) + obj.get_html() + args = obj.doc.fields + args.update(outer_env_dict) + + if doc_type == 'Blog': + template = 'blog.html' + args['insert_code'] = 1 + elif doc_type == 'Web Page': + template = 'web_page.html' + + html = build_html(args, template) + + # save html in web cache + webnotes.conn.begin() + webnotes.conn.set_value('Web Cache', page_name, 'html', html) + webnotes.conn.commit() + + return html + +def build_html(args, template): + """build html using jinja2 templates""" + from jinja2 import Environment, FileSystemLoader + jenv = Environment(loader = FileSystemLoader('../erpnext/website/templates')) + html = jenv.get_template(template).render(args) + return html + +def get_outer_env(): + """env dict for outer template""" + import webnotes + return { + 'top_bar_items': webnotes.conn.sql("""select * from `tabTop Bar Item` + where parent='Website Settings' and parentfield='top_bar_items' + order by idx asc""", as_dict=1), + + 'footer_items': webnotes.conn.sql("""select * from `tabTop Bar Item` + where parent='Website Settings' and parentfield='footer_items' + order by idx asc""", as_dict=1), + + 'brand': webnotes.conn.get_value('Website Settings', None, 'brand_html'), + 'copyright': webnotes.conn.get_value('Website Settings', None, 'copyright'), + } + +def get_index_page(): + import webnotes + doc_type = 'Web Page' + doc_name = webnotes.conn.get_value('Website Settings', None, 'home_page') + page_name = webnotes.conn.get_value(doc_type, doc_name, 'page_name') + return page_name, doc_type, doc_name + +# cache management +def clear_web_cache(doc_type, doc_name, page_name): + """ + * check if a record corresponding to (type, name) exists + * if exists, just clear html column + * if does not exist, create a record for (type, name) + * if a record like (some other type, name) exists, raise exception that the page name is not unique + """ + import webnotes + res = webnotes.conn.get_value('Web Cache', page_name, 'doc_type') + if not res: + import webnotes.model.doc + d = webnotes.model.doc.Document('Web Cache') + d.name = page_name + d.doc_type = doc_type + d.doc_name = doc_name + d.html = None + d.save() + elif res == doc_type: + webnotes.conn.set_value('Web Cache', page_name, 'html', None) + else: + webnotes.msgprint("""Page with name "%s" already exists as a %s. + Please save it with another name.""" % (page_name, res), raise_exception=1) + +def clear_all_web_cache(): + import webnotes + webnotes.conn.sql("update `tabWeb Cache` set html = NULL") + +def delete_web_cache(page_name): + """ + delete entry of page_name from Web Cache + used when: + * web page is deleted + * blog is un-published + """ + import webnotes + webnotes.conn.sql("""\ + delete from `tabWeb Cache` + where name=%s""", page_name) + +def build_web_cache(): + """build web cache so that pages can load faster""" + pass \ No newline at end of file diff --git a/erpnext/website/web_page.py b/erpnext/website/web_page.py new file mode 100644 index 0000000000..4d6f9f0b6b --- /dev/null +++ b/erpnext/website/web_page.py @@ -0,0 +1,78 @@ +# ERPNext - web based ERP (http://erpnext.com) +# Copyright (C) 2012 Web Notes Technologies Pvt Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import webnotes +import website.utils +import website.web_cache + +class Page(object): + def __init__(self, doctype): + self.doctype = doctype + + def autoname(self): + """name from title""" + self.doc.name = website.utils.page_name(self.doc.title) + + def validate(self): + if self.doc.name: + self.old_page_name = webnotes.conn.get_value(self.doctype, self.doc.name, 'page_name') + + def on_update(self): + # page name updates with the title + self.update_page_name() + + # delete web cache entry of old name + if hasattr(self, 'old_page_name') and self.old_page_name != self.doc.page_name: + self.delete_web_cache(self.old_page_name) + + self.clear_web_cache() + + self.doc.save(ignore_fields=1) + + def on_trash(self): + """delete Web Cache entry""" + self.delete_web_cache(self.doc.page_name) + + def update_page_name(self): + """set page_name and check if it is unique""" + self.doc.page_name = website.utils.page_name(self.doc.title) + + res = webnotes.conn.sql("""\ + select count(*) from `tab%s` + where page_name=%s and name!=%s""" % (self.doctype, '%s', '%s'), + (self.doc.page_name, self.doc.name)) + if res and res[0][0] > 0: + webnotes.msgprint("""A %s with the same title already exists. + Please change the title and save again.""" % self.doctype, raise_exception=1) + + def clear_web_cache(self): + """ + if web cache entry doesn't exist, it creates one + if duplicate entry exists for another doctype, it raises exception + """ + website.web_cache.clear_web_cache(self.doctype, self.doc.name, self.doc.page_name) + + def delete_web_cache(self, page_name): + """delete entry of page name from Web Cache""" + website.web_cache.delete_web_cache(page_name) + + def markdown_to_html(self, fields_list): + """convert fields from markdown to html""" + import markdown2 + for f in fields_list: + field_name = "%s_html" % f + self.doc.fields[field_name] = markdown2.markdown(self.doc.fields.get(f) or '', \ + extras=["wiki-tables"]) \ No newline at end of file diff --git a/public/js/all-app.js b/public/js/all-app.js index 5e3f8f2db4..026903bf41 100644 --- a/public/js/all-app.js +++ b/public/js/all-app.js @@ -310,13 +310,13 @@ if(me.show_filters){this.add_button('Show Filters',function(){me.filter_list.sho if(me.no_toolbar||me.hide_toolbar){me.$w.find('.list-toolbar-wrapper').toggle(false);}},make_new_doc:function(new_doctype){new_doc(new_doctype);},make_filters:function(){this.filter_list=new wn.ui.FilterList({listobj:this,$parent:this.$w.find('.list-filters').toggle(true),doctype:this.doctype,filter_fields:this.filter_fields});},clear:function(){this.data=[];this.$w.find('.result-list').empty();this.$w.find('.result').toggle(true);this.$w.find('.no-result').toggle(false);this.start=0;},run:function(){var me=this;var a0=arguments[0];var a1=arguments[1];if(a0&&typeof a0=='function') this.onrun=a0;if(a0&&a0.callback) this.onrun=a0.callback;if(!a1&&!(a0&&a0.append)) -this.start=0;me.set_working(true);wn.call({method:this.opts.method||'webnotes.widgets.query_builder.runquery',args:this.get_call_args(a0),callback:function(r){me.set_working(false);me.render_results(r)},no_spinner:this.opts.no_loading});},set_working:function(flag){this.$w.find('.img-load').toggle(flag);},get_call_args:function(opts){if(!this.method){this.query=this.get_query?this.get_query():this.query;this.add_limits();var args={query_max:this.query_max,as_dict:1} -args.simple_query=this.query;}else{var args={limit_start:this.start,limit_page_length:this.page_length}} +this.start=0;me.set_working(true);wn.call({method:this.opts.method||'webnotes.widgets.query_builder.runquery',args:this.get_call_args(a0),callback:function(r){me.set_working(false);me.render_results(r)},no_spinner:this.opts.no_loading});},set_working:function(flag){this.$w.find('.img-load').toggle(flag);},get_call_args:function(opts){if(!this.method){var query=this.get_query?this.get_query():this.query;query=this.add_limits(query);var args={query_max:this.query_max,as_dict:1} +args.simple_query=query;}else{var args={limit_start:this.start,limit_page_length:this.page_length}} if(this.args) $.extend(args,this.args) if(this.get_args){$.extend(args,this.get_args(opts));} return args;},render_results:function(r){if(this.start==0)this.clear();this.$w.find('.btn-more').toggle(false);if(r.message)r.values=r.message;if(r.values&&r.values.length){this.data=this.data.concat(r.values);this.render_list(r.values);this.update_paging(r.values);}else{if(this.start==0){this.$w.find('.result').toggle(false);this.$w.find('.no-result').toggle(true);}} -if(this.onrun)this.onrun();if(this.callback)this.callback(r);},render_list:function(values){var m=Math.min(values.length,this.page_length);for(var i=0;i=this.page_length){this.$w.find('.btn-more').toggle(true);this.start+=this.page_length;}},add_row:function(){return $('
').appendTo(this.$w.find('.result-list')).get(0);},refresh:function(){this.run();},add_limits:function(){this.query+=' LIMIT '+this.start+','+(this.page_length+1);}}); +if(this.onrun)this.onrun();if(this.callback)this.callback(r);},render_list:function(values){var m=Math.min(values.length,this.page_length);for(var i=0;i=this.page_length){this.$w.find('.btn-more').toggle(true);this.start+=this.page_length;}},add_row:function(){return $('
').appendTo(this.$w.find('.result-list')).get(0);},refresh:function(){this.run();},add_limits:function(query){query+=' LIMIT '+this.start+','+(this.page_length+1);return query}}); /* * lib/js/wn/ui/filters.js */ diff --git a/public/js/all-web.js b/public/js/all-web.js index a549dc9e54..9712ff6d14 100644 --- a/public/js/all-web.js +++ b/public/js/all-web.js @@ -197,13 +197,13 @@ if(me.show_filters){this.add_button('Show Filters',function(){me.filter_list.sho if(me.no_toolbar||me.hide_toolbar){me.$w.find('.list-toolbar-wrapper').toggle(false);}},make_new_doc:function(new_doctype){new_doc(new_doctype);},make_filters:function(){this.filter_list=new wn.ui.FilterList({listobj:this,$parent:this.$w.find('.list-filters').toggle(true),doctype:this.doctype,filter_fields:this.filter_fields});},clear:function(){this.data=[];this.$w.find('.result-list').empty();this.$w.find('.result').toggle(true);this.$w.find('.no-result').toggle(false);this.start=0;},run:function(){var me=this;var a0=arguments[0];var a1=arguments[1];if(a0&&typeof a0=='function') this.onrun=a0;if(a0&&a0.callback) this.onrun=a0.callback;if(!a1&&!(a0&&a0.append)) -this.start=0;me.set_working(true);wn.call({method:this.opts.method||'webnotes.widgets.query_builder.runquery',args:this.get_call_args(a0),callback:function(r){me.set_working(false);me.render_results(r)},no_spinner:this.opts.no_loading});},set_working:function(flag){this.$w.find('.img-load').toggle(flag);},get_call_args:function(opts){if(!this.method){this.query=this.get_query?this.get_query():this.query;this.add_limits();var args={query_max:this.query_max,as_dict:1} -args.simple_query=this.query;}else{var args={limit_start:this.start,limit_page_length:this.page_length}} +this.start=0;me.set_working(true);wn.call({method:this.opts.method||'webnotes.widgets.query_builder.runquery',args:this.get_call_args(a0),callback:function(r){me.set_working(false);me.render_results(r)},no_spinner:this.opts.no_loading});},set_working:function(flag){this.$w.find('.img-load').toggle(flag);},get_call_args:function(opts){if(!this.method){var query=this.get_query?this.get_query():this.query;query=this.add_limits(query);var args={query_max:this.query_max,as_dict:1} +args.simple_query=query;}else{var args={limit_start:this.start,limit_page_length:this.page_length}} if(this.args) $.extend(args,this.args) if(this.get_args){$.extend(args,this.get_args(opts));} return args;},render_results:function(r){if(this.start==0)this.clear();this.$w.find('.btn-more').toggle(false);if(r.message)r.values=r.message;if(r.values&&r.values.length){this.data=this.data.concat(r.values);this.render_list(r.values);this.update_paging(r.values);}else{if(this.start==0){this.$w.find('.result').toggle(false);this.$w.find('.no-result').toggle(true);}} -if(this.onrun)this.onrun();if(this.callback)this.callback(r);},render_list:function(values){var m=Math.min(values.length,this.page_length);for(var i=0;i=this.page_length){this.$w.find('.btn-more').toggle(true);this.start+=this.page_length;}},add_row:function(){return $('
').appendTo(this.$w.find('.result-list')).get(0);},refresh:function(){this.run();},add_limits:function(){this.query+=' LIMIT '+this.start+','+(this.page_length+1);}}); +if(this.onrun)this.onrun();if(this.callback)this.callback(r);},render_list:function(values){var m=Math.min(values.length,this.page_length);for(var i=0;i=this.page_length){this.$w.find('.btn-more').toggle(true);this.start+=this.page_length;}},add_row:function(){return $('
').appendTo(this.$w.find('.result-list')).get(0);},refresh:function(){this.run();},add_limits:function(query){query+=' LIMIT '+this.start+','+(this.page_length+1);return query}}); /* * lib/js/wn/ui/filters.js */ diff --git a/public/web.py b/public/web.py index 751d76206a..6f3569e327 100755 --- a/public/web.py +++ b/public/web.py @@ -23,71 +23,41 @@ def init(): webnotes.connect() def respond(): - html = get_html() + import webnotes + try: + if 'page' in webnotes.form_dict: + html = get_html(webnotes.form_dict['page']) + else: + # show home page + html = get_html('index') + except Exception, e: + html = get_html('404') + print "Content-Type: text/html" print print html.encode('utf-8') -def get_html(): +def scrub_page_name(page_name): + if page_name.endswith('.html'): + page_name = page_name[:-5] + return page_name + +def get_html(page_name): import webnotes - from webnotes.model.doc import Document - # Get web page - outer_env_dict = get_outer_env() - try: - if 'page' in webnotes.form_dict: - page_name = webnotes.form_dict['page'] - if page_name.endswith('.html'): - page_name = page_name[:-5] - - if page_name.startswith('blog'): - raise Exception - #page_name = - else: - page_name = get_web_page_name(page_name) - else: - from webnotes.cms import get_home_page - page_name = get_home_page('Guest') - - page = Document('Web Page', page_name) - page.fields.update(outer_env_dict) - - return build_html(page.fields, "page: %s" % page_name) - - except Exception, e: - return build_html(outer_env_dict, "error: %s" % webnotes.getTraceback(), '404.html') - -def get_outer_env(): - """env dict for outer template""" - import webnotes - return { - 'top_bar_items': webnotes.conn.sql("""select * from `tabTop Bar Item` - where parent='Website Settings' and parentfield='top_bar_items' - order by idx asc""", as_dict=1), + import website.web_cache + page_name = scrub_page_name(page_name) - 'footer_items': webnotes.conn.sql("""select * from `tabTop Bar Item` - where parent='Website Settings' and parentfield='footer_items' - order by idx asc""", as_dict=1), - - 'brand': webnotes.conn.get_value('Website Settings', None, 'brand_html'), - 'copyright': webnotes.conn.get_value('Website Settings', None, 'copyright'), - } - -def build_html(args, comments, template='page.html'): - """build html using jinja2 templates""" - from webnotes.utils import cstr - from jinja2 import Environment, FileSystemLoader - jenv = Environment(loader = FileSystemLoader('../erpnext/website/templates')) + if page_name == '404': + comments = """error: %s""" % webnotes.getTraceback() + template = '404.html' + else: + comments = """page: %s""" % page_name + template = 'page.html' + + html = website.web_cache.load_from_web_cache(page_name, comments, template) - html = jenv.get_template(template).render(args) - html += "\n" % cstr(comments) return html -def get_web_page_name(page_name): - """get page by shortname""" - import webnotes - return webnotes.conn.sql("""select name from `tabWeb Page` where page_name=%s""", page_name)[0][0] - - if __name__=="__main__": init() respond()