diff --git a/setup/web_notify/odoo_addons/__init__.py b/setup/web_notify/odoo_addons/__init__.py new file mode 100644 index 00000000..de40ea7c --- /dev/null +++ b/setup/web_notify/odoo_addons/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/setup/web_notify/odoo_addons/web_notify b/setup/web_notify/odoo_addons/web_notify new file mode 120000 index 00000000..93a0a1fd --- /dev/null +++ b/setup/web_notify/odoo_addons/web_notify @@ -0,0 +1 @@ +../../../web_notify \ No newline at end of file diff --git a/setup/web_notify/setup.py b/setup/web_notify/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/web_notify/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/web_notify/README.rst b/web_notify/README.rst new file mode 100644 index 00000000..f24f58fe --- /dev/null +++ b/web_notify/README.rst @@ -0,0 +1,80 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +========== +Web Notify +========== + +Send instant notification messages to the user in live. + +This technical module allows you to send instant notification messages from the server to the user in live. +Two kinds of notification are supported. + +* Warning: Displayed in a red flying popup div +* Information: Displayed in a light yellow flying popup div + +To send a notification to the user you just need to call one of the new methods defined on res.users: + +.. code-block:: python + + self.env.user.notify_info('My information message') + +or + +.. code-block:: python + + self.env.user.notify_warning('My marning message') + +.. figure:: static/description/notifications_screenshot.png + :scale: 80 % + :alt: Sample notifications + +Installation +============ + +This module is based on the Instant Messaging Bus. To work properly, the server must be launched in gevent mode. + + +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/162/9.0 + +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. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Laurent Mignon + +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 https://odoo-community.org. diff --git a/web_notify/__init__.py b/web_notify/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/web_notify/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/web_notify/__openerp__.py b/web_notify/__openerp__.py new file mode 100644 index 00000000..a6e542eb --- /dev/null +++ b/web_notify/__openerp__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Web Notify', + 'summary': """ + Send notification messages to user""", + 'version': '9.0.1.0.0', + 'license': 'AGPL-3', + 'author': 'ACSONE SA/NV,Odoo Community Association (OCA)', + 'website': 'https://acsone.eu/', + 'depends': [ + 'web', + 'bus', + ], + 'data': [ + 'views/web_notify.xml' + ], + 'demo': [ + ], +} diff --git a/web_notify/models/__init__.py b/web_notify/models/__init__.py new file mode 100644 index 00000000..88351653 --- /dev/null +++ b/web_notify/models/__init__.py @@ -0,0 +1 @@ +from . import res_users diff --git a/web_notify/models/res_users.py b/web_notify/models/res_users.py new file mode 100644 index 00000000..51147455 --- /dev/null +++ b/web_notify/models/res_users.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models, _ + + +class ResUsers(models.Model): + + _inherit = 'res.users' + + @api.multi + @api.depends('create_date') + def _compute_channel_names(self): + for record in self: + res_id = record.id + record.notify_info_channel_name = 'notify_info_%s' % res_id + record.notify_warning_channel_name = 'notify_warning_%s' % res_id + + notify_info_channel_name = fields.Char( + compute='_compute_channel_names') + notify_warning_channel_name = fields.Char( + compute='_compute_channel_names') + + @api.multi + def notify_info(self, message, title=None, sticky=False): + title = title or _('Information') + self._notify_channel( + 'notify_info_channel_name', message, title, sticky) + + @api.multi + def notify_warning(self, message, title=None, sticky=False): + title = title or _('Warning') + self._notify_channel( + 'notify_warning_channel_name', message, title, sticky) + + @api.multi + def _notify_channel(self, channel_name_field, message, title, sticky): + bus_message = { + 'message': message, + 'title': title, + 'sticky': sticky + } + notifications = [(getattr(record, channel_name_field), bus_message) + for record in self] + self.env['bus.bus'].sendmany(notifications) diff --git a/web_notify/static/description/icon.png b/web_notify/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/web_notify/static/description/icon.png differ diff --git a/web_notify/static/description/notifications_screenshot.png b/web_notify/static/description/notifications_screenshot.png new file mode 100644 index 00000000..1a1062cd Binary files /dev/null and b/web_notify/static/description/notifications_screenshot.png differ diff --git a/web_notify/static/src/js/web_client.js b/web_notify/static/src/js/web_client.js new file mode 100644 index 00000000..3c908a07 --- /dev/null +++ b/web_notify/static/src/js/web_client.js @@ -0,0 +1,53 @@ +odoo.define('web_notify.WebClient', function (require) { +"use strict"; + +var WebClient = require('web.WebClient'); +var base_bus = require('bus.bus'); +var _ = require('_'); + +WebClient.include({ + init: function(parent, client_options){ + this._super(parent, client_options); + }, + show_application: function() { + this._super(); + this.start_polling(); + }, + on_logout: function() { + var self = this; + base_bus.bus.off('notification', this, this.bus_notification); + this._super(); + }, + start_polling: function() { + this.channel_warning = 'notify_warning_' + this.session.uid; + this.channel_info = 'notify_info_' + this.session.uid; + base_bus.bus.add_channel(this.channel_warning); + base_bus.bus.add_channel(this.channel_info); + base_bus.bus.on('notification', this, this.bus_notification); + base_bus.bus.start_polling(); + }, + bus_notification: function(notifications) { + var self = this; + _.each(notifications, function (notification) { + var channel = notification[0]; + var message = notification[1]; + if (channel === self.channel_warning) { + self.on_message_warning(message); + } else if (channel == self.channel_info) { + self.on_message_info(message); + } + }); + }, + on_message_warning: function(message){ + if(this.notification_manager) { + this.notification_manager.do_warn(message.title, message.message, message.sticky); + } + }, + on_message_info: function(message){ + if(this.notification_manager) { + this.notification_manager.do_notify(message.title, message.message, message.sticky); + } + } +}); + +}); \ No newline at end of file diff --git a/web_notify/tests/__init__.py b/web_notify/tests/__init__.py new file mode 100644 index 00000000..03c963d7 --- /dev/null +++ b/web_notify/tests/__init__.py @@ -0,0 +1 @@ +from . import test_res_users diff --git a/web_notify/tests/test_res_users.py b/web_notify/tests/test_res_users.py new file mode 100644 index 00000000..f6751fed --- /dev/null +++ b/web_notify/tests/test_res_users.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Copyright 2016 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.tests import common +from openerp.addons.bus.models.bus import json_dump +import mock + + +class TestResUsers(common.TransactionCase): + + def test_notify_info(self): + bus_bus = self.env['bus.bus'] + domain = [ + ('channel', '=', + json_dump(self.env.user.notify_info_channel_name)) + ] + existing = bus_bus.search(domain) + self.env.user.notify_info( + message='message', title='title', sticky=True) + news = bus_bus.search(domain) - existing + self.assertEqual(1, len(news)) + self.assertEqual( + '{"message":"message","sticky":true,"title":"title"}', + news.message) + + def test_notify_warning(self): + bus_bus = self.env['bus.bus'] + domain = [ + ('channel', '=', + json_dump(self.env.user.notify_warning_channel_name)) + ] + existing = bus_bus.search(domain) + self.env.user.notify_warning( + message='message', title='title', sticky=True) + news = bus_bus.search(domain) - existing + self.assertEqual(1, len(news)) + self.assertEqual( + '{"message":"message","sticky":true,"title":"title"}', + news.message) + + def test_notify_many(self): + # check that the notification of a list of users is done with + # a single call to the bus + with mock.patch('openerp.addons.bus.models.bus.ImBus.sendmany' + ) as mockedSendMany: + users = self.env.user.search([(1, "=", 1)]) + self.assertTrue(len(users) > 1) + users.notify_warning('message') + self.assertEqual(1, mockedSendMany.call_count) + self.assertEqual(len(users), len(mockedSendMany.call_args)) diff --git a/web_notify/views/web_notify.xml b/web_notify/views/web_notify.xml new file mode 100644 index 00000000..b85d2e6f --- /dev/null +++ b/web_notify/views/web_notify.xml @@ -0,0 +1,10 @@ + + + +