diff --git a/chat/.gitignore b/chat/.gitignore
index c63e593..3b7caa1 100644
--- a/chat/.gitignore
+++ b/chat/.gitignore
@@ -2,3 +2,6 @@
.*.swp
*.pyc
*.egg-info
+.webassets-cache/
+*.min.css
+*.min.js
diff --git a/chat/MANIFEST.in b/chat/MANIFEST.in
new file mode 100644
index 0000000..8519a44
--- /dev/null
+++ b/chat/MANIFEST.in
@@ -0,0 +1,2 @@
+graft indico_chat/static
+graft indico_chat/migrations
diff --git a/chat/indico_chat/blueprint.py b/chat/indico_chat/blueprint.py
new file mode 100644
index 0000000..9f1f77c
--- /dev/null
+++ b/chat/indico_chat/blueprint.py
@@ -0,0 +1,19 @@
+# This file is part of Indico.
+# Copyright (C) 2002 - 2014 European Organization for Nuclear Research (CERN).
+#
+# Indico is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# Indico is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Indico; if not, see .
+
+from indico.core.plugins import IndicoPluginBlueprint
+
+blueprint = IndicoPluginBlueprint('chat', 'indico_chat')
diff --git a/chat/indico_chat/models/chatrooms.py b/chat/indico_chat/models/chatrooms.py
index 809760c..fb62f4d 100644
--- a/chat/indico_chat/models/chatrooms.py
+++ b/chat/indico_chat/models/chatrooms.py
@@ -25,8 +25,6 @@ from indico.util.string import return_ascii
from MaKaC.user import AvatarHolder
from MaKaC.conference import ConferenceHolder
-from indico_chat.plugin import ChatPlugin
-
class Chatroom(db.Model):
__tablename__ = 'chatrooms'
@@ -96,6 +94,8 @@ class Chatroom(db.Model):
Usually the default one unless a custom one is set.
"""
+ from indico_chat.plugin import ChatPlugin
+
return self.custom_server or ChatPlugin.settings.get('muc_server')
@return_ascii
diff --git a/chat/indico_chat/plugin.py b/chat/indico_chat/plugin.py
index b08961a..d4eedf9 100644
--- a/chat/indico_chat/plugin.py
+++ b/chat/indico_chat/plugin.py
@@ -16,14 +16,33 @@
from __future__ import unicode_literals
+from flask_pluginengine import render_plugin_template
+from wtforms import ValidationError
+from wtforms.fields.simple import TextField, TextAreaField
+
from indico.core.plugins import IndicoPlugin
from indico.web.forms.base import IndicoForm
-from wtforms.fields.simple import TextField
+from indico.web.forms.fields import MultipleItemsField
+from indico.web.forms.widgets import CKEditorWidget
+from MaKaC.webinterface.pages.conferences import WPTPLConferenceDisplay, WPXSLConferenceDisplay
+
+from indico_chat.blueprint import blueprint
+from indico_chat.models.chatrooms import ChatroomEventAssociation
class SettingsForm(IndicoForm):
server = TextField('XMPP server')
- muc_server = TextField('XMPP MUC server (conference.*)')
+ muc_server = TextField('XMPP MUC server', description='Usually conference.XMPPSERVER')
+ how_to_connect = TextAreaField('How to connect', widget=CKEditorWidget(),
+ description='Text shown below the chatrooms on an event page')
+ chat_links = MultipleItemsField('Chatroom links', fields=(('title', 'Title'), ('link', 'Link')),
+ description='Links to join the chatroom. You can use the placeholders {room} and '
+ '{server}.')
+
+ def validate_chat_links(self, field):
+ for item in field.data:
+ if not all(item.values()):
+ raise ValidationError('All fields must contain a value.')
class ChatPlugin(IndicoPlugin):
@@ -33,3 +52,31 @@ class ChatPlugin(IndicoPlugin):
"""
settings_form = SettingsForm
+
+ @property
+ def default_settings(self):
+ return {'how_to_connect': render_plugin_template('how_to_connect.html'),
+ 'chat_links': [{'title': 'Desktop Client', 'link': 'xmpp:{room}@{server}?join'}]}
+
+ def init(self):
+ super(ChatPlugin, self).init()
+ self.template_hook('event-header', self.inject_event_header)
+ for wp in (WPTPLConferenceDisplay, WPXSLConferenceDisplay):
+ self.inject_css('chat_css', wp)
+ self.inject_js('chat_js', wp)
+
+ def get_blueprints(self):
+ return blueprint
+
+ def register_assets(self):
+ self.register_css_bundle('chat_css', 'css/chat.scss')
+ self.register_js_bundle('chat_js', 'js/chat.js')
+
+ def inject_event_header(self, event, **kwargs):
+ chatrooms = ChatroomEventAssociation.find_all(ChatroomEventAssociation.event_id == event.id,
+ ~ChatroomEventAssociation.hidden)
+ if not chatrooms:
+ return ''
+ how_to_connect = self.settings.get('how_to_connect')
+ return render_plugin_template('event_header.html', event=event, event_chatrooms=chatrooms,
+ how_to_connect=how_to_connect, chat_links=self.settings.get('chat_links'))
diff --git a/chat/indico_chat/static/css/chat.scss b/chat/indico_chat/static/css/chat.scss
new file mode 100644
index 0000000..a66076b
--- /dev/null
+++ b/chat/indico_chat/static/css/chat.scss
@@ -0,0 +1,28 @@
+@import 'base/palette';
+
+.plugin-chat {
+ .chat-toggle-details {
+ color: #0B63A5;
+ text-decoration: none;
+ }
+
+ .chatroom + .chatroom {
+ margin-top: 5px;
+ }
+
+ dl.chat-details {
+ clear: left;
+ font-size: 90%;
+ margin: 5px 0 0 0;
+
+ dt {
+ float: left;
+ color: $light-black;
+ }
+
+ dd {
+ margin-left: 100px;
+ display: block;
+ }
+ }
+}
diff --git a/chat/indico_chat/static/js/chat.js b/chat/indico_chat/static/js/chat.js
new file mode 100644
index 0000000..36f5ac1
--- /dev/null
+++ b/chat/indico_chat/static/js/chat.js
@@ -0,0 +1,54 @@
+/*
+ * This file is part of Indico.
+ * Copyright (C) 2002 - 2014 European Organization for Nuclear Research (CERN).
+ *
+ * Indico is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Indico is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Indico; if not, see .
+ */
+
+(function(global) {
+ 'use strict';
+
+ global.eventChatInfo = function eventChatInfo() {
+ var menu = null;
+ var links = $('#chat-info-container').data('chatLinks');
+
+ $('.chat-toggle-details').on('click', function(e) {
+ e.preventDefault();
+ $(this).siblings('.js-chat-details').slideToggle();
+ });
+
+ $('.js-chat-join').on('click', function(e) {
+ e.preventDefault();
+ var $this = $(this);
+ var menuItems = {};
+ $.each(links, function(i, link) {
+ var action = link.link;
+ action = action.replace(/\{server\}/g, $this.data('server'));
+ action = action.replace(/\{room\}/g, $this.data('room'));
+ menuItems[i] = {display: link.title, action: action};
+ });
+
+ if (menu && menu.isOpen()) {
+ menu.close();
+ if (menu._link == this) {
+ return;
+ }
+ }
+ menu = new PopupMenu(menuItems, [$E(this)], 'categoryDisplayPopupList', true, false, null, null, true);
+ menu._link = this;
+ var pos = $this.offset();
+ menu.open(pos.left - 3, pos.top + $this.height());
+ });
+ }
+})(window);
diff --git a/chat/indico_chat/templates/event_header.html b/chat/indico_chat/templates/event_header.html
new file mode 100644
index 0000000..bafa120
--- /dev/null
+++ b/chat/indico_chat/templates/event_header.html
@@ -0,0 +1,57 @@
+
+ | Chat rooms |
+
+
+ {% for event_chatroom in event_chatrooms %}
+ {% set chatroom = event_chatroom.chatroom %}
+ {% set server = chatroom.server %}
+
+ {{ chatroom.name }}
+
+ {% trans %}More Info{% endtrans %}
+ {% if chat_links %}
+ |
+
+ {% endif %}
+
+ - {% trans %}Name{% endtrans %}:
+ - {{ chatroom.name }}
+ - {% trans %}Server{% endtrans %}:
+ - {{ chatroom.server }}
+ {% if chatroom.description %}
+ - {% trans %}Description{% endtrans %}:
+ - {{ chatroom.description }}
+ {% endif %}
+ {% if chatroom.password %}
+ - {% trans %}Password{% endtrans %}:
+ -
+ {% if event_chatroom.show_password %}
+ {{ chatroom.password }}
+ {% else %}
+ {% trans %}Hidden{% endtrans %}
+ {% endif %}
+
+ {% endif %}
+
+
+ {% endfor %}
+
+
+ |
+
+{% if how_to_connect %}
+
+
+
+
+ | {% trans %}How to connect to the chat{% endtrans %} |
+
+
+ | {{ how_to_connect | safe }} |
+
+
+ |
+
+{% endif %}
diff --git a/chat/indico_chat/templates/how_to_connect.html b/chat/indico_chat/templates/how_to_connect.html
new file mode 100644
index 0000000..85322db
--- /dev/null
+++ b/chat/indico_chat/templates/how_to_connect.html
@@ -0,0 +1,9 @@
+
+ -
+ Download a messaging client compatible with XMPP (such as Pidgin, Gajim, Adium, Spark).
+ You may want to look here) and install it.
+
+ - Add the XMPP account that you want to use.
+ - In the menus, try to find something like 'Join a Chat', 'Join Group Chat', or related.
+ - Fill the fields Room and Server with the information above. In case there is only one field for both the room and the server, the format to use is 'room@server'.
+
diff --git a/chat/indico_chat/zodbimport.py b/chat/indico_chat/zodbimport.py
index b17d2b0..05aa604 100644
--- a/chat/indico_chat/zodbimport.py
+++ b/chat/indico_chat/zodbimport.py
@@ -44,10 +44,17 @@ class ChatImporter(Importer):
def migrate_settings(self):
print cformat('%{white!}migrating settings')
ChatPlugin.settings.delete_all()
+ type_opts = self.zodb_root['plugins']['InstantMessaging']._PluginBase__options
opts = self.zodb_root['plugins']['InstantMessaging']._PluginType__plugins['XMPP']._PluginBase__options
host = convert_to_unicode(opts['chatServerHost'].getValue())
ChatPlugin.settings.set('server', host)
ChatPlugin.settings.set('muc_server', 'conference.{}'.format(host))
+ ChatPlugin.settings.set('how_to_connect', opts['ckEditor'].getValue().strip())
+ chat_links = []
+ for item in type_opts['customLinks'].getValue():
+ link = item['structure'].replace('[chatroom]', '{room}').replace('[host]', '{server}')
+ chat_links.append({'title': item['name'], 'link': link})
+ ChatPlugin.settings.set('chat_links', chat_links)
# TODO: migrate other settings
db.session.commit()