mirror of
https://github.com/OCA/knowledge.git
synced 2025-12-19 11:52:18 -06:00
[MIG] document_page_reference: Migration to 18.0
[FIX]document_page_reference :log warning updated [FIX]document_page_reference: null value issue fixed
This commit is contained in:
@@ -2,57 +2,29 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from odoo import _, api, fields, models, tools
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from markupsafe import Markup
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools.misc import html_escape
|
||||
|
||||
from odoo.addons.http_routing.models.ir_http import slugify
|
||||
from odoo.tools import html_escape
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import re
|
||||
|
||||
from jinja2 import Undefined
|
||||
from jinja2.lexer import name_re as old_name_re
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
|
||||
name_re = re.compile("^%s$" % old_name_re.pattern)
|
||||
|
||||
class Context(SandboxedEnvironment.context_class):
|
||||
def resolve(self, key):
|
||||
res = super().resolve(key)
|
||||
if not isinstance(res, Undefined):
|
||||
return res
|
||||
return self.parent["ref"](key)
|
||||
|
||||
class Environment(SandboxedEnvironment):
|
||||
context_class = Context
|
||||
|
||||
mako_template_env = Environment(
|
||||
block_start_string="<%",
|
||||
block_end_string="%>",
|
||||
variable_start_string="${",
|
||||
variable_end_string="}",
|
||||
comment_start_string="<%doc>",
|
||||
comment_end_string="</%doc>",
|
||||
line_statement_prefix="%",
|
||||
line_comment_prefix="##",
|
||||
trim_blocks=True, # do not output newline after blocks
|
||||
autoescape=False,
|
||||
)
|
||||
except Exception:
|
||||
_logger.error("Jinja2 is not available")
|
||||
env = SandboxedEnvironment(autoescape=False)
|
||||
|
||||
|
||||
class DocumentPage(models.Model):
|
||||
_inherit = "document.page"
|
||||
_description = "Document Page"
|
||||
|
||||
reference = fields.Char(
|
||||
help="Used to find the document, it can contain letters, numbers and _"
|
||||
)
|
||||
content_parsed = fields.Html(compute="_compute_content_parsed")
|
||||
content_parsed = fields.Html(
|
||||
"Parsed Content", compute="_compute_content_parsed", sanitize=False, store=True
|
||||
)
|
||||
|
||||
def get_formview_action(self, access_uid=None):
|
||||
res = super().get_formview_action(access_uid)
|
||||
@@ -60,90 +32,71 @@ class DocumentPage(models.Model):
|
||||
res["views"] = [(view_id, "form")]
|
||||
return res
|
||||
|
||||
@api.depends("history_head")
|
||||
@api.depends("content")
|
||||
def _compute_content_parsed(self):
|
||||
for record in self:
|
||||
content = record.get_content()
|
||||
if content == "<p>" and self.content != "<p>":
|
||||
_logger.error(
|
||||
"Template from page with id = %s cannot be processed correctly"
|
||||
% self.id
|
||||
)
|
||||
content = self.content
|
||||
record.content_parsed = content
|
||||
try:
|
||||
raw = record.content or ""
|
||||
converted = re.sub(r"\$\{([\w_]+)\}", r"{{ resolve('\1') }}", raw)
|
||||
template = env.from_string(converted)
|
||||
rendered = template.render(resolve=record._resolve_reference)
|
||||
record.content_parsed = rendered
|
||||
except Exception as e:
|
||||
_logger.info("Render failed for %s: %s", record.id, e)
|
||||
record.content_parsed = record.content or ""
|
||||
|
||||
@api.constrains("reference")
|
||||
def _check_reference(self):
|
||||
for record in self:
|
||||
if not record.reference:
|
||||
def _check_reference_validity(self):
|
||||
for rec in self:
|
||||
if not rec.reference:
|
||||
continue
|
||||
record._validate_reference(record=record)
|
||||
|
||||
@api.model
|
||||
def _validate_reference(self, record=None, reference=None):
|
||||
if not reference:
|
||||
reference = self.reference
|
||||
if not name_re.match(reference):
|
||||
raise ValidationError(_("Reference is not valid"))
|
||||
uniq_domain = [("reference", "=", reference)]
|
||||
if record:
|
||||
uniq_domain += [("id", "!=", record.id)]
|
||||
if self.search(uniq_domain):
|
||||
raise ValidationError(_("Reference must be unique"))
|
||||
regex = r"^[a-zA-Z_][a-zA-Z0-9_]*$"
|
||||
if not re.match(regex, rec.reference):
|
||||
raise ValidationError(_("Reference is not valid"))
|
||||
domain = [("reference", "=", rec.reference), ("id", "!=", rec.id)]
|
||||
if self.search(domain):
|
||||
raise ValidationError(_("Reference must be unique"))
|
||||
|
||||
def _get_document(self, code):
|
||||
# Hook created in order to add check on other models
|
||||
document = self.search([("reference", "=", code)])
|
||||
if document:
|
||||
return document
|
||||
else:
|
||||
return self.env[self._name]
|
||||
|
||||
def get_reference(self, code):
|
||||
element = self._get_document(code)
|
||||
if self.env.context.get("raw_reference", False):
|
||||
return html_escape(element.display_name)
|
||||
text = """<a href="#" class="oe_direct_line"
|
||||
data-oe-model="%s" data-oe-id="%s" name="%s">%s</a>
|
||||
"""
|
||||
if not element:
|
||||
text = "<i>%s</i>" % text
|
||||
res = text % (
|
||||
element._name,
|
||||
element and element.id or "",
|
||||
code,
|
||||
html_escape(element.display_name or code),
|
||||
)
|
||||
return res
|
||||
|
||||
def _get_template_variables(self):
|
||||
return {"ref": self.get_reference}
|
||||
return self.search([("reference", "=", code)], limit=1)
|
||||
|
||||
def get_content(self):
|
||||
try:
|
||||
content = self.content
|
||||
mako_env = mako_template_env
|
||||
template = mako_env.from_string(tools.ustr(content))
|
||||
return template.render(self._get_template_variables())
|
||||
except Exception:
|
||||
_logger.error(
|
||||
"Template from page with id = %s cannot be processed" % self.id
|
||||
for record in self:
|
||||
try:
|
||||
raw = record.content or ""
|
||||
converted = re.sub(r"\$\{([\w_]+)\}", r"{{ resolve('\1') }}", raw)
|
||||
template = env.from_string(converted)
|
||||
return template.render(resolve=record._resolve_reference)
|
||||
except Exception:
|
||||
_logger.error(
|
||||
"Template from page with id = %s cannot be processed", record.id
|
||||
)
|
||||
return record.content
|
||||
|
||||
def _resolve_reference(self, code):
|
||||
doc = self._get_document(code)
|
||||
if self.env.context.get("raw_reference", False):
|
||||
return html_escape(doc.display_name if doc else code)
|
||||
sanitized_code = html_escape(code)
|
||||
if not doc:
|
||||
return (
|
||||
f"<i><a href='#' class='oe_direct_line' "
|
||||
f"data-oe-model='document.page' data-oe-id='' "
|
||||
f"name='{sanitized_code}'>{sanitized_code}</a></i>"
|
||||
)
|
||||
return self.content
|
||||
return (
|
||||
f"<a href='#' class='oe_direct_line' data-oe-model='{doc._name}' "
|
||||
f"data-oe-id='{doc.id}' name='{sanitized_code}'>"
|
||||
f"{html_escape(doc.display_name)}</a>"
|
||||
)
|
||||
|
||||
def get_raw_content(self):
|
||||
return self.with_context(raw_reference=True).get_content()
|
||||
return Markup(self.with_context(raw_reference=True).get_content())
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if not vals.get("reference"):
|
||||
# Propose a default reference
|
||||
reference = slugify(vals.get("name")).replace("-", "_")
|
||||
try:
|
||||
self._validate_reference(reference=reference)
|
||||
vals["reference"] = reference
|
||||
except ValidationError: # pylint: disable=W8138
|
||||
# Do not fill reference.
|
||||
pass
|
||||
if not vals.get("reference") and vals.get("name"):
|
||||
reference = self.env["ir.http"]._slugify(vals["name"]).replace("-", "_")
|
||||
vals["reference"] = reference
|
||||
return super().create(vals_list)
|
||||
|
||||
Reference in New Issue
Block a user