[FIX] (portal_)rating: do not crash if website is not installed

Current rule to edit publisher fields (comment, ...) is to have the editor
group. However when having only portal, this group does not exist. The
feature should work as a standalone feature without depending on website.

The rule is then updated as follow: either the current user belongs to the
editor group (if it exists), either it can write on the related record
(given res_model / res_id).

Currently no crash in standard addons occur because its main usage is in
eLearning application, where editor can answer and update publisher comment
from the frontend (course review).

Task-3322905

Part-of: odoo/odoo#121104
This commit is contained in:
Thibault Delavallée
2023-05-16 15:55:18 +02:00
parent c64ac52854
commit 2f196bf7c4
2 changed files with 57 additions and 3 deletions
+23 -3
View File
@@ -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'):
+34
View File
@@ -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