135 lines
5.1 KiB
Python
135 lines
5.1 KiB
Python
import ast
|
|
|
|
import werkzeug
|
|
|
|
from odoo.addons.http_routing.models.ir_http import slug, unslug
|
|
from odoo.http import Controller, request, route
|
|
from odoo.osv.expression import AND, OR
|
|
|
|
|
|
class ModelPageController(Controller):
|
|
pager_step = 20
|
|
|
|
@route([
|
|
"/model/<string:page_name_slugified>",
|
|
"/model/<string:page_name_slugified>/page/<int:page_number>",
|
|
"/model/<string:page_name_slugified>/<string:record_slug>",
|
|
], website=True, auth="public")
|
|
def generic_model(self, page_name_slugified=None, page_number=1, record_slug=None, **searches):
|
|
if not page_name_slugified:
|
|
raise werkzeug.exceptions.NotFound()
|
|
|
|
website = request.website
|
|
|
|
page_type = "listing"
|
|
if record_slug is not None:
|
|
page_type = "single"
|
|
|
|
website_page_domain = AND([
|
|
[("page_type", "=", page_type)],
|
|
[("name_slugified", "=", page_name_slugified)],
|
|
[("website_published", "=", True)],
|
|
website.website_domain(),
|
|
])
|
|
|
|
page = request.env["website.controller.page"].search(website_page_domain, limit=1)
|
|
if not page:
|
|
raise werkzeug.exceptions.NotFound()
|
|
|
|
view = page.sudo().view_id
|
|
if not view:
|
|
raise werkzeug.exceptions.NotFound()
|
|
|
|
target_model_name = page.sudo().model_id.model
|
|
Model = request.env[target_model_name]
|
|
if not Model.check_access_rights("read", raise_exception=False):
|
|
raise werkzeug.exceptions.Forbidden()
|
|
|
|
rec_domain = ast.literal_eval(page.record_domain or "[]")
|
|
domains = [rec_domain]
|
|
|
|
if record_slug:
|
|
_, res_id = unslug(record_slug)
|
|
record = Model.browse(res_id).filtered_domain(AND(domains))
|
|
# We check for slug matching because we are not entirely sure
|
|
# that we end up seeing record for the right model
|
|
# i.e. in case of a redirect when a "single" page doesn't match the listing
|
|
if not record.exists() or record_slug != slug(record):
|
|
raise werkzeug.exceptions.NotFound()
|
|
|
|
listing = request.env["website.controller.page"].search(AND([
|
|
[("name_slugified", "=", page_name_slugified)],
|
|
[("page_type", "=", "listing")],
|
|
[("model", "=", target_model_name)],
|
|
website.website_domain(),
|
|
]))
|
|
|
|
render_context = {
|
|
"main_object": page.sudo(), # The template reads some fields that are actually on view
|
|
"record": record,
|
|
"listing": {
|
|
'href': '.',
|
|
'name': listing.page_name
|
|
} if listing else False
|
|
}
|
|
return request.render(view.key, render_context)
|
|
|
|
layout_mode = request.session.get(f'website_{view.id}_layout_mode')
|
|
if not layout_mode:
|
|
# use the default layout set for this page
|
|
layout_mode = page.default_layout
|
|
|
|
searches.setdefault("search", "")
|
|
searches.setdefault("order", "create_date desc")
|
|
|
|
single_record_pages = request.env["website.controller.page"].search(AND([
|
|
[("page_type", "=", "single")],
|
|
[("model", "=", target_model_name)],
|
|
website.website_domain(),
|
|
]))
|
|
|
|
single_record_page = single_record_pages.filtered(lambda rec: rec.name_slugified == page_name_slugified)
|
|
if single_record_page:
|
|
single_record_page = single_record_page[0]
|
|
else:
|
|
single_record_page = single_record_pages[:1]
|
|
|
|
def record_to_url(record):
|
|
if not single_record_page:
|
|
return None
|
|
return "/model/%s/%s" % (single_record_page.name_slugified, slug(record))
|
|
|
|
if searches["search"]:
|
|
# _name_search doesn't take offset, we reimplement the logic that builds the name domain here
|
|
search_fnames = set(Model._rec_names_search or ([Model._rec_name] if Model._rec_name else []))
|
|
if "seo_name" in Model._fields:
|
|
search_fnames.add("seo_name")
|
|
if search_fnames:
|
|
name_domain = OR([[(name_field, "ilike", searches["search"])] for name_field in search_fnames])
|
|
domains.append(name_domain)
|
|
|
|
search_count = Model.search_count(AND(domains))
|
|
pager = website.pager(
|
|
url=f"/model/{page.name_slugified}",
|
|
url_args=searches,
|
|
total=search_count,
|
|
page=page_number,
|
|
step=self.pager_step,
|
|
scope=5,
|
|
)
|
|
|
|
records = Model.search(AND(domains), limit=self.pager_step, offset=self.pager_step * (page_number - 1), order=searches["order"])
|
|
|
|
render_context = {
|
|
"order_by": searches["order"],
|
|
"search": searches["search"],
|
|
"search_count": search_count,
|
|
"pager": pager,
|
|
"records": records,
|
|
"record_to_url": record_to_url,
|
|
"layout_mode": layout_mode,
|
|
"view_id": view.id,
|
|
"main_object": page.sudo(), # The template reads some fields that are actually on view
|
|
}
|
|
return request.render(view.key, render_context)
|