summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérome Maes <jem@openerp.com>2017-08-09 13:09:32 +0200
committerJérome Maes <jem@openerp.com>2017-08-16 14:56:40 +0200
commit3cfd64f63f6153c170c9c876fa65976a95da22cb (patch)
treedcd477f6e8225ed788fa38484fc28272e77073bb
parent2972976962617d4b8a0113bae58c640ab41cdff8 (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
-rw-r--r--addons/portal/controllers/__init__.py1
-rw-r--r--addons/portal/controllers/mail.py103
-rw-r--r--addons/portal/models/__init__.py4
-rw-r--r--addons/portal/models/mail_message.py24
-rw-r--r--addons/portal/models/mail_thread.py (renamed from addons/website_mail/models/mail_thread.py)0
-rw-r--r--addons/portal/static/src/js/portal_chatter.js238
-rw-r--r--addons/portal/static/src/less/portal_chatter.less33
-rw-r--r--addons/portal/static/src/xml/portal_chatter.xml117
-rw-r--r--addons/portal/views/assets.xml2
-rw-r--r--addons/portal/views/portal_templates.xml18
-rw-r--r--addons/website_blog/views/website_blog_templates.xml2
-rw-r--r--addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml4
-rw-r--r--addons/website_mail/__manifest__.py5
-rw-r--r--addons/website_mail/controllers/main.py95
-rw-r--r--addons/website_mail/models/__init__.py1
-rw-r--r--addons/website_mail/models/mail_message.py15
-rw-r--r--addons/website_mail/security/website_mail_security.xml2
-rw-r--r--addons/website_mail/static/src/css/website_mail.less34
-rw-r--r--addons/website_mail/static/src/js/website_mail.js231
-rw-r--r--addons/website_mail/static/src/xml/website_mail.xml125
-rw-r--r--addons/website_mail/views/website_mail_templates.xml17
-rw-r--r--addons/website_project/views/project_templates.xml4
-rw-r--r--addons/website_quote/controllers/main.py2
-rw-r--r--addons/website_quote/views/website_quote_templates.xml2
-rw-r--r--addons/website_rating/controllers/website_mail.py16
-rw-r--r--addons/website_rating/models/mail_message.py10
-rw-r--r--addons/website_rating/static/src/js/website_mail.js6
-rw-r--r--addons/website_rating/static/src/xml/website_mail.xml16
-rw-r--r--addons/website_rating/views/website_rating_templates.xml2
-rw-r--r--addons/website_sale/views/templates.xml2
-rw-r--r--addons/website_slides/views/website_slides.xml2
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 &gt; 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 &gt; 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>