diff --git a/addons/portal/controllers/mail.py b/addons/portal/controllers/mail.py
index e2bb31c961b..44bc004cd34 100644
--- a/addons/portal/controllers/mail.py
+++ b/addons/portal/controllers/mail.py
@@ -112,6 +112,10 @@ class PortalChatter(http.Controller):
except (AccessError, MissingError):
raise UserError(_("The attachment %s does not exist or you do not have the rights to access it.", attachment_id))
+ def _portal_post_has_content(self, res_model, res_id, message, attachment_ids=None, **kw):
+ """ Tells if we can effectively post on the model based on content. """
+ return bool(message) or bool(attachment_ids)
+
@http.route(['/mail/chatter_post'], type='json', methods=['POST'], auth='public', website=True)
def portal_chatter_post(self, res_model, res_id, message, attachment_ids=None, attachment_tokens=None, **kw):
"""Create a new `mail.message` with the given `message` and/or `attachment_ids` and return new message values.
@@ -120,38 +124,42 @@ class PortalChatter(http.Controller):
`res_model`. The user must have access rights on this target document or
must provide valid identifiers through `kw`. See `_message_post_helper`.
"""
+ if not self._portal_post_has_content(res_model, res_id, message,
+ attachment_ids=attachment_ids, attachment_tokens=attachment_tokens,
+ **kw):
+ return
+
res_id = int(res_id)
self._portal_post_check_attachments(attachment_ids, attachment_tokens)
- if message or attachment_ids:
- result = {'default_message': message}
- # message is received in plaintext and saved in html
- if message:
- message = plaintext2html(message)
- post_values = {
- 'res_model': res_model,
- 'res_id': res_id,
- 'message': message,
- 'send_after_commit': False,
- 'attachment_ids': False, # will be added afterward
- }
- post_values.update((fname, kw.get(fname)) for fname in self._portal_post_filter_params())
- message = _message_post_helper(**post_values)
- result.update({'default_message_id': message.id})
+ result = {'default_message': message}
+ # message is received in plaintext and saved in html
+ if message:
+ message = plaintext2html(message)
+ post_values = {
+ 'res_model': res_model,
+ 'res_id': res_id,
+ 'message': message,
+ 'send_after_commit': False,
+ 'attachment_ids': False, # will be added afterward
+ }
+ post_values.update((fname, kw.get(fname)) for fname in self._portal_post_filter_params())
+ message = _message_post_helper(**post_values)
+ result.update({'default_message_id': message.id})
- if attachment_ids:
- # sudo write the attachment to bypass the read access
- # verification in mail message
- record = request.env[res_model].browse(res_id)
- message_values = {'res_id': res_id, 'model': res_model}
- attachments = record._message_post_process_attachments([], attachment_ids, message_values)
+ if attachment_ids:
+ # sudo write the attachment to bypass the read access
+ # verification in mail message
+ record = request.env[res_model].browse(res_id)
+ message_values = {'res_id': res_id, 'model': res_model}
+ attachments = record._message_post_process_attachments([], attachment_ids, message_values)
- if attachments.get('attachment_ids'):
- message.sudo().write(attachments)
+ if attachments.get('attachment_ids'):
+ message.sudo().write(attachments)
- result.update({'default_attachment_ids': message.attachment_ids.sudo().read(['id', 'name', 'mimetype', 'file_size', 'access_token'])})
- return result
+ result.update({'default_attachment_ids': message.attachment_ids.sudo().read(['id', 'name', 'mimetype', 'file_size', 'access_token'])})
+ return result
@http.route('/mail/chatter_init', type='json', auth='public', website=True)
def portal_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs):
diff --git a/addons/portal/static/src/js/portal_composer.js b/addons/portal/static/src/js/portal_composer.js
index 645210c0116..1622f34bda0 100644
--- a/addons/portal/static/src/js/portal_composer.js
+++ b/addons/portal/static/src/js/portal_composer.js
@@ -158,9 +158,9 @@ var PortalComposer = publicWidget.Widget.extend({
*/
_onSubmitButtonClick: function (ev) {
ev.preventDefault();
- if (!this.$inputTextarea.val().trim() && !this.attachments.length) {
+ const error = this._onSubmitCheckContent();
+ if (error) {
this.$inputTextarea.addClass('border-danger');
- const error = _t('Some fields are required. Please make sure to write a message or attach a document');
this.$(".o_portal_chatter_composer_error").text(error).removeClass('d-none');
return Promise.reject();
} else {
@@ -168,6 +168,15 @@ var PortalComposer = publicWidget.Widget.extend({
}
},
+ /**
+ * @private
+ */
+ _onSubmitCheckContent: function () {
+ if (!this.$inputTextarea.val().trim() && !this.attachments.length) {
+ return _t('Some fields are required. Please make sure to write a message or attach a document');
+ };
+ },
+
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
diff --git a/addons/portal_rating/static/src/js/portal_composer.js b/addons/portal_rating/static/src/js/portal_composer.js
index 3d1bb0ea7fc..7833de0b86c 100644
--- a/addons/portal_rating/static/src/js/portal_composer.js
+++ b/addons/portal_rating/static/src/js/portal_composer.js
@@ -34,9 +34,10 @@ PortalComposer.include({
// default options
this.options = _.defaults(this.options, {
+ 'rate_with_void_content': false,
'default_message': false,
'default_message_id': false,
- 'default_rating_value': 0.0,
+ 'default_rating_value': 4.0,
'force_submit_url': false,
});
// star input widget
@@ -61,6 +62,10 @@ PortalComposer.include({
// rating stars
self.$input = self.$('input[name="rating_value"]');
self.$star_list = self.$('.stars').find('i');
+ // if this is the first review, we do not use grey color contrast, even with default rating value.
+ if (!self.options.default_message_id) {
+ self.$star_list.removeClass('text-black-25');
+ }
// set the default value to trigger the display of star widget and update the hidden input value.
self.set("star_value", self.options.default_rating_value);
@@ -149,5 +154,19 @@ PortalComposer.include({
$modal.modal('hide');
});
},
+
+ /**
+ * @override
+ * @private
+ */
+ _onSubmitCheckContent: function (ev) {
+ if (this.options.rate_with_void_content) {
+ if (this.$input.val() === 0) {
+ return _t('The rating is required. Please make sure to select one before sending your review.')
+ }
+ return false;
+ }
+ return this._super.apply(this, arguments);
+ },
});
});
diff --git a/addons/portal_rating/views/rating_templates.xml b/addons/portal_rating/views/rating_templates.xml
index 2fcc31e5894..d5f6b9b7451 100644
--- a/addons/portal_rating/views/rating_templates.xml
+++ b/addons/portal_rating/views/rating_templates.xml
@@ -67,6 +67,7 @@
t-att-data-default_rating_value="default_rating_value"
t-att-data-default_attachment_ids="default_attachment_ids"
t-att-data-force_submit_url="force_submit_url"
+ t-att-data-rate_with_void_content="rate_with_void_content"
t-att-data-disable_composer="disable_composer"
t-att-data-display_composer="display_composer"
t-att-data-link_btn_classes="_link_btn_classes"
diff --git a/addons/website_slides/controllers/mail.py b/addons/website_slides/controllers/mail.py
index 8c72322e290..7c52fa46b35 100644
--- a/addons/website_slides/controllers/mail.py
+++ b/addons/website_slides/controllers/mail.py
@@ -13,10 +13,17 @@ from odoo.tools import plaintext2html, html2plaintext
class SlidesPortalChatter(PortalChatter):
+ def _portal_post_has_content(self, res_model, res_id, message, attachment_ids=None, **kw):
+ """ Relax constraint on slide model: having a rating value is sufficient
+ to consider we have a content. """
+ if res_model == 'slide.channel' and kw.get('rating_value'):
+ return True
+ return super()._portal_post_has_content(res_model, res_id, message, attachment_ids=attachment_ids, **kw)
+
@http.route(['/mail/chatter_post'], type='json', methods=['POST'], auth='public', website=True)
def portal_chatter_post(self, res_model, res_id, message, **kw):
result = super(SlidesPortalChatter, self).portal_chatter_post(res_model, res_id, message, **kw)
- if res_model == 'slide.channel':
+ if result and res_model == 'slide.channel':
rating_value = kw.get('rating_value', False)
slide_channel = request.env[res_model].sudo().browse(int(res_id))
if rating_value and slide_channel and request.env.user.partner_id.id == int(kw.get('pid')):
diff --git a/addons/website_slides/views/website_slides_templates_course.xml b/addons/website_slides/views/website_slides_templates_course.xml
index e753b91f439..b5e5f72bce6 100644
--- a/addons/website_slides/views/website_slides_templates_course.xml
+++ b/addons/website_slides/views/website_slides_templates_course.xml
@@ -153,6 +153,7 @@
+