diff --git a/addons/portal_rating/models/rating_rating.py b/addons/portal_rating/models/rating_rating.py index b66eb2e9524..4a9ed3b094b 100644 --- a/addons/portal_rating/models/rating_rating.py +++ b/addons/portal_rating/models/rating_rating.py @@ -16,19 +16,39 @@ class Rating(models.Model): def create(self, values_list): for values in values_list: self._synchronize_publisher_values(values) - return super().create(values_list) + ratings = super().create(values_list) + if any(rating.publisher_comment for rating in ratings): + ratings._check_synchronize_publisher_values() + return ratings def write(self, values): self._synchronize_publisher_values(values) return super().write(values) + def _check_synchronize_publisher_values(self): + """ Either current user is a member of website restricted editor group + (done here by fetching the group record then using has_group, as it may + not be defined and we do not want to make a complete bridge module just + for that). Either write access on document is granted. """ + editor_group = self.env['ir.model.data']._xmlid_to_res_id('website.group_website_restricted_editor') + if editor_group and self.env.user.has_group('website.group_website_restricted_editor'): + return + for model, model_data in self._classify_by_model().items(): + records = self.env[model].browse(model_data['record_ids']) + try: + records.check_access_rights('write') + records.check_access_rule('write') + except exceptions.AccessError as e: + raise exceptions.AccessError( + _("Updating rating comment require write access on related record") + ) from e + def _synchronize_publisher_values(self, values): """ Force publisher partner and date if not given in order to have coherent values. Those fields are readonly as they are not meant to be modified manually, behaving like a tracking. """ if values.get('publisher_comment'): - if not self.env.user.has_group("website.group_website_restricted_editor"): - raise exceptions.AccessError(_("Only the publisher of the website can change the rating comment")) + self._check_synchronize_publisher_values() if not values.get('publisher_datetime'): values['publisher_datetime'] = fields.Datetime.now() if not values.get('publisher_id'): diff --git a/addons/rating/models/rating.py b/addons/rating/models/rating.py index 80948a0bfd4..b47e04d751d 100644 --- a/addons/rating/models/rating.py +++ b/addons/rating/models/rating.py @@ -108,6 +108,10 @@ class Rating(models.Model): for rating in self: rating.rating_text = rating_data._rating_to_text(rating.rating) + # ------------------------------------------------------------ + # CRUD + # ------------------------------------------------------------ + @api.model_create_multi def create(self, vals_list): for values in vals_list: @@ -141,6 +145,10 @@ class Rating(models.Model): data['parent_res_id'] = parent_res_model.id return data + # ------------------------------------------------------------ + # ACTIONS + # ------------------------------------------------------------ + def reset(self): for record in self: record.write({ @@ -158,3 +166,29 @@ class Rating(models.Model): 'res_id': self.res_id, 'views': [[False, 'form']] } + + # ------------------------------------------------------------ + # TOOLS + # ------------------------------------------------------------ + + def _classify_by_model(self): + """ To ease batch computation of various ratings related methods they + are classified by model. Ratings not linked to a valid record through + res_model / res_id are ignored. + + :return dict: for each model having at least one rating in self, have + a sub-dict containing + * ratings: ratings related to that model; + * record IDs: records linked to the ratings of that model, in same + order; + """ + data_by_model = {} + for rating in self.filtered(lambda act: act.res_model and act.res_id): + if rating.res_model not in data_by_model: + data_by_model[rating.res_model] = { + 'ratings': self.env['rating.rating'], + 'record_ids': [], + } + data_by_model[rating.res_model]['ratings'] += rating + data_by_model[rating.res_model]['record_ids'].append(rating.res_id) + return data_by_model