diff --git a/addons/website_mail_channel/__openerp__.py b/addons/website_mail_channel/__openerp__.py
index f38e434dcd8..ab541dac6b0 100644
--- a/addons/website_mail_channel/__openerp__.py
+++ b/addons/website_mail_channel/__openerp__.py
@@ -10,6 +10,7 @@ Odoo Mail Group : Mailing List Archives
""",
'depends': ['website_mail'],
'data': [
+ 'data/mail_template_data.xml',
'views/website_mail_channel_templates.xml',
'views/snippets.xml',
],
diff --git a/addons/website_mail_channel/controllers/main.py b/addons/website_mail_channel/controllers/main.py
index 8cac7b0ee30..1b043caf8ac 100644
--- a/addons/website_mail_channel/controllers/main.py
+++ b/addons/website_mail_channel/controllers/main.py
@@ -89,23 +89,30 @@ class MailGroup(http.Controller):
# search partner_id
if request.env.user != request.website.user_id:
+ # connected users are directly (un)subscribed
partner_ids = request.env.user.partner_id.ids
- else: # mail_thread method
+
+ # add or remove channel members
+ if unsubscribe:
+ channel.check_access_rule('read')
+ channel.sudo().write({'channel_partner_ids': [(3, partner_id) for partner_id in partner_ids]})
+ return "off"
+ else: # add partner to the channel
+ request.session['partner_id'] = partner_ids[0]
+ channel.check_access_rule('read')
+ channel.sudo().write({'channel_partner_ids': [(4, partner_id) for partner_id in partner_ids]})
+ return "on"
+
+ else:
+ # public users will recieve confirmation email
partner_ids = channel.sudo()._find_partner_from_emails([email], check_followers=True)
if not partner_ids or not partner_ids[0]:
name = email.split('@')[0]
- partner_ids = request.env['res.partner'].sudo().create({'name': name, 'email': email}).ids
+ partner_ids = [request.env['res.partner'].sudo().create({'name': name, 'email': email}).id]
+
+ channel.sudo()._send_confirmation_email(partner_ids, unsubscribe)
+ return "email"
- # add or remove channel members
- if unsubscribe:
- channel.check_access_rule('read')
- channel.sudo().write({'channel_partner_ids': [(3, partner_id) for partner_id in partner_ids]})
- return False
- else: # add partner to the channel
- request.session['partner_id'] = partner_ids[0]
- channel.check_access_rule('read')
- channel.sudo().write({'channel_partner_ids': [(4, partner_id) for partner_id in partner_ids]})
- return True
@http.route([
"/groups/",
@@ -189,3 +196,35 @@ class MailGroup(http.Controller):
return {
'alias_name': group.alias_id and group.alias_id.alias_name and group.alias_id.alias_domain and '%s@%s' % (group.alias_id.alias_name, group.alias_id.alias_domain) or False
}
+
+ @http.route("/groups/subscribe///", type='http', auth='public', website=True)
+ def confirm_subscribe(self, channel, partner_id, token, **kw):
+ subscriber = request.env['mail.channel.partner'].search([('channel_id', '=', channel.id), ('partner_id', '=', partner_id)])
+ if subscriber:
+ # already registered, maybe clicked twice
+ return request.render('website_mail_channel.invalid_token_subscription')
+
+ subscriber_token = channel._generate_action_token(partner_id, action='subscribe')
+ if token != subscriber_token:
+ return request.render('website_mail_channel.invalid_token_subscription')
+
+ # add partner
+ channel.sudo().write({'channel_partner_ids': [(4, partner_id)]})
+
+ return request.website.render("website_mail_channel.confirmation_subscription", {'subscribing': True})
+
+ @http.route("/groups/unsubscribe///", type='http', auth='public', website=True)
+ def confirm_unsubscribe(self, channel, partner_id, token, **kw):
+ subscriber = request.env['mail.channel.partner'].search([('channel_id', '=', channel.id), ('partner_id', '=', partner_id)])
+ if not subscriber:
+ # not registered, maybe already unsubsribed
+ return request.render('website_mail_channel.invalid_token_subscription')
+
+ subscriber_token = channel._generate_action_token(partner_id, action='unsubscribe')
+ if token != subscriber_token:
+ return request.render('website_mail_channel.invalid_token_subscription')
+
+ # remove partner
+ channel.sudo().write({'channel_partner_ids': [(3, partner_id)]})
+
+ return request.website.render("website_mail_channel.confirmation_subscription", {'subscribing': False})
diff --git a/addons/website_mail_channel/data/mail_template_data.xml b/addons/website_mail_channel/data/mail_template_data.xml
new file mode 100644
index 00000000000..31c602f99a3
--- /dev/null
+++ b/addons/website_mail_channel/data/mail_template_data.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ Subscribe to mailing list
+
+ Please confirm subscription to ${object.name}
+
+Hello,
+You have requested to be subscribed to the mailing list ${object.name}
+To confirm, please visit the following link:
+${ctx['token_url']}
+If this was a mistake or you did not requested this action, please ignore this message.
+
+
+
+
+ Unsubscribe to mailing list
+
+ Please confirm unsubscription to ${object.name}
+
+Hello,
+You have requested to be unsubscribed to the mailing list ${object.name}
+To confirm, please visit the following link:
+${ctx['token_url']}
+If this was a mistake or you did not requested this action, please ignore this message.
+
+
+
diff --git a/addons/website_mail_channel/models/mail_channel.py b/addons/website_mail_channel/models/mail_channel.py
index d57d82c51a8..fb1db7ce97b 100644
--- a/addons/website_mail_channel/models/mail_channel.py
+++ b/addons/website_mail_channel/models/mail_channel.py
@@ -1,6 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+import hmac
+
+from urlparse import urljoin
+
from odoo import api, models
from odoo.tools.safe_eval import safe_eval as eval
from odoo.addons.website.models.website import slug
@@ -27,3 +31,41 @@ class MailGroup(models.Model):
})
res['headers'] = repr(headers)
return res
+
+ @api.multi
+ def _send_confirmation_email(self, partner_ids, unsubscribe=False):
+ base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+ route = "/groups/%(action)s/%(channel)s/%(partner)s/%(token)s"
+ if unsubscribe:
+ template = self.env.ref('website_mail_channel.mail_template_list_unsubscribe')
+ action = 'unsubscribe'
+ else:
+ template = self.env.ref('website_mail_channel.mail_template_list_subscribe')
+ action = 'subscribe'
+
+ for partner_id in partner_ids:
+ # generate a new token per subscriber
+ token = self._generate_action_token(partner_id, action=action)
+
+ token_url = urljoin(base_url, route % {
+ 'action': action,
+ 'channel': self.id,
+ 'partner': partner_id,
+ 'token': token,
+ })
+ template.with_context(token_url=token_url).send_mail(self.id,
+ force_send=True,
+ email_values={'recipient_ids': [(4, partner_id)]}
+ )
+
+ return True
+
+ @api.multi
+ def _generate_action_token(self, partner_id, action='unsubscribe'):
+ self.ensure_one()
+ secret = self.env['ir.config_parameter'].sudo().get_param('database.secret')
+ data = '$'.join([
+ str(self.id),
+ str(partner_id),
+ action])
+ return hmac.new(secret.encode('utf-8'), data).hexdigest()
diff --git a/addons/website_mail_channel/static/src/js/website_mail_channel.snippet.js b/addons/website_mail_channel/static/src/js/website_mail_channel.snippet.js
index 8a872783e5e..7fdc14f8c2a 100644
--- a/addons/website_mail_channel/static/src/js/website_mail_channel.snippet.js
+++ b/addons/website_mail_channel/static/src/js/website_mail_channel.snippet.js
@@ -18,7 +18,7 @@ animation.registry.follow_alias = animation.Class.extend({
self.is_user = data.is_user;
self.email = data.email;
self.$target.find('.js_mg_link').attr('href', '/groups/' + self.$target.data('id'));
- self.toggle_subscription(data.is_member, data.email);
+ self.toggle_subscription(data.is_member ? 'on' : 'off', data.email);
self.$target.removeClass("hidden");
});
@@ -43,29 +43,47 @@ animation.registry.follow_alias = animation.Class.extend({
}
this.$target.removeClass('has-error');
+ var subscription_action = this.$target.attr("data-follow") || "off";
+ if (location.search.slice(1).split('&').indexOf("unsubscribe") >= 0) {
+ // force unsubscribe mode via URI /groups?unsubscribe
+ subscription_action = 'on';
+ }
ajax.jsonRpc('/groups/subscription', 'call', {
'channel_id': +this.$target.data('id'),
- 'object': this.$target.data('object'),
- 'subscription': this.$target.attr("data-follow") || "off",
+ 'object': this.$target.data('object'),
+ 'subscription': subscription_action,
'email': $email.length ? $email.val() : false,
}).then(function (follow) {
self.toggle_subscription(follow, self.email);
});
},
toggle_subscription: function(follow, email) {
+ // .js_mg_follow_form contains subscribe form
+ // .js_mg_details contains send/archives/unsubscribe links
+ // .js_mg_confirmation contains message warning has been sent
var alias_done = this.get_alias_info();
- if (follow) {
+ if (follow === "on") {
+ // user is connected and can unsubscribe
this.$target.find(".js_mg_follow_form").addClass("hidden");
this.$target.find(".js_mg_details").removeClass("hidden");
- }
- else {
+ this.$target.find(".js_mg_confirmation").addClass("hidden");
+ } else if (follow === "off") {
+ // user is connected and can subscribe
this.$target.find(".js_mg_follow_form").removeClass("hidden");
this.$target.find(".js_mg_details").addClass("hidden");
+ this.$target.find(".js_mg_confirmation").addClass("hidden");
+ } else if (follow === "email") {
+ // a confirmation email has been sent
+ this.$target.find(".js_mg_follow_form").addClass("hidden");
+ this.$target.find(".js_mg_details").addClass("hidden");
+ this.$target.find(".js_mg_confirmation").removeClass("hidden");
+ } else {
+ console.error("Unknown subscription action", follow)
}
this.$target.find('input.js_follow_email')
.val(email ? email : "")
- .attr("disabled", follow || (email.length && this.is_user) ? "disabled" : false);
- this.$target.attr("data-follow", follow ? 'on' : 'off');
+ .attr("disabled", follow === "on" || (email.length && this.is_user) ? "disabled" : false);
+ this.$target.attr("data-follow", follow);
return $.when(alias_done);
},
get_alias_info: function() {
diff --git a/addons/website_mail_channel/views/snippets.xml b/addons/website_mail_channel/views/snippets.xml
index 7439414b9d7..1cada8717b2 100644
--- a/addons/website_mail_channel/views/snippets.xml
+++ b/addons/website_mail_channel/views/snippets.xml
@@ -29,6 +29,10 @@
archives -
unsubscribe
+
+ a confirmation email has been sent.
+
+
diff --git a/addons/website_mail_channel/views/website_mail_channel_templates.xml b/addons/website_mail_channel/views/website_mail_channel_templates.xml
index 2c3060398c9..dfbebe1f4fe 100644
--- a/addons/website_mail_channel/views/website_mail_channel_templates.xml
+++ b/addons/website_mail_channel/views/website_mail_channel_templates.xml
@@ -58,15 +58,18 @@
+ t-att-data-follow="'on' if 'unsubscribe' in request.params else 'off'">
-
-
+
+
+
+
+
@@ -306,4 +309,32 @@
+
+
+
+
+
+
+ You have been correctly
+ subscribed
+ unsubscribed
+ to the mailing list.
+
+
+
+
+
+
+
+
+
+
+
+ Invalid or expired confirmation link.
+
+
+
+
+
+