Просмотр исходного кода

[enhance] Web View settings in DocType (#2798)

* [enhance] add web view settings doctype

* [enhance] add web view settings doctype

* [fix] default for checks (?)

* [fix] framework json

* [fix] missing return

* [fix] hooks for website_generators
version-14
Rushabh Mehta 8 лет назад
committed by GitHub
Родитель
Сommit
6dff729d88
18 измененных файлов: 631 добавлений и 251 удалений
  1. +4
    -2
      frappe/core/doctype/docfield/docfield.json
  2. +30
    -1
      frappe/core/doctype/docperm/docperm.json
  3. +1
    -1
      frappe/core/doctype/doctype/boilerplate/controller.js
  4. +1
    -1
      frappe/core/doctype/doctype/boilerplate/controller.py
  5. +7
    -0
      frappe/core/doctype/doctype/boilerplate/templates/controller.html
  6. +4
    -0
      frappe/core/doctype/doctype/boilerplate/templates/controller_row.html
  7. +1
    -3
      frappe/core/doctype/doctype/boilerplate/test_controller.py
  8. +442
    -177
      frappe/core/doctype/doctype/doctype.json
  9. +18
    -8
      frappe/core/doctype/doctype/doctype.py
  10. +4
    -1
      frappe/data/Framework.sql
  11. +15
    -1
      frappe/model/meta.py
  12. +8
    -4
      frappe/modules/utils.py
  13. +3
    -3
      frappe/patches.txt
  14. +3
    -0
      frappe/website/context.py
  15. +20
    -5
      frappe/website/render.py
  16. +34
    -38
      frappe/website/router.py
  17. +25
    -5
      frappe/website/website_generator.py
  18. +11
    -1
      frappe/www/list.py

+ 4
- 2
frappe/core/doctype/docfield/docfield.json Просмотреть файл

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"autoname": "hash", "autoname": "hash",
@@ -470,7 +471,7 @@
"columns": 0, "columns": 0,
"description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.", "description": "For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.",
"fieldname": "options", "fieldname": "options",
"fieldtype": "Text",
"fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@@ -1278,6 +1279,7 @@
"unique": 0 "unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"idx": 1, "idx": 1,
@@ -1288,7 +1290,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-02-22 21:43:00.771400",
"modified": "2017-03-03 16:18:13.523592",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Core", "module": "Core",
"name": "DocField", "name": "DocField",


+ 30
- 1
frappe/core/doctype/docperm/docperm.json Просмотреть файл

@@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"autoname": "hash", "autoname": "hash",
@@ -8,6 +9,7 @@
"custom": 0, "custom": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1, "editable_grid": 1,
"fields": [ "fields": [
{ {
@@ -21,6 +23,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Role and Level", "label": "Role and Level",
@@ -48,6 +51,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Role", "label": "Role",
@@ -81,6 +85,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Apply User Permissions", "label": "Apply User Permissions",
@@ -109,6 +114,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "If user is the owner", "label": "If user is the owner",
@@ -137,6 +143,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"length": 0, "length": 0,
@@ -164,6 +171,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Level", "label": "Level",
@@ -197,6 +205,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "User Permission DocTypes", "label": "User Permission DocTypes",
@@ -224,6 +233,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Permissions", "label": "Permissions",
@@ -252,6 +262,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Read", "label": "Read",
@@ -284,6 +295,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Write", "label": "Write",
@@ -316,6 +328,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Create", "label": "Create",
@@ -348,6 +361,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Delete", "label": "Delete",
@@ -375,6 +389,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"length": 0, "length": 0,
@@ -401,6 +416,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Submit", "label": "Submit",
@@ -432,6 +448,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Cancel", "label": "Cancel",
@@ -463,6 +480,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Amend", "label": "Amend",
@@ -494,6 +512,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Additional Permissions", "label": "Additional Permissions",
@@ -522,6 +541,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Report", "label": "Report",
@@ -552,6 +572,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Export", "label": "Export",
@@ -579,6 +600,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Import", "label": "Import",
@@ -607,6 +629,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Set User Permissions", "label": "Set User Permissions",
@@ -634,6 +657,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"length": 0, "length": 0,
@@ -661,6 +685,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Share", "label": "Share",
@@ -690,6 +715,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Print", "label": "Print",
@@ -718,6 +744,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Email", "label": "Email",
@@ -735,6 +762,7 @@
"unique": 0 "unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"idx": 1, "idx": 1,
@@ -745,7 +773,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-01-11 04:21:44.249780",
"modified": "2017-03-03 16:18:18.890031",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Core", "module": "Core",
"name": "DocPerm", "name": "DocPerm",
@@ -754,6 +782,7 @@
"quick_entry": 0, "quick_entry": 0,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_order": "ASC", "sort_order": "ASC",
"track_changes": 0, "track_changes": 0,
"track_seen": 0 "track_seen": 0

+ 1
- 1
frappe/core/doctype/doctype/boilerplate/controller.js Просмотреть файл

@@ -1,4 +1,4 @@
// Copyright (c) 2016, {app_publisher} and contributors
// Copyright (c) {year}, {app_publisher} and contributors
// For license information, please see license.txt // For license information, please see license.txt


frappe.ui.form.on('{doctype}', {{ frappe.ui.form.on('{doctype}', {{


+ 1
- 1
frappe/core/doctype/doctype/boilerplate/controller.py Просмотреть файл

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2015, {app_publisher} and contributors
# Copyright (c) {year}, {app_publisher} and contributors
# For license information, please see license.txt # For license information, please see license.txt


from __future__ import unicode_literals from __future__ import unicode_literals


+ 7
- 0
frappe/core/doctype/doctype/boilerplate/templates/controller.html Просмотреть файл

@@ -0,0 +1,7 @@
{{% extends "templates/web.html" %}}

{{% block page_content %}}
<h1>{{{{ title }}}}</h1>
{{% endblock %}}

<!-- this is a sample default web page template -->

+ 4
- 0
frappe/core/doctype/doctype/boilerplate/templates/controller_row.html Просмотреть файл

@@ -0,0 +1,4 @@
<div>
<a href={{{{ route }}}}>{{{{ title }}}}</a>
</div>
<!-- this is a sample default list template -->

+ 1
- 3
frappe/core/doctype/doctype/boilerplate/test_controller.py Просмотреть файл

@@ -1,12 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (c) 2015, {app_publisher} and Contributors
# Copyright (c) {year}, {app_publisher} and Contributors
# See license.txt # See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals


import frappe import frappe
import unittest import unittest


# test_records = frappe.get_test_records('{doctype}')

class Test{classname}(unittest.TestCase): class Test{classname}(unittest.TestCase):
pass pass

+ 442
- 177
frappe/core/doctype/doctype/doctype.json
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 18
- 8
frappe/core/doctype/doctype/doctype.py Просмотреть файл

@@ -15,6 +15,7 @@ from frappe.custom.doctype.property_setter.property_setter import make_property_
from frappe.desk.notifications import delete_notification_count_for from frappe.desk.notifications import delete_notification_count_for
from frappe.modules import make_boilerplate from frappe.modules import make_boilerplate
from frappe.model.db_schema import validate_column_name from frappe.model.db_schema import validate_column_name
import frappe.website.render


class InvalidFieldNameError(frappe.ValidationError): pass class InvalidFieldNameError(frappe.ValidationError): pass


@@ -122,15 +123,13 @@ class DocType(Document):


def validate_website(self): def validate_website(self):
"""Ensure that website generator has field 'route'""" """Ensure that website generator has field 'route'"""
from frappe.model.base_document import get_controller
try:
controller = get_controller(self.name)
except:
controller = None

if controller and getattr(controller, 'website', None):
if self.has_web_view:
# route field must be present
if not 'route' in [d.fieldname for d in self.fields]: if not 'route' in [d.fieldname for d in self.fields]:
frappe.throw('Field "route" is mandatory for Website Generator pages', title='Missing Field')
frappe.throw('Field "route" is mandatory for Web Views', title='Missing Field')

# clear website cache
frappe.website.render.clear_cache()


def change_modified_of_parent(self): def change_modified_of_parent(self):
"""Change the timestamp of parent DocType if the current one is a child to clear caches.""" """Change the timestamp of parent DocType if the current one is a child to clear caches."""
@@ -297,6 +296,10 @@ class DocType(Document):
if not self.istable: if not self.istable:
make_boilerplate("controller.js", self.as_dict()) make_boilerplate("controller.js", self.as_dict())


if self.has_web_view:
make_boilerplate('templates/controller.html', self.as_dict())
make_boilerplate('templates/controller_row.html', self.as_dict())

def make_amendable(self): def make_amendable(self):
"""If is_submittable is set, add amended_from docfields.""" """If is_submittable is set, add amended_from docfields."""
if self.is_submittable: if self.is_submittable:
@@ -497,6 +500,12 @@ def validate_fields(meta):
if df[0].fieldtype != 'Attach Image': if df[0].fieldtype != 'Attach Image':
frappe.throw(_("Image field must be of type Attach Image"), InvalidFieldNameError) frappe.throw(_("Image field must be of type Attach Image"), InvalidFieldNameError)


def check_is_published_field(meta):
if not meta.is_published_field:
return

if meta.is_published_field not in fieldname_list:
frappe.throw(_("Is Published Field must be a valid fieldname"), InvalidFieldNameError)


def check_timeline_field(meta): def check_timeline_field(meta):
if not meta.timeline_field: if not meta.timeline_field:
@@ -549,6 +558,7 @@ def validate_fields(meta):
check_search_fields(meta) check_search_fields(meta)
check_title_field(meta) check_title_field(meta)
check_timeline_field(meta) check_timeline_field(meta)
check_is_published_field(meta)
check_sort_field(meta) check_sort_field(meta)


def validate_permissions_for_doctype(doctype, for_remove=False): def validate_permissions_for_doctype(doctype, for_remove=False):


+ 4
- 1
frappe/data/Framework.sql Просмотреть файл

@@ -141,7 +141,6 @@ CREATE TABLE `tabDocType` (
`max_attachments` int(11) NOT NULL DEFAULT 0, `max_attachments` int(11) NOT NULL DEFAULT 0,
`print_outline` varchar(255) DEFAULT NULL, `print_outline` varchar(255) DEFAULT NULL,
`read_only_onload` int(1) NOT NULL DEFAULT 0, `read_only_onload` int(1) NOT NULL DEFAULT 0,
`in_dialog` int(1) NOT NULL DEFAULT 0,
`document_type` varchar(255) DEFAULT NULL, `document_type` varchar(255) DEFAULT NULL,
`icon` varchar(255) DEFAULT NULL, `icon` varchar(255) DEFAULT NULL,
`tag_fields` varchar(255) DEFAULT NULL, `tag_fields` varchar(255) DEFAULT NULL,
@@ -155,6 +154,10 @@ CREATE TABLE `tabDocType` (
`custom` int(1) NOT NULL DEFAULT 0, `custom` int(1) NOT NULL DEFAULT 0,
`beta` int(1) NOT NULL DEFAULT 0, `beta` int(1) NOT NULL DEFAULT 0,
`image_view` int(1) NOT NULL DEFAULT 0, `image_view` int(1) NOT NULL DEFAULT 0,
`has_web_view` int(1) NOT NULL DEFAULT 0,
`allow_guest_to_view` int(1) NOT NULL DEFAULT 0,
`route` varchar(255) DEFAULT NULL,
`is_published_field` varchar(255) DEFAULT NULL,
PRIMARY KEY (`name`), PRIMARY KEY (`name`),
KEY `parent` (`parent`) KEY `parent` (`parent`)
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


+ 15
- 1
frappe/model/meta.py Просмотреть файл

@@ -16,7 +16,7 @@ Example:
''' '''


from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, json
import frappe, json, os
from frappe.utils import cstr, cint from frappe.utils import cstr, cint
from frappe.model import default_fields, no_value_fields, optional_fields from frappe.model import default_fields, no_value_fields, optional_fields
from frappe.model.document import Document from frappe.model.document import Document
@@ -352,6 +352,20 @@ class Meta(Document):


return data return data


def get_row_template(self):
return self.get_web_template(suffix='_row')

def get_web_template(self, suffix=''):
'''Returns the relative path of the row template for this doctype'''
module_name = frappe.scrub(self.module)
doctype = frappe.scrub(self.name)
template_path = frappe.get_module_path(module_name, 'doctype',
doctype, 'templates', doctype + suffix + '.html')
if os.path.exists(template_path):
return '{module_name}/doctype/{doctype_name}/templates/{doctype_name}{suffix}.html'.format(
module_name = module_name, doctype_name = doctype, suffix=suffix)
return None

doctype_table_fields = [ doctype_table_fields = [
frappe._dict({"fieldname": "fields", "options": "DocField"}), frappe._dict({"fieldname": "fields", "options": "DocField"}),
frappe._dict({"fieldname": "permissions", "options": "DocPerm"}) frappe._dict({"fieldname": "permissions", "options": "DocPerm"})


+ 8
- 4
frappe/modules/utils.py Просмотреть файл

@@ -19,12 +19,11 @@ def export_module_json(doc, is_standard, module):
if (not frappe.flags.in_import and getattr(frappe.get_conf(),'developer_mode', 0) if (not frappe.flags.in_import and getattr(frappe.get_conf(),'developer_mode', 0)
and is_standard): and is_standard):
from frappe.modules.export_file import export_to_files from frappe.modules.export_file import export_to_files
from frappe.modules import get_module_path


# json # json
export_to_files(record_list=[[doc.doctype, doc.name]], record_module=module) export_to_files(record_list=[[doc.doctype, doc.name]], record_module=module)


path = os.path.join(get_module_path(module), scrub(doc.doctype),
path = os.path.join(frappe.get_module_path(module), scrub(doc.doctype),
scrub(doc.name), scrub(doc.name)) scrub(doc.name), scrub(doc.name))


return path return path
@@ -209,6 +208,8 @@ def make_boilerplate(template, doc, opts=None):
template_name = template.replace("controller", scrub(doc.name)) template_name = template.replace("controller", scrub(doc.name))
target_file_path = os.path.join(target_path, template_name) target_file_path = os.path.join(target_path, template_name)


if not doc: doc = {}

app_publisher = get_app_publisher(doc.module) app_publisher = get_app_publisher(doc.module)


if not os.path.exists(target_file_path): if not os.path.exists(target_file_path):
@@ -219,6 +220,9 @@ def make_boilerplate(template, doc, opts=None):
with open(os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype), with open(os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype),
"boilerplate", template), 'r') as source: "boilerplate", template), 'r') as source:
target.write(frappe.utils.encode( target.write(frappe.utils.encode(
frappe.utils.cstr(source.read()).format(app_publisher=app_publisher,
classname=doc.name.replace(" ", ""), doctype=doc.name, **opts)
frappe.utils.cstr(source.read()).format(
app_publisher=app_publisher,
year=frappe.utils.nowdate()[:4],
classname=doc.name.replace(" ", ""),
doctype=doc.name, **opts)
)) ))

+ 3
- 3
frappe/patches.txt Просмотреть файл

@@ -6,9 +6,9 @@ frappe.patches.v7_1.rename_scheduler_log_to_error_log
frappe.patches.v6_1.rename_file_data frappe.patches.v6_1.rename_file_data
frappe.patches.v7_0.re_route #2016-06-27 frappe.patches.v7_0.re_route #2016-06-27
frappe.patches.v7_2.remove_in_filter frappe.patches.v7_2.remove_in_filter
execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2016-10-17
execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2017-01-06
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2014-06-24
execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2017-03-03
execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2017-03-03
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2017-03-03
execute:frappe.reload_doc('core', 'doctype', 'custom_docperm') execute:frappe.reload_doc('core', 'doctype', 'custom_docperm')
frappe.patches.v7_2.setup_custom_perms #2017-01-19 frappe.patches.v7_2.setup_custom_perms #2017-01-19
execute:frappe.reload_doc('core', 'doctype', 'role') execute:frappe.reload_doc('core', 'doctype', 'role')


+ 3
- 0
frappe/website/context.py Просмотреть файл

@@ -83,6 +83,9 @@ def build_context(context):
if ret: if ret:
context.update(ret) context.update(ret)


if not context.template:
context.template = context.doc.meta.get_web_template()

for prop in ("no_cache", "no_sitemap"): for prop in ("no_cache", "no_sitemap"):
if not prop in context: if not prop in context:
context[prop] = getattr(context.doc, prop, False) context[prop] = getattr(context.doc, prop, False)


+ 20
- 5
frappe/website/render.py Просмотреть файл

@@ -169,7 +169,7 @@ def resolve_path(path):


def resolve_from_map(path): def resolve_from_map(path):
m = Map([Rule(r["from_route"], endpoint=r["to_route"], defaults=r.get("defaults")) m = Map([Rule(r["from_route"], endpoint=r["to_route"], defaults=r.get("defaults"))
for r in frappe.get_hooks("website_route_rules")])
for r in get_website_rules()])
urls = m.bind_to_environ(frappe.local.request.environ) urls = m.bind_to_environ(frappe.local.request.environ)
try: try:
endpoint, args = urls.match("/" + path) endpoint, args = urls.match("/" + path)
@@ -184,6 +184,18 @@ def resolve_from_map(path):


return path return path


def get_website_rules():
'''Get website route rules from hooks and DocType route'''
def _get():
rules = frappe.get_hooks("website_route_rules")
for d in frappe.get_all('DocType', 'name, route', dict(has_web_view=1)):
if d.route:
rules.append(dict(from_route = '/' + d.route.strip('/'), to_route=d.name))

return rules

return frappe.cache().get_value('website_route_rules', _get)

def set_content_type(response, data, path): def set_content_type(response, data, path):
if isinstance(data, dict): if isinstance(data, dict):
response.mimetype = 'application/json' response.mimetype = 'application/json'
@@ -204,20 +216,23 @@ def set_content_type(response, data, path):
return data return data


def clear_cache(path=None): def clear_cache(path=None):
'''Clear website caches

:param path: (optional) for the given path'''
frappe.cache().delete_value("website_generator_routes") frappe.cache().delete_value("website_generator_routes")
delete_page_cache(path) delete_page_cache(path)
frappe.cache().delete_value("website_404") frappe.cache().delete_value("website_404")
if not path: if not path:
clear_sitemap() clear_sitemap()
frappe.clear_cache("Guest") frappe.clear_cache("Guest")
frappe.cache().delete_value("portal_menu_items")
frappe.cache().delete_value("home_page")
for key in ('portal_menu_items', 'home_page', 'website_route_rules',
'doctypes_with_web_view'):
frappe.cache().delete_value(key)


for method in frappe.get_hooks("website_clear_cache"): for method in frappe.get_hooks("website_clear_cache"):
frappe.get_attr(method)(path) frappe.get_attr(method)(path)


def render_403(e, pathname): def render_403(e, pathname):
path = "message"
frappe.local.message = cstr(e.message) frappe.local.message = cstr(e.message)
frappe.local.message_title = _("Not Permitted") frappe.local.message_title = _("Not Permitted")
frappe.local.response['context'] = dict( frappe.local.response['context'] = dict(
@@ -225,7 +240,7 @@ def render_403(e, pathname):
primary_action = '/login', primary_action = '/login',
primary_label = _('Login') primary_label = _('Login')
) )
return render_page(path), e.http_status_code
return render_page("message"), e.http_status_code


def get_doctype_from_path(path): def get_doctype_from_path(path):
doctypes = frappe.db.sql_list("select name from tabDocType") doctypes = frappe.db.sql_list("select name from tabDocType")


+ 34
- 38
frappe/website/router.py Просмотреть файл

@@ -90,29 +90,30 @@ def get_all_page_context_from_doctypes():


def get_page_info_from_doctypes(path=None): def get_page_info_from_doctypes(path=None):
routes = {} routes = {}
for app in frappe.get_installed_apps():
for doctype in frappe.get_hooks("website_generators", app_name = app):
condition = ""
values = []
controller = get_controller(doctype)

if controller.website.condition_field:
condition ="where {0}=1".format(controller.website.condition_field)

if path:
condition += ' {0} `route`=%s limit 1'.format('and' if 'where' in condition else 'where')
values.append(path)

try:
for r in frappe.db.sql("""select route, name, modified from `tab{0}`
{1}""".format(doctype, condition), values=values, as_dict=True):
routes[r.route] = {"doctype": doctype, "name": r.name, "modified": r.modified}

# just want one path, return it!
if path:
return routes[r.route]
except Exception, e:
if e.args[0]!=1054: raise e
for doctype in get_doctypes_with_web_view():
condition = ""
values = []
controller = get_controller(doctype)
meta = frappe.get_meta(doctype)
condition_field = meta.is_published_field or controller.website.condition_field

if condition_field:
condition ="where {0}=1".format(condition_field)

if path:
condition += ' {0} `route`=%s limit 1'.format('and' if 'where' in condition else 'where')
values.append(path)

try:
for r in frappe.db.sql("""select route, name, modified from `tab{0}`
{1}""".format(doctype, condition), values=values, as_dict=True):
routes[r.route] = {"doctype": doctype, "name": r.name, "modified": r.modified}

# just want one path, return it!
if path:
return routes[r.route]
except Exception, e:
if e.args[0]!=1054: raise e


return routes return routes


@@ -316,18 +317,13 @@ def load_properties(page_info):
if "<!-- no-sitemap -->" in page_info.source: if "<!-- no-sitemap -->" in page_info.source:
page_info.no_cache = 1 page_info.no_cache = 1


def process_generators(func):
for app in frappe.get_installed_apps():
for doctype in frappe.get_hooks("website_generators", app_name = app):
order_by = "name asc"
condition_field = None
controller = get_controller(doctype)

if "condition_field" in controller.website:
condition_field = controller.website['condition_field']
if 'order_by' in controller.website:
order_by = controller.website['order_by']

val = func(doctype, condition_field, order_by)
if val:
return val
def get_doctypes_with_web_view():
'''Return doctypes with Has Web View or set via hooks'''
def _get():
installed_apps = frappe.get_installed_apps()
doctypes = frappe.get_hooks("website_generators")
doctypes += [d.name for d in frappe.get_all('DocType', 'name, module',
dict(has_web_view=1)) if frappe.local.module_app[frappe.scrub(d.module)] in installed_apps]
return doctypes

return frappe.cache().get_value('doctypes_with_web_view', _get)

+ 25
- 5
frappe/website/website_generator.py Просмотреть файл

@@ -43,7 +43,20 @@ class WebsiteGenerator(Document):
return self.scrubbed_title() return self.scrubbed_title()


def scrubbed_title(self): def scrubbed_title(self):
return self.scrub(self.get(self.get_website_properties('page_title_field', 'title')))
return self.scrub(self.get(self.get_title_field()))

def get_title_field(self):
'''return title field from website properties or meta.title_field'''
title_field = self.get_website_properties('page_title_field')
if not title_field:
if self.meta.title_field:
title_field = self.meta.title_field
elif self.meta.has_field('title'):
title_field = 'title'
else:
title_field = 'name'

return title_field


def clear_cache(self): def clear_cache(self):
clear_cache(self.route) clear_cache(self.route)
@@ -60,11 +73,19 @@ class WebsiteGenerator(Document):


def is_website_published(self): def is_website_published(self):
"""Return true if published in website""" """Return true if published in website"""
if self.get_website_properties('condition_field'):
return self.get(self.get_website_properties('condition_field')) and True or False
if self.get_condition_field():
return self.get(self.get_condition_field()) and True or False
else: else:
return True return True


def get_condition_field(self):
condition_field = self.get_website_properties('condition_field')
if not condition_field:
if self.meta.is_published_field:
condition_field = self.meta.is_published_field

return condition_field

def get_page_info(self): def get_page_info(self):
route = frappe._dict() route = frappe._dict()
route.update({ route.update({
@@ -79,7 +100,6 @@ class WebsiteGenerator(Document):
route.update(self.get_website_properties()) route.update(self.get_website_properties())


if not route.page_title: if not route.page_title:
route.page_title = self.get(self.get_website_properties('page_title_field'), 'title') \
or self.get('name')
route.page_title = self.get(self.get_title_field())


return route return route

+ 11
- 1
frappe/www/list.py Просмотреть файл

@@ -45,10 +45,16 @@ def get(doctype, txt=None, limit_start=0, limit=20, **kwargs):


_get_list = list_context.get_list or get_list _get_list = list_context.get_list or get_list


raw_result = _get_list(doctype=doctype, txt=txt, filters=filters,
kwargs = dict(doctype=doctype, txt=txt, filters=filters,
limit_start=limit_start, limit_page_length=limit_page_length + 1, limit_start=limit_start, limit_page_length=limit_page_length + 1,
order_by = list_context.order_by or 'modified desc') order_by = list_context.order_by or 'modified desc')


# allow guest if flag is set
if not list_context.get_list and (list_context.allow_guest or meta.allow_guest_to_view):
kwargs['ignore_permissions'] = True

raw_result = _get_list(**kwargs)

if not raw_result: return {"result": []} if not raw_result: return {"result": []}


show_more = len(raw_result) > limit_page_length show_more = len(raw_result) > limit_page_length
@@ -123,6 +129,10 @@ def get_list_context(context, doctype):
if out: if out:
list_context = out list_context = out


# get path from '/templates/' folder of the doctype
if not list_context.row_template:
list_context.row_template = frappe.get_meta(doctype).get_row_template()

# is web form, show the default web form filters # is web form, show the default web form filters
# which is only the owner # which is only the owner
if frappe.form_dict.web_form_name: if frappe.form_dict.web_form_name:


Загрузка…
Отмена
Сохранить