Browse Source

[MIG] mail_follower_custom_notification to v10

pull/392/head
Holger Brunn 6 years ago
parent
commit
31c1eff584
  1. 88
      mail_follower_custom_notification/README.rst
  2. 3
      mail_follower_custom_notification/__init__.py
  3. 4
      mail_follower_custom_notification/__manifest__.py
  4. 4
      mail_follower_custom_notification/controllers/__init__.py
  5. 29
      mail_follower_custom_notification/controllers/mail_controller.py
  6. 5
      mail_follower_custom_notification/models/__init__.py
  7. 92
      mail_follower_custom_notification/models/base_patch_models_mixin.py
  8. 5
      mail_follower_custom_notification/models/mail_followers.py
  9. 23
      mail_follower_custom_notification/models/mail_message.py
  10. 16
      mail_follower_custom_notification/models/mail_message_subtype.py
  11. 33
      mail_follower_custom_notification/models/mail_notification.py
  12. 42
      mail_follower_custom_notification/models/mail_thread.py
  13. 30
      mail_follower_custom_notification/models/res_partner.py
  14. 10
      mail_follower_custom_notification/readme/CONFIGURE.rst
  15. 1
      mail_follower_custom_notification/readme/CONTRIBUTORS.rst
  16. 1
      mail_follower_custom_notification/readme/CREDITS.rst
  17. 6
      mail_follower_custom_notification/readme/DESCRIPTION.rst
  18. 442
      mail_follower_custom_notification/static/description/index.html
  19. 15
      mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css
  20. 98
      mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js
  21. 63
      mail_follower_custom_notification/static/src/xml/mail_follower_custom_notification.xml
  22. 86
      mail_follower_custom_notification/tests/test_mail_follower_custom_notification.py
  23. 30
      mail_follower_custom_notification/views/mail_message_subtype.xml
  24. 18
      mail_follower_custom_notification/views/templates.xml
  25. 2
      mail_follower_custom_notification/wizards/__init__.py
  26. 5
      mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.py
  27. 55
      mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.xml

88
mail_follower_custom_notification/README.rst

@ -1,73 +1,97 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
========================================== ==========================================
Custom notification settings for followers Custom notification settings for followers
========================================== ==========================================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github
:target: https://github.com/OCA/social/tree/10.0/mail_follower_custom_notification
:alt: OCA/social
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/social-10-0/social-10-0-mail_follower_custom_notification
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/205/10.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
In standard Odoo, receiving mail notifications is an all or nothing affair. 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
This module allows users to decide per followed record if they want to
receive emails or not. Further, they can choose to receive notifications about
their own messages. their own messages.
You can also set defaults for this settings on the subtype in question. You can also set defaults for this settings on the subtype in question.
**Table of contents**
.. contents::
:local:
Configuration Configuration
============= =============
When followers open their subscriptions, they will be offered the choice to When followers open their subscriptions, they will be offered the choice to
override mail settings and to force being notified about their own messages. 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 /
Note subscriptions are only editable for users of the `Technical settings`
group.
You can add defaults per message subtype for this settings in Settings /
Technical / Email / Subtypes. Here, you also have the opportunity to apply Technical / Email / Subtypes. Here, you also have the opportunity to apply
those defaults to existing subscriptions. Note that this overrides all those defaults to existing subscriptions. Note that this overrides all
customizations your users already have done. 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
For further information, please visit:
* https://www.odoo.com/forum/help-1
Bug Tracker Bug Tracker
=========== ===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/social/issues>`_. Bugs are tracked on `GitHub Issues <https://github.com/OCA/social/issues>`_.
In case of trouble, please check there if your issue has already been reported. 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 <https://github.com/OCA/social/issues/new?body=module:%20mail_follower_custom_notification%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/social/issues/new?body=module:%20mail_follower_custom_notification%0Aversion:%2010.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits Credits
======= =======
Authors
~~~~~~~
* Therp BV
Contributors Contributors
------------
~~~~~~~~~~~~
* Holger Brunn <hbrunn@therp.nl> * Holger Brunn <hbrunn@therp.nl>
Maintainer
----------
Other credits
~~~~~~~~~~~~~
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png .. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association :alt: Odoo Community Association
:target: https://odoo-community.org :target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.
This module is part of the `OCA/social <https://github.com/OCA/social/tree/10.0/mail_follower_custom_notification>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

3
mail_follower_custom_notification/__init__.py

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models from . import models
from . import wizards from . import wizards
from . import controllers

4
mail_follower_custom_notification/__openerp__.py → mail_follower_custom_notification/__manifest__.py

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{ {
"name": "Custom notification settings for followers", "name": "Custom notification settings for followers",
"version": "8.0.1.0.0",
"version": "10.0.1.0.0",
"author": "Therp BV,Odoo Community Association (OCA)", "author": "Therp BV,Odoo Community Association (OCA)",
"license": "AGPL-3", "license": "AGPL-3",
"category": "Social Network", "category": "Social Network",

4
mail_follower_custom_notification/controllers/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Therp BV <https://therp.nl>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import mail_controller

29
mail_follower_custom_notification/controllers/mail_controller.py

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Therp BV <https://therp.nl>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import http
from odoo.http import request
from odoo.addons.mail.controllers.main import MailController as _MailController
class MailController(_MailController):
@http.route()
def read_subscription_data(self, res_model, follower_id):
"""Add custom notification data to subscriptions"""
subtypes_list = super(MailController, self).read_subscription_data(
res_model, follower_id,
)
follower = request.env['mail.followers'].browse(follower_id)
for subtype_dict in subtypes_list:
subtype = request.env['mail.message.subtype'].browse(
subtype_dict['id']
)
subtype_dict['force_mail'] = 'default'
if subtype in follower.force_mail_subtype_ids:
subtype_dict['force_mail'] = 'force_yes'
elif subtype in follower.force_nomail_subtype_ids:
subtype_dict['force_mail'] = 'force_no'
subtype_dict['force_own'] = (
subtype in follower.force_own_subtype_ids
)
return subtypes_list

5
mail_follower_custom_notification/models/__init__.py

@ -1,9 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # 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_followers
from . import mail_thread from . import mail_thread
from . import mail_message from . import mail_message
from . import mail_notification
from . import mail_message_subtype from . import mail_message_subtype
from . import res_partner

92
mail_follower_custom_notification/models/base_patch_models_mixin.py

@ -1,92 +0,0 @@
# -*- coding: utf-8 -*-
# © 2016 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
from openerp import 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)

5
mail_follower_custom_notification/models/mail_followers.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import api, fields, models
from odoo import api, fields, models
class MailFollowers(models.Model): class MailFollowers(models.Model):
@ -23,7 +23,6 @@ class MailFollowers(models.Model):
string='Force own mails from subtype') string='Force own mails from subtype')
@api.model @api.model
@api.returns('self', lambda x: x.id)
def create(self, values): def create(self, values):
this = super(MailFollowers, self).create(values) this = super(MailFollowers, self).create(values)
for subtype in this.subtype_ids: for subtype in this.subtype_ids:

23
mail_follower_custom_notification/models/mail_message.py

@ -1,25 +1,28 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import api, models
from odoo import api, models
class MailMessage(models.Model): class MailMessage(models.Model):
_inherit = 'mail.message' _inherit = 'mail.message'
@api.multi @api.multi
def _notify(self, force_send=False, user_signature=True):
def _notify(
self, force_send=False, send_after_commit=True, user_signature=True,
):
"""notify author if she's a follower and turned on force_own""" """notify author if she's a follower and turned on force_own"""
self.ensure_one() self.ensure_one()
if self.subtype_id and self.model and self.res_id:
author_follower = self.env['mail.followers'].search([
if self.subtype_id and self.model and self.res_id and self.env[
'mail.followers'
].search([
('res_model', '=', self.model), ('res_model', '=', self.model),
('res_id', '=', self.res_id), ('res_id', '=', self.res_id),
('partner_id', '=', self.author_id.id), ('partner_id', '=', self.author_id.id),
('force_own_subtype_ids', '=', self.subtype_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)
]):
self = self.with_context(mail_notify_author=True)
return super(MailMessage, self)._notify( return super(MailMessage, self)._notify(
self.id, force_send=force_send, user_signature=user_signature)
force_send=force_send, send_after_commit=send_after_commit,
user_signature=user_signature,
)

16
mail_follower_custom_notification/models/mail_message_subtype.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import fields, models
from odoo import fields, models
class MailMessageSubtype(models.Model): class MailMessageSubtype(models.Model):
@ -9,14 +9,18 @@ class MailMessageSubtype(models.Model):
custom_notification_mail = fields.Selection( custom_notification_mail = fields.Selection(
[('force_yes', 'Force yes'), ('force_no', 'Force no')], [('force_yes', 'Force yes'), ('force_no', 'Force no')],
string='Send mail notification', help='Leave empty to use the '
string='Send mail notification', help='Leave empty to use the setting '
'on the partner\'s form, set to "Force yes" to always send messages ' '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 ' 'of this type via email, and "Force no" to never send messages of '
'type via email')
'type via email',
)
custom_notification_own = fields.Boolean( custom_notification_own = fields.Boolean(
'Notify about own messages', help='Check this to have notifications ' 'Notify about own messages', help='Check this to have notifications '
'generated and sent via email about own messages')
'generated and sent via email about own messages',
)
custom_notification_model_ids = fields.Many2many( custom_notification_model_ids = fields.Many2many(
'ir.model', string='Models', help='Choose for which models the ' 'ir.model', string='Models', help='Choose for which models the '
'custom configuration applies. This is only necessary if your subtype ' 'custom configuration applies. This is only necessary if your subtype '
'doesn\'t set a model itself', domain=[('osv_memory', '=', False)])
'doesn\'t set a model itself',
domain=[('transient', '=', False)],
)

33
mail_follower_custom_notification/models/mail_notification.py

@ -1,33 +0,0 @@
# -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# 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

42
mail_follower_custom_notification/models/mail_thread.py

@ -1,40 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import api, models
from odoo import api, models
class MailThread(models.AbstractModel): 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):
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
_inherit = 'mail.thread'
@api.multi @api.multi
def message_custom_notification_update_user(self, custom_notifications): def message_custom_notification_update_user(self, custom_notifications):
@ -54,9 +25,10 @@ class MailThread(models.AbstractModel):
and dictionaries mapping message subtype ids to custom notification and dictionaries mapping message subtype ids to custom notification
values""" values"""
def ids_with_value(data, key, value): def ids_with_value(data, key, value):
return map(lambda x: int(x[0]),
filter(lambda x: x[1][key] == value,
data.iteritems()))
return map(
lambda x: int(x[0]),
filter(lambda x: x[1][key] == value, data.iteritems())
)
custom_notifications = { custom_notifications = {
int(key): value int(key): value

30
mail_follower_custom_notification/models/res_partner.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Copyright 2019 Therp BV <https://therp.nl>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, models
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.multi
def _notify_by_email(
self, message, force_send=False, send_after_commit=True,
user_signature=True,
):
"""remove partners from `self` who requested not to be mailed,
add the ones who did the opposite"""
domain = [
('res_model', '=', message.model),
('res_id', '=', message.res_id),
]
self |= self.env['mail.followers'].search(
domain + [('force_mail_subtype_ids', '=', message.subtype_id.id)]
).mapped('partner_id')
self -= self.env['mail.followers'].search(
domain + [('force_nomail_subtype_ids', '=', message.subtype_id.id)]
).mapped('partner_id')
return super(ResPartner, self)._notify_by_email(
message, force_send=force_send,
send_after_commit=send_after_commit, user_signature=user_signature,
)

10
mail_follower_custom_notification/readme/CONFIGURE.rst

@ -0,0 +1,10 @@
When followers open their subscriptions, they will be offered the choice to
override mail settings and to force being notified about their own messages.
Note subscriptions are only editable for users of the `Technical settings`
group.
You can add defaults per message subtype 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.

1
mail_follower_custom_notification/readme/CONTRIBUTORS.rst

@ -0,0 +1 @@
* Holger Brunn <hbrunn@therp.nl>

1
mail_follower_custom_notification/readme/CREDITS.rst

@ -0,0 +1 @@
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.

6
mail_follower_custom_notification/readme/DESCRIPTION.rst

@ -0,0 +1,6 @@
In standard Odoo, receiving mail notifications is an all or nothing affair.
This module allows users to decide per followed record if they want to
receive emails or not. Further, they can choose to receive notifications about
their own messages.
You can also set defaults for this settings on the subtype in question.

442
mail_follower_custom_notification/static/description/index.html

@ -0,0 +1,442 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
<title>Custom notification settings for followers</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="custom-notification-settings-for-followers">
<h1 class="title">Custom notification settings for followers</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/social/tree/10.0/mail_follower_custom_notification"><img alt="OCA/social" src="https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/social-10-0/social-10-0-mail_follower_custom_notification"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/205/10.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>In standard Odoo, receiving mail notifications is an all or nothing affair.
This module allows users to decide per followed record if they want to
receive emails or not. Further, they can choose to receive notifications about
their own messages.</p>
<p>You can also set defaults for this settings on the subtype in question.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="id6">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id1">Configuration</a></h1>
<p>When followers open their subscriptions, they will be offered the choice to
override mail settings and to force being notified about their own messages.</p>
<p>Note subscriptions are only editable for users of the <cite>Technical settings</cite>
group.</p>
<p>You can add defaults per message subtype 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.</p>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/social/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/social/issues/new?body=module:%20mail_follower_custom_notification%0Aversion:%2010.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple">
<li>Therp BV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<ul class="simple">
<li>Holger Brunn &lt;<a class="reference external" href="mailto:hbrunn&#64;therp.nl">hbrunn&#64;therp.nl</a>&gt;</li>
</ul>
</div>
<div class="section" id="other-credits">
<h2><a class="toc-backref" href="#id6">Other credits</a></h2>
<ul class="simple">
<li>Odoo Community Association: <a class="reference external" href="https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg">Icon</a>.</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/social/tree/10.0/mail_follower_custom_notification">OCA/social</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

15
mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css

@ -1,5 +1,18 @@
.oe_custom_notification legend
.o_mail_follower_custom_notification
{
padding: 5px 10px 10px 10px;
}
.o_mail_follower_custom_notification fieldset > legend
{ {
font-size: inherit; font-size: inherit;
margin-bottom: 0px; margin-bottom: 0px;
} }
.o_mail_follower_custom_notification fieldset > div,
.o_mail_follower_custom_notification fieldset > div > label
{
white-space: nowrap;
}
.o_mail_follower_custom_notification fieldset > div > label
{
font-weight: normal;
}

98
mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js

@ -1,79 +1,65 @@
//-*- coding: utf-8 -*-
//© 2015 Therp BV <http://therp.nl>
//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;
// -*- coding: utf-8 -*-
// Copyright 2015-2019 Therp BV <http://therp.nl>
// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
odoo.define('mail_follower_custom_notification', function(require) {
'use strict';
var core = require('web.core');
require('mail.Followers');
core.form_widget_registry.get('mail_followers').include({
/* eslint-disable-next-line no-unused-vars */
display_subtypes:function (data, dialog, display_warning) {
this._super.apply(this, arguments);
var $list = this.$('ul.o_followers_list');
if (dialog) {
$list = this.dialog.$('ul');
} }
$list.empty();
this._super(data, id, dialog);
$list.find('input[type=checkbox]').change(function()
{
$list.find('input[type=checkbox]').change(function() {
$list.find(_.str.sprintf( $list.find(_.str.sprintf(
'#custom_notification_%s%s', '#custom_notification_%s%s',
jQuery(this).data('id'), jQuery(this).data('id'),
dialog ? '_dialog' : '' dialog ? '_dialog' : ''
))
.toggle(jQuery(this).prop('checked'));
)).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();
if (!dialog) {
$list.find(
'.oe_custom_notification input[type=radio]'
).change(this.proxy('do_update_subscription'));
} }
*/
},
/* eslint-disable-next-line no-unused-vars */
do_update_subscription: function (event, follower_id, is_channel) {
var self = this, var self = this,
update_func = 'message_custom_notification_update_user', update_func = 'message_custom_notification_update_user',
follower_ids = [this.session.uid], follower_ids = [this.session.uid],
custom_notifications = {}, custom_notifications = {},
oe_action = this.$('.oe_actions');
if(user_pid)
{
$list = this.$('ul');
if (follower_id !== undefined) {
update_func = 'message_custom_notification_update'; update_func = 'message_custom_notification_update';
follower_ids = [user_pid];
oe_action = jQuery('.oe_edit_actions');
follower_ids = [follower_id];
$list = this.dialog.$('ul');
} }
_(follower_ids).each(function(follower)
{
_(follower_ids).each(function(follower) {
var follower_settings = custom_notifications[follower] = {}; var follower_settings = custom_notifications[follower] = {};
oe_action.find('.oe_custom_notification')
.each(function()
{
var id = parseInt(jQuery(this).data('id')),
$list.find(
'.o_mail_follower_custom_notification'
).each(function () {
var id = parseInt(jQuery(this).data('id'), 10),
settings = follower_settings[id] = {}; settings = follower_settings[id] = {};
settings['force_mail'] = jQuery(this)
.find('.oe_custom_notification_mail input:checked')
settings.force_mail = jQuery(this)
.find('.mail input:checked')
.val(); .val();
settings['force_own'] = jQuery(this)
.find('.oe_custom_notification_own input:checked')
settings.force_own = jQuery(this)
.find('.own input:checked')
.val(); .val();
}); });
}); });
return jQuery.when(this._super.apply(this, arguments))
.then(function()
{
return jQuery.when(
this._super.apply(this, arguments)
).then(function () {
return self.ds_model.call( return self.ds_model.call(
update_func, update_func,
[[self.view.datarecord.id], custom_notifications])
})
[[self.view.datarecord.id], custom_notifications]);
}).then(this.proxy('render_value'));
}, },
}); });
}
});

63
mail_follower_custom_notification/static/src/xml/mail_follower_custom_notification.xml

@ -1,38 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<template> <template>
<t t-extend="mail.followers.subtype">
<t t-jquery="table" t-operation="append">
<tr class="oe_custom_notification" t-att-style="record.followed ? '' : 'display: none'" t-attf-id="custom_notification_#{record.id}#{dialog ? '_dialog' : ''}" t-att-data-id="record.id">
<td />
<td>
<fieldset class="oe_custom_notification_mail">
<legend>Mail notifications</legend>
<div>
<input type="radio" t-att-checked="record.force_mail=='default' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_default_#{record.id}#{dialog ? '_dialog' : ''}" value="default" />
<label t-attf-for="custom_notification_mail_default_#{record.id}#{dialog ? '_dialog' : ''}">Use default mail preferences</label>
</div>
<div>
<input type="radio" t-att-checked="record.force_mail=='force_yes' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_force_#{record.id}#{dialog ? '_dialog' : ''}" value="force_yes" />
<label t-attf-for="custom_notification_mail_force_#{record.id}#{dialog ? '_dialog' : ''}">Force sending mails</label>
</div>
<div>
<input type="radio" t-att-checked="record.force_mail=='force_no' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_force_no_#{record.id}#{dialog ? '_dialog' : ''}" value="force_no" />
<label t-attf-for="custom_notification_mail_force_no_#{record.id}#{dialog ? '_dialog' : ''}">Force not sending mails</label>
</div>
</fieldset>
<fieldset class="oe_custom_notification_own">
<legend>Own messages</legend>
<div>
<input type="radio" t-att-checked="!record.force_own ? 'checked' : null" t-attf-name="custom_notification_own_#{record.id}" t-attf-id="custom_notification_own_no_#{record.id}#{dialog ? '_dialog' : ''}" value="" />
<label t-attf-for="custom_notification_own_no_#{record.id}#{dialog ? '_dialog' : ''}">No notification</label>
</div>
<div>
<input type="radio" t-att-checked="record.force_own ? 'checked' : null" t-attf-name="custom_notification_own_#{record.id}" t-attf-id="custom_notification_own_yes_#{record.id}#{dialog ? '_dialog' : ''}" value="1" />
<label t-attf-for="custom_notification_own_yes_#{record.id}#{dialog ? '_dialog' : ''}">Notify me</label>
</div>
</fieldset>
</td>
</tr>
<t t-extend="mail.Followers.subtype">
<t t-jquery="li i" t-operation="before">
<div class="o_mail_follower_custom_notification" t-att-style="record.followed ? False : 'display: none'" t-attf-id="custom_notification_#{record.id}#{dialog ? '_dialog' : ''}" t-att-data-id="record.id">
<fieldset class="mail">
<legend>Mail notifications</legend>
<div>
<input type="radio" t-att-checked="record.force_mail=='default' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_default_#{record.id}#{dialog ? '_dialog' : ''}" value="default" />
<label t-attf-for="custom_notification_mail_default_#{record.id}#{dialog ? '_dialog' : ''}">Use default mail preferences</label>
</div>
<div>
<input type="radio" t-att-checked="record.force_mail=='force_yes' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_force_#{record.id}#{dialog ? '_dialog' : ''}" value="force_yes" />
<label t-attf-for="custom_notification_mail_force_#{record.id}#{dialog ? '_dialog' : ''}">Force sending mails</label>
</div>
<div>
<input type="radio" t-att-checked="record.force_mail=='force_no' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_force_no_#{record.id}#{dialog ? '_dialog' : ''}" value="force_no" />
<label t-attf-for="custom_notification_mail_force_no_#{record.id}#{dialog ? '_dialog' : ''}">Force not sending mails</label>
</div>
</fieldset>
<fieldset class="own">
<legend>Own messages</legend>
<div>
<input type="radio" t-att-checked="!record.force_own ? 'checked' : null" t-attf-name="custom_notification_own_#{record.id}" t-attf-id="custom_notification_own_no_#{record.id}#{dialog ? '_dialog' : ''}" value="" />
<label t-attf-for="custom_notification_own_no_#{record.id}#{dialog ? '_dialog' : ''}">No notification</label>
</div>
<div>
<input type="radio" t-att-checked="record.force_own ? 'checked' : null" t-attf-name="custom_notification_own_#{record.id}" t-attf-id="custom_notification_own_yes_#{record.id}#{dialog ? '_dialog' : ''}" value="1" />
<label t-attf-for="custom_notification_own_yes_#{record.id}#{dialog ? '_dialog' : ''}">Notify me</label>
</div>
</fieldset>
</div>
</t> </t>
</t> </t>
</template> </template>

86
mail_follower_custom_notification/tests/test_mail_follower_custom_notification.py

@ -1,33 +1,48 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from mock import Mock, patch
from openerp.tests.common import TransactionCase from openerp.tests.common import TransactionCase
from ..controllers.mail_controller import MailController
class TestMailFollowerCustomNotification(TransactionCase): class TestMailFollowerCustomNotification(TransactionCase):
def _call_controller(self, res_model, follower_id):
mt_comment = self.env.ref('mail.mt_comment')
with patch('__builtin__.super') as mock_super, patch(
'odoo.addons.mail_follower_custom_notification.controllers.'
'mail_controller.request'
) as mock_request:
mock_super.return_value = Mock(
read_subscription_data=lambda res_model, follower_id: [{
'id': mt_comment.id,
}],
)
mock_request.env = self.env
return MailController.read_subscription_data.__func__(
None, res_model, follower_id,
)[0]
def test_mail_follower_custom_notification(self): def test_mail_follower_custom_notification(self):
self.env['mail.thread']._register_hook()
followed_partner = self.env['res.partner'].create({ followed_partner = self.env['res.partner'].create({
'name': 'I\'m followed', 'name': 'I\'m followed',
}) })
demo_user = self.env.ref('base.user_demo') demo_user = self.env.ref('base.user_demo')
mt_comment = self.env.ref('mail.mt_comment')
followed_partner_demo = followed_partner.sudo(demo_user.id) followed_partner_demo = followed_partner.sudo(demo_user.id)
followed_partner_demo.message_subscribe_users() followed_partner_demo.message_subscribe_users()
follower = followed_partner_demo.message_follower_ids.filtered(
lambda x: x.partner_id == demo_user.partner_id
)
# see if default subscriptions return default custom settings # 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)
subscription_data = self._call_controller(
follower.res_model, follower.id,
)
self.assertEqual(subscription_data['force_mail'], 'default')
self.assertEqual(subscription_data['force_own'], False)
# set custom settings # set custom settings
mt_comment = self.env.ref('mail.mt_comment')
followed_partner_demo.message_custom_notification_update_user({ followed_partner_demo.message_custom_notification_update_user({
str(demo_user.id): { str(demo_user.id): {
str(mt_comment.id): { str(mt_comment.id): {
@ -37,39 +52,34 @@ class TestMailFollowerCustomNotification(TransactionCase):
}, },
}) })
# see if we can read them back # 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)
subscription_data = self._call_controller(
follower.res_model, follower.id,
)
self.assertEqual(subscription_data['force_mail'], 'force_yes')
self.assertEqual(subscription_data['force_own'], True)
# post a message and see if we successfully forced a notification to # post a message and see if we successfully forced a notification to
# ourselves # ourselves
# pylint: disable=translation-required
followed_partner_demo.message_post('hello world', subtype='mt_comment') 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)
self.assertIn(
demo_user.partner_id,
followed_partner_demo.message_ids[:-1].notification_ids.mapped(
'res_partner_id',
)
)
# assign default values on message subtype and apply them to all # assign default values on message subtype and apply them to all
# followers # followers
mt_comment.custom_notification_model_ids = self.env['ir.model']\
.search([('model', '=', 'res.partner')])
mt_comment.custom_notification_model_ids = self.env['ir.model'].search(
[('model', '=', 'res.partner')]
)
wizard = self.env['mail.subtype.assign.custom.notifications']\ wizard = self.env['mail.subtype.assign.custom.notifications']\
.with_context(active_ids=mt_comment.ids)\ .with_context(active_ids=mt_comment.ids)\
.create({}) .create({})
wizard.button_apply() 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)
subscription_data = self._call_controller(
follower.res_model, follower.id,
)
self.assertEqual(subscription_data['force_mail'], 'default')
self.assertEqual(subscription_data['force_own'], False)

30
mail_follower_custom_notification/views/mail_message_subtype.xml

@ -1,18 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_mail_message_subtype_form" model="ir.ui.view">
<field name="model">mail.message.subtype</field>
<field name="inherit_id" ref="mail.view_mail_message_subtype_form" />
<field name="arch" type="xml">
<group position="inside">
<group string="Custom notifications">
<field name="custom_notification_mail" />
<field name="custom_notification_own" />
<field name="custom_notification_model_ids" attrs="{'invisible': [('res_model', '!=', False)]}" widget="many2many_tags" />
</group>
<odoo>
<record id="view_mail_message_subtype_form" model="ir.ui.view">
<field name="model">mail.message.subtype</field>
<field name="inherit_id" ref="mail.view_mail_message_subtype_form" />
<field name="arch" type="xml">
<group position="inside">
<group name="mail_follower_custom_notification" string="Custom notifications">
<field name="custom_notification_mail" />
<field name="custom_notification_own" />
<field name="custom_notification_model_ids" attrs="{'invisible': [('res_model', '!=', False)]}" widget="many2many_tags" />
</group> </group>
</field>
</record>
</data>
</openerp>
</group>
</field>
</record>
</odoo>

18
mail_follower_custom_notification/views/templates.xml

@ -1,11 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<template id="assets_backend" name="mail_follower_custom_notification assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js"></script>
<link rel="stylesheet" href="/mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css"/>
</xpath>
</template>
</data>
</openerp>
<odoo>
<template id="assets_backend" name="mail_follower_custom_notification assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js"></script>
<link rel="stylesheet" href="/mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css"/>
</xpath>
</template>
</odoo>

2
mail_follower_custom_notification/wizards/__init__.py

@ -1,4 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import mail_subtype_assign_custom_notifications from . import mail_subtype_assign_custom_notifications

5
mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.py

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Therp BV <http://therp.nl>
# Copyright 2015 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import api, fields, models from openerp import api, fields, models
@ -15,8 +15,7 @@ class MailSubtypeAssignCustomNotifications(models.TransientModel):
@api.multi @api.multi
def button_apply(self): def button_apply(self):
self.ensure_one()
for subtype in self.subtype_ids:
for subtype in self.mapped('subtype_ids'):
domain = [('subtype_ids', '=', subtype.id)] domain = [('subtype_ids', '=', subtype.id)]
if subtype.custom_notification_model_ids: if subtype.custom_notification_model_ids:
domain.append( domain.append(

55
mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.xml

@ -1,30 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_mail_subtype_assign_custom_notifications" model="ir.ui.view">
<field name="model">mail.subtype.assign.custom.notifications</field>
<field name="arch" type="xml">
<form>
<group>
<field name="subtype_ids" widget="many2many_tags" />
</group>
<footer>
<button type="object" name="button_apply" string="Apply"
class="oe_highlight" />
or
<button type="special" special="cancel" string="Cancel"
class="oe_link" />
</footer>
</form>
</field>
</record>
<act_window id="action_mail_subtype_assign_custom_notifications"
name="Update existing subscriptions"
src_model="mail.message.subtype"
res_model="mail.subtype.assign.custom.notifications"
view_id="view_mail_subtype_assign_custom_notifications"
multi="False"
key2="client_action_multi"
target="new" />
</data>
</openerp>
<odoo>
<record id="view_mail_subtype_assign_custom_notifications" model="ir.ui.view">
<field name="model">mail.subtype.assign.custom.notifications</field>
<field name="arch" type="xml">
<form>
<group>
<field name="subtype_ids" widget="many2many_tags" />
</group>
<footer>
<button type="object" name="button_apply" string="Apply"
class="btn-primary" />
<button type="special" special="cancel" string="Cancel"
class="btn-default" />
</footer>
</form>
</field>
</record>
<act_window id="action_mail_subtype_assign_custom_notifications"
name="Update existing subscriptions"
src_model="mail.message.subtype"
res_model="mail.subtype.assign.custom.notifications"
view_id="view_mail_subtype_assign_custom_notifications"
multi="False"
key2="client_action_multi"
target="new" />
</odoo>
Loading…
Cancel
Save