# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # MIT License. See license.txt from __future__ import unicode_literals import frappe from frappe.utils import now from frappe.model.document import Document from frappe.model.naming import append_number_if_name_exists from frappe.website.utils import cleanup_page_name, get_home_page from frappe.website.render import clear_cache from frappe.modules import get_module_name from frappe.website.router import get_page_route class WebsiteGenerator(Document): website = frappe._dict( page_title_field = "name" ) def autoname(self): if self.meta.autoname != "hash": self.name = self.get_page_name() append_number_if_name_exists(self) def onload(self): self.get("__onload").update({ "is_website_generator": True, "website_route": self.get_route(), "published": self.website_published() }) def validate(self): self.set_parent_website_route() if not self.page_name: self.page_name = self.make_page_name() if self.meta.get_field("page_name") and not self.get("__islocal"): current_route = self.get_route() current_page_name = self.page_name # page name changed, rename everything if current_page_name and current_page_name != self.page_name: self.update_routes_of_descendants(current_route) def on_update(self): clear_cache(self.get_route()) if getattr(self, "save_versions", False): frappe.add_version(self) def get_route(self, doc = None): self.get_page_name() return make_route(self) def clear_cache(self): clear_cache(self.get_route()) def get_page_name(self): return self.get_or_make_page_name() def get_or_make_page_name(self): page_name = self.get("page_name") if not page_name: page_name = self.make_page_name() self.set("page_name", page_name) return page_name def make_page_name(self): return cleanup_page_name(self.get(self.page_title_field)) def before_rename(self, oldname, name, merge): self._local = self.get_route() self.clear_cache() def after_rename(self, olddn, newdn, merge): if getattr(self, "_local"): self.update_routes_of_descendants(self._local) self.clear_cache() def on_trash(self): clear_cache(self.get_route()) def website_published(self): if self.website.condition_field: return self.get(self.website.condition_field) and True or False else: return True def set_parent_website_route(self): parent_website_route_field = self.website.parent_website_route_field if parent_website_route_field: field = self.meta.get_field(parent_website_route_field) parent = self.get(parent_website_route_field) if parent: self.parent_website_route = frappe.get_doc(field.options, parent).get_route() def update_routes_of_descendants(self, old_route = None): if not self.is_new() and self.meta.get_field("parent_website_route"): if not old_route: old_route = frappe.get_doc(self.doctype, self.name).get_route() if old_route and old_route != self.get_route(): # clear cache of old routes old_routes = frappe.get_all(self.doctype, fields=["parent_website_route", "page_name"], filters={"parent_website_route": ("like", old_route + "%")}) if old_routes: for old_route in old_routes: clear_cache(make_route(old_route)) frappe.db.sql("""update `tab{0}` set parent_website_route = replace(parent_website_route, %s, %s), modified = %s modified_by = %s where parent_website_route like %s""".format(self.doctype), (old_route, self.get_route(), now(), frappe.session.user, old_route + "%")) def get_website_route(self): route = frappe._dict() route.update({ "doc": self, "page_or_generator": "Generator", "ref_doctype":self.doctype, "idx": self.idx, "docname": self.name, "page_name": self.get_page_name(), "controller": get_module_name(self.doctype, self.meta.module), }) route.update(self.website) if not route.page_title: route.page_title = self.get(self.website.page_title_field) self.update_permissions(route) return route def update_permissions(self, route): if self.meta.get_field("public_read"): route.public_read = self.public_read route.public_write = self.public_write else: route.public_read = 1 def get_parents(self, context): # already set if context.parents: return context.parents # home_page = get_home_page() parents = [] me = self while me: _parent_field = me.website.parent_website_route_field _parent_val = me.get(_parent_field) if _parent_field else None # if no parent and not home page, then parent is home page # if not _parent_val and me.get_route() != home_page: # _parent_val = home_page if _parent_val: df = me.meta.get_field(_parent_field) if not df: break parent_doc = frappe.get_doc(df.options, _parent_val) if not parent_doc.website_published(): break if parent_doc: parent_info = frappe._dict(name = parent_doc.get_route(), title= parent_doc.get(parent_doc.website.page_title_field or "name")) else: parent_info = frappe._dict(name=self.parent_website_route, title=self.parent_website_route.replace("_", " ").title()) if parent_info.name in [p.name for p in parents]: raise frappe.ValidationError, "Recursion in parent link" parents.append(parent_info) me = parent_doc else: # parent route is a page e.g. "blog" if me.get("parent_website_route"): page_route = get_page_route(me.parent_website_route) if page_route: parents.append(frappe._dict(name = page_route.name, title=page_route.page_title)) me = None parents.reverse() return parents def get_parent(self): parent_website_route_field = self.website.parent_website_route_field if parent_website_route_field: return self.get(parent_website_route_field) def get_children(self, context=None): children = [] route = self.get_route() if route==get_home_page(): children = frappe.db.sql("""select url as name, label as page_title, 1 as public_read from `tabTop Bar Item` where parentfield='sidebar_items' order by idx""", as_dict=True) route = "" if not children and self.meta.get_field("parent_website_route"): children = self.get_children_of(route) if not children and self.parent_website_route: children = self.get_children_of(self.parent_website_route) return children def get_children_of(self, route): children = frappe.db.sql("""select name, page_name, parent_website_route, {title_field} as title from `tab{doctype}` where ifnull(parent_website_route,'')=%s order by {order_by}""".format( doctype = self.doctype, title_field = self.website.page_title_field or "name", order_by = self.website.order_by or "idx asc" ), route, as_dict=True) for c in children: c.name = make_route(c) return children def get_next(self): if self.meta.get_field("parent_website_route") and self.parent_website_route: route = self.get_route() siblings = frappe.get_doc(self.doctype, self.get_parent()).get_children() for i, r in enumerate(siblings): if i < len(siblings) - 1: if route==r.name: return siblings[i+1] else: return frappe._dict() def make_route(doc): parent = doc.get("parent_website_route", "") return ((parent + "/") if parent else "") + doc.page_name