Brett Wood
7 years ago
committed by
Holger Brunn
13 changed files with 430 additions and 0 deletions
-
52bus_presence_override/README.rst
-
5bus_presence_override/__init__.py
-
24bus_presence_override/__manifest__.py
-
5bus_presence_override/models/__init__.py
-
83bus_presence_override/models/res_partner.py
-
BINbus_presence_override/static/description/icon.png
-
59bus_presence_override/static/src/js/systray.js
-
47bus_presence_override/static/src/less/systray.less
-
35bus_presence_override/static/src/xml/systray.xml
-
7bus_presence_override/status_constants.py
-
5bus_presence_override/tests/__init__.py
-
92bus_presence_override/tests/test_res_partner.py
-
16bus_presence_override/views/assets.xml
@ -0,0 +1,52 @@ |
|||||
|
.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html |
||||
|
:alt: License: LGPL-3 |
||||
|
|
||||
|
===================== |
||||
|
Bus Presence Override |
||||
|
===================== |
||||
|
|
||||
|
This module adds the ability for users to define their Online, Away, or Offline status |
||||
|
manually instead of the system calculating it. |
||||
|
|
||||
|
Away and disconnection timers are still in effect. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/205/10.0 |
||||
|
|
||||
|
Known Issues / Roadmap |
||||
|
====================== |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
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. If you spotted it first, |
||||
|
help us smash it by providing detailed and welcomed feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Images |
||||
|
------ |
||||
|
|
||||
|
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Brett Wood <bwood@laslabs.com> |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
@ -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 models |
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
{ |
||||
|
"name": "Bus Presence Override", |
||||
|
"summary": "Adds user-defined im status (online, away, offline).", |
||||
|
"version": "10.0.1.0.0", |
||||
|
"category": "Social", |
||||
|
"website": "https://github.com/OCA/social", |
||||
|
"author": "LasLabs, Odoo Community Association (OCA)", |
||||
|
"license": "AGPL-3", |
||||
|
"application": False, |
||||
|
"installable": True, |
||||
|
"depends": [ |
||||
|
"mail", |
||||
|
], |
||||
|
"data": [ |
||||
|
"views/assets.xml", |
||||
|
], |
||||
|
"qweb": [ |
||||
|
"static/src/xml/systray.xml", |
||||
|
], |
||||
|
} |
@ -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 res_partner |
@ -0,0 +1,83 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from odoo import api, fields, 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 |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
|
||||
|
_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 |
||||
|
def _compute_im_status(self): |
||||
|
presence = self._get_partners_presence() |
||||
|
|
||||
|
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 |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
@ -0,0 +1,59 @@ |
|||||
|
/* 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); |
||||
|
|
||||
|
}); |
@ -0,0 +1,47 @@ |
|||||
|
/* 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; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- Copyright 2017 LasLabs Inc. |
||||
|
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). --> |
||||
|
|
||||
|
<templates> |
||||
|
|
||||
|
<t t-name="systray"> |
||||
|
<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"> |
||||
|
<li> |
||||
|
<span name="online" class="o_user_presence_status"> |
||||
|
<i t-attf-class="o_mail_user_status o_user_online fa fa-circle" /> |
||||
|
Online |
||||
|
</span> |
||||
|
</li> |
||||
|
<li> |
||||
|
<span name="away" class="o_user_presence_status"> |
||||
|
<i class="o_mail_user_status o_user_idle fa fa-circle" /> |
||||
|
Away |
||||
|
</span> |
||||
|
</li> |
||||
|
<li> |
||||
|
<span name="offline" class="o_user_presence_status"> |
||||
|
<i class="o_mail_user_status fa fa-circle-o" /> |
||||
|
Offline |
||||
|
</span> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
</t> |
||||
|
|
||||
|
</templates> |
@ -0,0 +1,7 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
ONLINE = 'online' |
||||
|
AWAY = 'away' |
||||
|
OFFLINE = 'offline' |
@ -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 test_res_partner |
@ -0,0 +1,92 @@ |
|||||
|
# -*- 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 odoo.tests.common import TransactionCase |
||||
|
|
||||
|
from ..status_constants import ONLINE, AWAY, OFFLINE |
||||
|
|
||||
|
|
||||
|
GET_PRESENCE = 'odoo.addons.bus_presence_override.models.res_partner.' \ |
||||
|
'ResPartner._get_partners_presence' |
||||
|
|
||||
|
|
||||
|
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 |
||||
|
self.assertEquals( |
||||
|
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, |
||||
|
) |
@ -0,0 +1,16 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- Copyright 2017 LasLabs Inc. |
||||
|
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). --> |
||||
|
|
||||
|
<odoo> |
||||
|
|
||||
|
<template id="assets_backend" name="Bus Presence Override Assets" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<link rel="stylesheet" href="/bus_presence_override/static/src/less/systray.less"/> |
||||
|
<script type="text/javascript" |
||||
|
src="/bus_presence_override/static/src/js/systray.js" |
||||
|
/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue