Properly handle JIDs

This commit is contained in:
Adrian Moennich 2014-10-07 12:06:51 +02:00
parent f650f4225e
commit 0242a9790c
10 changed files with 59 additions and 17 deletions

View File

@ -115,7 +115,9 @@ class RHChatManageEventCreate(RHChatManageEventBase):
event_chatroom = ChatroomEventAssociation(event_id=self.event_id, chatroom=chatroom)
form.populate_obj(event_chatroom, fields=form.event_specific_fields)
form.populate_obj(chatroom, skip=form.event_specific_fields)
chatroom.generate_jid()
db.session.add_all((chatroom, event_chatroom))
db.session.flush()
create_room(chatroom)
flash('Chatroom created', 'success')
return redirect(url_for_plugin('.manage_rooms', self.event))

View File

@ -18,11 +18,14 @@ from __future__ import unicode_literals
from wtforms.fields.core import BooleanField
from wtforms.fields.simple import TextField, TextAreaField
from wtforms.validators import DataRequired
from wtforms.validators import DataRequired, ValidationError
from indico.web.forms.base import IndicoForm
from indico.util.string import strip_whitespace
from indico_chat.models.chatrooms import Chatroom
from indico_chat.xmpp import generate_jid
class EditChatroomForm(IndicoForm):
event_specific_fields = {'hidden', 'show_password'}
@ -38,5 +41,14 @@ class EditChatroomForm(IndicoForm):
class AddChatroomForm(EditChatroomForm):
custom_server = TextField('Server', filters=[strip_whitespace],
custom_server = TextField('Server', filters=[strip_whitespace, lambda x: x.lower() if x else x],
description='External Jabber server. Should be left empty in most cases.')
def validate_name(self, field):
jid = generate_jid(field.data)
if not jid:
# This error is not very helpful to a user, but it is extremely unlikely - only if he uses a name
# which does not contain a single char usable in a JID
raise ValidationError('Could not convert name to a jabber ID')
if Chatroom.find_first(jid_node=jid, custom_server=self.custom_server.data):
raise ValidationError('A room with this name already exists')

View File

@ -21,6 +21,7 @@ def upgrade():
op.execute(CreateSchema('plugin_chat'))
op.create_table('chatrooms',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('jid_node', sa.String(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('description', sa.Text(), nullable=False),
sa.Column('password', sa.String(), nullable=False),
@ -29,8 +30,7 @@ def upgrade():
sa.Column('created_dt', UTCDateTime(), nullable=False),
sa.Column('modified_dt', UTCDateTime(), nullable=True),
sa.PrimaryKeyConstraint('id'),
schema='plugin_chat')
op.create_index('ix_chatrooms_name_lower', 'chatrooms', [sa.text('lower(plugin_chat.chatrooms.name)')], unique=True,
sa.UniqueConstraint('jid_node', 'custom_server'),
schema='plugin_chat')
op.create_table('chatroom_events',
sa.Column('event_id', sa.Integer(), nullable=False, primary_key=True, index=True,

View File

@ -16,7 +16,6 @@
from __future__ import unicode_literals
from sqlalchemy import func
from sqlalchemy.ext.declarative import declared_attr
from indico.core.db.sqlalchemy import db, UTCDateTime
@ -24,6 +23,7 @@ from indico.util.date_time import now_utc
from indico.util.string import return_ascii
from MaKaC.user import AvatarHolder
from MaKaC.conference import ConferenceHolder
from indico_chat.xmpp import generate_jid
class Chatroom(db.Model):
@ -31,7 +31,7 @@ class Chatroom(db.Model):
@declared_attr
def __table_args__(cls):
return (db.Index('ix_chatrooms_name_lower', func.lower(cls.name), unique=True),
return (db.UniqueConstraint(cls.jid_node, cls.custom_server),
{'schema': 'plugin_chat'})
#: Chatroom ID
@ -39,7 +39,11 @@ class Chatroom(db.Model):
db.Integer,
primary_key=True
)
# TODO: jid column
#: Node of the chatroom's JID (the part before `@domain`)
jid_node = db.Column(
db.String,
nullable=False
)
#: Name of the chatroom
name = db.Column(
db.String,
@ -108,7 +112,12 @@ class Chatroom(db.Model):
server = self.server
if self.custom_server:
server = '!' + server
return '<Chatroom({}, {}, {})>'.format(self.id, self.name, server)
return '<Chatroom({}, {}, {}, {})>'.format(self.id, self.name, self.jid_node, server)
def generate_jid(self):
"""Generates the JID based on the room name"""
assert self.jid_node is None
self.jid_node = generate_jid(self.name)
class ChatroomEventAssociation(db.Model):

View File

@ -56,7 +56,7 @@
$('.js-chat-remove-room').on('click', function(e) {
e.preventDefault();
var $this = $(this);
var msg = $T('Do you really want to delete this chatroom?');
var msg = $T('Do you really want to remove this chatroom from the event?');
if ($this.data('numEvents') == 1) {
msg += '<br>' + $T('Since it is only used in this event, it will be deleted from the Jabber server, too!');
}

View File

@ -11,7 +11,7 @@
<a class="chat-toggle-details" href="#">{% trans %}More Info{% endtrans %}</a>
{% if chat_links %}
-
<strong><a class="dropDownMenu highlight js-chat-join" href="#" data-server="{{ server }}" data-room="{{ chatroom.name }}">{% trans %}Join now!{% endtrans %}</a></strong>
<strong><a class="dropDownMenu highlight js-chat-join" href="#" data-server="{{ server }}" data-room="{{ chatroom.jid_node }}">{% trans %}Join now!{% endtrans %}</a></strong>
{% endif %}
<dl class="chat-details" style="display: none;">
<dt>{% trans %}Name{% endtrans %}:</dt>

View File

@ -42,7 +42,7 @@
{% endif %}
{% if chat_links %}
<td style="white-space: nowrap;">
<strong><a class="dropDownMenu highlight js-chat-join" href="#" data-server="{{ server }}" data-room="{{ chatroom.name }}">{% trans %}Join now!{% endtrans %}</a></strong>
<strong><a class="dropDownMenu highlight js-chat-join" href="#" data-server="{{ server }}" data-room="{{ chatroom.jid_node }}">{% trans %}Join now!{% endtrans %}</a></strong>
</td>
{% endif %}
</tr>

View File

@ -16,11 +16,15 @@
<a class="js-chat-remove-room" href="#" data-href="{{ url_for_plugin('.manage_rooms_remove', event_chatroom) }}" data-num-events="{{ chatroom.events | count }}">{% trans %}Remove{% endtrans %}</a>
{% if chat_links %}
-
<strong><a class="dropDownMenu highlight js-chat-join" href="#" data-server="{{ server }}" data-room="{{ chatroom.name }}">{% trans %}Join now!{% endtrans %}</a></strong>
<strong><a class="dropDownMenu highlight js-chat-join" href="#" data-server="{{ server }}" data-room="{{ chatroom.jid_node }}">{% trans %}Join now!{% endtrans %}</a></strong>
{% endif %}
<dl class="chat-details" style="display: none;">
<dt>{% trans %}Name{% endtrans %}:</dt>
<dd>{{ chatroom.name }}</dd>
{% if chatroom.jid_node != chatroom.name.lower() %}
<dt>JID:</dt>
<dd>{{ chatroom.jid_node }}</dd>
{% endif %}
<dt>{% trans %}Server{% endtrans %}:</dt>
<dd><span class="{% if chatroom.custom_server %}chat-custom-server{% endif %}">{{ server }}</span></dd>
{% if chatroom.description %}
@ -53,7 +57,6 @@
</div>
<div style="margin-top: 2em;">
<div class="groupTitle">{% trans %}Add chat room{% endtrans %}</div>
<a class="i-button" href="{{ url_for_plugin('.manage_rooms_create', event) }}">{% trans %}Create new room{% endtrans %}</a>
{% if available_chatrooms %}
<form action="{{ url_for_plugin('.manage_rooms_attach', event) }}" method="post">
<select name="chatroom_id">
@ -61,9 +64,10 @@
<option value="{{ chatroom.id }}">{{ chatroom.name }}</option>
{% endfor %}
</select>
<input class="i-button" type="submit" value="{% trans %}Attach{% endtrans %}">
<input class="i-button" type="submit" value="{% trans %}Attach existing room{% endtrans %}">
</form>
{% endif %}
<a class="i-button" href="{{ url_for_plugin('.manage_rooms_create', event) }}">{% trans %}Create new room{% endtrans %}</a>
</div>
<script>
eventChatInfo();

View File

@ -16,10 +16,16 @@
from __future__ import unicode_literals
import re
from indico.util.string import unicode_to_ascii
INVALID_JID_CHARS = re.compile(r'[^-!#()*+,.=^_a-z0-9]')
WHITESPACE = re.compile(r'\s+')
# TODO: implement the XMPP gateway
def create_room(room):
"""Creates a `Chatroom` on the XMPP server."""
print 'create_room / not implemented yet'
@ -33,3 +39,11 @@ def update_room(room):
def delete_room(room):
"""Deletes a `Chatroom` from the XMPP server."""
print 'delete_room / not implemented yet'
def generate_jid(name):
"""Generates a valid JID node identifier from a name"""
jid = unicode_to_ascii(name).lower()
jid = WHITESPACE.sub('-', jid)
jid = INVALID_JID_CHARS.sub('', jid)
return jid.strip()[:256]

View File

@ -88,7 +88,8 @@ class ChatImporter(Importer):
if room:
print cformat('- %{cyan}{} %{yellow!}DUPLICATE%{reset}').format(room.name)
else:
room = Chatroom(name=convert_to_unicode(old_room._name),
room = Chatroom(jid_node=convert_to_unicode(old_room._name.lower()),
name=convert_to_unicode(old_room._name),
description=convert_to_unicode(old_room._description),
password=convert_to_unicode(old_room._password),
custom_server=custom_server,