@@ -20,7 +20,7 @@ class AggregationService(models.AbstractModel):
2020 """
2121
2222 _name = "spp.analytics.service"
23- _description = "Aggregation Service"
23+ _description = "Analytics Service"
2424
2525 MAX_GROUP_BY_DIMENSIONS = 3
2626
@@ -62,16 +62,19 @@ def compute_aggregation(
6262 # Resolve scope
6363 scope_record = self ._resolve_scope (scope )
6464
65+ # Resolve user access context once (single DB lookup)
66+ rule = self ._get_effective_rule ()
67+
6568 # Validate group_by dimensions
6669 group_by = group_by or []
67- self ._validate_group_by (group_by )
70+ self ._validate_group_by (group_by , rule )
6871
69- # Determine access level from user permissions
70- access_level = self ._determine_access_level ( )
71- k_threshold = self ._get_k_threshold ( )
72+ # Determine access level and k-threshold from the resolved rule
73+ access_level = self ._access_level_from_rule ( rule )
74+ k_threshold = self ._k_threshold_from_rule ( rule )
7275
7376 # Check scope is allowed for user
74- self ._check_scope_allowed (scope )
77+ self ._check_scope_allowed (scope , rule )
7578
7679 # Check cache if enabled
7780 cache_service = self .env ["spp.analytics.cache" ]
@@ -136,11 +139,23 @@ def _resolve_scope(self, scope):
136139 # Assume it's already a record
137140 return scope
138141
139- def _validate_group_by (self , group_by ):
142+ def _get_effective_rule (self , user = None ):
143+ """
144+ Look up the effective access rule for a user (single DB query).
145+
146+ :param user: res.users record (defaults to current user)
147+ :returns: access rule record or None
148+ """
149+ user = user or self .env .user
150+ # Use sudo() to read access rules - this is an internal security check
151+ return self .env ["spp.analytics.access.rule" ].sudo ().get_effective_rule_for_user (user ) # nosemgrep: odoo-sudo-without-context # noqa: E501 # fmt: skip
152+
153+ def _validate_group_by (self , group_by , rule = None ):
140154 """
141155 Validate group_by dimensions.
142156
143157 :param group_by: List of dimension names
158+ :param rule: Pre-resolved access rule (or None)
144159 :raises: ValidationError if invalid
145160 """
146161 if len (group_by ) > self .MAX_GROUP_BY_DIMENSIONS :
@@ -155,52 +170,42 @@ def _validate_group_by(self, group_by):
155170 raise ValidationError (_ ("Unknown dimension: %s" ) % dim_name )
156171
157172 # Check access rule dimension restrictions
158- user = self .env .user
159- # Use sudo() to read access rules - this is an internal security check
160- rule = self .env ["spp.analytics.access.rule" ].sudo ().get_effective_rule_for_user (user ) # nosemgrep: odoo-sudo-without-context # noqa: E501 # fmt: skip
161173 if rule and group_by :
162174 rule .check_dimensions_allowed (group_by )
163175
164- def _determine_access_level (self , user = None ):
176+ def _access_level_from_rule (self , rule ):
165177 """
166- Determine access level from user permissions .
178+ Extract access level from a pre-resolved rule .
167179
168- :param user: res.users record (defaults to current user)
180+ :param rule: access rule record or None
169181 :returns: "aggregate" or "individual"
170182 :rtype: str
171183 """
172- user = user or self .env .user
173- rule = self .env ["spp.analytics.access.rule" ].sudo ().get_effective_rule_for_user (user ) # nosemgrep: odoo-sudo-without-context # noqa: E501 # fmt: skip
174184 if rule :
175185 return rule .access_level
176186 # Default to aggregate-only for safety
177187 return "aggregate"
178188
179- def _get_k_threshold (self , user = None ):
189+ def _k_threshold_from_rule (self , rule ):
180190 """
181- Get k-anonymity threshold for user .
191+ Extract k-anonymity threshold from a pre-resolved rule .
182192
183- :param user: res.users record (defaults to current user)
193+ :param rule: access rule record or None
184194 :returns: k threshold value
185195 :rtype: int
186196 """
187- user = user or self .env .user
188- rule = self .env ["spp.analytics.access.rule" ].sudo ().get_effective_rule_for_user (user ) # nosemgrep: odoo-sudo-without-context # noqa: E501 # fmt: skip
189197 if rule :
190198 return rule .minimum_k_anonymity
191199 return self .env ["spp.metric.privacy" ].DEFAULT_K_THRESHOLD
192200
193- def _check_scope_allowed (self , scope ):
201+ def _check_scope_allowed (self , scope , rule = None ):
194202 """
195203 Check if scope is allowed for current user.
196204
197205 :param scope: Scope record or dict
206+ :param rule: Pre-resolved access rule (or None)
198207 :raises: AccessError if not allowed
199208 """
200- user = self .env .user
201- # Use sudo() to read access rules - this is an internal security check
202- rule = self .env ["spp.analytics.access.rule" ].sudo ().get_effective_rule_for_user (user ) # nosemgrep: odoo-sudo-without-context # noqa: E501 # fmt: skip
203-
204209 if not rule :
205210 # No explicit rule - allow with defaults
206211 return
0 commit comments