83 lines
3.7 KiB
Python
83 lines
3.7 KiB
Python
from odoo import _, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class DocumentsSentinel:
|
|
"""Sentinel class to prevent context spoofing via RPC."""
|
|
pass
|
|
|
|
|
|
class IrActionsServer(models.Model):
|
|
_inherit = 'ir.actions.server'
|
|
|
|
# The documents actions add a check that the current document is in a folder
|
|
# on which the current action is pinned (to avoid executing server action
|
|
# means to be used in a different folder).
|
|
usage = fields.Selection(
|
|
selection_add=[('documents_embedded', 'Documents')],
|
|
ondelete={'documents_embedded': 'set ir_actions_server'},
|
|
)
|
|
|
|
def action_open_documents_server_action_view(self):
|
|
self.check_access('read')
|
|
form_view = self.env.ref('documents.ir_actions_server_view_form_documents', raise_if_not_found=False)
|
|
search_view = self.env.ref('documents.ir_actions_server_action_search_documents', raise_if_not_found=False)
|
|
return {
|
|
'context': {
|
|
'default_model_id': self.env['ir.model']._get_id('documents.document'),
|
|
'default_update_path': 'tag_ids',
|
|
'default_usage': 'documents_embedded',
|
|
},
|
|
'display_name': _('Server Actions'),
|
|
'domain': [
|
|
('model_name', '=', 'documents.document'),
|
|
('parent_id', '=', False),
|
|
],
|
|
'help': """
|
|
<div style="width:650px;">
|
|
<p class="d-none">%s</p>
|
|
<img class="w-100 w-md-75" src="/documents/static/img/documents_server_action.svg"/>
|
|
</div>
|
|
""" % _('No server actions found for Documents!'),
|
|
'res_model': 'ir.actions.server',
|
|
'target': 'current',
|
|
'type': 'ir.actions.act_window',
|
|
'view_mode': 'list,form',
|
|
'views': [(False, 'list'), (form_view.id if form_view else False, 'form')],
|
|
'search_view_id': [search_view.id if search_view else False, 'search'],
|
|
}
|
|
|
|
def _run(self, records, eval_context):
|
|
"""Override to implement 'Entry Point' security for Documents actions."""
|
|
if isinstance(self.env.context.get('__documents_embedded_checked'), DocumentsSentinel):
|
|
return super()._run(records, eval_context)
|
|
|
|
descendants = self
|
|
while descendants.child_ids - descendants:
|
|
descendants |= descendants.child_ids
|
|
|
|
if 'documents_embedded' in descendants.mapped('usage'):
|
|
self._check_is_document_action_embedded(records)
|
|
return super(IrActionsServer, self.with_context(
|
|
__documents_embedded_checked=DocumentsSentinel()
|
|
))._run(records, eval_context)
|
|
|
|
return super()._run(records, eval_context)
|
|
|
|
def _check_is_document_action_embedded(self, records):
|
|
"""Verify that the action is explicitly embedded (pinned) on the current folder of the given records."""
|
|
for record in records:
|
|
record_actions = record.available_embedded_actions_ids.action_id
|
|
record_server_actions_sudo = record_actions.sudo().filtered(lambda a: a.type == 'ir.actions.server')
|
|
available_server_actions_sudo = self.env['ir.actions.server'].browse(record_server_actions_sudo.ids).sudo()
|
|
|
|
# Add the child actions
|
|
actions = available_server_actions_sudo
|
|
while actions.child_ids:
|
|
next_actions = actions.child_ids - available_server_actions_sudo
|
|
available_server_actions_sudo |= actions.child_ids
|
|
actions = next_actions
|
|
|
|
if self not in available_server_actions_sudo:
|
|
raise UserError(_('This action was not made available on the containing folder.'))
|