diff options
| author | Jérome Maes <jem@openerp.com> | 2017-08-09 13:09:32 +0200 |
|---|---|---|
| committer | Jérome Maes <jem@openerp.com> | 2017-08-16 14:56:40 +0200 |
| commit | 3cfd64f63f6153c170c9c876fa65976a95da22cb (patch) | |
| tree | dcd477f6e8225ed788fa38484fc28272e77073bb | |
| parent | 2972976962617d4b8a0113bae58c640ab41cdff8 (diff) | |
[MOV] portal,website_mail: move chatter frontend to portal
This split responsiblilies :
- portal provides basic chatter for portal document, and
website documents (slides, blog, ...).
- website_mail provides comments moderation (unpublished mail
message)
- website_rating integrate rating when posting comments
31 files changed, 594 insertions, 539 deletions
diff --git a/addons/portal/controllers/__init__.py b/addons/portal/controllers/__init__.py index ac871b40c75..c1b076c5a27 100644 --- a/addons/portal/controllers/__init__.py +++ b/addons/portal/controllers/__init__.py @@ -3,3 +3,4 @@ from . import web from . import portal +from . import mail diff --git a/addons/portal/controllers/mail.py b/addons/portal/controllers/mail.py new file mode 100644 index 00000000000..4ee2414548a --- /dev/null +++ b/addons/portal/controllers/mail.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from werkzeug.exceptions import NotFound, Forbidden + +from odoo import http +from odoo.http import request +from odoo.tools import consteq + + +def _special_access_object(res_model, res_id, token='', token_field=''): + record = request.env[res_model].browse(res_id).sudo() + if token and record and getattr(record, token_field, None) and consteq(getattr(record, token_field), token): + return True + return False + +def _message_post_helper(res_model='', res_id=None, message='', token='', token_field='token', nosubscribe=True, **kw): + """ Generic chatter function, allowing to write on *any* object that inherits mail.thread. + If a token is specified, all logged in users will be able to write a message regardless + of access rights; if the user is the public user, the message will be posted under the name + of the partner_id of the object (or the public user if there is no partner_id on the object). + + :param string res_model: model name of the object + :param int res_id: id of the object + :param string message: content of the message + + optional keywords arguments: + :param string token: access token if the object's model uses some kind of public access + using tokens (usually a uuid4) to bypass access rules + :param string token_field: name of the field that contains the token on the object (defaults to 'token') + :param bool nosubscribe: set False if you want the partner to be set as follower of the object when posting (default to True) + + The rest of the kwargs are passed on to message_post() + """ + record = request.env[res_model].browse(res_id) + author_id = request.env.user.partner_id.id if request.env.user.partner_id else False + if token_field and token: + access_as_sudo = _special_access_object(res_model, res_id, token=token, token_field=token_field) + if access_as_sudo: + record = record.sudo() + if request.env.user == request.env.ref('base.public_user'): + author_id = record.partner_id.id if hasattr(record, 'partner_id') else author_id + else: + if not author_id: + raise NotFound() + else: + raise Forbidden() + kw.pop('csrf_token', None) + return record.with_context(mail_create_nosubscribe=nosubscribe).message_post(body=message, + message_type=kw.pop('message_type', "comment"), + subtype=kw.pop('subtype', "mt_comment"), + author_id=author_id, + **kw) + + +class PortalChatter(http.Controller): + + @http.route(['/mail/chatter_post'], type='http', methods=['POST'], auth='public', website=True) + def portal_chatter_post(self, res_model, res_id, message, **kw): + url = request.httprequest.referrer + if message: + _message_post_helper(res_model, int(res_id), message, **kw) + url = url + "#discussion" + return request.redirect(url) + + @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): + is_user_public = request.env.user.has_group('base.group_public') + message_data = self.portal_message_fetch(res_model, res_id, domain=domain, limit=limit, **kwargs) + display_composer = False + if kwargs.get('allow_composer'): + display_composer = kwargs.get('token') or not is_user_public + return { + 'messages': message_data['messages'], + 'options': { + 'message_count': message_data['message_count'], + 'is_user_public': is_user_public, + 'is_user_publisher': request.env.user.has_group('website.group_website_publisher'), + 'display_composer': display_composer, + 'partner_id': request.env.user.partner_id.id + } + } + + @http.route('/mail/chatter_fetch', type='json', auth='public', website=True) + def portal_message_fetch(self, res_model, res_id, domain=False, limit=10, offset=0, **kw): + if not domain: + domain = [] + # Only search into website_message_ids, so apply the same domain to perform only one search + # extract domain from the 'website_message_ids' field + field_domain = request.env[res_model]._fields['website_message_ids'].domain + domain += field_domain(request.env[res_model]) if callable(field_domain) else field_domain + domain += [('res_id', '=', res_id)] + # Check access + Message = request.env['mail.message'] + if kw.get('token'): + access_as_sudo = _special_access_object(res_model, res_id, token=kw.get('token'), token_field=kw.get('token_field')) + if not access_as_sudo: # if token is not correct, raise Forbidden + raise Forbidden() + Message = request.env['mail.message'].sudo() + return { + 'messages': Message.search(domain, limit=limit, offset=offset).portal_message_format(), + 'message_count': Message.search_count(domain) + } diff --git a/addons/portal/models/__init__.py b/addons/portal/models/__init__.py index bccc8440508..320a9e84f38 100644 --- a/addons/portal/models/__init__.py +++ b/addons/portal/models/__init__.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import portal_mixin +from . import mail_thread +from . import mail_message +from . import portal_mixin
\ No newline at end of file diff --git a/addons/portal/models/mail_message.py b/addons/portal/models/mail_message.py new file mode 100644 index 00000000000..6a242609d14 --- /dev/null +++ b/addons/portal/models/mail_message.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class MailMessage(models.Model): + _inherit = 'mail.message' + + @api.multi + def portal_message_format(self): + return self._portal_message_format([ + 'id', 'body', 'date', 'author_id', 'email_from', # base message fields + 'message_type', 'subtype_id', 'subject', # message specific + 'model', 'res_id', 'record_name', # document related + 'website_published', + ]) + + @api.multi + def _portal_message_format(self, fields_list): + message_values = self.read(fields_list) + message_tree = dict((m.id, m) for m in self.sudo()) + self._message_read_dict_postprocess(message_values, message_tree) + return message_values diff --git a/addons/website_mail/models/mail_thread.py b/addons/portal/models/mail_thread.py index 08cd54aa301..08cd54aa301 100644 --- a/addons/website_mail/models/mail_thread.py +++ b/addons/portal/models/mail_thread.py diff --git a/addons/portal/static/src/js/portal_chatter.js b/addons/portal/static/src/js/portal_chatter.js new file mode 100644 index 00000000000..bfb44837bf4 --- /dev/null +++ b/addons/portal/static/src/js/portal_chatter.js @@ -0,0 +1,238 @@ +odoo.define('portal.chatter', function(require) { +'use strict'; + +var base = require('web_editor.base'); +var ajax = require('web.ajax'); +var core = require('web.core'); +var Widget = require('web.Widget'); +var rpc = require('web.rpc'); + +var qweb = core.qweb; +var _t = core._t; + +/** + * Widget PortalChatter + * + * - Fetch message fron controller + * - Display chatter: pager, total message, composer (according to access right) + * - Provider API to filter displayed messages + */ +var PortalChatter = Widget.extend({ + template: 'portal.chatter', + events: { + "click .o_portal_chatter_pager_btn": '_onClickPager' + }, + + init: function(parent, options){ + this._super.apply(this, arguments); + this.options = _.defaults(options || {}, { + 'allow_composer': true, + 'display_composer': false, + 'csrf_token': odoo.csrf_token, + 'message_count': 0, + 'pager_step': 10, + 'pager_scope': 5, + 'pager_start': 1, + 'is_user_public': true, + 'is_user_publisher': false, + 'domain': [], + }); + this.set('messages', []); + this.set('message_count', this.options['message_count']); + this.set('pager', {}); + this.set('domain', this.options['domain']); + this._current_page = this.options['pager_start']; + }, + willStart: function(){ + var self = this; + // load qweb template and init data + return $.when( + rpc.query({ + route: '/mail/chatter_init', + params: this._messageFetchPrepareParams() + }), this._loadTemplates() + ).then(function(result){ + // bind events + self.on("change:messages", self, self._renderMessages); + self.on("change:message_count", self, function(){ + self._renderMessageCount(); + self.set('pager', self._pager(self._current_page)); + }); + self.on("change:pager", self, self._renderPager); + self.on("change:domain", self, self._onChangeDomain); + // set options and parameters + self.options = _.extend(self.options, result['options'] || {}); + self.set('message_count', self.options['message_count']); + self.set('messages', self.preprocessMessages(result['messages'])); + return result; + }); + }, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Fetch the messages and the message count from the server for the + * current page and current domain. + * + * @param {Array} + * @returns {Deferred} + */ + messageFetch: function(domain){ + var self = this; + return rpc.query({ + route: '/mail/chatter_fetch', + params: self._messageFetchPrepareParams() + }).then(function(result){ + self.set('messages', self.preprocessMessages(result['messages'])); + self.set('message_count', result['message_count']); + }); + }, + /** + * Update the messages format + * + * @param {Array<Object>} + * @returns {Array} + */ + preprocessMessages: function(messages){ + _.each(messages, function(m){ + m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id); + m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(m.date).format('MMMM Do YYYY, h:mm:ss a')); + }); + return messages; + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Change the current page by refreshing current domain + * + * @private + * @param {Number} page + * @param {Array} domain + */ + _changeCurrentPage: function(page, domain){ + this._current_page = page; + var d = domain ? domain : _.clone(this.get('domain')); + this.set('domain', d); // trigger fetch message + }, + /** + * @private + * @returns {Deferred} + */ + _loadTemplates: function(){ + return ajax.loadXML('/portal/static/src/xml/portal_chatter.xml', qweb); + }, + _messageFetchPrepareParams: function(){ + var self = this; + var data = { + 'res_model': this.options['res_model'], + 'res_id': this.options['res_id'], + 'limit': this.options['pager_step'], + 'offset': (this._current_page-1) * this.options['pager_step'], + 'allow_composer': this.options['allow_composer'], + }; + // add fields to allow to post comment without being logged + _.each(['token', 'token_field'], function(field){ + if(self.options[field]){ + data[field] = self.options[field]; + } + }); + // add domain + if(this.get('domain')){ + data['domain'] = this.get('domain'); + } + return data; + }, + /** + * Generate the pager data for the given page number + * + * @private + * @param {Number} page + * @returns {Object} + */ + _pager: function(page){ + var page = page || 1; + var total = this.get('message_count'); + var scope = this.options['pager_scope']; + var step = this.options['pager_step']; + + // Compute Pager + var page_count = Math.ceil(parseFloat(total) / step); + + var page = Math.max(1, Math.min(parseInt(page), page_count)); + scope -= 1; + + var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1); + var pmax = Math.min(pmin + scope, page_count); + + if(pmax - scope > 0){ + pmin = pmax - scope; + }else{ + pmin = 1; + } + + var pages = []; + _.each(_.range(pmin, pmax+1), function(index){ + pages.push(index); + }); + + return { + "page_count": page_count, + "offset": (page - 1) * step, + "page": page, + "page_start": pmin, + "page_previous": Math.max(pmin, page - 1), + "page_next": Math.min(pmax, page + 1), + "page_end": pmax, + "pages": pages + }; + }, + _renderMessages: function(){ + this.$('.o_portal_chatter_messages').html(qweb.render("portal.chatter_messages", {widget: this})); + }, + _renderMessageCount: function(){ + this.$('.o_message_counter').replaceWith(qweb.render("portal.chatter_message_count", {widget: this})); + }, + _renderPager: function(){ + this.$('.o_portal_chatter_pager').replaceWith(qweb.render("portal.pager", {widget: this})); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + _onChangeDomain: function(){ + var self = this; + this.messageFetch().then(function(){ + var p = self._current_page; + self.set('pager', self._pager(p)); + }); + }, + /** + * @private + * @param {MouseEvent} event + */ + _onClickPager: function(ev){ + ev.preventDefault(); + var page = $(ev.currentTarget).data('page'); + this._changeCurrentPage(page); + }, +}); + +base.ready().then(function () { + $('.o_website_mail_thread').each(function (index) { + var $elem = $(this); + var mail_thread = new WebsiteMailThread(null, $elem.data()); + mail_thread.appendTo($elem); + }); +}); + +return { + PortalChatter: PortalChatter, +}; + +}); diff --git a/addons/portal/static/src/less/portal_chatter.less b/addons/portal/static/src/less/portal_chatter.less new file mode 100644 index 00000000000..00cda0afe7e --- /dev/null +++ b/addons/portal/static/src/less/portal_chatter.less @@ -0,0 +1,33 @@ + +.o_portal_chatter { + padding: 10px; + + .o_portal_chatter_avatar{ + width: 45px; + height: 45px; + } + + .o_portal_chatter_header { + margin-bottom: 15px; + } + + .o_portal_chatter_composer { + margin-bottom: 15px; + } + + .o_portal_chatter_messages { + margin-bottom: 15px; + + .o_portal_chatter_message_title { + p { + font-size:85%; + color:@odoo-main-color-muted; + margin: 0px; + } + } + } + + .o_portal_chatter_pager { + text-align: center; + } +} diff --git a/addons/portal/static/src/xml/portal_chatter.xml b/addons/portal/static/src/xml/portal_chatter.xml new file mode 100644 index 00000000000..c4cfca119e0 --- /dev/null +++ b/addons/portal/static/src/xml/portal_chatter.xml @@ -0,0 +1,117 @@ +<templates id="template" xml:space="preserve"> + + <t t-name="portal.chatter_message_count"> + <t t-set="count" t-value="widget.get('message_count')"/> + <div class="o_message_counter"> + <t t-if="count"> + <span class="o_message_count fa fa-comments"> <t t-esc="count"/></span> + <t t-if="count == 1">comment</t> + <t t-else="">comments</t> + </t> + <t t-else=""> + There are no comments for now. + </t> + </div> + </t> + + <t t-name="portal.chatter_composer"> + <div class="o_portal_chatter_composer" t-if="widget.options['allow_composer']"> + <t t-if="!widget.options['display_composer']"> + <h4>Leave a comment</h4> + <p>You must be <a t-attf-href="/web/login?redirect=#{window.encodeURI(window.location.href + '#discussion')}">logged in</a> to post a comment.</p> + </t> + <t t-if="widget.options['display_composer']"> + <div class="media"> + <div class="media-left"> + <img class="o_portal_chatter_avatar pull-left" t-attf-src="/web/image/res.partner/#{widget.options['partner_id']}/image_small/50x50"/> + </div> + <div class="media-body"> + <form class="o_portal_chatter_composer_form" t-attf-action="/mail/chatter_post" method="POST"> + <input type="hidden" name="csrf_token" t-att-value="widget.options['csrf_token']"/> + <div class="mb32"> + <textarea rows="4" name="message" class="form-control" placeholder="Write a message..."></textarea> + <input type='hidden' name="res_model" t-att-value="widget.options['res_model']"/> + <input type='hidden' name="res_id" t-att-value="widget.options['res_id']"/> + <input type='hidden' name="token" t-att-value="widget.options['token']" t-if="widget.options['token']"/> + <input type='hidden' name="sha_in" t-att-value="widget.options['sha_in']" t-if="widget.options['sha_in']"/> + <input type='hidden' name="sha_time" t-att-value="widget.options['sha_time']" t-if="widget.options['sha_time']"/> + <input type='hidden' name="token_field" t-att-value="widget.options['token_field']" t-if="widget.options['token_field']"/> + <div class="alert alert-danger mt8 mb0 o_portal_chatter_composer_error" style="display:none;"> + Oops! Something went wrong. Try to reload the page and log in. + </div> + <button t-attf-class="o_portal_chatter_composer_btn btn btn-primary mt8 o_website_message_post_helper" type="submit">Send</button> + </div> + </form> + </div> + </div> + </t> + <hr/> + </div> + </t> + + <t t-name="portal.chatter_messages"> + <div class="o_portal_chatter_messages"> + <t t-foreach="widget.get('messages')" t-as="message"> + <div class="media o_portal_chatter_message" t-att-id="'message-' + message.id"> + <div class="media-left"> + <img class="media-object o_portal_chatter_avatar" t-att-src="message.author_avatar_url" alt="avatar"/> + </div> + <div class="media-body"> + + <div class="o_portal_chatter_message_title"> + <h5 class="media-heading"> + <t t-esc="message.author_id[1]"/> + </h5> + <p class="o_portal_chatter_puslished_date"><t t-esc="message.published_date_str"/></p> + </div> + <t t-raw="message.body"/> + + <div class="o_portal_chatter_attachments"> + <div class="col-md-2 col-sm-3 text-center" t-foreach='message.attachment_ids' t-as='attachment'> + <a t-attf-href="/web/content/#{attachment.id}?download=true" target="_blank"> + <div class='oe_attachment_embedded o_image' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/100x80"/> + <div class='oe_attachment_name'><t t-raw='attachment.name'/></div> + </a> + </div> + </div> + </div> + </div> + </t> + </div> + </t> + + <t t-name="portal.pager"> + <div class="o_portal_chatter_pager"> + <t t-if="!_.isEmpty(widget.get('pager'))"> + <ul class="pagination" t-if="widget.get('pager')['pages'].length > 1"> + <li t-if="widget.get('pager')['page'] != widget.get('pager')['page_previous']" t-att-data-page="widget.get('pager')['page_previous']" class="o_portal_chatter_pager_btn"> + <a href="#"><i class="fa fa-chevron-left"/></a> + </li> + <t t-foreach="widget.get('pager')['pages']" t-as="page"> + <li t-att-data-page="page" t-att-class="page == widget.get('pager')['page'] ? 'o_portal_chatter_pager_btn active' : 'o_portal_chatter_pager_btn'"> + <a href="#"><t t-esc="page"/></a> + </li> + </t> + <li t-if="widget.get('pager')['page'] != widget.get('pager')['page_next']" t-att-data-page="widget.get('pager')['page_next']" class="o_portal_chatter_pager_btn"> + <a href="#"><i class="fa fa-chevron-right"/></a> + </li> + </ul> + </t> + </div> + </t> + + <t t-name="portal.chatter"> + <div class="o_portal_chatter"> + <div class="o_portal_chatter_header"> + <t t-call="portal.chatter_message_count"/> + </div> + <hr/> + <t t-call="portal.chatter_composer"/> + <t t-call="portal.chatter_messages"/> + <div class="o_portal_chatter_footer"> + <t t-call="portal.pager"/> + </div> + </div> + </t> + +</templates> diff --git a/addons/portal/views/assets.xml b/addons/portal/views/assets.xml index af6569e150f..f02205681c6 100644 --- a/addons/portal/views/assets.xml +++ b/addons/portal/views/assets.xml @@ -5,10 +5,12 @@ <link rel="stylesheet" type="text/less" href="/portal/static/src/less/website.ui.less"/> <link rel="stylesheet" type="text/less" href="/portal/static/src/less/website.wrapwrap.less"/> <link rel="stylesheet" type="text/less" href="/portal/static/src/less/bootstrap.extend.less"/> + <link rel="stylesheet" type="text/less" href="/portal/static/src/less/portal_chatter.less"/> </xpath> <xpath expr="//script[last()]" position="after"> <script type="text/javascript" src="/portal/static/src/js/portal.js"></script> <script type="text/javascript" src="/portal/static/src/js/portal_tour.js"></script> + <script type="text/javascript" src="/portal/static/src/js/portal_chatter.js"></script> </xpath> </template> </odoo> diff --git a/addons/portal/views/portal_templates.xml b/addons/portal/views/portal_templates.xml index 67e027aea48..87e566b874e 100644 --- a/addons/portal/views/portal_templates.xml +++ b/addons/portal/views/portal_templates.xml @@ -336,4 +336,22 @@ <li><a href="/my/home" role="menuitem">My Account</a></li> </xpath> </template> + + <!-- + Generic chatter template for the frontend + This template provide the container of the chatter. The rest is done in js. + To use this template, you need to call it after setting the following variable in your template or in your controller: + :object browserecord : the mail_thread object + :message_per_page int (optional): number of message per chatter page + :token string (optional): if you want your chatter to be available for non-logged user, + you can use a token to verify the identity of the user; + the message will be posted with the identity of the partner_id of the object + :token_field string (optional): name of the field that contains the token on the object (default to 'token') + --> + <template id="message_thread"> + <div id="discussion" class="hidden-print o_portal_chatter" + t-att-data-token="token" t-att-data-res_model="object._name" t-att-data-res_id="object.id" t-att-data-token_field="token_field" t-att-data-pager_step="message_per_page or 10" t-att-data-allow_composer="'0' if disable_composer else '1'"> + </div> + </template> + </odoo> diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml index 2bd30f00c2a..534dea06da3 100644 --- a/addons/website_blog/views/website_blog_templates.xml +++ b/addons/website_blog/views/website_blog_templates.xml @@ -302,7 +302,7 @@ <template id="opt_blog_post_complete_comment" name="Allow blog post comment" inherit_id="website_blog.blog_post_complete" active="False" customize_show="True"> <xpath expr="//div[hasclass('o_blog_post_complete','o_sharing_links')]" position="after"> <section id="comments" class="read_width"> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="blog_post"/> </t> </section> diff --git a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml index ae449b901af..ad4d418dc16 100644 --- a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml +++ b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml @@ -507,7 +507,7 @@ <h4><strong>Message and communication history</strong></h4> </div> <div class="col-md-10 col-md-offset-1 mt16"> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="lead"/> </t> </div> @@ -772,7 +772,7 @@ <h4><strong>Message and communication history</strong></h4> </div> <div class="col-md-10 col-md-offset-1 mt16"> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="opportunity"/> </t> </div> diff --git a/addons/website_mail/__manifest__.py b/addons/website_mail/__manifest__.py index d0c73141faa..45571be05b3 100644 --- a/addons/website_mail/__manifest__.py +++ b/addons/website_mail/__manifest__.py @@ -6,7 +6,10 @@ 'category': 'Hidden', 'summary': 'Website Module for Mail', 'version': '0.1', - 'description': """Glue module holding mail improvements for website.""", + 'description': """ +Module holding mail improvements for website. +It is responsible of comments moderation for published documents (forum, slides, blog, ...) +""", 'depends': ['website', 'mail'], 'data': [ 'views/website_mail_templates.xml', diff --git a/addons/website_mail/controllers/main.py b/addons/website_mail/controllers/main.py index c10525fd5e0..ac73c0653c1 100644 --- a/addons/website_mail/controllers/main.py +++ b/addons/website_mail/controllers/main.py @@ -1,56 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from werkzeug.exceptions import NotFound, Forbidden - from odoo import http from odoo.http import request -from odoo.tools import consteq - - -def _special_access_object(res_model, res_id, token='', token_field=''): - record = request.env[res_model].browse(res_id).sudo() - if token and record and getattr(record, token_field, None) and consteq(getattr(record, token_field), token): - return True - return False - -def _message_post_helper(res_model='', res_id=None, message='', token='', token_field='token', nosubscribe=True, **kw): - """ Generic chatter function, allowing to write on *any* object that inherits mail.thread. - If a token is specified, all logged in users will be able to write a message regardless - of access rights; if the user is the public user, the message will be posted under the name - of the partner_id of the object (or the public user if there is no partner_id on the object). - - :param string res_model: model name of the object - :param int res_id: id of the object - :param string message: content of the message - - optional keywords arguments: - :param string token: access token if the object's model uses some kind of public access - using tokens (usually a uuid4) to bypass access rules - :param string token_field: name of the field that contains the token on the object (defaults to 'token') - :param bool nosubscribe: set False if you want the partner to be set as follower of the object when posting (default to True) - - The rest of the kwargs are passed on to message_post() - """ - record = request.env[res_model].browse(res_id) - author_id = request.env.user.partner_id.id if request.env.user.partner_id else False - if token_field and token: - access_as_sudo = _special_access_object(res_model, res_id, token=token, token_field=token_field) - if access_as_sudo: - record = record.sudo() - if request.env.user == request.env.ref('base.public_user'): - author_id = record.partner_id.id if hasattr(record, 'partner_id') else author_id - else: - if not author_id: - raise NotFound() - else: - raise Forbidden() - kw.pop('csrf_token', None) - return record.with_context(mail_create_nosubscribe=nosubscribe).message_post(body=message, - message_type=kw.pop('message_type', "comment"), - subtype=kw.pop('subtype', "mt_comment"), - author_id=author_id, - **kw) class WebsiteMail(http.Controller): @@ -108,50 +60,3 @@ class WebsiteMail(http.Controller): ('partner_id', '=', partner.id) ])) return values - - @http.route(['/website_mail/post/post'], type='http', methods=['POST'], auth='public', website=True) - def website_chatter_post(self, res_model, res_id, message, **kw): - url = request.httprequest.referrer - if message: - _message_post_helper(res_model, int(res_id), message, **kw) - url = url + "#discussion" - return request.redirect(url) - - @http.route('/website_mail/init', type='json', auth='public', website=True) - def website_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs): - is_user_public = bool(request.env.user == request.website.user_id) - message_data = self.website_message_fetch(res_model, res_id, domain=domain, limit=limit, **kwargs) - display_composer = False - if kwargs.get('allow_composer'): - display_composer = kwargs.get('token') or not is_user_public - return { - 'messages': message_data['messages'], - 'options': { - 'message_count': message_data['message_count'], - 'is_user_public': is_user_public, - 'is_user_publisher': request.env.user.has_group('website.group_website_publisher'), - 'display_composer': display_composer, - 'partner_id': request.env.user.partner_id.id - } - } - - @http.route('/website_mail/fetch', type='json', auth='public', website=True) - def website_message_fetch(self, res_model, res_id, domain=False, limit=10, offset=0, **kw): - if not domain: - domain = [] - # Only search into website_message_ids, so apply the same domain to perform only one search - # extract domain from the 'website_message_ids' field - field_domain = request.env[res_model]._fields['website_message_ids'].domain - domain += field_domain(request.env[res_model]) if callable(field_domain) else field_domain - domain += [('res_id', '=', res_id)] - # Check access - Message = request.env['mail.message'] - if kw.get('token'): - access_as_sudo = _special_access_object(res_model, res_id, token=kw.get('token'), token_field=kw.get('token_field')) - if not access_as_sudo: # if token is not correct, raise Forbidden - raise Forbidden() - Message = request.env['mail.message'].sudo() - return { - 'messages': Message.search(domain, limit=limit, offset=offset).website_message_format(), - 'message_count': Message.search_count(domain) - } diff --git a/addons/website_mail/models/__init__.py b/addons/website_mail/models/__init__.py index e90621e2bd2..75ea63bd6d8 100644 --- a/addons/website_mail/models/__init__.py +++ b/addons/website_mail/models/__init__.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import mail_thread from . import mail_message from . import update diff --git a/addons/website_mail/models/mail_message.py b/addons/website_mail/models/mail_message.py index f1ebde86c2a..34609160f1d 100644 --- a/addons/website_mail/models/mail_message.py +++ b/addons/website_mail/models/mail_message.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models, SUPERUSER_ID, _ +from odoo import api, fields, models, _ from odoo.osv import expression from odoo.tools import html2plaintext from odoo.exceptions import AccessError @@ -58,13 +58,6 @@ class MailMessage(models.Model): return super(MailMessage, self).check_access_rule(operation=operation) @api.multi - def website_message_format(self): - message_values = self.read([ - 'id', 'body', 'date', 'author_id', 'email_from', # base message fields - 'message_type', 'subtype_id', 'subject', # message specific - 'model', 'res_id', 'record_name', # document related - 'website_published', - ]) - message_tree = dict((m.id, m) for m in self.sudo()) - self._message_read_dict_postprocess(message_values, message_tree) - return message_values + def _portal_message_format(self, fields_list): + fields_list += ['website_published'] + return super(MailMessage, self)._portal_message_format(fields_list) diff --git a/addons/website_mail/security/website_mail_security.xml b/addons/website_mail/security/website_mail_security.xml index 0144b11e5ed..d814fff16ef 100644 --- a/addons/website_mail/security/website_mail_security.xml +++ b/addons/website_mail/security/website_mail_security.xml @@ -4,7 +4,7 @@ <record id="mail_message_rule_public" model="ir.rule"> <field name="name">mail.message: portal/public: read published messages</field> - <field name="model_id" ref="model_mail_message"/> + <field name="model_id" ref="mail.model_mail_message"/> <field name="domain_force">[('website_published', '=', True)]</field> <field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_public'))]"/> </record> diff --git a/addons/website_mail/static/src/css/website_mail.less b/addons/website_mail/static/src/css/website_mail.less index dda250e65e5..6be6bf9007c 100644 --- a/addons/website_mail/static/src/css/website_mail.less +++ b/addons/website_mail/static/src/css/website_mail.less @@ -2,37 +2,3 @@ .js_follow[data-follow='off'] .js_unfollow_btn { display: none; } - -.o_website_mail_chatter { - padding: 10px; - - .o_website_mail_avatar{ - width: 45px; - height: 45px; - } - - .o_website_mail_header { - margin-bottom: 15px; - } - - .o_website_mail_composer { - margin-bottom: 15px; - } - - .o_website_mail_messages { - margin-bottom: 15px; - - .o_website_mail_message_title { - p { - font-size:85%; - color:@odoo-main-color-muted; - margin: 0px; - } - } - - } - - .o_website_mail_pager { - text-align: center; - } -} diff --git a/addons/website_mail/static/src/js/website_mail.js b/addons/website_mail/static/src/js/website_mail.js index 3e373c4dce0..711df6ebbae 100644 --- a/addons/website_mail/static/src/js/website_mail.js +++ b/addons/website_mail/static/src/js/website_mail.js @@ -1,237 +1,20 @@ -odoo.define('website_mail.thread', function (require) { +odoo.define('website_mail.thread', function(require) { 'use strict'; -var base = require('web_editor.base'); var ajax = require('web.ajax'); var core = require('web.core'); -var Widget = require('web.Widget'); -var rpc = require('web.rpc'); var qweb = core.qweb; -var _t = core._t; + +var PortalChatter = require('portal.chatter').PortalChatter; /** - * Widget WebsiteMailThread - * - * - Fetch message fron controller - * - Display chatter: pager, total message, composer (according to access right) - * - Provider API to filter displayed messages + * Extends Frontend Chatter to handle rating */ -var WebsiteMailThread = Widget.extend({ - template: 'website_mail.chatter', - events: { - "click .o_website_mail_pager_btn": '_onClickPager' - }, - - init: function (parent, options){ - this._super.apply(this, arguments); - this.options = _.defaults(options || {}, { - 'allow_composer': true, - 'display_composer': false, - 'csrf_token': odoo.csrf_token, - 'message_count': 0, - 'pager_step': 10, - 'pager_scope': 5, - 'pager_start': 1, - 'is_user_public': true, - 'is_user_publisher': false, - 'domain': [], - }); - this.set('messages', []); - this.set('message_count', this.options['message_count']); - this.set('pager', {}); - this.set('domain', this.options['domain']); - this._current_page = this.options['pager_start']; - }, - willStart: function (){ - var self = this; - // load qweb template and init data - return $.when( - rpc.query({ - route: '/website_mail/init', - params: this._messageFetchPrepareParams() - }), this._loadTemplates() - ).then(function (result){ - // bind events - self.on("change:messages", self, self._renderMessages); - self.on("change:message_count", self, function () { - self._renderMessageCount(); - self.set('pager', self._pager(self._current_page)); - }); - self.on("change:pager", self, self._renderPager); - self.on("change:domain", self, self._onChangeDomain); - // set options and parameters - self.options = _.extend(self.options, result['options'] || {}); - self.set('message_count', self.options['message_count']); - self.set('messages', self.preprocessMessages(result['messages'])); - return result; - }); - }, - - //-------------------------------------------------------------------------- - // Public - //-------------------------------------------------------------------------- - - /** - * Fetch the messages and the message count from the server for the - * current page and current domain. - * - * @param {Array} - * @returns {Deferred} - */ - messageFetch: function (domain){ - var self = this; - return rpc.query({ - route: '/website_mail/fetch', - params: self._messageFetchPrepareParams() - }).then(function (result){ - self.set('messages', self.preprocessMessages(result['messages'])); - self.set('message_count', result['message_count']); - }); - }, - /** - * Update the messages format - * - * @param {Array<Object>} - * @returns {Array} - */ - preprocessMessages: function (messages){ - _.each(messages, function (m){ - m['author_avatar_url'] = _.str.sprintf('/web/image/%s/%s/author_avatar/50x50', 'mail.message', m.id); - m['published_date_str'] = _.str.sprintf(_t('Published on %s'), moment(m.date).format('MMMM Do YYYY, h:mm:ss a')); - }); - return messages; +PortalChatter.include({ + _loadTemplates: function(){ + return $.when(this._super(), ajax.loadXML('/website_mail/static/src/xml/website_mail.xml', qweb)); }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Change the current page by refreshing current domain - * - * @private - * @param {Number} page - * @param {Array} domain - */ - _changeCurrentPage: function (page, domain){ - this._current_page = page; - var d = domain ? domain : _.clone(this.get('domain')); - this.set('domain', d); // trigger fetch message - }, - /** - * @private - * @returns {Deferred} - */ - _loadTemplates: function () { - return ajax.loadXML('/website_mail/static/src/xml/website_mail.xml', qweb); - }, - _messageFetchPrepareParams: function () { - var self = this; - var data = { - 'res_model': this.options['res_model'], - 'res_id': this.options['res_id'], - 'limit': this.options['pager_step'], - 'offset': (this._current_page-1) * this.options['pager_step'], - 'allow_composer': this.options['allow_composer'], - }; - // add fields to allow to post comment without being logged - _.each(['token', 'token_field'], function (field) { - if (self.options[field]){ - data[field] = self.options[field]; - } - }); - // add domain - if (this.get('domain')){ - data['domain'] = this.get('domain'); - } - return data; - }, - /** - * Generate the pager data for the given page number - * - * @private - * @param {Number} page - * @returns {Object} - */ - _pager: function (page) { - page = page || 1; - var total = this.get('message_count'); - var scope = this.options['pager_scope']; - var step = this.options['pager_step']; - - // Compute Pager - var page_count = Math.ceil(parseFloat(total) / step); - - page = Math.max(1, Math.min(parseInt(page), page_count)); - scope -= 1; - - var pmin = Math.max(page - parseInt(Math.floor(scope/2)), 1); - var pmax = Math.min(pmin + scope, page_count); - - if (pmax - scope > 0){ - pmin = pmax - scope; - } else { - pmin = 1; - } - - var pages = []; - _.each(_.range(pmin, pmax+1), function (index) { - pages.push(index); - }); - - return { - "page_count": page_count, - "offset": (page - 1) * step, - "page": page, - "page_start": pmin, - "page_previous": Math.max(pmin, page - 1), - "page_next": Math.min(pmax, page + 1), - "page_end": pmax, - "pages": pages - }; - }, - _renderMessages: function () { - this.$('.o_website_mail_messages').html(qweb.render("website_mail.chatter_messages", {widget: this})); - }, - _renderMessageCount: function () { - this.$('.o_message_counter').replaceWith(qweb.render("website_mail.chatter_message_count", {widget: this})); - }, - _renderPager: function () { - this.$('.o_website_mail_pager').replaceWith(qweb.render("website_mail.pager", {widget: this})); - }, - - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - - _onChangeDomain: function () { - var self = this; - this.messageFetch().then(function () { - var p = self.get('current_page'); - self.set('pager', self._pager(p)); - }); - }, - /** - * @private - * @param {MouseEvent} event - */ - _onClickPager: function (ev) { - ev.preventDefault(); - var page = $(ev.currentTarget).data('page'); - this._changeCurrentPage(page); - }, -}); - -base.ready().then(function () { - $('.o_website_mail_thread').each(function (index) { - var $elem = $(this); - var mail_thread = new WebsiteMailThread(null, $elem.data()); - mail_thread.appendTo($elem); - }); }); -return { - WebsiteMailThread: WebsiteMailThread, -}; }); diff --git a/addons/website_mail/static/src/xml/website_mail.xml b/addons/website_mail/static/src/xml/website_mail.xml index 01eefeb5d8b..b80e2eb8af8 100644 --- a/addons/website_mail/static/src/xml/website_mail.xml +++ b/addons/website_mail/static/src/xml/website_mail.xml @@ -9,124 +9,15 @@ </t> </t> - <t t-name="website_mail.chatter_message_count"> - <t t-set="count" t-value="widget.get('message_count')"/> - <div class="o_message_counter"> - <t t-if="count"> - <span class="o_message_count fa fa-comments"> <t t-esc="count"/></span> - <t t-if="count == 1">comment</t> - <t t-else="">comments</t> + <t t-extend="portal.chatter_messages"> + <t t-jquery=".o_portal_chatter_message_title" t-operation="before"> + <t t-call="website_mail.publish_short"> + <t t-set="res_model" t-value="'mail.message'"/> + <t t-set="res_id" t-value="message.id"/> + <t t-set="object" t-value="message"/> + <t t-set="is_publisher" t-value="widget.options['is_user_publisher']"/> </t> - <t t-else=""> - There are no comments for now. - </t> - </div> - </t> - - <t t-name="website_mail.chatter_composer"> - <div class="o_website_mail_composer" t-if="widget.options['allow_composer']"> - <t t-if="!widget.options['display_composer']"> - <h4>Leave a comment</h4> - <p>You must be <a t-attf-href="/web/login?redirect=#{window.encodeURI(window.location.href + '#discussion')}">logged in</a> to post a comment.</p> - </t> - <t t-if="widget.options['display_composer']"> - <div class="media"> - <div class="media-left"> - <img class="o_website_mail_avatar pull-left" t-attf-src="/web/image/res.partner/#{widget.options['partner_id']}/image_small/50x50"/> - </div> - <div class="media-body"> - <form class="o_website_mail_composer_form" t-attf-action="/website_mail/post/post" method="POST"> - <input type="hidden" name="csrf_token" t-att-value="widget.options['csrf_token']"/> - <div class="mb32"> - <textarea rows="4" name="message" class="form-control" placeholder="Write a message..."></textarea> - <input type='hidden' name="res_model" t-att-value="widget.options['res_model']"/> - <input type='hidden' name="res_id" t-att-value="widget.options['res_id']"/> - <input type='hidden' name="token" t-att-value="widget.options['token']" t-if="widget.options['token']"/> - <input type='hidden' name="sha_in" t-att-value="widget.options['sha_in']" t-if="widget.options['sha_in']"/> - <input type='hidden' name="sha_time" t-att-value="widget.options['sha_time']" t-if="widget.options['sha_time']"/> - <input type='hidden' name="token_field" t-att-value="widget.options['token_field']" t-if="widget.options['token_field']"/> - <div class="alert alert-danger mt8 mb0 o_website_mail_composer_error" style="display:none;"> - Oops! Something went wrong. Try to reload the page and log in. - </div> - <button t-attf-class="o_website_mail_composer_btn btn btn-primary mt8 o_website_message_post_helper" type="submit">Send</button> - </div> - </form> - </div> - </div> - </t> - <hr/> - </div> - </t> - - <t t-name="website_mail.chatter_messages"> - <div class="o_website_mail_messages"> - <t t-foreach="widget.get('messages')" t-as="message"> - <div class="media o_website_mail_message" t-att-id="'message-' + message.id"> - <div class="media-left"> - <img class="media-object o_website_mail_avatar" t-att-src="message.author_avatar_url" alt="avatar"/> - </div> - <div class="media-body"> - - <t t-call="website_mail.publish_short"> - <t t-set="res_model" t-value="'mail.message'"/> - <t t-set="res_id" t-value="message.id"/> - <t t-set="object" t-value="message"/> - <t t-set="is_publisher" t-value="widget.options['is_user_publisher']"/> - </t> - - <div class="o_website_mail_message_title"> - <h5 class="media-heading"> - <t t-esc="message.author_id[1]"/> - </h5> - <p class="o_website_mail_puslished_date"><t t-esc="message.published_date_str"/></p> - </div> - <t t-raw="message.body"/> - - <div class="o_website_mail_attachments"> - <div class="col-md-2 col-sm-3 text-center" t-foreach='message.attachment_ids' t-as='attachment'> - <a t-attf-href="/web/content/#{attachment.id}?download=true" target="_blank"> - <div class='oe_attachment_embedded o_image' t-att-title="attachment.name" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/100x80"/> - <div class='oe_attachment_name'><t t-raw='attachment.name'/></div> - </a> - </div> - </div> - </div> - </div> - </t> - </div> - </t> - - <t t-name="website_mail.pager"> - <div class="o_website_mail_pager"> - <t t-if="!_.isEmpty(widget.get('pager'))"> - <ul class="pagination" t-if="widget.get('pager')['pages'].length > 1"> - <li t-if="widget.get('pager')['page'] != widget.get('pager')['page_previous']" t-att-data-page="widget.get('pager')['page_previous']" class="o_website_mail_pager_btn"> - <a href="#"><i class="fa fa-chevron-left"/></a> - </li> - <t t-foreach="widget.get('pager')['pages']" t-as="page"> - <li t-att-data-page="page" t-att-class="page == widget.get('pager')['page'] ? 'o_website_mail_pager_btn active' : 'o_website_mail_pager_btn'"> - <a href="#"><t t-esc="page"/></a> - </li> - </t> - <li t-if="widget.get('pager')['page'] != widget.get('pager')['page_next']" t-att-data-page="widget.get('pager')['page_next']" class="o_website_mail_pager_btn"> - <a href="#"><i class="fa fa-chevron-right"/></a> - </li> - </ul> - </t> - </div> + </t> </t> - <t t-name="website_mail.chatter"> - <div class="o_website_mail_chatter"> - <div class="o_website_mail_header"> - <t t-call="website_mail.chatter_message_count"/> - </div> - <hr/> - <t t-call="website_mail.chatter_composer"/> - <t t-call="website_mail.chatter_messages"/> - <div class="o_website_mail_footer"> - <t t-call="website_mail.pager"/> - </div> - </div> - </t> </templates> diff --git a/addons/website_mail/views/website_mail_templates.xml b/addons/website_mail/views/website_mail_templates.xml index d703dad5e79..50efe171a5d 100644 --- a/addons/website_mail/views/website_mail_templates.xml +++ b/addons/website_mail/views/website_mail_templates.xml @@ -25,21 +25,4 @@ </xpath> </template> - <!-- - Generic chatter template for the frontend - This template provide the container of the chatter. The rest is done in js. - To use this template, you need to call it after setting the following variable in your template or in your controller: - :object browserecord : the mail_thread object - :message_per_page int (optional): number of message per chatter page - :token string (optional): if you want your chatter to be available for non-logged user, - you can use a token to verify the identity of the user; - the message will be posted with the identity of the partner_id of the object - :token_field string (optional): name of the field that contains the token on the object (default to 'token') - --> - <template id="message_thread"> - <div id="discussion" class="hidden-print o_website_mail_thread" - t-att-data-token="token" t-att-public-user="website.env.user == request.website.user_id" t-att-data-res_model="object._name" t-att-data-res_id="object.id" t-att-data-token_field="token_field" t-att-data-pager_step="message_per_page or 10" t-att-data-allow_composer="'0' if disable_composer else '1'"> - </div> - </template> - </odoo> diff --git a/addons/website_project/views/project_templates.xml b/addons/website_project/views/project_templates.xml index c9e4b047d53..dca48749e88 100644 --- a/addons/website_project/views/project_templates.xml +++ b/addons/website_project/views/project_templates.xml @@ -117,7 +117,7 @@ <h4><strong>Message and communication history</strong></h4> </div> <div class="col-md-10 col-md-offset-1 mt16"> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="project"/> </t> </div> @@ -235,7 +235,7 @@ <h4><strong>Message and communication history</strong></h4> </div> <div class="col-md-10 col-md-offset-1 mt16"> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="task"/> </t> </div> diff --git a/addons/website_quote/controllers/main.py b/addons/website_quote/controllers/main.py index 522d3561b7f..89d93a1854e 100644 --- a/addons/website_quote/controllers/main.py +++ b/addons/website_quote/controllers/main.py @@ -6,7 +6,7 @@ import werkzeug from odoo import fields, http, _ from odoo.http import request from odoo.addons.portal.controllers.portal import get_records_pager -from odoo.addons.website_mail.controllers.main import _message_post_helper +from odoo.addons.portal.controllers.mail import _message_post_helper class sale_quote(http.Controller): diff --git a/addons/website_quote/views/website_quote_templates.xml b/addons/website_quote/views/website_quote_templates.xml index 9567e0241e2..92e9dbbc846 100644 --- a/addons/website_quote/views/website_quote_templates.xml +++ b/addons/website_quote/views/website_quote_templates.xml @@ -430,7 +430,7 @@ <xpath expr="//div[@id='quote_content']" position="inside"> <h1 class="page-header">History</h1> <!-- Options:Quotation Chatter: user can reply --> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="quotation"/> <t t-set="token_field" t-value="'access_token'"/> </t> diff --git a/addons/website_rating/controllers/website_mail.py b/addons/website_rating/controllers/website_mail.py index 4487307effd..26c0f4dedfa 100644 --- a/addons/website_rating/controllers/website_mail.py +++ b/addons/website_rating/controllers/website_mail.py @@ -1,19 +1,17 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from werkzeug.exceptions import NotFound - from odoo import http from odoo.http import request -from odoo.addons.website_mail.controllers.main import WebsiteMail +from odoo.addons.portal.controllers.mail import PortalChatter -class WebsiteRating(WebsiteMail): +class WebsiteRating(PortalChatter): @http.route() - def website_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs): - result = super(WebsiteRating, self).website_chatter_init(res_model, res_id, domain=domain, limit=limit, **kwargs) + def portal_chatter_init(self, res_model, res_id, domain=False, limit=False, **kwargs): + result = super(WebsiteRating, self).portal_chatter_init(res_model, res_id, domain=domain, limit=limit, **kwargs) # get the rating statistics about the record if kwargs.get('rating_include'): record = request.env[res_model].browse(res_id) @@ -22,10 +20,10 @@ class WebsiteRating(WebsiteMail): return result @http.route() - def website_message_fetch(self, res_model, res_id, domain=False, limit=False, offset=False, **kw): - # add 'rating_include' in context, to fetch them in website_message_format + def portal_message_fetch(self, res_model, res_id, domain=False, limit=False, offset=False, **kw): + # add 'rating_include' in context, to fetch them in portal_message_format if kw.get('rating_include'): context = dict(request.context) context['rating_include'] = True request.context = context - return super(WebsiteRating, self).website_message_fetch(res_model, res_id, domain=domain, limit=limit, offset=offset, **kw) + return super(WebsiteRating, self).portal_message_fetch(res_model, res_id, domain=domain, limit=limit, offset=offset, **kw) diff --git a/addons/website_rating/models/mail_message.py b/addons/website_rating/models/mail_message.py index 8e6c67fc601..2f1f59cc320 100644 --- a/addons/website_rating/models/mail_message.py +++ b/addons/website_rating/models/mail_message.py @@ -8,12 +8,8 @@ class MailMessage(models.Model): _inherit = 'mail.message' @api.multi - def website_message_format(self): - result = super(MailMessage, self).website_message_format() + def _portal_message_format(self, field_list): # inlude rating value in data if requested if self._context.get('rating_include'): - message_data = self.read(['rating_value']) - message_tree = dict((m['id'], m['rating_value']) for m in message_data) - for message_vals in result: - message_vals['rating_value'] = message_tree.get(message_vals['id'], False) # False for no rating - return result + field_list += ['rating_value'] + return super(MailMessage, self)._portal_message_format(field_list) diff --git a/addons/website_rating/static/src/js/website_mail.js b/addons/website_rating/static/src/js/website_mail.js index d9d114de502..d672af6788d 100644 --- a/addons/website_rating/static/src/js/website_mail.js +++ b/addons/website_rating/static/src/js/website_mail.js @@ -8,13 +8,13 @@ odoo.define('website_rating.thread', function(require) { var qweb = core.qweb; var _t = core._t; - var WebsiteMailThread = require('website_mail.thread').WebsiteMailThread; + var PortalChatter = require('portal.chatter').PortalChatter; /** * Extends Frontend Chatter to handle rating */ - WebsiteMailThread.include({ - events: _.extend({}, WebsiteMailThread.prototype.events, { + PortalChatter.include({ + events: _.extend({}, PortalChatter.prototype.events, { "mousemove .stars i" : "_onMoveStar", "mouseleave .stars i" : "_onMoveOutStar", "click .stars" : "_onClickStar", diff --git a/addons/website_rating/static/src/xml/website_mail.xml b/addons/website_rating/static/src/xml/website_mail.xml index ffe0df540c4..2f3dd132a8b 100644 --- a/addons/website_rating/static/src/xml/website_mail.xml +++ b/addons/website_rating/static/src/xml/website_mail.xml @@ -27,7 +27,7 @@ <t t-call="website_rating.rating_stars_static"> <t t-set="val" t-value="widget.get('rating_card_values')['avg'] || 0"/> </t> - <t t-call="website_mail.chatter_message_count"/> + <t t-call="portal.chatter_message_count"/> </div> </div> <div class="col-md-6" t-if="!_.isEmpty(widget.get('rating_card_values'))"> @@ -76,15 +76,15 @@ </t> <!-- - Inherited templates from website_mail to custom chatter with rating + Inherited templates from portal to custom chatter with rating --> - <t t-extend="website_mail.chatter_composer"> - <t t-jquery=".o_website_mail_composer_form input[name='csrf_token']" t-operation="after"> + <t t-extend="portal.chatter_composer"> + <t t-jquery=".o_portal_chatter_composer_form input[name='csrf_token']" t-operation="after"> <t t-call="website_rating.rating_star_input"/> </t> </t> - <t t-extend="website_mail.chatter_messages"> + <t t-extend="portal.chatter_messages"> <t t-jquery="t[t-raw='message.body']" t-operation="before"> <t t-if="message['rating_value']"> <t t-call="website_rating.rating_stars_static"> @@ -94,13 +94,13 @@ </t> </t> - <t t-extend="website_mail.chatter"> - <t t-jquery="t[t-call='website_mail.chatter_message_count']" t-operation="replace"> + <t t-extend="portal.chatter"> + <t t-jquery="t[t-call='portal.chatter_message_count']" t-operation="replace"> <t t-if="widget.options['display_rating']"> <t t-call="website_rating.rating_card"/> </t> <t t-if="!widget.options['display_rating']"> - <t t-call="website_mail.chatter_message_count"/> + <t t-call="portal.chatter_message_count"/> </t> </t> </t> diff --git a/addons/website_rating/views/website_rating_templates.xml b/addons/website_rating/views/website_rating_templates.xml index c5c6684e371..058b643f2ae 100644 --- a/addons/website_rating/views/website_rating_templates.xml +++ b/addons/website_rating/views/website_rating_templates.xml @@ -8,7 +8,7 @@ </xpath> </template> - <template id="message_thread" inherit_id="website_mail.message_thread"> + <template id="message_thread" inherit_id="portal.message_thread"> <xpath expr="//div[@id='discussion']" position="attributes"> <attribute name="t-att-data-display_rating">display_rating or False</attribute> </xpath> diff --git a/addons/website_sale/views/templates.xml b/addons/website_sale/views/templates.xml index 7c6eccfae10..9331071d790 100644 --- a/addons/website_sale/views/templates.xml +++ b/addons/website_sale/views/templates.xml @@ -552,7 +552,7 @@ <hr/> <div class="row"> <div class="col-md-8 col-md-offset-2"> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="product"/> <t t-set="display_rating" t-value="True"/> </t> diff --git a/addons/website_slides/views/website_slides.xml b/addons/website_slides/views/website_slides.xml index afcf7747203..aff237ee6a4 100644 --- a/addons/website_slides/views/website_slides.xml +++ b/addons/website_slides/views/website_slides.xml @@ -543,7 +543,7 @@ </h4> </div> <div t-att-class="comments and 'tab-pane fade active in' or 'tab-pane fade'" id="discuss"> - <t t-call="website_mail.message_thread"> + <t t-call="portal.message_thread"> <t t-set="object" t-value="slide"/> </t> </div> |
