From 3637e829ca3d0ec7dffb07f1b23c9c624197e94b Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Wed, 25 Nov 2015 10:56:03 +0100 Subject: [PATCH 1/8] [ADD] mail_follower_custom_notification --- mail_follower_custom_notification/README.rst | 66 +++++++++++ mail_follower_custom_notification/__init__.py | 5 + .../__openerp__.py | 27 +++++ .../mail_follower_custom_notification.png | Bin 0 -> 8816 bytes .../models/__init__.py | 8 ++ .../models/mail_followers.py | 42 +++++++ .../models/mail_message.py | 25 ++++ .../models/mail_message_subtype.py | 22 ++++ .../models/mail_notification.py | 33 ++++++ .../models/mail_thread.py | 108 ++++++++++++++++++ .../static/description/icon.png | Bin 0 -> 9455 bytes .../css/mail_follower_custom_notification.css | 5 + .../js/mail_follower_custom_notification.js | 79 +++++++++++++ .../xml/mail_follower_custom_notification.xml | 38 ++++++ .../tests/__init__.py | 4 + .../test_mail_follower_custom_notification.py | 75 ++++++++++++ .../views/mail_message_subtype.xml | 18 +++ .../views/templates.xml | 11 ++ .../wizards/__init__.py | 4 + ...ail_subtype_assign_custom_notifications.py | 46 ++++++++ ...il_subtype_assign_custom_notifications.xml | 30 +++++ 21 files changed, 646 insertions(+) create mode 100644 mail_follower_custom_notification/README.rst create mode 100644 mail_follower_custom_notification/__init__.py create mode 100644 mail_follower_custom_notification/__openerp__.py create mode 100644 mail_follower_custom_notification/images/mail_follower_custom_notification.png create mode 100644 mail_follower_custom_notification/models/__init__.py create mode 100644 mail_follower_custom_notification/models/mail_followers.py create mode 100644 mail_follower_custom_notification/models/mail_message.py create mode 100644 mail_follower_custom_notification/models/mail_message_subtype.py create mode 100644 mail_follower_custom_notification/models/mail_notification.py create mode 100644 mail_follower_custom_notification/models/mail_thread.py create mode 100644 mail_follower_custom_notification/static/description/icon.png create mode 100644 mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css create mode 100644 mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js create mode 100644 mail_follower_custom_notification/static/src/xml/mail_follower_custom_notification.xml create mode 100644 mail_follower_custom_notification/tests/__init__.py create mode 100644 mail_follower_custom_notification/tests/test_mail_follower_custom_notification.py create mode 100644 mail_follower_custom_notification/views/mail_message_subtype.xml create mode 100644 mail_follower_custom_notification/views/templates.xml create mode 100644 mail_follower_custom_notification/wizards/__init__.py create mode 100644 mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.py create mode 100644 mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.xml diff --git a/mail_follower_custom_notification/README.rst b/mail_follower_custom_notification/README.rst new file mode 100644 index 00000000..406f160d --- /dev/null +++ b/mail_follower_custom_notification/README.rst @@ -0,0 +1,66 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :alt: License: AGPL-3 + +========================================== +Custom notification settings for followers +========================================== + +In standard Odoo, receiving mail notifications is an all or nothing affair. +This module allows you users to decide per followed record if they want to +receive emails or not. Further, they can choose to receive notification about +their own messages. + +You can also set defaults for this settings on the subtype in question. + +Configuration +============= + +When followers open their subscriptions, they will be offered the choice to +override mail settings and to force being notified about their own messages. + +You can add defaults per message sub type for this settings in Settings / +Technical / Email / Subtypes. Here, you also have the opportunity to apply +those defaults to existing subscriptions. Note that this overrides all +customizations your users already have done. + +Usage +===== + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/205/8.0 + +For further information, please visit: + +* https://www.odoo.com/forum/help-1 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed feedback +`here `_. + +Credits +======= + +Contributors +------------ + +* Holger Brunn + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/mail_follower_custom_notification/__init__.py b/mail_follower_custom_notification/__init__.py new file mode 100644 index 00000000..968fe660 --- /dev/null +++ b/mail_follower_custom_notification/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import models +from . import wizards diff --git a/mail_follower_custom_notification/__openerp__.py b/mail_follower_custom_notification/__openerp__.py new file mode 100644 index 00000000..e15b28ba --- /dev/null +++ b/mail_follower_custom_notification/__openerp__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Custom notification settings for followers", + "version": "8.0.1.0.0", + "author": "Therp BV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": "Social Network", + "summary": "Let followers choose if they want to receive email " + "notifications for a given subscription", + "depends": [ + 'mail', + ], + "data": [ + "wizards/mail_subtype_assign_custom_notifications.xml", + "views/mail_message_subtype.xml", + 'views/templates.xml', + ], + "qweb": [ + 'static/src/xml/mail_follower_custom_notification.xml', + ], + "images": [ + 'images/mail_follower_custom_notification.png', + ], + "installable": True, +} diff --git a/mail_follower_custom_notification/images/mail_follower_custom_notification.png b/mail_follower_custom_notification/images/mail_follower_custom_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..3c63b9a769ec4810e34457cfedd1540e88c9c258 GIT binary patch literal 8816 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 literal 0 HcmV?d00001 diff --git a/mail_follower_custom_notification/models/__init__.py b/mail_follower_custom_notification/models/__init__.py new file mode 100644 index 00000000..b0a8e2ce --- /dev/null +++ b/mail_follower_custom_notification/models/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import mail_followers +from . import mail_thread +from . import mail_message +from . import mail_notification +from . import mail_message_subtype diff --git a/mail_follower_custom_notification/models/mail_followers.py b/mail_follower_custom_notification/models/mail_followers.py new file mode 100644 index 00000000..82719402 --- /dev/null +++ b/mail_follower_custom_notification/models/mail_followers.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import api, fields, models + + +class MailFollowers(models.Model): + _inherit = 'mail.followers' + + force_mail_subtype_ids = fields.Many2many( + 'mail.message.subtype', 'mail_followers_force_mail_rel', + 'mail_followers_id', 'mail_message_subtype_id', + string='Force mails from subtype') + + force_nomail_subtype_ids = fields.Many2many( + 'mail.message.subtype', 'mail_followers_force_nomail_rel', + 'mail_followers_id', 'mail_message_subtype_id', + string='Force no mails from subtype') + + force_own_subtype_ids = fields.Many2many( + 'mail.message.subtype', 'mail_followers_force_own_rel', + 'mail_followers_id', 'mail_message_subtype_id', + string='Force own mails from subtype') + + @api.model + @api.returns('self', lambda x: x.id) + def create(self, values): + this = super(MailFollowers, self).create(values) + for subtype in this.subtype_ids: + if not subtype.res_model and\ + subtype.custom_notification_model_ids and\ + this.res_model not in\ + subtype.custom_notification_model_ids\ + .mapped('model'): + continue + if subtype.custom_notification_mail == 'force_yes': + this.force_mail_subtype_ids += subtype + if subtype.custom_notification_mail == 'force_no': + this.force_nomail_subtype_ids += subtype + if subtype.custom_notification_own: + this.force_own_subtype_ids += subtype + return this diff --git a/mail_follower_custom_notification/models/mail_message.py b/mail_follower_custom_notification/models/mail_message.py new file mode 100644 index 00000000..6ec41b24 --- /dev/null +++ b/mail_follower_custom_notification/models/mail_message.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import api, models + + +class MailMessage(models.Model): + _inherit = 'mail.message' + + @api.multi + def _notify(self, force_send=False, user_signature=True): + """notify author if she's a follower and turned on force_own""" + self.ensure_one() + if self.subtype_id and self.model and self.res_id: + author_follower = self.env['mail.followers'].search([ + ('res_model', '=', self.model), + ('res_id', '=', self.res_id), + ('partner_id', '=', self.author_id.id), + ('force_own_subtype_ids', '=', self.subtype_id.id), + ]) + self.env['mail.notification']._notify( + self.id, partners_to_notify=author_follower.partner_id.ids, + force_send=force_send, user_signature=user_signature) + return super(MailMessage, self)._notify( + self.id, force_send=force_send, user_signature=user_signature) diff --git a/mail_follower_custom_notification/models/mail_message_subtype.py b/mail_follower_custom_notification/models/mail_message_subtype.py new file mode 100644 index 00000000..f58e199d --- /dev/null +++ b/mail_follower_custom_notification/models/mail_message_subtype.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import fields, models + + +class MailMessageSubtype(models.Model): + _inherit = 'mail.message.subtype' + + custom_notification_mail = fields.Selection( + [('force_yes', 'Force yes'), ('force_no', 'Force no')], + string='Send mail notification', help='Leave empty to use the ' + 'on the partner\'s form, set to "Force yes" to always send messages ' + 'of this type via email, and "Force no" to never send messages of ' + 'type via email') + custom_notification_own = fields.Boolean( + 'Notify about own messages', help='Check this to have notifications ' + 'generated and sent via email about own messages') + custom_notification_model_ids = fields.Many2many( + 'ir.model', string='Models', help='Choose for which models the ' + 'custom configuration applies. This is only necessary if your subtype ' + 'doesn\'t set a model itself', domain=[('osv_memory', '=', False)]) diff --git a/mail_follower_custom_notification/models/mail_notification.py b/mail_follower_custom_notification/models/mail_notification.py new file mode 100644 index 00000000..c70e0f50 --- /dev/null +++ b/mail_follower_custom_notification/models/mail_notification.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import api, models + + +class MailNotification(models.Model): + _inherit = 'mail.notification' + + @api.multi + def get_partners_to_email(self, message): + partner_ids = super(MailNotification, self)\ + .get_partners_to_email(message) + for this in self: + follower = self.env['mail.followers'].search([ + ('res_model', '=', message.model), + ('res_id', '=', message.res_id), + ('partner_id', '=', this.partner_id.id), + '|', '|', + ('force_nomail_subtype_ids', '=', message.subtype_id.id), + ('force_mail_subtype_ids', '=', message.subtype_id.id), + ('force_own_subtype_ids', '=', message.subtype_id.id), + ]) + if not follower: + continue + if (message.subtype_id in follower.force_mail_subtype_ids or + message.subtype_id in follower.force_own_subtype_ids) and\ + this.partner_id.id not in partner_ids: + partner_ids.append(this.partner_id.id) + if message.subtype_id in follower.force_nomail_subtype_ids and\ + this.partner_id.id in partner_ids: + partner_ids.remove(this.partner_id.id) + return partner_ids diff --git a/mail_follower_custom_notification/models/mail_thread.py b/mail_follower_custom_notification/models/mail_thread.py new file mode 100644 index 00000000..910eb222 --- /dev/null +++ b/mail_follower_custom_notification/models/mail_thread.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import SUPERUSER_ID, api, models +from openerp.addons.mail.mail_thread import mail_thread + + +class MailThread(models.Model): + _inherit = 'mail.thread' + + @api.multi + def _get_subscription_data(self, name, args, user_pid=None): + result = super(MailThread, self)._get_subscription_data( + name, args, user_pid=user_pid) + subtypes = self.env['mail.message.subtype'].search([ + ('hidden', '=', False), + '|', + ('res_model', '=', self._name), + ('res_model', '=', False), + ]) + for follower in self.env['mail.followers'].search([ + ('res_model', '=', self._name), + ('res_id', 'in', result.keys()), + ('partner_id', '=', user_pid or self.env.user.partner_id.id), + ]): + # values are ordered dicts, so we get the correct matches + for subtype, data in zip( + subtypes, + result[follower.res_id]['message_subtype_data'].values()): + data['force_mail'] = 'default' + if subtype in follower.force_mail_subtype_ids: + data['force_mail'] = 'force_yes' + elif subtype in follower.force_nomail_subtype_ids: + data['force_mail'] = 'force_no' + data['force_own'] =\ + subtype in follower.force_own_subtype_ids + return result + + @api.multi + def message_custom_notification_update_user(self, custom_notifications): + """change custom_notifications from user ids to partner ids""" + user2partner = dict( + self.env['res.users'].browse(map(int, custom_notifications.keys())) + .mapped(lambda user: (str(user.id), str(user.partner_id.id))) + ) + return self.message_custom_notification_update({ + user2partner[user_id]: data + for user_id, data in custom_notifications.iteritems() + }) + + @api.multi + def message_custom_notification_update(self, custom_notifications): + """custom_notifications is a dictionary with partner ids as keys + and dictionaries mapping message subtype ids to custom notification + values""" + def ids_with_value(data, key, value): + return map(lambda x: int(x[0]), + filter(lambda x: x[1][key] == value, + data.iteritems())) + + custom_notifications = { + int(key): value + for key, value in custom_notifications.iteritems() + if key != 'False' + } + + for follower in self.env['mail.followers'].search([ + ('res_model', '=', self._name), + ('res_id', 'in', self.ids), + ('partner_id', 'in', custom_notifications.keys()), + ]): + data = custom_notifications[follower.partner_id.id] + follower.write({ + 'force_mail_subtype_ids': [(6, 0, ids_with_value( + data, 'force_mail', 'force_yes'))], + 'force_nomail_subtype_ids': [(6, 0, ids_with_value( + data, 'force_mail', 'force_no'))], + 'force_own_subtype_ids': [(6, 0, ids_with_value( + data, 'force_own', '1'))] + }), + + def _register_hook(self, cr): + model_ids = self.pool['ir.model'].search(cr, SUPERUSER_ID, []) + rebuilt = [] + for model in self.pool['ir.model'].browse(cr, SUPERUSER_ID, model_ids): + if model.model not in self.pool: + continue + model_object = self.pool[model.model] + if not isinstance(model_object, mail_thread): + continue + if isinstance(model_object, MailThread): + continue + bases = list(model_object.__class__.__bases__) + if MailThread not in bases: + bases.insert(1, MailThread) + class_dict = dict(model_object.__dict__) + class_dict['_inherit'] = model_object._name + new_model_class = type(model_object._name, tuple(bases), + class_dict) + new_model = new_model_class._build_model(self.pool, cr) + self.pool.models[model.model] = new_model + new_model._prepare_setup(cr, SUPERUSER_ID) + new_model._setup_base(cr, SUPERUSER_ID, False) + new_model._setup_fields(cr, SUPERUSER_ID) + rebuilt.append(new_model) + for model in rebuilt: + model._setup_complete(cr, SUPERUSER_ID) + return super(MailThread, self)._register_hook(cr) diff --git a/mail_follower_custom_notification/static/description/icon.png b/mail_follower_custom_notification/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css b/mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css new file mode 100644 index 00000000..92b9ecb9 --- /dev/null +++ b/mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css @@ -0,0 +1,5 @@ +.oe_custom_notification legend +{ + font-size: inherit; + margin-bottom: 0px; +} diff --git a/mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js b/mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js new file mode 100644 index 00000000..104342b1 --- /dev/null +++ b/mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js @@ -0,0 +1,79 @@ +//-*- coding: utf-8 -*- +//© 2015 Therp BV +//License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +openerp.mail_follower_custom_notification = function(instance) +{ + instance.mail_followers.Followers.include({ + display_subtypes: function(data, id, dialog) + { + var $list = this.$('.oe_subtype_list ul'); + if (dialog) + { + $list = this.$dialog.$el; + } + $list.empty(); + this._super(data, id, dialog); + $list.find('input[type=checkbox]').change(function() + { + $list.find(_.str.sprintf( + '#custom_notification_%s%s', + jQuery(this).data('id'), + dialog ? '_dialog' : '' + )) + .toggle(jQuery(this).prop('checked')); + }); + if(!dialog) + { + $list.find('.oe_custom_notification input[type=radio]') + .change(this.proxy('do_update_subscription')); + }; + }, + do_update_subscription: function(event, user_pid) + { + /* + if(jQuery(event.currentTarget).parents('.oe_custom_notification') + .length) + { + // mail reacts on all inputs, suppress for our inputs + return jQuery.when(); + } + */ + var self = this, + update_func = 'message_custom_notification_update_user', + follower_ids = [this.session.uid], + custom_notifications = {}, + oe_action = this.$('.oe_actions'); + if(user_pid) + { + update_func = 'message_custom_notification_update'; + follower_ids = [user_pid]; + oe_action = jQuery('.oe_edit_actions'); + } + _(follower_ids).each(function(follower) + { + + var follower_settings = custom_notifications[follower] = {}; + oe_action.find('.oe_custom_notification') + .each(function() + { + var id = parseInt(jQuery(this).data('id')), + settings = follower_settings[id] = {}; + settings['force_mail'] = jQuery(this) + .find('.oe_custom_notification_mail input:checked') + .val(); + settings['force_own'] = jQuery(this) + .find('.oe_custom_notification_own input:checked') + .val(); + }); + }); + return jQuery.when(this._super.apply(this, arguments)) + .then(function() + { + return self.ds_model.call( + update_func, + [[self.view.datarecord.id], custom_notifications]) + }) + }, + }); +} diff --git a/mail_follower_custom_notification/static/src/xml/mail_follower_custom_notification.xml b/mail_follower_custom_notification/static/src/xml/mail_follower_custom_notification.xml new file mode 100644 index 00000000..25fee159 --- /dev/null +++ b/mail_follower_custom_notification/static/src/xml/mail_follower_custom_notification.xml @@ -0,0 +1,38 @@ + + diff --git a/mail_follower_custom_notification/tests/__init__.py b/mail_follower_custom_notification/tests/__init__.py new file mode 100644 index 00000000..ef042795 --- /dev/null +++ b/mail_follower_custom_notification/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import test_mail_follower_custom_notification diff --git a/mail_follower_custom_notification/tests/test_mail_follower_custom_notification.py b/mail_follower_custom_notification/tests/test_mail_follower_custom_notification.py new file mode 100644 index 00000000..11bed947 --- /dev/null +++ b/mail_follower_custom_notification/tests/test_mail_follower_custom_notification.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp.tests.common import TransactionCase + + +class TestMailFollowerCustomNotification(TransactionCase): + def test_mail_follower_custom_notification(self): + self.env['mail.thread']._register_hook() + followed_partner = self.env['res.partner'].create({ + 'name': 'I\'m followed', + }) + demo_user = self.env.ref('base.user_demo') + followed_partner_demo = followed_partner.sudo(demo_user.id) + followed_partner_demo.message_subscribe_users() + + # see if default subscriptions return default custom settings + subscription_data = followed_partner_demo._get_subscription_data( + None, None) + self.assertEqual( + subscription_data[followed_partner.id]['message_subtype_data'] + ['Discussions']['force_mail'], + 'default') + self.assertEqual( + subscription_data[followed_partner.id]['message_subtype_data'] + ['Discussions']['force_own'], + False) + + # set custom settings + mt_comment = self.env.ref('mail.mt_comment') + followed_partner_demo.message_custom_notification_update_user({ + str(demo_user.id): { + str(mt_comment.id): { + 'force_mail': 'force_yes', + 'force_own': '1', + }, + }, + }) + # see if we can read them back + subscription_data = followed_partner_demo._get_subscription_data( + None, None) + self.assertEqual( + subscription_data[followed_partner.id]['message_subtype_data'] + ['Discussions']['force_mail'], + 'force_yes') + self.assertEqual( + subscription_data[followed_partner.id]['message_subtype_data'] + ['Discussions']['force_own'], + True) + + # post a message and see if we successfully forced a notification to + # ourselves + followed_partner_demo.message_post('hello world', subtype='mt_comment') + self.assertEqual( + followed_partner_demo.message_ids[:-1].notification_ids.partner_id, + demo_user.partner_id) + + # assign default values on message subtype and apply them to all + # followers + mt_comment.custom_notification_model_ids = self.env['ir.model']\ + .search([('model', '=', 'res.partner')]) + wizard = self.env['mail.subtype.assign.custom.notifications']\ + .with_context(active_ids=mt_comment.ids)\ + .create({}) + wizard.button_apply() + subscription_data = followed_partner_demo._get_subscription_data( + None, None) + self.assertEqual( + subscription_data[followed_partner.id]['message_subtype_data'] + ['Discussions']['force_mail'], + 'default') + self.assertEqual( + subscription_data[followed_partner.id]['message_subtype_data'] + ['Discussions']['force_own'], + False) diff --git a/mail_follower_custom_notification/views/mail_message_subtype.xml b/mail_follower_custom_notification/views/mail_message_subtype.xml new file mode 100644 index 00000000..0d60986c --- /dev/null +++ b/mail_follower_custom_notification/views/mail_message_subtype.xml @@ -0,0 +1,18 @@ + + + + + mail.message.subtype + + + + + + + + + + + + + diff --git a/mail_follower_custom_notification/views/templates.xml b/mail_follower_custom_notification/views/templates.xml new file mode 100644 index 00000000..fbfbec8b --- /dev/null +++ b/mail_follower_custom_notification/views/templates.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/mail_follower_custom_notification/wizards/__init__.py b/mail_follower_custom_notification/wizards/__init__.py new file mode 100644 index 00000000..e968c053 --- /dev/null +++ b/mail_follower_custom_notification/wizards/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import mail_subtype_assign_custom_notifications diff --git a/mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.py b/mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.py new file mode 100644 index 00000000..c0413e7e --- /dev/null +++ b/mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# © 2015 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import api, fields, models + + +class MailSubtypeAssignCustomNotifications(models.TransientModel): + _name = 'mail.subtype.assign.custom.notifications' + _description = 'Assign custom notification settings to existing followers' + + subtype_ids = fields.Many2many( + 'mail.message.subtype', 'mail_subtype_assign_custom_notifications_rel', + string='Subtypes', required=True, + default=lambda self: [(6, 0, self.env.context.get('active_ids', []))]) + + @api.multi + def button_apply(self): + self.ensure_one() + for subtype in self.subtype_ids: + domain = [('subtype_ids', '=', subtype.id)] + if subtype.custom_notification_model_ids: + domain.append( + ('res_model', 'in', + subtype.custom_notification_model_ids.mapped('model'))) + self.env['mail.followers'].with_context(active_test=False)\ + .search(domain)\ + .write({ + 'force_mail_subtype_ids': [ + (4, subtype.id) + if subtype.custom_notification_mail == 'force_yes' + else + (3, subtype.id) + ], + 'force_nomail_subtype_ids': [ + (4, subtype.id) + if subtype.custom_notification_mail == 'force_no' + else + (3, subtype.id) + ], + 'force_own_subtype_ids': [ + (4, subtype.id) + if subtype.custom_notification_own + else + (3, subtype.id) + ], + }) diff --git a/mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.xml b/mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.xml new file mode 100644 index 00000000..adbab627 --- /dev/null +++ b/mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.xml @@ -0,0 +1,30 @@ + + + + + mail.subtype.assign.custom.notifications + +
+ + + +
+
+
+
+
+ +
+
From 5d1bef2102e8d14ce477e27a787dc6e4bb050971 Mon Sep 17 00:00:00 2001 From: Rafael Blasco Date: Wed, 16 Dec 2015 01:32:59 +0100 Subject: [PATCH 2/8] Add some Usage steps It would be nice to add an image of a screen-shoot but I don't know where to store it. Next time --- mail_follower_custom_notification/README.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mail_follower_custom_notification/README.rst b/mail_follower_custom_notification/README.rst index 406f160d..7f14c572 100644 --- a/mail_follower_custom_notification/README.rst +++ b/mail_follower_custom_notification/README.rst @@ -26,6 +26,13 @@ customizations your users already have done. Usage ===== +To use this module, for example you need to: + +- Go to Sales -> Sales -> Customers +- Go Inside any customer and in the right-botton corner press "Follow" button +- Unfold Following menu and check new functionality with "mail notificacions" + + .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot :target: https://runbot.odoo-community.org/runbot/205/8.0 From 03126bfc769d476a03effdbfb07aea0323a7ce64 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Thu, 28 Jan 2016 16:42:24 +0100 Subject: [PATCH 3/8] [IMP] use base_patch_models_mixin --- .../models/__init__.py | 1 + .../models/base_patch_models_mixin.py | 92 +++++++++++++++++++ .../models/mail_thread.py | 36 +------- 3 files changed, 97 insertions(+), 32 deletions(-) create mode 100644 mail_follower_custom_notification/models/base_patch_models_mixin.py diff --git a/mail_follower_custom_notification/models/__init__.py b/mail_follower_custom_notification/models/__init__.py index b0a8e2ce..507fec24 100644 --- a/mail_follower_custom_notification/models/__init__.py +++ b/mail_follower_custom_notification/models/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # © 2015 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import base_patch_models_mixin from . import mail_followers from . import mail_thread from . import mail_message diff --git a/mail_follower_custom_notification/models/base_patch_models_mixin.py b/mail_follower_custom_notification/models/base_patch_models_mixin.py new file mode 100644 index 00000000..0107f4fc --- /dev/null +++ b/mail_follower_custom_notification/models/base_patch_models_mixin.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# © 2016 Therp BV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import logging +from openerp import SUPERUSER_ID, models + + +_logger = logging.getLogger(__file__) + + +# TODO: this should be a helper module to cetralize the point of failure +# in case this introduces tacit bugs +class BasePatchModelsMixin(models.AbstractModel): + """ + This is a mixin class meant to simplify working with patches + on BaseModel or on abstract models like mail.thread. + If you just change them, models created earlier will lack the + attributes you add. Just inherit from this mixin, it will check + which existing models need your changes and apply them. + + In your module, do something like + + class MailThread(models.AbstractModel): + _name = 'mail.thread' + _inherit = ['base.patch.models.mixin', 'mail.thread'] + + in case you need to patch BaseModel, say + + class BaseModel(models.BaseModel): + _name = 'my.unique.model.name' + _inherit = 'base.patch.models.mixin' + + Your code will behave as if it was an inherited class of the class you pass + in the second parameter to _base_patch_models. + """ + _name = 'base.patch.models.mixin' + + def _base_patch_models(self, cr, our_class=None, parent_class=None): + """iterate through existing models to apply our changes there if + necessary""" + if self._name == BasePatchModelsMixin._name: + return + my_bases = self.__class__.__bases__ + for i in range(max(len(my_bases) - 1, 0)): + if my_bases[i]._name == BasePatchModelsMixin._name: + our_class = my_bases[i - 1] + parent_class = my_bases[i + 1] + inherit = [self._inherit]\ + if isinstance(self._inherit, basestring) else self._inherit + for i in range(len(my_bases) - 1, 0, -1): + # this can be different from the above if our mixin is used + # multiple times on the same model + if my_bases[i]._name in inherit: + parent_class = my_bases[i] + break + if self.__class__.__bases__[-1] == BasePatchModelsMixin\ + and not our_class or not parent_class: + our_class = self.__class__.__bases__[-2] + parent_class = models.BaseModel + if not our_class or not parent_class: + _logger.info( + 'Failed to autodetect own class or parent class for %s, ' + 'ignoring', self._name) + return + + for model_name, model_object in self.pool.models.iteritems(): + if not isinstance(model_object, parent_class): + continue + if isinstance(model_object, our_class): + continue + if not isinstance(model_object, models.Model): + continue + bases = list(model_object.__class__.__bases__) + position = 1 + if parent_class == models.BaseModel: + position = len(bases) + else: + for i in range(len(bases) - 1, position, -1): + if bases[i]._name in inherit: + position = i + break + bases.insert(position, our_class) + model_object.__class__.__bases__ = tuple(bases) + + def _register_hook(self, cr): + self._base_patch_models(cr) + for base in self.__class__.__bases__: + if not hasattr(super(base, self), '_register_hook'): + return + if super(base, self)._register_hook != self._register_hook: + return super(base, self)._register_hook.__func__( + super(base, self), cr) diff --git a/mail_follower_custom_notification/models/mail_thread.py b/mail_follower_custom_notification/models/mail_thread.py index 910eb222..11c23eb8 100644 --- a/mail_follower_custom_notification/models/mail_thread.py +++ b/mail_follower_custom_notification/models/mail_thread.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- # © 2015 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import SUPERUSER_ID, api, models -from openerp.addons.mail.mail_thread import mail_thread +from openerp import api, models -class MailThread(models.Model): - _inherit = 'mail.thread' +class MailThread(models.AbstractModel): + _inherit = ['base.patch.models.mixin', 'mail.thread'] + _name = 'mail.thread' @api.multi def _get_subscription_data(self, name, args, user_pid=None): @@ -78,31 +78,3 @@ class MailThread(models.Model): 'force_own_subtype_ids': [(6, 0, ids_with_value( data, 'force_own', '1'))] }), - - def _register_hook(self, cr): - model_ids = self.pool['ir.model'].search(cr, SUPERUSER_ID, []) - rebuilt = [] - for model in self.pool['ir.model'].browse(cr, SUPERUSER_ID, model_ids): - if model.model not in self.pool: - continue - model_object = self.pool[model.model] - if not isinstance(model_object, mail_thread): - continue - if isinstance(model_object, MailThread): - continue - bases = list(model_object.__class__.__bases__) - if MailThread not in bases: - bases.insert(1, MailThread) - class_dict = dict(model_object.__dict__) - class_dict['_inherit'] = model_object._name - new_model_class = type(model_object._name, tuple(bases), - class_dict) - new_model = new_model_class._build_model(self.pool, cr) - self.pool.models[model.model] = new_model - new_model._prepare_setup(cr, SUPERUSER_ID) - new_model._setup_base(cr, SUPERUSER_ID, False) - new_model._setup_fields(cr, SUPERUSER_ID) - rebuilt.append(new_model) - for model in rebuilt: - model._setup_complete(cr, SUPERUSER_ID) - return super(MailThread, self)._register_hook(cr) From e245158f683371d7f9214dafb6a1b08f479f83e1 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Wed, 10 Feb 2016 10:03:24 +0100 Subject: [PATCH 4/8] [FIX] flake8 --- .../models/base_patch_models_mixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail_follower_custom_notification/models/base_patch_models_mixin.py b/mail_follower_custom_notification/models/base_patch_models_mixin.py index 0107f4fc..21ea5e68 100644 --- a/mail_follower_custom_notification/models/base_patch_models_mixin.py +++ b/mail_follower_custom_notification/models/base_patch_models_mixin.py @@ -2,7 +2,7 @@ # © 2016 Therp BV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import logging -from openerp import SUPERUSER_ID, models +from openerp import models _logger = logging.getLogger(__file__) From 77ad6c9a7c8444001e3ce935b7327b12568edb5d Mon Sep 17 00:00:00 2001 From: Jairo Llopis Date: Mon, 15 Feb 2016 16:42:36 +0100 Subject: [PATCH 5/8] [8.0][FIX][website_snippet_bg_color][website_snippet_responsive] Allow to pick color for almost-background element. Right now only able to pick for the backest element in responsive snippets. This allows it for the previous one. Also allow other elements than divs to be colored. --- website_mail_snippet_bg_color/views/snippets.xml | 3 +-- website_mail_snippet_responsive/views/templates.xml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website_mail_snippet_bg_color/views/snippets.xml b/website_mail_snippet_bg_color/views/snippets.xml index 3d83da68..a2ca12bd 100644 --- a/website_mail_snippet_bg_color/views/snippets.xml +++ b/website_mail_snippet_bg_color/views/snippets.xml @@ -10,8 +10,7 @@
*, .bg_color_picker" data-selector-siblings="[data-oe-field='body_html'] > *" data-selector-children="[data-oe-field='body_html']"> diff --git a/website_mail_snippet_responsive/views/templates.xml b/website_mail_snippet_responsive/views/templates.xml index fed9f1fd..8d5dcd0d 100644 --- a/website_mail_snippet_responsive/views/templates.xml +++ b/website_mail_snippet_responsive/views/templates.xml @@ -20,6 +20,7 @@ style="padding:0px; width:100%; background-color:#ececec; color:rgb(0,0,0); line-height:20px; font-family:Arial,sans-serif; font-size:9pt"> Date: Thu, 18 Feb 2016 09:29:09 +0100 Subject: [PATCH 6/8] [UPD] addons table in README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index daff2ca4..20f30f9c 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ addon | version | summary [mail_footer_notified_partners](mail_footer_notified_partners/) | 8.0.1.0.0 | This module adds the list of notified partners in the footer of notification e-mails sent by Odoo. [mail_forward](mail_forward/) | 8.0.7.0.0 | Add option to forward messages [mail_full_expand](mail_full_expand/) | 8.0.3.0.0 | Expand mail in a big window +[mail_mandrill](mail_mandrill/) | 8.0.1.0.0 | Mandrill mail events integration [mail_read_new_window](mail_read_new_window/) | 8.0.1.0.0 | Open mail in new window [mail_restrict_follower_selection](mail_restrict_follower_selection/) | 8.0.1.0.0 | Define a domain from which followers can be selected [mail_sent](mail_sent/) | 8.0.1.0.0 | Provide a view of sent mails From 4275c8112599861757526de5ec9407f7c98f873a Mon Sep 17 00:00:00 2001 From: OCA Git Bot Date: Sun, 21 Feb 2016 02:33:32 +0100 Subject: [PATCH 7/8] [UPD] addons table in README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 20f30f9c..d3052629 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ addon | version | summary --- | --- | --- [mail_attach_existing_attachment](mail_attach_existing_attachment/) | 8.0.1.0.0 | Adding attachment on the object by sending this one [mail_compose_select_lang](mail_compose_select_lang/) | 8.0.1.0.0 | Select language in mail compose window +[mail_follower_custom_notification](mail_follower_custom_notification/) | 8.0.1.0.0 | Let followers choose if they want to receive email notifications for a given subscription [mail_footer_notified_partners](mail_footer_notified_partners/) | 8.0.1.0.0 | This module adds the list of notified partners in the footer of notification e-mails sent by Odoo. [mail_forward](mail_forward/) | 8.0.7.0.0 | Add option to forward messages [mail_full_expand](mail_full_expand/) | 8.0.3.0.0 | Expand mail in a big window From 39b55f72ddd887132eced4dacfea027ed20c6db6 Mon Sep 17 00:00:00 2001 From: OCA Transbot Date: Sat, 20 Feb 2016 23:56:18 -0500 Subject: [PATCH 8/8] OCA Transbot updated translations from Transifex --- marketing_security_group/i18n/es.po | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 marketing_security_group/i18n/es.po diff --git a/marketing_security_group/i18n/es.po b/marketing_security_group/i18n/es.po new file mode 100644 index 00000000..3763a689 --- /dev/null +++ b/marketing_security_group/i18n/es.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * marketing_security_group +# +# Translators: +# Antonio Trueba, 2016 +msgid "" +msgstr "" +"Project-Id-Version: social (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-01-17 01:37+0000\n" +"PO-Revision-Date: 2016-02-16 12:32+0000\n" +"Last-Translator: Antonio Trueba\n" +"Language-Team: Spanish (http://www.transifex.com/oca/OCA-social-8-0/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: marketing_security_group +#: model:ir.model,name:marketing_security_group.model_mail_mass_mailing_test +msgid "Sample Mail Wizard" +msgstr "Asistente para correo de ejemplo"