Add support for emails on the chat channels
This commit is contained in:
+232
-59
@@ -3,6 +3,16 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function add_size(url, size=32) {
|
||||
if (url) {
|
||||
url = new URL(url, window.location);
|
||||
url.searchParams.set('s', size);
|
||||
return url.href;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
class _Chat {
|
||||
constructor(record) {
|
||||
this.notify = this.notify.bind(this);
|
||||
@@ -46,63 +56,221 @@
|
||||
});
|
||||
}
|
||||
|
||||
_get_followers() {
|
||||
return Sao.rpc({
|
||||
'method': 'model.ir.chat.channel.get_followers',
|
||||
'params': [this.record, {}],
|
||||
}, Sao.Session.current_session);
|
||||
}
|
||||
|
||||
_search_followers(text) {
|
||||
if (!text) {
|
||||
return jQuery.when();
|
||||
}
|
||||
|
||||
return Sao.rpc({
|
||||
'method': 'model.ir.chat.channel.search_followers',
|
||||
'params': [this.record, text, {}],
|
||||
}, Sao.Session.current_session).then(followers => {
|
||||
return followers.filter(e => {
|
||||
return !((e.type == 'user') &&
|
||||
(e.key == Sao.Session.current_session.login));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_add_follower(follower) {
|
||||
let method;
|
||||
switch (follower.type) {
|
||||
case 'user':
|
||||
method = 'subscribe';
|
||||
break;
|
||||
case 'email':
|
||||
method = 'subscribe_email';
|
||||
break;
|
||||
}
|
||||
Sao.rpc({
|
||||
'method': `model.ir.chat.channel.${method}`,
|
||||
'params': [this.record, follower.key, {}],
|
||||
}, Sao.Session.current_session);
|
||||
}
|
||||
|
||||
_remove_follower(follower) {
|
||||
let method;
|
||||
switch (follower.type) {
|
||||
case 'user':
|
||||
method = 'unsubscribe';
|
||||
break;
|
||||
case 'email':
|
||||
method = 'unsubscribe_email';
|
||||
break;
|
||||
}
|
||||
Sao.rpc({
|
||||
'method': `model.ir.chat.channel.${method}`,
|
||||
'params': [this.record, follower.key, {}],
|
||||
}, Sao.Session.current_session);
|
||||
}
|
||||
|
||||
__build() {
|
||||
let el = jQuery('<div/>', {
|
||||
'class': 'chat',
|
||||
});
|
||||
|
||||
let btn_group = jQuery('<div/>', {
|
||||
'class': 'btn-group',
|
||||
'role': 'group',
|
||||
let toolbar = jQuery('<div/>', {
|
||||
'class': 'btn-toolbar',
|
||||
'role': 'toolbar',
|
||||
}).appendTo(el);
|
||||
let input_group = jQuery('<div/>', {
|
||||
'class': 'input-group',
|
||||
'role': 'group',
|
||||
}).appendTo(toolbar);
|
||||
this.subscribe_input = jQuery('<input/>', {
|
||||
'class': 'form-control input-sm',
|
||||
'placeholder': Sao.i18n.gettext("Add a follower"),
|
||||
'title': Sao.i18n.gettext("Subscribe a follower to this channel"),
|
||||
}).appendTo(input_group);
|
||||
|
||||
let avatar_size = 32;
|
||||
|
||||
let format = function(val) {
|
||||
return jQuery('<div/>', {
|
||||
'title': val.key,
|
||||
})
|
||||
.append(jQuery('<img/>', {
|
||||
'src': add_size(val.avatar_url, avatar_size),
|
||||
'class': 'img-circle',
|
||||
'style': `width: ${avatar_size}px; height: ${avatar_size}px;`,
|
||||
}))
|
||||
.append(jQuery('<span/>', {
|
||||
})
|
||||
.text(val.name));
|
||||
};
|
||||
new Sao.common.InputCompletion(
|
||||
input_group, this._search_followers.bind(this),
|
||||
(follower) => {
|
||||
this._add_follower(follower);
|
||||
this.subscribe_input.val('');
|
||||
this.subscribe_input.focus();
|
||||
}, format);
|
||||
|
||||
let dropdown = jQuery('<div/>', {
|
||||
'class': 'btn-group dropdown',
|
||||
'role': 'group',
|
||||
}).appendTo(toolbar);
|
||||
let subscribe_btn = jQuery('<button/>', {
|
||||
'class': 'btn btn-default pull-right',
|
||||
'type': 'button',
|
||||
'title': Sao.i18n.gettext("Toggle notification"),
|
||||
'class': 'btn btn-default pull-right dropdown-toggle',
|
||||
'data-toggle': 'dropdown',
|
||||
'aria-expanded': false,
|
||||
'aria-haspopup': true,
|
||||
'title': Sao.i18n.gettext("Show followers"),
|
||||
}).append(Sao.common.ICONFACTORY.get_icon_img(
|
||||
'tryton-notification'))
|
||||
.appendTo(btn_group);
|
||||
.appendTo(dropdown);
|
||||
subscribe_btn.uniqueId();
|
||||
|
||||
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));
|
||||
})
|
||||
this._get_followers().then((followers) => {
|
||||
let subscribed = followers.some((e) => (
|
||||
(e.type == 'user') &&
|
||||
(e.key == Sao.Session.current_session.login)));
|
||||
set_subscribe_state(subscribed);
|
||||
});;
|
||||
|
||||
let set_subscribe_state = (subscribed) => {
|
||||
let img;
|
||||
if (subscribed) {
|
||||
img = 'tryton-notification-on';
|
||||
subscribe_btn.addClass('active').off().click(unsubscribe);
|
||||
subscribe_btn.addClass('active');
|
||||
} else {
|
||||
img = 'tryton-notification-off';
|
||||
subscribe_btn.removeClass('active').off().click(subscribe);
|
||||
subscribe_btn.removeClass('active');
|
||||
}
|
||||
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 menu = jQuery('<ul/>', {
|
||||
'class': 'dropdown-menu dropdown-menu-right',
|
||||
'role': 'menu',
|
||||
'aria-labelledby': subscribe_btn.id,
|
||||
}).appendTo(dropdown);
|
||||
|
||||
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);
|
||||
})
|
||||
};
|
||||
dropdown.on('show.bs.dropdown', () => {
|
||||
menu.empty();
|
||||
|
||||
let user_action;
|
||||
if (subscribe_btn.hasClass('active')) {
|
||||
user_action = jQuery('<a/>', {
|
||||
'href': '#',
|
||||
'class': 'text-danger text-uppercase',
|
||||
}).text(Sao.i18n.gettext("Unsubscribe"))
|
||||
.click(() => {
|
||||
Sao.rpc({
|
||||
'method': 'model.ir.chat.channel.unsubscribe',
|
||||
'params': [this.record, {}],
|
||||
}, Sao.Session.current_session).then(() => {
|
||||
set_subscribe_state(false);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
user_action = jQuery('<a/>', {
|
||||
'href': '#',
|
||||
'class': 'text-primary text-uppercase',
|
||||
}).text(Sao.i18n.gettext("Subscribe"))
|
||||
.click(() => {
|
||||
Sao.rpc({
|
||||
'method': 'model.ir.chat.channel.subscribe',
|
||||
'params': [this.record, {}],
|
||||
}, Sao.Session.current_session).then(() => {
|
||||
set_subscribe_state(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
jQuery('<li/>', {
|
||||
'role': 'presentation',
|
||||
}).append(user_action).appendTo(menu);
|
||||
|
||||
this._get_followers().then((followers) => {
|
||||
followers = followers.filter(e => {
|
||||
return !((e.type == 'user') &&
|
||||
(e.key == Sao.Session.current_session.login));
|
||||
});
|
||||
if (followers.length) {
|
||||
jQuery('<li/>', {
|
||||
'class': 'divider',
|
||||
}).appendTo(menu);
|
||||
}
|
||||
let add_follower = (follower) => {
|
||||
jQuery('<li/>', {
|
||||
'role': 'presentation',
|
||||
})
|
||||
.append(jQuery('<div/>', {
|
||||
'title': follower.key,
|
||||
})
|
||||
.append(jQuery('<img/>', {
|
||||
'class': 'img-circle chat-avatar',
|
||||
'src': add_size(follower.avatar_url, avatar_size),
|
||||
'style': `width: ${avatar_size}px; height: ${avatar_size}px;`,
|
||||
}))
|
||||
.append(jQuery('<span/>')
|
||||
.text(follower.name))
|
||||
.append(jQuery('<button/>', {
|
||||
'class': 'btn btn-link',
|
||||
'title': Sao.i18n.gettext("Unsubscribe"),
|
||||
'type': 'button',
|
||||
}).append("×").click((evt) => {
|
||||
Sao.common.sur.run(
|
||||
Sao.i18n.gettext(
|
||||
'Are you sure to unsubscribe "%1" from this channel?',
|
||||
follower.name)
|
||||
).then(() => {
|
||||
this._remove_follower(follower);
|
||||
});
|
||||
}))
|
||||
).appendTo(menu);
|
||||
};
|
||||
followers.forEach(add_follower);
|
||||
});
|
||||
});
|
||||
|
||||
this._messages = jQuery('<div/>', {
|
||||
'class': 'chat-messages',
|
||||
@@ -167,35 +335,40 @@
|
||||
}
|
||||
|
||||
create_message(message) {
|
||||
let avatar_size = 32;
|
||||
let timestamp = Sao.common.format_datetime(
|
||||
Sao.common.date_format() + ' %X', message.timestamp);
|
||||
let avatar_url = '';
|
||||
if (message.avatar_url) {
|
||||
let url = new URL(message.avatar_url, window.location);
|
||||
url.searchParams.set('s', avatar_size);
|
||||
avatar_url = url.href;
|
||||
if (message.user) {
|
||||
let avatar_size = 32;
|
||||
let avatar_url = add_size(message.avatar_url, avatar_size);
|
||||
|
||||
return jQuery('<div/>', {
|
||||
'class': 'media chat-message',
|
||||
}).append(jQuery('<div/>', {
|
||||
'class': 'media-left',
|
||||
}).append(jQuery('<img/>', {
|
||||
'class': 'media-object img-circle chat-avatar',
|
||||
'src': avatar_url,
|
||||
'alt': message.author,
|
||||
'style': `width: ${avatar_size}px; height: ${avatar_size}px;`,
|
||||
}))).append(jQuery('<div/>', {
|
||||
'class': 'media-body well well-sm',
|
||||
}).append(jQuery('<h6/>', {
|
||||
'class': 'media-heading',
|
||||
}).text(message.author)
|
||||
.append(jQuery('<small/>', {
|
||||
'class': 'text-muted pull-right',
|
||||
}).text(timestamp)))
|
||||
.append(jQuery('<div/>', {
|
||||
'class': `chat-content chat-content-${message.audience}`,
|
||||
}).text(message.content)));
|
||||
} else {
|
||||
return jQuery('<div/>', {
|
||||
'class': 'media chat-message system-message',
|
||||
}).append(jQuery('<div/>', {
|
||||
'class': 'chat-content',
|
||||
'title': timestamp,
|
||||
}).text(message.content));
|
||||
}
|
||||
return jQuery('<div/>', {
|
||||
'class': 'media chat-message',
|
||||
}).append(jQuery('<div/>', {
|
||||
'class': 'media-left',
|
||||
}).append(jQuery('<img/>', {
|
||||
'class': 'media-object img-circle chat-avatar',
|
||||
'src': avatar_url,
|
||||
'alt': message.author,
|
||||
'style': `width: ${avatar_size}px; height: ${avatar_size}px;`,
|
||||
}))).append(jQuery('<div/>', {
|
||||
'class': 'media-body well well-sm',
|
||||
}).append(jQuery('<h6/>', {
|
||||
'class': 'media-heading',
|
||||
}).text(message.author)
|
||||
.append(jQuery('<small/>', {
|
||||
'class': 'text-muted pull-right',
|
||||
}).text(timestamp)))
|
||||
.append(jQuery('<div/>', {
|
||||
'class': `chat-content chat-content-${message.audience}`,
|
||||
}).text(message.content)));
|
||||
}
|
||||
}
|
||||
Sao.Chat = _Chat;
|
||||
|
||||
@@ -520,6 +520,40 @@ html[theme="default"] {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
|
||||
.btn-toolbar {
|
||||
display: flex;
|
||||
|
||||
.input-group {
|
||||
flex: 1;
|
||||
|
||||
.img-circle {
|
||||
height: 2em;
|
||||
margin-inline-end: 1ex;
|
||||
}
|
||||
}
|
||||
|
||||
ul.dropdown-menu {
|
||||
width: 20em;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
margin: 1ex;
|
||||
gap: 5px;
|
||||
|
||||
img {
|
||||
align-self: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-messages-outer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -535,6 +569,15 @@ html[theme="default"] {
|
||||
|
||||
.chat-message {
|
||||
margin-top: 5px;
|
||||
|
||||
&.system-message {
|
||||
align-items: center;
|
||||
color: @text-muted;
|
||||
display: flex;
|
||||
font-size: small;
|
||||
justify-content: center;
|
||||
padding: 0 2ex;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-content {
|
||||
|
||||
Reference in New Issue
Block a user