Browse Source

[IMP] bus_presence_override: Add new features.

* Add caching so status change in 1 tab affects other open tabs.
* Add automatic polling to update status if away or disconnection timers hit
pull/382/head
Brett Wood 7 years ago
committed by Holger Brunn
parent
commit
2a94a29f5c
  1. 1
      bus_presence_override/__init__.py
  2. 4
      bus_presence_override/__manifest__.py
  3. 5
      bus_presence_override/controllers/__init__.py
  4. 21
      bus_presence_override/controllers/main.py
  5. 2
      bus_presence_override/models/__init__.py
  6. 88
      bus_presence_override/models/bus_presence.py
  7. 76
      bus_presence_override/models/res_partner.py
  8. 21
      bus_presence_override/models/res_users.py
  9. 106
      bus_presence_override/static/src/js/bus_presence_systray.js
  10. 59
      bus_presence_override/static/src/js/systray.js
  11. 21
      bus_presence_override/static/src/less/bus_presence_systray.less
  12. 47
      bus_presence_override/static/src/less/systray.less
  13. 25
      bus_presence_override/static/src/xml/bus_presence_systray.xml
  14. 2
      bus_presence_override/tests/__init__.py
  15. 28
      bus_presence_override/tests/bus_setup.py
  16. 120
      bus_presence_override/tests/test_bus_presence.py
  17. 91
      bus_presence_override/tests/test_res_partner.py
  18. 28
      bus_presence_override/tests/test_res_users.py
  19. 4
      bus_presence_override/views/assets.xml

1
bus_presence_override/__init__.py

@ -2,4 +2,5 @@
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from . import controllers
from . import models from . import models

4
bus_presence_override/__manifest__.py

@ -9,7 +9,7 @@
"category": "Social", "category": "Social",
"website": "https://github.com/OCA/social", "website": "https://github.com/OCA/social",
"author": "LasLabs, Odoo Community Association (OCA)", "author": "LasLabs, Odoo Community Association (OCA)",
"license": "AGPL-3",
"license": "LGPL-3",
"application": False, "application": False,
"installable": True, "installable": True,
"depends": [ "depends": [
@ -19,6 +19,6 @@
"views/assets.xml", "views/assets.xml",
], ],
"qweb": [ "qweb": [
"static/src/xml/systray.xml",
"static/src/xml/bus_presence_systray.xml",
], ],
} }

5
bus_presence_override/controllers/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from . import main

21
bus_presence_override/controllers/main.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo.http import request
from odoo.addons.bus.controllers.main import BusController
class BusController(BusController):
def _poll(self, dbname, channels, last, options):
if request.uid:
partner = request.env.user.partner_id
if 'bus_presence_partner_ids' in options:
options['bus_presence_partner_ids'].append(partner.id)
else:
options['bus_presence_partner_ids'] = [partner.id]
return super(BusController, self)._poll(
dbname, channels, last, options,
)

2
bus_presence_override/models/__init__.py

@ -2,4 +2,6 @@
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from . import bus_presence
from . import res_partner from . import res_partner
from . import res_users

88
bus_presence_override/models/bus_presence.py

@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from datetime import datetime
from odoo import api, fields, models
from odoo.addons.bus.models.bus_presence import AWAY_TIMER, DISCONNECTION_TIMER
from ..status_constants import ONLINE, AWAY, OFFLINE
class BusPresence(models.Model):
_inherit = 'bus.presence'
status_realtime = fields.Selection(
selection=[
(ONLINE, 'Online'),
(AWAY, 'Away'),
(OFFLINE, 'Offline')
],
string='Realtime IM Status',
compute='_compute_status_realtime',
help='Status that is affected by disconnection '
'and away timers. Used to override the bus.presence '
'status field in _get_partners_statuses or '
'_get_users_statuses if the timers have been reached. '
'If wanting to change the user status, write '
'directly to the status field.',
)
partner_id = fields.Many2one(
string='Partner',
related='user_id.partner_id',
comodel_name='res.partner',
)
@api.multi
def _get_partners_statuses(self):
self._status_check_disconnection_and_away_timers()
return {rec.partner_id.id: rec.status for rec in self}
@api.multi
def _get_users_statuses(self):
self._status_check_disconnection_and_away_timers()
return {rec.user_id.id: rec.status for rec in self}
@api.multi
def _status_check_disconnection_and_away_timers(self):
""" Overrides user-defined status if timers reached """
for record in self:
status_realtime = record.status_realtime
status_stored = record.status
conditions = (
status_realtime == OFFLINE,
status_realtime == AWAY and status_stored == ONLINE,
)
if any(conditions):
record.status = status_realtime
@api.multi
def _compute_status_realtime(self):
now_dt = datetime.now()
for record in self:
last_poll = fields.Datetime.from_string(
record.last_poll
)
last_presence = fields.Datetime.from_string(
record.last_presence
)
last_poll_s = (now_dt - last_poll).total_seconds()
last_presence_s = (now_dt - last_presence).total_seconds()
if last_poll_s > DISCONNECTION_TIMER:
record.status_realtime = OFFLINE
elif last_presence_s > AWAY_TIMER:
record.status_realtime = AWAY
else:
record.status_realtime = ONLINE

76
bus_presence_override/models/res_partner.py

@ -2,82 +2,20 @@
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
from odoo import api, models
from odoo.addons.bus.models.bus_presence import AWAY_TIMER
from odoo.addons.bus.models.bus_presence import DISCONNECTION_TIMER
from ..status_constants import ONLINE, AWAY, OFFLINE
from ..status_constants import OFFLINE
class ResPartner(models.Model): class ResPartner(models.Model):
_inherit = 'res.partner' _inherit = 'res.partner'
im_status_custom = fields.Selection(
selection=[
(ONLINE, 'Online'),
(AWAY, 'Away'),
(OFFLINE, 'Offline'),
],
string='Status',
default=ONLINE,
)
@api.model
def _get_partners_presence(self):
""" This method gets any relevant partners' im status.
Example:
.. code-block:: python
res = self.env['res.partner']._get_partners_presence()
im_status = res.get(partner.id, OFFLINE)
Returns:
dict: Structured like so: {partner_id: im_status}
"""
self.env.cr.execute(
"""
SELECT
U.partner_id as id,
CASE WHEN age(now() AT TIME ZONE 'UTC', B.last_poll)
> interval %s THEN 'offline'
WHEN age(now() AT TIME ZONE 'UTC', B.last_presence)
> interval %s THEN 'away'
ELSE 'online'
END as status
FROM bus_presence B
JOIN res_users U ON B.user_id = U.id
WHERE U.partner_id IN %s AND U.active = 't'
""",
("%s seconds" % DISCONNECTION_TIMER,
"%s seconds" % AWAY_TIMER, tuple(self.ids))
)
all_status = self.env.cr.dictfetchall()
all_status_dict = dict(
((status['id'], status['status']) for status in all_status)
)
return all_status_dict
@api.multi @api.multi
def _compute_im_status(self): def _compute_im_status(self):
presence = self._get_partners_presence()
bus_recs = self.env['bus.presence'].search([
('partner_id', 'in', self.ids),
])
statuses = bus_recs._get_partners_statuses()
for record in self: for record in self:
record.im_status = presence.get(record.id, OFFLINE)
computed = record.im_status
custom = record.im_status_custom
if computed == OFFLINE:
record.im_status_custom = computed
elif custom in (AWAY, OFFLINE):
record.im_status = custom
elif computed == AWAY and custom == ONLINE:
record.im_status_custom = computed
record.im_status = statuses.get(record.id, OFFLINE)

21
bus_presence_override/models/res_users.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api, models
from ..status_constants import OFFLINE
class ResUsers(models.Model):
_inherit = 'res.users'
@api.multi
def _compute_im_status(self):
bus_recs = self.env['bus.presence'].search([
('user_id', 'in', self.ids),
])
statuses = bus_recs._get_users_statuses()
for record in self:
record.im_status = statuses.get(record.id, OFFLINE)

106
bus_presence_override/static/src/js/bus_presence_systray.js

@ -0,0 +1,106 @@
/* Copyright 2017 LasLabs Inc.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define('bus_presence_systray', function (require) {
"use strict";
var Bus = require('bus.bus').bus;
var DataModel = require('web.DataModel');
var Session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var Qweb = require('web.core').qweb;
var LocalStorage = require('web.local_storage');
function on(type, listener) {
if (window.addEventListener) {
window.addEventListener(type, listener);
} else {
// IE8
window.attachEvent('on' + type, listener);
}
}
var BusPresenceSystray = Widget.extend({
template: 'bus_presence_systray',
events: {
'click .o-user-status-select': 'onClickUserStatusSelect',
},
init: function() {
this._super.apply(this, arguments);
this.resPartnerMod = new DataModel('res.partner');
this.busPresenceMod = new DataModel('bus.presence');
Bus.on('notification', this, _.throttle(this.notificationsUpdateCurrentUserStatus.bind(this), 100, {leading: false}));
on('storage', this.onStorage.bind(this));
},
start: function () {
this.startDetermineUserStatus();
Bus.start_polling();
return this._super();
},
startDetermineUserStatus: function () {
if (Bus.is_master === true) {
this.writeBusPresenceStatus('online');
this.updateUserStatusIcon('online');
LocalStorage.setItem('user.partner_im_status', 'online');
} else {
var statusVal = LocalStorage.getItem('user.partner_im_status');
this.updateUserStatusIcon(statusVal);
}
},
onStorage: function (event) {
if (event.key === 'user.partner_im_status') {
this.updateUserStatusIcon(event.newValue);
}
},
notificationsUpdateCurrentUserStatus: function (notifications) {
_.each(notifications, $.proxy(
function (notification) {
var model = notification[0][1];
var partnerId = notification[1].id;
if (model === 'bus.presence' && partnerId === Session.partner_id) {
var status = notification[1].im_status;
this.updateUserStatusIcon(status);
LocalStorage.setItem('user.partner_im_status', status);
}
}, this)
);
},
queryUpdateCurrentUserStatus: function () {
this.resPartnerMod.query(['im_status'])
.filter([['id', '=', Session.partner_id]])
.first()
.then($.proxy(
function (result) {
this.updateUserStatusIcon(result.im_status);
LocalStorage.setItem('user.partner_im_status', status);
}, this)
);
},
updateUserStatusIcon: function (status) {
var options = {'status': status};
var $icon = this.$('.o-user-systray-status');
$icon.empty().append($(Qweb.render('mail.chat.UserStatus', options)));
},
onClickUserStatusSelect: function (event) {
var status = $(event.currentTarget).attr('name');
this.updateUserStatusIcon(status);
this.writeBusPresenceStatus(status);
LocalStorage.setItem('user.partner_im_status', status);
},
writeBusPresenceStatus: function (status) {
this.busPresenceMod.query(['id'])
.filter([['partner_id', '=', Session.partner_id]])
.first()
.then($.proxy(
function (result) {
this.busPresenceMod.call('write', [[result.id], {'status': status}]);
}, this)
);
},
});
SystrayMenu.Items.push(BusPresenceSystray);
});

59
bus_presence_override/static/src/js/systray.js

@ -1,59 +0,0 @@
/* Copyright 2017 LasLabs Inc.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
odoo.define('bus_presence_override.systray', function (require) {
"use strict";
var DataModel = require('web.DataModel');
var session = require('web.session');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var Systray = Widget.extend({
template:'systray',
events: {
'click .o_user_presence_status': 'on_click_user_presence_status',
},
init: function() {
this._super.apply(this, arguments);
this.Partners = new DataModel('res.partner');
this.status_icons = {
'online': 'fa fa-circle o_user_online',
'away': 'fa fa-circle o_user_idle',
'offline': 'fa fa-circle-o',
}
},
start: function () {
this._update_im_status_custom(status='online');
return this._super()
},
on_click_user_presence_status: function (event) {
var status = $(event.target).attr('name');
this._update_im_status_custom(status);
},
_get_im_status: function () {
var self = this;
this.Partners.query(['im_status'])
.filter([['id', '=', session.partner_id]])
.first()
.then(function (result) {
self._update_systray_status_icon(result['im_status']);
});
},
_update_systray_status_icon: function (status) {
$('#userStatus i').removeClass()
.addClass('o_mail_user_status ' + this.status_icons[status]);
},
_update_im_status_custom: function (status) {
var self = this;
this.Partners.call('write', [[session.partner_id], {'im_status_custom': status}])
.then(function () {
self._update_systray_status_icon(status);
});
},
});
SystrayMenu.Items.push(Systray);
});

21
bus_presence_override/static/src/less/bus_presence_systray.less

@ -0,0 +1,21 @@
/* Copyright 2017 LasLabs Inc.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
.o-user-systray-status {
i {
margin-top: 2px;
&:hover {
color: @gray-lighter;
}
}
}
.o-user-presence-dropdown {
min-width: 85px;
.o-user-status-select {
margin-top: 2px;
padding: 4px 8px;
width: 100%;
display: block;
font-size: 13px;
}
}

47
bus_presence_override/static/src/less/systray.less

@ -1,47 +0,0 @@
/* Copyright 2017 LasLabs Inc.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
#userStatus {
&:hover i {
color: #d3d3d3 !important;
}
i {
padding-top: 2px;
}
}
.o_user_presence_dropdown {
min-width: 85px;
.o_user_presence_status {
margin-top: 2px;
padding: 4px 8px;
width: 100%;
display: block;
font-size: 13px;
}
&:hover {
cursor: pointer;
}
}
@media (max-width: @screen-xs-max) {
.o_user_presence_status {
color: #9d9d9d;
&:hover {
color: #ffffff;
}
}
}
@media (min-width: @screen-sm-min) {
.o_user_presence_status:hover {
background-color: #e0e0e0;
}
}

25
bus_presence_override/static/src/xml/systray.xml → bus_presence_override/static/src/xml/bus_presence_systray.xml

@ -4,29 +4,32 @@
<templates> <templates>
<t t-name="systray">
<t t-name="bus_presence_systray">
<li class="o_mail_navbar_item"> <li class="o_mail_navbar_item">
<a id="userStatus" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="Status" href="#">
<i class="o_mail_user_status" />
</a>
<ul class="dropdown-menu o_user_presence_dropdown" role="menu">
<a title="Status"
class="dropdown-toggle o-user-systray-status"
data-toggle="dropdown"
aria-expanded="false"
href="#"
/>
<ul class="dropdown-menu o-user-presence-dropdown" role="menu">
<li> <li>
<span name="online" class="o_user_presence_status">
<a name="online" class="o-user-status-select" href="#">
<i t-attf-class="o_mail_user_status o_user_online fa fa-circle" /> <i t-attf-class="o_mail_user_status o_user_online fa fa-circle" />
Online Online
</span>
</a>
</li> </li>
<li> <li>
<span name="away" class="o_user_presence_status">
<a name="away" class="o-user-status-select" href="#">
<i class="o_mail_user_status o_user_idle fa fa-circle" /> <i class="o_mail_user_status o_user_idle fa fa-circle" />
Away Away
</span>
</a>
</li> </li>
<li> <li>
<span name="offline" class="o_user_presence_status">
<a name="offline" class="o-user-status-select" href="#">
<i class="o_mail_user_status fa fa-circle-o" /> <i class="o_mail_user_status fa fa-circle-o" />
Offline Offline
</span>
</a>
</li> </li>
</ul> </ul>
</li> </li>

2
bus_presence_override/tests/__init__.py

@ -2,4 +2,6 @@
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from . import test_bus_presence
from . import test_res_partner from . import test_res_partner
from . import test_res_users

28
bus_presence_override/tests/bus_setup.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo.tests.common import TransactionCase
class BusSetup(TransactionCase):
def setUp(self):
super(BusSetup, self).setUp()
self.u_admin = self.env.ref('base.user_root')
self.p_admin = self.u_admin.partner_id
self.u_demo = self.env.ref('base.user_demo')
self.p_demo = self.u_demo.partner_id
self.pres_admin = self._get_bus_presence(self.u_admin)
self.pres_demo = self._get_bus_presence(self.u_demo)
# AWAY_TIMER = 55 seconds
# DISCONNECTION_TIMER = 1800 seconds (30 minutes)
def _get_bus_presence(self, user):
pres = self.env['bus.presence'].search([('user_id', '=', user.id)])
if not pres:
pres = self.env['bus.presence'].create({'user_id': user.id})
return pres

120
bus_presence_override/tests/test_bus_presence.py

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from mock import patch
from .bus_setup import BusSetup
from ..status_constants import ONLINE, AWAY, OFFLINE
AWAY_TIMER = 'odoo.addons.bus_presence_override.models.' \
'bus_presence.AWAY_TIMER'
DISCONNECTION_TIMER = 'odoo.addons.bus_presence_override.models.' \
'bus_presence.DISCONNECTION_TIMER'
class TestBusPresence(BusSetup):
@patch(AWAY_TIMER, 10000000)
@patch(DISCONNECTION_TIMER, 10000000)
def test_compute_status_realtime_online(self):
""" It should be computed to online """
self.assertEquals(
self.pres_admin.status_realtime,
ONLINE,
)
@patch(AWAY_TIMER, 10000000)
@patch(DISCONNECTION_TIMER, 0)
def test_compute_status_realtime_offline(self):
""" It should be computed to offline """
self.assertEquals(
self.pres_admin.status_realtime,
OFFLINE,
)
@patch(AWAY_TIMER, 0)
@patch(DISCONNECTION_TIMER, 10000000)
def test_compute_status_realtime_away(self):
""" It should be computed to away """
self.assertEquals(
self.pres_admin.status_realtime,
AWAY,
)
@patch(AWAY_TIMER, 0)
@patch(DISCONNECTION_TIMER, 0)
def test_compute_status_realtime_both(self):
""" It should be computed to offline even though away as well """
self.assertEquals(
self.pres_admin.status_realtime,
OFFLINE,
)
@patch(AWAY_TIMER, 0)
@patch(DISCONNECTION_TIMER, 0)
def test_status_check_timers_offline(self):
""" It should be changed to offline from online """
self.pres_admin.status = ONLINE
self.assertEquals(
self.pres_admin.status,
ONLINE,
)
self.pres_admin._status_check_disconnection_and_away_timers()
self.assertEquals(
self.pres_admin.status,
OFFLINE,
)
@patch(AWAY_TIMER, 0)
@patch(DISCONNECTION_TIMER, 10000000)
def test_status_check_timers_away(self):
""" It should be changed to away from online """
self.pres_admin.status = ONLINE
self.assertEquals(
self.pres_admin.status,
ONLINE,
)
self.pres_admin._status_check_disconnection_and_away_timers()
self.assertEquals(
self.pres_admin.status,
AWAY,
)
@patch(AWAY_TIMER, 0)
@patch(DISCONNECTION_TIMER, 10000000)
def test_status_check_timers_unchanged(self):
""" It should remain at offline even if status_realtime away """
self.pres_admin.status = OFFLINE
self.assertEquals(
self.pres_admin.status,
OFFLINE,
)
self.pres_admin._status_check_disconnection_and_away_timers()
self.assertEquals(
self.pres_admin.status,
OFFLINE,
)
def test_get_partners_im_statuses(self):
""" It should include demo and admin partner statuses """
recs = self.env['bus.presence'].search([(
'partner_id', 'in', [self.p_admin.id, self.p_demo.id])]
)
statuses = recs._get_partners_statuses()
self.assertIn(
self.p_admin.id,
statuses,
)
def test_get_users_im_statuses(self):
""" It should include demo and admin user statuses """
recs = self.env['bus.presence'].search([(
'user_id', 'in', [self.u_admin.id, self.u_demo.id])]
)
statuses = recs._get_users_statuses()
self.assertIn(
self.u_admin.id,
statuses,
)

91
bus_presence_override/tests/test_res_partner.py

@ -4,89 +4,24 @@
from mock import patch from mock import patch
from odoo.tests.common import TransactionCase
from .bus_setup import BusSetup
from ..status_constants import ONLINE
from ..status_constants import ONLINE, AWAY, OFFLINE
AWAY_TIMER = 'odoo.addons.bus_presence_override.models.' \
'bus_presence.AWAY_TIMER'
DISCONNECTION_TIMER = 'odoo.addons.bus_presence_override.models.' \
'bus_presence.DISCONNECTION_TIMER'
GET_PRESENCE = 'odoo.addons.bus_presence_override.models.res_partner.' \
'ResPartner._get_partners_presence'
class TestResPartner(BusSetup):
class TestResPartner(TransactionCase):
def setUp(self):
super(TestResPartner, self).setUp()
self.admin = self.env.ref(
'base.partner_root',
)
@patch(GET_PRESENCE)
def test_compute_im_status_online(self, get_presence):
""" im_status_custom and im_status should both be online """
get_presence.return_value = {self.admin.id: ONLINE}
self.admin.im_status_custom = ONLINE
@patch(AWAY_TIMER, 10000000)
@patch(DISCONNECTION_TIMER, 10000000)
def test_compute_im_status_online(self):
""" It should be computed to online """
self.pres_admin.status = ONLINE
self.assertEquals( self.assertEquals(
self.p_admin.im_status,
ONLINE, ONLINE,
self.admin.im_status,
)
self.assertEquals(
ONLINE,
self.admin.im_status_custom,
)
@patch(GET_PRESENCE)
def test_compute_im_status_custom_away_override(self, get_presence):
""" im_status_custom away should override im_status """
get_presence.return_value = {self.admin.id: ONLINE}
self.admin.im_status_custom = AWAY
self.assertEquals(
AWAY,
self.admin.im_status,
)
self.assertEquals(
AWAY,
self.admin.im_status_custom,
)
@patch(GET_PRESENCE)
def test_compute_im_status_custom_offline_override(self, get_presence):
""" im_status_custom offline should override im_status """
get_presence.return_value = {self.admin.id: ONLINE}
self.admin.im_status_custom = OFFLINE
self.assertEquals(
OFFLINE,
self.admin.im_status,
)
self.assertEquals(
OFFLINE,
self.admin.im_status_custom,
)
@patch(GET_PRESENCE)
def test_compute_im_status_away_override(self, get_presence):
""" im_status away should override im_status_custom """
get_presence.return_value = {self.admin.id: AWAY}
self.admin.im_status_custom = ONLINE
self.assertEquals(
AWAY,
self.admin.im_status,
)
self.assertEquals(
AWAY,
self.admin.im_status_custom,
)
@patch(GET_PRESENCE)
def test_compute_im_status_offline_override(self, get_presence):
""" im_status offline should override im_status_custom """
get_presence.return_value = {self.admin.id: OFFLINE}
self.admin.im_status_custom = ONLINE
self.assertEquals(
OFFLINE,
self.admin.im_status,
)
self.assertEquals(
OFFLINE,
self.admin.im_status_custom,
) )

28
bus_presence_override/tests/test_res_users.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from mock import patch
from .bus_setup import BusSetup
from ..status_constants import ONLINE
AWAY_TIMER = 'odoo.addons.bus_presence_override.models.' \
'bus_presence.AWAY_TIMER'
DISCONNECTION_TIMER = 'odoo.addons.bus_presence_override.models.' \
'bus_presence.DISCONNECTION_TIMER'
class TestResUsers(BusSetup):
@patch(AWAY_TIMER, 10000000)
@patch(DISCONNECTION_TIMER, 10000000)
def test_compute_im_status_online(self):
""" It should be computed to online """
self.pres_admin.status = ONLINE
self.assertEquals(
self.u_admin.im_status,
ONLINE,
)

4
bus_presence_override/views/assets.xml

@ -6,9 +6,9 @@
<template id="assets_backend" name="Bus Presence Override Assets" inherit_id="web.assets_backend"> <template id="assets_backend" name="Bus Presence Override Assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside"> <xpath expr="." position="inside">
<link rel="stylesheet" href="/bus_presence_override/static/src/less/systray.less"/>
<link rel="stylesheet" href="/bus_presence_override/static/src/less/bus_presence_systray.less"/>
<script type="text/javascript" <script type="text/javascript"
src="/bus_presence_override/static/src/js/systray.js"
src="/bus_presence_override/static/src/js/bus_presence_systray.js"
/> />
</xpath> </xpath>
</template> </template>

Loading…
Cancel
Save