Skip to content

Commit 7128196

Browse files
committed
[19.0][MIG] dms: Migration to 19.0
- `dms_security_mixin`: override `_search()` to restore the access filter after 19.0's `Domain.optimize(basic)` bypass; update `_read_group` to the new aggregate-tuple return signature. - `directory._search_starred`: handle the 19.0 Domain optimizer normalisation that turns `('starred', '=', True)` into `('starred', 'in', {True})`. Without this, starred-search returns the inverse set (test_starred fails). - Switch `odoo.osv.expression` (`AND`/`OR`) to `odoo.fields.Domain` (`Domain.AND`/`Domain.OR`). - Rename `auto_join` → `bypass_search_access` across one2many/many2one fields (10 sites). - `res.users` references: `groups_id` → `group_ids` (m2m rename). - `_sql_constraints` → `models.Constraint` declarations. - Controllers: `@route(type='json')` → `@route(type='jsonrpc')`. - Security: replace `category_id` with `privilege_id`; add the privilege records the 2-tier user/manager group structure expects. - Demo data: `groups_id` → `group_ids` on `res.users` fixtures. - Tests: add `require_demo_xmlid` helper so demo-dependent tests skip gracefully on CI (which runs without demo data). - Translation calls in `directory.py` modernised to `self.env._()` to satisfy 19.0's pylint_odoo W8161/W8301 (co-located with the `_search_starred` fix; portal.py/test cleanup lives in `[IMP]`). - Search view: drop deprecated `expand="0"` + `string="Group By"` from `<group>`; trivial XPath updates to OWL 2 templates. - Portal tour: drop deprecated `test: true` flag; adapt step to the 19.0 verify-only pattern. Signed-off-by: Daniel Kendall <dkendall@ledoweb.com>
1 parent 194b7ec commit 7128196

25 files changed

Lines changed: 205 additions & 121 deletions

dms/controllers/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
class OnboardingController(http.Controller):
8-
@http.route("/config/dms.forbidden_extensions", type="json", auth="user")
8+
@http.route("/config/dms.forbidden_extensions", type="jsonrpc", auth="user")
99
def forbidden_extensions(self, **_kwargs):
1010
params = request.env["ir.config_parameter"].sudo()
1111
return {

dms/demo/res_users.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
-->
88
<odoo noupdate="1">
99
<record id="base.user_demo" model="res.users">
10-
<field eval="[(4, ref('dms.group_dms_user'))]" name="groups_id" />
10+
<field eval="[(4, ref('dms.group_dms_user'))]" name="group_ids" />
1111
</record>
1212
</odoo>

dms/models/access_groups.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Copyright 2024 Timothée Vannier - Subteno (https://www.subteno.com).
44
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
55

6-
from odoo import _, api, fields, models
6+
from odoo import Command, api, fields, models
77
from odoo.exceptions import ValidationError
88

99

@@ -47,7 +47,7 @@ class DmsAccessGroups(models.Model):
4747
string="Directories",
4848
column1="gid",
4949
column2="aid",
50-
auto_join=True,
50+
bypass_search_access=True,
5151
readonly=True,
5252
)
5353
complete_directory_ids = fields.Many2many(
@@ -56,7 +56,7 @@ class DmsAccessGroups(models.Model):
5656
column1="gid",
5757
column2="aid",
5858
string="Complete directories",
59-
auto_join=True,
59+
bypass_search_access=True,
6060
readonly=True,
6161
)
6262
count_users = fields.Integer(compute="_compute_users", store=True)
@@ -94,7 +94,7 @@ class DmsAccessGroups(models.Model):
9494
column2="uid",
9595
string="Group Users",
9696
compute="_compute_users",
97-
auto_join=True,
97+
bypass_search_access=True,
9898
store=True,
9999
recursive=True,
100100
)
@@ -104,9 +104,10 @@ def _compute_count_directories(self):
104104
for record in self:
105105
record.count_directories = len(record.directory_ids)
106106

107-
_sql_constraints = [
108-
("name_uniq", "unique (name)", "The name of the group must be unique!")
109-
]
107+
_name_uniq = models.Constraint(
108+
"unique (name)",
109+
"The name of the group must be unique!",
110+
)
110111

111112
@api.depends(
112113
"parent_group_id.perm_inclusive_create",
@@ -136,20 +137,20 @@ def default_get(self, fields_list):
136137
if res.get("explicit_user_ids"):
137138
res["explicit_user_ids"] = res["explicit_user_ids"] + [self.env.uid]
138139
else:
139-
res["explicit_user_ids"] = [(6, 0, [self.env.uid])]
140+
res["explicit_user_ids"] = [Command.set([self.env.uid])]
140141
return res
141142

142143
@api.depends(
143144
"parent_group_id",
144145
"parent_group_id.users",
145146
"group_ids",
146-
"group_ids.users",
147+
"group_ids.user_ids",
147148
"explicit_user_ids",
148149
)
149150
def _compute_users(self):
150151
for record in self:
151152
users = (
152-
record.group_ids.users
153+
record.group_ids.user_ids
153154
| record.explicit_user_ids
154155
| record.parent_group_id.users
155156
)
@@ -158,7 +159,7 @@ def _compute_users(self):
158159
def copy_data(self, default=None):
159160
vals_list = super().copy_data(default)
160161
for group, vals in zip(self, vals_list, strict=False):
161-
vals["name"] = _("%s (copy)") % group.name
162+
vals["name"] = self.env._("%s (copy)", group.name)
162163
return vals_list
163164

164165
@api.constrains("parent_path")
@@ -169,9 +170,9 @@ def _check_parent_recursiveness(self):
169170
for one in self.filtered("parent_group_id"):
170171
if str(one.id) in one.parent_path.split("/"):
171172
raise ValidationError(
172-
_("Parent group '%(parent)s' is child of '%(current)s'.")
173-
% {
174-
"parent": one.parent_group_id.display_name,
175-
"current": one.display_name,
176-
}
173+
self.env._(
174+
"Parent group '%(parent)s' is child of '%(current)s'.",
175+
parent=one.parent_group_id.display_name,
176+
current=one.display_name,
177+
)
177178
)

dms/models/directory.py

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
from collections import defaultdict
1313
from typing import Literal # noqa # pylint: disable=unused-import
1414

15-
from odoo import _, api, fields, models, tools
15+
from odoo import api, fields, models, tools
1616
from odoo.exceptions import UserError, ValidationError
17-
from odoo.osv.expression import AND, OR
17+
from odoo.fields import Domain
1818
from odoo.tools import consteq, human_size
1919

2020
from ..tools.file import check_name, unique_name
@@ -60,7 +60,7 @@ class DmsDirectory(models.Model):
6060
comodel_name="dms.storage",
6161
string="Storage",
6262
ondelete="restrict",
63-
auto_join=True,
63+
bypass_search_access=True,
6464
store=True,
6565
)
6666
parent_id = fields.Many2one(
@@ -116,7 +116,7 @@ def _default_parent_id(self):
116116
comodel_name="dms.directory",
117117
inverse_name="parent_id",
118118
string="Subdirectories",
119-
auto_join=False,
119+
bypass_search_access=False,
120120
copy=True,
121121
)
122122

@@ -153,7 +153,7 @@ def _default_parent_id(self):
153153
comodel_name="dms.file",
154154
inverse_name="directory_id",
155155
string="Files",
156-
auto_join=False,
156+
bypass_search_access=False,
157157
copy=True,
158158
)
159159

@@ -221,7 +221,7 @@ def _get_domain_by_access_groups(self, operation):
221221
if operation == "create":
222222
# When creating, I need create access in parent directory, or
223223
# self-create permission if it's a root directory
224-
result = OR(
224+
result = Domain.OR(
225225
[
226226
[("is_root_directory", "=", False)] + result,
227227
[("is_root_directory", "=", True)] + self_filter,
@@ -379,7 +379,11 @@ def _search_panel_directory(self, **kwargs):
379379
# Search
380380
@api.model
381381
def _search_starred(self, operator, operand):
382-
if operator == "=" and operand:
382+
# The 19.0 Domain optimizer normalises ('starred', '=', True) to
383+
# ('starred', 'in', {True}); accept both shapes.
384+
if isinstance(operand, (set, list, tuple)):
385+
operand = True in operand
386+
if operator in ("=", "in") and operand:
383387
return [("user_star_ids", "in", [self.env.uid])]
384388
return [("user_star_ids", "not in", [self.env.uid])]
385389

@@ -412,14 +416,16 @@ def _compute_count_directories(self):
412416
for record in self:
413417
directories = len(record.child_directory_ids)
414418
record.count_directories = directories
415-
record.count_directories_title = _("%s Subdirectories") % directories
419+
record.count_directories_title = self.env._(
420+
"%s Subdirectories", directories
421+
)
416422

417423
@api.depends("file_ids")
418424
def _compute_count_files(self):
419425
for record in self:
420426
files = len(record.file_ids)
421427
record.count_files = files
422-
record.count_files_title = _("%s Files") % files
428+
record.count_files_title = self.env._("%s Files", files)
423429

424430
@api.depends("child_directory_ids", "file_ids")
425431
def _compute_count_elements(self):
@@ -528,7 +534,9 @@ def _onchange_model_id(self):
528534
@api.constrains("parent_id")
529535
def _check_directory_recursion(self):
530536
if self._has_cycle():
531-
raise ValidationError(_("Error! You cannot create recursive directories."))
537+
raise ValidationError(
538+
self.env._("Error! You cannot create recursive directories.")
539+
)
532540
return True
533541

534542
@api.constrains("storage_id", "model_id")
@@ -538,34 +546,40 @@ def _check_storage_id_attachment_model_id(self):
538546
):
539547
if not record.model_id:
540548
raise ValidationError(
541-
_("A directory has to have model in attachment storage.")
549+
self.env._("A directory has to have model in attachment storage.")
542550
)
543551
if not record.is_root_directory and not record.res_id:
544552
raise ValidationError(
545-
_("This directory needs to be associated to a record.")
553+
self.env._("This directory needs to be associated to a record.")
546554
)
547555

548556
@api.constrains("is_root_directory", "storage_id")
549557
def _check_directory_storage(self):
550558
for record in self:
551559
if record.is_root_directory and not record.storage_id:
552-
raise ValidationError(_("A root directory has to have a storage."))
560+
raise ValidationError(
561+
self.env._("A root directory has to have a storage.")
562+
)
553563

554564
@api.constrains("is_root_directory", "parent_id")
555565
def _check_directory_parent(self):
556566
for record in self:
557567
if record.is_root_directory and record.parent_id:
558568
raise ValidationError(
559-
_("A directory can't be a root and have a parent directory.")
569+
self.env._(
570+
"A directory can't be a root and have a parent directory."
571+
)
560572
)
561573
if not record.is_root_directory and not record.parent_id:
562-
raise ValidationError(_("A directory has to have a parent directory."))
574+
raise ValidationError(
575+
self.env._("A directory has to have a parent directory.")
576+
)
563577

564578
@api.constrains("name")
565579
def _check_name(self):
566580
for record in self:
567581
if self.env.context.get("check_name", True) and not check_name(record.name):
568-
raise ValidationError(_("The directory name is invalid."))
582+
raise ValidationError(self.env._("The directory name is invalid."))
569583
if record.is_root_directory:
570584
children = record.sudo().storage_id.root_directory_ids
571585
else:
@@ -576,7 +590,7 @@ def _check_name(self):
576590
and child != record
577591
):
578592
raise ValidationError(
579-
_("A directory with the same name already exists.")
593+
self.env._("A directory with the same name already exists.")
580594
)
581595

582596
# Create, Update, Delete
@@ -626,7 +640,7 @@ def message_new(self, msg_dict, custom_values=None):
626640
return parent_directory
627641
names = parent_directory.child_directory_ids.mapped("name")
628642
slug = self.env["ir.http"]._slug
629-
subject = slug(msg_dict.get("subject", _("Alias-Mail-Extraction")))
643+
subject = slug(msg_dict.get("subject", self.env._("Alias-Mail-Extraction")))
630644
defaults = dict(
631645
{"name": unique_name(subject, names, escape_suffix=True)}, **custom_values
632646
)
@@ -678,13 +692,15 @@ def write(self, vals):
678692
if new_parent_id:
679693
if old_storage_id != self.browse(new_parent_id).storage_id.id:
680694
raise UserError(
681-
_(
695+
self.env._(
682696
"It is not possible to change to a parent "
683697
"with other storage."
684698
)
685699
)
686700
elif old_storage_id != new_storage_id:
687-
raise UserError(_("It is not possible to change the storage."))
701+
raise UserError(
702+
self.env._("It is not possible to change the storage.")
703+
)
688704
# Groups part
689705
if any(key in vals for key in ["group_ids", "inherit_group_ids"]):
690706
res = super().write(vals)
@@ -743,7 +759,7 @@ def action_dms_directories_all_directory(self):
743759
action = self.env["ir.actions.act_window"]._for_xml_id(
744760
"dms.action_dms_directory"
745761
)
746-
domain = AND(
762+
domain = Domain.AND(
747763
[
748764
literal_eval(action["domain"].strip()),
749765
[("parent_id", "child_of", self.id)],
@@ -761,7 +777,7 @@ def action_dms_directories_all_directory(self):
761777
def action_dms_files_all_directory(self):
762778
self.ensure_one()
763779
action = self.env["ir.actions.act_window"]._for_xml_id("dms.action_dms_file")
764-
domain = AND(
780+
domain = Domain.AND(
765781
[
766782
literal_eval(action["domain"].strip()),
767783
[("directory_id", "child_of", self.id)],

dms/models/dms_category.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import logging
77

8-
from odoo import _, api, fields, models
8+
from odoo import api, fields, models
99
from odoo.exceptions import ValidationError
1010

1111
_logger = logging.getLogger(__name__)
@@ -63,9 +63,10 @@ class DMSCategory(models.Model):
6363
count_directories = fields.Integer(compute="_compute_count_directories")
6464
count_files = fields.Integer(compute="_compute_count_files")
6565

66-
_sql_constraints = [
67-
("name_uniq", "unique (name)", "Category name already exists!"),
68-
]
66+
_name_uniq = models.Constraint(
67+
"unique (name)",
68+
"Category name already exists!",
69+
)
6970

7071
@api.depends("name", "parent_id.complete_name")
7172
def _compute_complete_name(self):
@@ -100,5 +101,7 @@ def _compute_count_files(self):
100101
@api.constrains("parent_id")
101102
def _check_category_recursion(self):
102103
if self._has_cycle():
103-
raise ValidationError(_("Error! You cannot create recursive categories."))
104+
raise ValidationError(
105+
self.env._("Error! You cannot create recursive categories.")
106+
)
104107
return True

0 commit comments

Comments
 (0)