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