Allow users to subscribe to chats
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
* Allow users to subscribe to chats
|
||||||
* Manage user notification
|
* Manage user notification
|
||||||
* Add search on empty relation field to domain parser
|
* Add search on empty relation field to domain parser
|
||||||
* Escape completion content with custom format (issue14363)
|
* Escape completion content with custom format (issue14363)
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M160-200v-80h80v-280q0-33 8.5-65t25.5-61l60 60q-7 16-10.5 32.5T320-560v280h248L56-792l56-56 736 736-56 56-146-144H160Zm560-154-80-80v-126q0-66-47-113t-113-47q-26 0-50 8t-44 24l-58-58q20-16 43-28t49-18v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v206Zm-276-50Zm36 324q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80Zm33-481Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 481 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M80-560q0-100 44.5-183.5T244-882l47 64q-60 44-95.5 111T160-560H80Zm720 0q0-80-35.5-147T669-818l47-64q75 55 119.5 138.5T880-560h-80ZM160-200v-80h80v-280q0-83 50-147.5T420-792v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v280h80v80H160Zm320-300Zm0 420q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-280h320v-280q0-66-47-113t-113-47q-66 0-113 47t-47 113v280Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 518 B |
@@ -50,6 +50,59 @@
|
|||||||
'class': 'chat',
|
'class': 'chat',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let btn_group = jQuery('<div/>', {
|
||||||
|
'class': 'btn-group',
|
||||||
|
'role': 'group',
|
||||||
|
}).appendTo(el);
|
||||||
|
|
||||||
|
let subscribe_btn = jQuery('<button/>', {
|
||||||
|
'class': 'btn btn-default pull-right',
|
||||||
|
'type': 'button',
|
||||||
|
'title': Sao.i18n.gettext("Toggle notification"),
|
||||||
|
}).append(Sao.common.ICONFACTORY.get_icon_img(
|
||||||
|
'tryton-notification'))
|
||||||
|
.appendTo(btn_group);
|
||||||
|
|
||||||
|
Sao.rpc({
|
||||||
|
'method': 'model.ir.chat.channel.get_followers',
|
||||||
|
'params': [this.record, {}],
|
||||||
|
}, Sao.Session.current_session).then((followers) => {
|
||||||
|
set_subscribe_state(~followers.users.indexOf(
|
||||||
|
Sao.Session.current_session.login));
|
||||||
|
})
|
||||||
|
|
||||||
|
let set_subscribe_state = (subscribed) => {
|
||||||
|
let img;
|
||||||
|
if (subscribed) {
|
||||||
|
img = 'tryton-notification-on';
|
||||||
|
subscribe_btn.addClass('active').off().click(unsubscribe);
|
||||||
|
} else {
|
||||||
|
img = 'tryton-notification-off';
|
||||||
|
subscribe_btn.removeClass('active').off().click(subscribe);
|
||||||
|
}
|
||||||
|
subscribe_btn.html(Sao.common.ICONFACTORY.get_icon_img(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
let subscribe = () => {
|
||||||
|
let session = Sao.Session.current_session;
|
||||||
|
Sao.rpc({
|
||||||
|
'method': 'model.ir.chat.channel.subscribe',
|
||||||
|
'params': [this.record, {}],
|
||||||
|
}, session).then(() => {
|
||||||
|
set_subscribe_state(true);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let unsubscribe = () => {
|
||||||
|
let session = Sao.Session.current_session;
|
||||||
|
Sao.rpc({
|
||||||
|
'method': 'model.ir.chat.channel.unsubscribe',
|
||||||
|
'params': [this.record, {}],
|
||||||
|
}, session).then(() => {
|
||||||
|
set_subscribe_state(false);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
this._messages = jQuery('<div/>', {
|
this._messages = jQuery('<div/>', {
|
||||||
'class': 'chat-messages',
|
'class': 'chat-messages',
|
||||||
}).appendTo(jQuery('<div/>', {
|
}).appendTo(jQuery('<div/>', {
|
||||||
|
|||||||
@@ -3155,6 +3155,8 @@
|
|||||||
'tryton-menu',
|
'tryton-menu',
|
||||||
'tryton-note',
|
'tryton-note',
|
||||||
'tryton-notification',
|
'tryton-notification',
|
||||||
|
'tryton-notification-off',
|
||||||
|
'tryton-notification-on',
|
||||||
'tryton-ok',
|
'tryton-ok',
|
||||||
'tryton-open',
|
'tryton-open',
|
||||||
'tryton-print',
|
'tryton-print',
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
* Allow users to subscribe to chats
|
||||||
* Manage user notification
|
* Manage user notification
|
||||||
* Add search on empty relation field to domain parser
|
* Add search on empty relation field to domain parser
|
||||||
* Add support for multiple button in the tree view
|
* Add support for multiple button in the tree view
|
||||||
|
|||||||
@@ -84,9 +84,53 @@ class Chat:
|
|||||||
'size-allocate', scroll_to_bottom)
|
'size-allocate', scroll_to_bottom)
|
||||||
|
|
||||||
def __build(self):
|
def __build(self):
|
||||||
|
tooltips = common.Tooltips()
|
||||||
|
|
||||||
widget = Gtk.VBox()
|
widget = Gtk.VBox()
|
||||||
widget.set_spacing(3)
|
widget.set_spacing(3)
|
||||||
|
|
||||||
|
hbuttonbox = Gtk.HButtonBox()
|
||||||
|
hbuttonbox.set_layout(Gtk.ButtonBoxStyle.END)
|
||||||
|
widget.pack_start(hbuttonbox, expand=False, fill=True, padding=0)
|
||||||
|
|
||||||
|
subscribe_btn = Gtk.ToggleButton()
|
||||||
|
subscribe_btn.set_image(common.IconFactory.get_image(
|
||||||
|
'tryton-notification', Gtk.IconSize.SMALL_TOOLBAR))
|
||||||
|
tooltips.set_tip(subscribe_btn, _("Toggle notification"))
|
||||||
|
subscribe_btn.set_relief(Gtk.ReliefStyle.NONE)
|
||||||
|
hbuttonbox.pack_start(
|
||||||
|
subscribe_btn, expand=False, fill=True, padding=0)
|
||||||
|
hbuttonbox.set_child_non_homogeneous(subscribe_btn, True)
|
||||||
|
|
||||||
|
followers = rpc.execute(
|
||||||
|
'model', 'ir.chat.channel', 'get_followers', self.record,
|
||||||
|
rpc.CONTEXT)
|
||||||
|
|
||||||
|
def set_subscribe_state(subscribed):
|
||||||
|
if subscribed:
|
||||||
|
img = 'tryton-notification-on'
|
||||||
|
else:
|
||||||
|
img = 'tryton-notification-off'
|
||||||
|
subscribe_btn.set_image(common.IconFactory.get_image(
|
||||||
|
img, Gtk.IconSize.SMALL_TOOLBAR))
|
||||||
|
|
||||||
|
subscribed = rpc._LOGIN in followers['users']
|
||||||
|
set_subscribe_state(subscribed)
|
||||||
|
subscribe_btn.set_active(subscribed)
|
||||||
|
|
||||||
|
def toggle_subscribe(button):
|
||||||
|
if button.props.active:
|
||||||
|
rpc.execute(
|
||||||
|
'model', 'ir.chat.channel', 'subscribe', self.record,
|
||||||
|
rpc.CONTEXT)
|
||||||
|
else:
|
||||||
|
rpc.execute(
|
||||||
|
'model', 'ir.chat.channel', 'unsubscribe', self.record,
|
||||||
|
rpc.CONTEXT)
|
||||||
|
set_subscribe_state(button.props.active)
|
||||||
|
|
||||||
|
subscribe_btn.connect('toggled', toggle_subscribe)
|
||||||
|
|
||||||
def _submit(button):
|
def _submit(button):
|
||||||
buffer = input_.get_buffer()
|
buffer = input_.get_buffer()
|
||||||
self.send_message(
|
self.send_message(
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M160-200v-80h80v-280q0-33 8.5-65t25.5-61l60 60q-7 16-10.5 32.5T320-560v280h248L56-792l56-56 736 736-56 56-146-144H160Zm560-154-80-80v-126q0-66-47-113t-113-47q-26 0-50 8t-44 24l-58-58q20-16 43-28t49-18v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v206Zm-276-50Zm36 324q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80Zm33-481Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 481 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M80-560q0-100 44.5-183.5T244-882l47 64q-60 44-95.5 111T160-560H80Zm720 0q0-80-35.5-147T669-818l47-64q75 55 119.5 138.5T880-560h-80ZM160-200v-80h80v-280q0-83 50-147.5T420-792v-28q0-25 17.5-42.5T480-880q25 0 42.5 17.5T540-820v28q80 20 130 84.5T720-560v280h80v80H160Zm320-300Zm0 420q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-280h320v-280q0-66-47-113t-113-47q-66 0-113 47t-47 113v280Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 518 B |
@@ -20,6 +20,7 @@ from tryton.jsonrpc import Fault, ServerPool, ServerProxy
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
CONNECTION = None
|
CONNECTION = None
|
||||||
_USER = None
|
_USER = None
|
||||||
|
_LOGIN = None
|
||||||
CONTEXT = {}
|
CONTEXT = {}
|
||||||
_VIEW_CACHE = {}
|
_VIEW_CACHE = {}
|
||||||
_TOOLBAR_CACHE = {}
|
_TOOLBAR_CACHE = {}
|
||||||
@@ -86,7 +87,7 @@ def authentication_services(host, port):
|
|||||||
def set_service_session(parameters):
|
def set_service_session(parameters):
|
||||||
from tryton import common
|
from tryton import common
|
||||||
from tryton.bus import Bus
|
from tryton.bus import Bus
|
||||||
global CONNECTION, _USER
|
global CONNECTION, _USER, _LOGIN
|
||||||
host = CONFIG['login.host']
|
host = CONFIG['login.host']
|
||||||
hostname = common.get_hostname(host)
|
hostname = common.get_hostname(host)
|
||||||
port = common.get_port(host)
|
port = common.get_port(host)
|
||||||
@@ -102,6 +103,7 @@ def set_service_session(parameters):
|
|||||||
if _USER != renew_id:
|
if _USER != renew_id:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
_USER = user_id
|
_USER = user_id
|
||||||
|
_LOGIN = username
|
||||||
bus_url_host = parameters.get('bus_url_host', [''])[0]
|
bus_url_host = parameters.get('bus_url_host', [''])[0]
|
||||||
session = ':'.join(map(str, [username, user_id, session]))
|
session = ':'.join(map(str, [username, user_id, session]))
|
||||||
if CONNECTION is not None:
|
if CONNECTION is not None:
|
||||||
@@ -114,7 +116,7 @@ def set_service_session(parameters):
|
|||||||
def login(parameters):
|
def login(parameters):
|
||||||
from tryton import common
|
from tryton import common
|
||||||
from tryton.bus import Bus
|
from tryton.bus import Bus
|
||||||
global CONNECTION, _USER
|
global CONNECTION, _USER, _LOGIN
|
||||||
host = CONFIG['login.host']
|
host = CONFIG['login.host']
|
||||||
hostname = common.get_hostname(host)
|
hostname = common.get_hostname(host)
|
||||||
port = common.get_port(host)
|
port = common.get_port(host)
|
||||||
@@ -127,6 +129,7 @@ def login(parameters):
|
|||||||
result = connection.common.db.login(username, parameters, language)
|
result = connection.common.db.login(username, parameters, language)
|
||||||
logger.debug('%r', result)
|
logger.debug('%r', result)
|
||||||
_USER = result[0]
|
_USER = result[0]
|
||||||
|
_LOGIN = username
|
||||||
session = ':'.join(map(str, [username] + result[:2]))
|
session = ':'.join(map(str, [username] + result[:2]))
|
||||||
bus_url_host = result[2]
|
bus_url_host = result[2]
|
||||||
if CONNECTION is not None:
|
if CONNECTION is not None:
|
||||||
@@ -138,7 +141,7 @@ def login(parameters):
|
|||||||
|
|
||||||
|
|
||||||
def logout():
|
def logout():
|
||||||
global CONNECTION, _USER
|
global CONNECTION, _USER, _LOGIN
|
||||||
if CONNECTION is not None:
|
if CONNECTION is not None:
|
||||||
try:
|
try:
|
||||||
logger.info('common.db.logout()')
|
logger.info('common.db.logout()')
|
||||||
@@ -148,7 +151,7 @@ def logout():
|
|||||||
pass
|
pass
|
||||||
CONNECTION.close()
|
CONNECTION.close()
|
||||||
CONNECTION = None
|
CONNECTION = None
|
||||||
_USER = None
|
_USER = _LOGIN = None
|
||||||
|
|
||||||
|
|
||||||
def reset_password():
|
def reset_password():
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class Channel(ModelSQL):
|
|||||||
unsubscribe=RPC(readonly=False),
|
unsubscribe=RPC(readonly=False),
|
||||||
subscribe_email=RPC(readonly=False),
|
subscribe_email=RPC(readonly=False),
|
||||||
unsubscribe_email=RPC(readonly=False),
|
unsubscribe_email=RPC(readonly=False),
|
||||||
|
get_followers=RPC(),
|
||||||
post=RPC(readonly=False, result=int),
|
post=RPC(readonly=False, result=int),
|
||||||
get_models=RPC(),
|
get_models=RPC(),
|
||||||
get=RPC(),
|
get=RPC(),
|
||||||
@@ -73,19 +74,24 @@ class Channel(ModelSQL):
|
|||||||
])
|
])
|
||||||
if channels:
|
if channels:
|
||||||
channel, = channels
|
channel, = channels
|
||||||
else:
|
elif not Transaction().readonly:
|
||||||
channel = cls(resource=str(resource))
|
channel = cls(resource=str(resource))
|
||||||
channel.save()
|
channel.save()
|
||||||
|
else:
|
||||||
|
return
|
||||||
return channel
|
return channel
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def subscribe(cls, resource, username):
|
def subscribe(cls, resource, username=None):
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
Follower = pool.get('ir.chat.follower')
|
Follower = pool.get('ir.chat.follower')
|
||||||
User = pool.get('res.user')
|
User = pool.get('res.user')
|
||||||
|
if username is not None:
|
||||||
user, = User.search([
|
user, = User.search([
|
||||||
('login', '=', username),
|
('login', '=', username),
|
||||||
])
|
])
|
||||||
|
else:
|
||||||
|
user = User(Transaction().user)
|
||||||
channel = cls._get_channel(resource)
|
channel = cls._get_channel(resource)
|
||||||
Follower.add_user(channel, user)
|
Follower.add_user(channel, user)
|
||||||
|
|
||||||
@@ -112,6 +118,26 @@ class Channel(ModelSQL):
|
|||||||
channel = cls._get_channel(resource)
|
channel = cls._get_channel(resource)
|
||||||
Follower.remove_email(channel, email)
|
Follower.remove_email(channel, email)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_followers(cls, resource):
|
||||||
|
pool = Pool()
|
||||||
|
Follower = pool.get('ir.chat.follower')
|
||||||
|
users, emails = [], []
|
||||||
|
channel = cls._get_channel(resource)
|
||||||
|
if channel:
|
||||||
|
followers = Follower.search([
|
||||||
|
('channel', '=', channel),
|
||||||
|
])
|
||||||
|
for follower in followers:
|
||||||
|
if follower.user:
|
||||||
|
users.append(follower.user.login)
|
||||||
|
elif follower.email:
|
||||||
|
emails.append(follower.email)
|
||||||
|
return {
|
||||||
|
'users': users,
|
||||||
|
'emails': emails,
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def post(cls, resource, content, audience='internal'):
|
def post(cls, resource, content, audience='internal'):
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ CLIENT_ICONS = [(x, x) for x in [
|
|||||||
'tryton-menu',
|
'tryton-menu',
|
||||||
'tryton-note',
|
'tryton-note',
|
||||||
'tryton-notification',
|
'tryton-notification',
|
||||||
|
'tryton-notification-off',
|
||||||
|
'tryton-notification-on',
|
||||||
'tryton-ok',
|
'tryton-ok',
|
||||||
'tryton-open',
|
'tryton-open',
|
||||||
'tryton-print',
|
'tryton-print',
|
||||||
|
|||||||
Reference in New Issue
Block a user