Merge pull request #1220 from emanuelschuetze/chatbox
Chatbox (Fixed #504)
This commit is contained in:
commit
dd7ae59f9a
@ -34,6 +34,7 @@ Other:
|
||||
- Created a poll description field for each assignment-poll.
|
||||
- Added possibility to use custom templates and static files in user data path
|
||||
directory.
|
||||
- Added global chatbox for managers.
|
||||
|
||||
Version 1.5.2 (unreleased)
|
||||
==========================
|
||||
|
13
README.rst
13
README.rst
@ -296,10 +296,6 @@ OpenSlides uses the following projects or parts of them:
|
||||
|
||||
* `jQuery <http://www.jquery.com>`_, License: MIT
|
||||
|
||||
* `jQuery UI <http://jqueryui.com>`_ with custom ui components: core,
|
||||
widget, mouse, sortable, datepicker, slider and css theme 'smoothness',
|
||||
License: MIT
|
||||
|
||||
* jQuery Plugins:
|
||||
|
||||
- `jQuery DataTables Plugin <http://www.datatables.net>`_, License:
|
||||
@ -309,7 +305,7 @@ OpenSlides uses the following projects or parts of them:
|
||||
License: MIT
|
||||
|
||||
- `jQuery Cookie Plugin <https://github.com/carhartl/jquery-cookie/>`_,
|
||||
License: MIT/GPL
|
||||
License: MIT
|
||||
|
||||
- `jQuery Form Plugin <http://malsup.com/jquery/form/>`_, License: MIT/GPLv2
|
||||
|
||||
@ -321,6 +317,12 @@ OpenSlides uses the following projects or parts of them:
|
||||
- `jQuery bsmSelect <https://github.com/vicb/bsmSelect/>`_, License:
|
||||
MIT/GPLv2
|
||||
|
||||
* `jQuery UI <http://jqueryui.com>`_ with custom ui components: core,
|
||||
widget, mouse, resizable, sortable, datepicker, slider and css theme 'smoothness',
|
||||
License: MIT
|
||||
|
||||
* jQuery UI AddOns:
|
||||
|
||||
- `jQuery UI Nested Sortable
|
||||
<https://github.com/mjsarfatti/nestedSortable/>`_, License: MIT
|
||||
|
||||
@ -332,7 +334,6 @@ OpenSlides uses the following projects or parts of them:
|
||||
<http://trentrichardson.com/examples/timepicker/>`_, License: MIT/GPLv2
|
||||
|
||||
|
||||
|
||||
VII. License and authors
|
||||
========================
|
||||
|
||||
|
@ -60,9 +60,8 @@ def setup_agenda_config(sender, **kwargs):
|
||||
help_text=ugettext_lazy('[Begin speach] starts the countdown, [End speach] stops the countdown.'),
|
||||
required=False))
|
||||
|
||||
extra_stylefiles = ['css/jquery-ui-timepicker.css', 'css/jquery-ui/jquery-ui.custom.min.css']
|
||||
extra_javascript = ['js/jquery/jquery-ui.custom.min.js',
|
||||
'js/jquery/jquery-ui-timepicker-addon.min.js',
|
||||
extra_stylefiles = ['css/jquery-ui-timepicker.css']
|
||||
extra_javascript = ['js/jquery/jquery-ui-timepicker-addon.min.js',
|
||||
'js/jquery/jquery-ui-sliderAccess.min.js',
|
||||
'js/jquery/datepicker-config.js']
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript" src="{% static 'js/agenda.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/jquery/jquery.cookie.js' %}"></script>
|
||||
{% if perms.agenda.can_manage_agenda %}
|
||||
<script type="text/javascript" src="{% static 'js/jquery/jquery-ui.custom.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/jquery/jquery.once.js' %}"></script>
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
{% block header %}
|
||||
<link type="text/css" rel="stylesheet" media="all" href="{% static 'css/agenda.css' %}" />
|
||||
<link rel="stylesheet" href="{% static 'css/jquery-ui/jquery-ui.custom.min.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
|
109
openslides/core/chatbox.py
Normal file
109
openslides/core/chatbox.py
Normal file
@ -0,0 +1,109 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sessions.models import Session
|
||||
from django.utils.html import urlize
|
||||
from sockjs.tornado import SockJSConnection
|
||||
|
||||
|
||||
class ChatboxSocketHandler(SockJSConnection):
|
||||
"""
|
||||
Websocket handler for the chatbox.
|
||||
"""
|
||||
clients = set()
|
||||
|
||||
def on_open(self, info):
|
||||
"""
|
||||
Checks connecting user and adds his client to the clients list.
|
||||
"""
|
||||
from openslides.participant.models import User
|
||||
|
||||
# TODO: Use the django way to get the session to be compatible with
|
||||
# other auth-backends; see comment in pull request #1220:
|
||||
# https://github.com/OpenSlides/OpenSlides/pull/1220#discussion_r11565705
|
||||
session_key = info.get_cookie(settings.SESSION_COOKIE_NAME).value
|
||||
session = Session.objects.get(session_key=session_key)
|
||||
try:
|
||||
self.user = User.objects.get(pk=session.get_decoded().get('_auth_user_id'))
|
||||
except User.DoesNotExist:
|
||||
return_value = False
|
||||
else:
|
||||
if self.user.has_perm('core.can_use_chat'):
|
||||
self.clients.add(self)
|
||||
return_value = True
|
||||
else:
|
||||
return_value = False
|
||||
return return_value
|
||||
|
||||
def on_message(self, message):
|
||||
"""
|
||||
Sends the given message to all clients.
|
||||
|
||||
Also appends the message to the cache and removes old messages if there
|
||||
are more than 100.
|
||||
"""
|
||||
if self.user.has_perm('core.can_use_chat') and message:
|
||||
message_object = ChatMessage(person=self.user, message=message)
|
||||
chat_messages.append(message_object)
|
||||
if len(chat_messages) > 100:
|
||||
chat_messages.pop(0)
|
||||
self.broadcast(
|
||||
self.clients,
|
||||
'%s %s %s' % (message_object.html_time(),
|
||||
message_object.html_person(),
|
||||
urlize(message_object.message)))
|
||||
|
||||
def on_close(self):
|
||||
"""
|
||||
Removes client from the clients list.
|
||||
"""
|
||||
self.clients.remove(self)
|
||||
|
||||
|
||||
class ChatMessage(object):
|
||||
"""
|
||||
Class for all chat messages. They are stored in the chat_messages object.
|
||||
|
||||
The argument person has to be a Person object, the argument message has to
|
||||
be the message as string. The argument color can be a three-tuple of RGB
|
||||
color values. Default is black (0, 0, 0).
|
||||
"""
|
||||
def __init__(self, person, message, color=None):
|
||||
self.person = person
|
||||
self.message = message
|
||||
self.color = color or (0, 0, 0)
|
||||
self.time = datetime.now()
|
||||
|
||||
def html_time(self):
|
||||
"""
|
||||
Returns the message time in html style.
|
||||
"""
|
||||
return '<small class="grey">%s</small>' % self.time.strftime('%H:%M')
|
||||
|
||||
def html_person(self):
|
||||
"""
|
||||
Returns the message sender name in html style.
|
||||
"""
|
||||
return "<span style='color:%(color)s;'>%(person)s:</span>" % {
|
||||
'color': 'rgb(%d,%d,%d)' % self.color,
|
||||
'person': self.person.clean_name}
|
||||
|
||||
|
||||
chat_messages = []
|
||||
"""
|
||||
Cache with all messages during livetime of the server.
|
||||
"""
|
||||
|
||||
|
||||
def chat_messages_context_processor(request):
|
||||
"""
|
||||
Adds all chat messages to the request context as template context processor.
|
||||
Returns None if the request user has no permission to use the chat.
|
||||
"""
|
||||
if request.user.has_perm('core.can_use_chat'):
|
||||
value = chat_messages
|
||||
else:
|
||||
value = None
|
||||
return {'chat_messages': value}
|
@ -24,6 +24,7 @@ class CustomSlide(SlideMixin, AbsoluteUrlMixin, models.Model):
|
||||
('can_manage_projector', ugettext_noop('Can manage the projector')),
|
||||
('can_see_projector', ugettext_noop('Can see the projector')),
|
||||
('can_see_dashboard', ugettext_noop('Can see the dashboard')),
|
||||
('can_use_chat', ugettext_noop('Can use the chat')),
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
|
@ -195,8 +195,7 @@ legend + .control-group {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/** Left sitebar navigation **/
|
||||
/** Left sidebar navigation **/
|
||||
.leftmenu ul {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
@ -320,6 +319,7 @@ legend + .control-group {
|
||||
.icon-presentations {
|
||||
background-position: -264px -48px;
|
||||
}
|
||||
|
||||
/** More glyphicons free icons **/
|
||||
.status_link .icon-on, .icon-checked-new {
|
||||
background-image: url("../img/glyphicons_152_check.png");
|
||||
@ -370,7 +370,6 @@ legend + .control-group {
|
||||
background-position: 0;
|
||||
}
|
||||
|
||||
|
||||
/** Responsive **/
|
||||
@media (max-width: 767px) {
|
||||
body {
|
||||
|
64
openslides/core/static/css/chatbox.css
Normal file
64
openslides/core/static/css/chatbox.css
Normal file
@ -0,0 +1,64 @@
|
||||
/** Chatbox **/
|
||||
.icon-comments {
|
||||
background-position: -240px -120px;
|
||||
}
|
||||
div#chatbox {
|
||||
width: 40%;
|
||||
height: 220px;
|
||||
min-height: 140px;
|
||||
min-width: 300px;
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
bottom: 0;
|
||||
z-index: 99;
|
||||
margin-bottom: 0;
|
||||
box-shadow: -3px -3px 10px rgba(0,0,0,0.2);
|
||||
border-width: 2px;
|
||||
border-color: darkgrey;
|
||||
padding: 0;
|
||||
}
|
||||
#chatbox-header{
|
||||
background-color: #333333;
|
||||
background-image: -moz-linear-gradient(top, #444444, #222222);
|
||||
background-image: -ms-linear-gradient(top, #444444, #222222);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));
|
||||
background-image: -webkit-linear-gradient(top, #444444, #222222);
|
||||
background-image: -o-linear-gradient(top, #444444, #222222);
|
||||
background-image: linear-gradient(top, #444444, #222222);
|
||||
border-color: #333333;
|
||||
}
|
||||
h1#chatbox-title {
|
||||
color: #999999;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
line-height: 16px;
|
||||
margin: 0;
|
||||
padding: 3px 10px 7px 10px;
|
||||
border-bottom: none;
|
||||
}
|
||||
div#chatbox div#chatbox-text {
|
||||
clear: both;
|
||||
overflow-y:scroll;
|
||||
background-color: white;
|
||||
padding: 0 10px;
|
||||
font-size: 12px;
|
||||
height: calc(100% - 65px);
|
||||
}
|
||||
#chatbox form {
|
||||
margin-bottom: 0px;
|
||||
padding: 5px;
|
||||
}
|
||||
#chatbox form input {
|
||||
width: 90%;
|
||||
}
|
||||
#newchatmessage {
|
||||
border-radius: 8px;
|
||||
background-color: red;
|
||||
color: white;
|
||||
font-size: 0.7em;
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: -6px;
|
||||
padding: 2px 6px;
|
||||
display: none;
|
||||
}
|
File diff suppressed because one or more lines are too long
111
openslides/core/static/js/chatbox.js
Normal file
111
openslides/core/static/js/chatbox.js
Normal file
@ -0,0 +1,111 @@
|
||||
// Functions for OpenSlides chatbox
|
||||
$(function() {
|
||||
// Chatbox is resizable on two sides (north and west) and
|
||||
// one corner (nortwest)
|
||||
$("div#chatbox").resizable({ handles: 'n, w, nw' });
|
||||
});
|
||||
|
||||
$("#chatboxbutton").click(function(){
|
||||
if ($(this).hasClass('active')) {
|
||||
/* close chatbox */
|
||||
$("#chatbox").addClass('hidden');
|
||||
// Save new chatbox state in cookie
|
||||
save_cookie(false);
|
||||
} else {
|
||||
/* open chatbox */
|
||||
$("#chatbox").removeClass('hidden');
|
||||
// Scroll chat content to end
|
||||
$("#chatbox-text").scrollTop(10000);
|
||||
// Set focus to input field
|
||||
$("#chatbox-form-input").val('').focus();
|
||||
// Save new chatbox state in cookie
|
||||
save_cookie(true)
|
||||
$.cookie('openslides-chatbox-new-message', 0, { path: "/"});
|
||||
// Hide new message number
|
||||
$("#newchatmessage").fadeOut();
|
||||
}
|
||||
});
|
||||
|
||||
$("#close-chatbox").click(function(){
|
||||
$("#chatbox").addClass('hidden');
|
||||
$("#chatboxbutton").removeClass('active');
|
||||
// Save new chatbox state in cookie
|
||||
save_cookie(false);
|
||||
});
|
||||
|
||||
$("#chatbox").resize(function() {
|
||||
// If resizing the chatbox window the chatbox text scrolls to latest message.
|
||||
// Sets a minimum for width and height.
|
||||
$("#chatbox-text").scrollTop(10000);
|
||||
$("#chatbox").resizable( "option", "minWidth", 300 );
|
||||
$("#chatbox").resizable( "option", "minHeight", 140 );
|
||||
save_cookie(true);
|
||||
});
|
||||
|
||||
|
||||
// Save chatbox state in cookie.
|
||||
// Parameter 'active': chatbox window is open (true) or closed (false).
|
||||
function save_cookie(active) {
|
||||
var status = {
|
||||
'active': active,
|
||||
'width': $("#chatbox").width(),
|
||||
'height': $("#chatbox").height()
|
||||
};
|
||||
$.cookie('openslides-chatbox', JSON.stringify(status), { path: "/"});
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
// Load chatbox state from cookie.
|
||||
var cookie = $.cookie('openslides-chatbox');
|
||||
if (cookie) {
|
||||
var status = $.parseJSON(cookie);
|
||||
if (status['active']) {
|
||||
$("#chatbox").removeClass('hidden');
|
||||
$("#chatboxbutton").addClass('active');
|
||||
// Scroll chat content to end
|
||||
$("#chatbox-text").scrollTop(10000);
|
||||
// Set focus to input field
|
||||
$('#chatbox-form-input').val('').focus();
|
||||
}
|
||||
if (status['width']) {
|
||||
$("#chatbox").width(status['width']);
|
||||
}
|
||||
if (status['height']) {
|
||||
$("#chatbox").height(status['height']);
|
||||
}
|
||||
}
|
||||
|
||||
// Load number of new messages from cookie
|
||||
if ($.cookie('openslides-chatbox-new-message') > 0) {
|
||||
$("#newchatmessage").html($.cookie('openslides-chatbox-new-message'));
|
||||
$("#newchatmessage").show(0);
|
||||
}
|
||||
|
||||
// Print chat messages into chatbox
|
||||
function print_message_into_box(message) {
|
||||
var chatcontent = $('#chatbox-text');
|
||||
chatcontent.html(chatcontent.html() + '<br>' + message);
|
||||
chatcontent.scrollTop(chatcontent.scrollTop() + 10000);
|
||||
// if chatbox is hidden show number of new messages and save in cookie
|
||||
if ($("#chatbox").hasClass('hidden')){
|
||||
new_messages = parseInt($.cookie('openslides-chatbox-new-message')) + 1;
|
||||
if (new_messages == 1)
|
||||
$("#newchatmessage").fadeIn();
|
||||
$("#newchatmessage").html(new_messages);
|
||||
$.cookie('openslides-chatbox-new-message', new_messages, { path: "/"});
|
||||
}
|
||||
}
|
||||
|
||||
var connection = new SockJS('http://' + window.location.host + '/core/chatbox');
|
||||
|
||||
connection.onmessage = function(event) {
|
||||
print_message_into_box(event.data);
|
||||
};
|
||||
|
||||
$("#chatbox-form").submit(function(){
|
||||
var message = $('#chatbox-form-input').val();
|
||||
connection.send(message);
|
||||
$('#chatbox-form-input').val('').focus();
|
||||
return false;
|
||||
});
|
||||
});
|
@ -7,7 +7,7 @@
|
||||
function saveOrder() {
|
||||
$(".column").each(function(index, value){
|
||||
var colid = value.id;
|
||||
var cookieName = "cookie-" + colid;
|
||||
var cookieName = "openslides-dashboard-" + colid;
|
||||
// Get the order for this column.
|
||||
var order = $('#' + colid).sortable("toArray");
|
||||
var cookie_content = [];
|
||||
@ -24,7 +24,7 @@ function saveOrder() {
|
||||
}
|
||||
cookie_content[i] = widget_id + '/' + is_collabsed + '/' + is_pinned;
|
||||
}
|
||||
$.cookie(cookieName, cookie_content, { path: "/", expiry: new Date(2012, 1, 1)});
|
||||
$.cookie(cookieName, cookie_content);
|
||||
});
|
||||
}
|
||||
|
||||
@ -32,9 +32,9 @@ function saveOrder() {
|
||||
function restoreOrder() {
|
||||
$(".column").each(function(index, value) {
|
||||
var colid = value.id;
|
||||
var cookieName = "cookie-" + colid;
|
||||
var cookieName = "openslides-dashboard-" + colid;
|
||||
var cookie = $.cookie(cookieName);
|
||||
if ( cookie === null ) { return; }
|
||||
if ( cookie === undefined ) { return; }
|
||||
var widgets = cookie.split(",");
|
||||
for (var i = 0, n = widgets.length; i < n; i++ ) {
|
||||
var widget_information = widgets[i].split('/');
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,12 +0,0 @@
|
||||
// $Id: jquery.cookie.js,v 1.1 2009/07/01 12:16:48 dries Exp $
|
||||
|
||||
/**
|
||||
* Cookie plugin 1.0
|
||||
*
|
||||
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
*/
|
||||
jQuery.cookie=function(b,j,m){if(typeof j!="undefined"){m=m||{};if(j===null){j="";m.expires=-1}var e="";if(m.expires&&(typeof m.expires=="number"||m.expires.toUTCString)){var f;if(typeof m.expires=="number"){f=new Date();f.setTime(f.getTime()+(m.expires*24*60*60*1000))}else{f=m.expires}e="; expires="+f.toUTCString()}var l=m.path?"; path="+(m.path):"";var g=m.domain?"; domain="+(m.domain):"";var a=m.secure?"; secure":"";document.cookie=[b,"=",encodeURIComponent(j),e,l,g,a].join("")}else{var d=null;if(document.cookie&&document.cookie!=""){var k=document.cookie.split(";");for(var h=0;h<k.length;h++){var c=jQuery.trim(k[h]);if(c.substring(0,b.length+1)==(b+"=")){d=decodeURIComponent(c.substring(b.length+1));break}}}return d}};
|
11
openslides/core/static/js/jquery/jquery.cookie.min.js
vendored
Normal file
11
openslides/core/static/js/jquery/jquery.cookie.min.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* jQuery Cookie Plugin v1.4.0
|
||||
* https://github.com/carhartl/jquery-cookie
|
||||
*
|
||||
* Copyright 2013 Klaus Hartl
|
||||
* Released under the MIT license
|
||||
*/
|
||||
(function(factory){if(typeof define==="function"&&define.amd)define(["jquery"],factory);else if(typeof exports==="object")factory(require("jquery"));else factory(jQuery)})(function($){var pluses=/\+/g;function encode(s){return config.raw?s:encodeURIComponent(s)}function decode(s){return config.raw?s:decodeURIComponent(s)}function stringifyCookieValue(value){return encode(config.json?JSON.stringify(value):String(value))}function parseCookieValue(s){if(s.indexOf('"')===0)s=s.slice(1,-1).replace(/\\"/g,
|
||||
'"').replace(/\\\\/g,"\\");try{s=decodeURIComponent(s.replace(pluses," "));return config.json?JSON.parse(s):s}catch(e){}}function read(s,converter){var value=config.raw?s:parseCookieValue(s);return $.isFunction(converter)?converter(value):value}var config=$.cookie=function(key,value,options){if(value!==undefined&&!$.isFunction(value)){options=$.extend({},config.defaults,options);if(typeof options.expires==="number"){var days=options.expires,t=options.expires=new Date;t.setTime(+t+days*864E5)}return document.cookie=
|
||||
[encode(key),"=",stringifyCookieValue(value),options.expires?"; expires="+options.expires.toUTCString():"",options.path?"; path="+options.path:"",options.domain?"; domain="+options.domain:"",options.secure?"; secure":""].join("")}var result=key?undefined:{};var cookies=document.cookie?document.cookie.split("; "):[];for(var i=0,l=cookies.length;i<l;i++){var parts=cookies[i].split("=");var name=decode(parts.shift());var cookie=parts.join("=");if(key&&key===name){result=read(cookie,value);break}if(!key&&
|
||||
(cookie=read(cookie))!==undefined)result[name]=cookie}return result};config.defaults={};$.removeCookie=function(key,options){if($.cookie(key)===undefined)return false;$.cookie(key,"",$.extend({},options,{expires:-1}));return!$.cookie(key)}});
|
@ -11,7 +11,9 @@
|
||||
<!-- styles -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" type="text/css" rel="stylesheet" />
|
||||
<link href="{% static 'css/bootstrap-responsive.min.css' %}" type="text/css" rel="stylesheet" />
|
||||
<link href="{% static 'css/jquery-ui/jquery-ui.custom.min.css'%}" type="text/css" rel="stylesheet" />
|
||||
<link href="{% static 'css/base.css' %}" type="text/css" rel="stylesheet" />
|
||||
<link href="{% static 'css/chatbox.css' %}" type="text/css" rel="stylesheet" />
|
||||
<link href="{% static 'img/favicon.png' %}" type="image/png" rel="shortcut icon" />
|
||||
{% for stylefile in extra_stylefiles %}
|
||||
<link href="{% static stylefile %}" type="text/css" rel="stylesheet" />
|
||||
@ -25,7 +27,7 @@
|
||||
<div class="span12">
|
||||
<div id="header">
|
||||
<a href="/" class="logo" title="{% trans 'Home' %}"><img src="{% static 'img/logo.png' %}" alt="{% trans 'Logo' %}" /></a>
|
||||
<span class="title optional">{% get_config 'event_name' %} – {% get_config 'event_description' %}</span>
|
||||
<span class="title optional">{% get_config 'event_name' %} {% if 'event_description'|get_config %}– {% get_config 'event_description' %}{% endif %}</span>
|
||||
{% block loginbutton %}
|
||||
<div class="pull-right">
|
||||
<!-- Search field -->
|
||||
@ -36,6 +38,15 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Chatbox button -->
|
||||
{% if chat_messages != None %}
|
||||
<button class="btn" id="chatboxbutton" data-toggle="button">
|
||||
<i class="icon-comments"></i>
|
||||
{% trans 'Chat' %}
|
||||
<span id="newchatmessage"></span>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
<!-- login/logout button -->
|
||||
<div class="btn-group">
|
||||
{% if user.is_authenticated %}
|
||||
@ -109,10 +120,16 @@
|
||||
</div><!--/#container-->
|
||||
{% endblock %}<!--/body-->
|
||||
|
||||
{% include 'core/chatbox.html' %}
|
||||
|
||||
<!-- JavaScript (Placed at the end of the document so the pages load faster) -->
|
||||
<script src="{% static 'js/jquery/jquery.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/jquery/jquery.cookie.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/jquery/jquery-ui.custom.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/sockjs-0.3.min.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/utils.js' %}" type="text/javascript"></script>
|
||||
<script src="{% static 'js/chatbox.js' %}" type="text/javascript"></script>
|
||||
<script src="{% url 'django.views.i18n.javascript_catalog' %}" type="text/javascript"></script>
|
||||
{% for javascript in extra_javascript %}
|
||||
<script src="{% static javascript %}" type="text/javascript"></script>
|
||||
|
22
openslides/core/templates/core/chatbox.html
Normal file
22
openslides/core/templates/core/chatbox.html
Normal file
@ -0,0 +1,22 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% if chat_messages != None %}
|
||||
<div class="hidden well" id="chatbox">
|
||||
<div id="chatbox-header">
|
||||
<h1 id="chatbox-title"><i class="icon-comments icon-white"></i> Chat
|
||||
<button class="btn btn-mini right" id="close-chatbox"><i class="icon-remove"></i></button>
|
||||
</h1>
|
||||
</div>
|
||||
<div id="chatbox-text">
|
||||
{% for message in chat_messages %}
|
||||
<br>{{ message.html_time|safe }} {{ message.html_person|safe }} {{ message.message|urlize }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<form class="form-inline" id="chatbox-form">
|
||||
<div class="input-append" style="width: calc(100% - 25px);">
|
||||
<input id="chatbox-form-input" type="text" />
|
||||
<button type="submit" class="btn"><i class="icon-comments"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
@ -8,8 +8,6 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript" src="{% static 'js/jquery/jquery-ui.custom.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/jquery/jquery.cookie.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/jquery/jquery.form.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/dashboard.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
@ -104,6 +104,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.core.context_processors.static',
|
||||
'openslides.utils.auth.anonymous_context_additions',
|
||||
'openslides.utils.main_menu.main_menu_entries',
|
||||
'openslides.core.chatbox.chat_messages_context_processor',
|
||||
)
|
||||
|
||||
CACHES = {
|
||||
|
@ -124,58 +124,63 @@ def create_builtin_groups_and_admin(sender, **kwargs):
|
||||
# Do completely nothing if there are already some of our groups in the database.
|
||||
return
|
||||
|
||||
# Anonymous and Registered
|
||||
# Anonymous (pk 1) and Registered (pk 2)
|
||||
ct_core = ContentType.objects.get(app_label='core', model='customslide')
|
||||
perm_1 = Permission.objects.get(content_type=ct_core, codename='can_see_projector')
|
||||
perm_2 = Permission.objects.get(content_type=ct_core, codename='can_see_dashboard')
|
||||
perm_11 = Permission.objects.get(content_type=ct_core, codename='can_see_projector')
|
||||
perm_12 = Permission.objects.get(content_type=ct_core, codename='can_see_dashboard')
|
||||
|
||||
ct_agenda = ContentType.objects.get(app_label='agenda', model='item')
|
||||
ct_speaker = ContentType.objects.get(app_label='agenda', model='speaker')
|
||||
perm_3 = Permission.objects.get(content_type=ct_agenda, codename='can_see_agenda')
|
||||
perm_3a = Permission.objects.get(content_type=ct_agenda, codename='can_see_orga_items')
|
||||
perm_13 = Permission.objects.get(content_type=ct_agenda, codename='can_see_agenda')
|
||||
perm_14 = Permission.objects.get(content_type=ct_agenda, codename='can_see_orga_items')
|
||||
can_speak = Permission.objects.get(content_type=ct_speaker, codename='can_be_speaker')
|
||||
|
||||
ct_motion = ContentType.objects.get(app_label='motion', model='motion')
|
||||
perm_4 = Permission.objects.get(content_type=ct_motion, codename='can_see_motion')
|
||||
perm_15 = Permission.objects.get(content_type=ct_motion, codename='can_see_motion')
|
||||
|
||||
ct_assignment = ContentType.objects.get(app_label='assignment', model='assignment')
|
||||
perm_5 = Permission.objects.get(content_type=ct_assignment, codename='can_see_assignment')
|
||||
perm_16 = Permission.objects.get(content_type=ct_assignment, codename='can_see_assignment')
|
||||
|
||||
ct_participant = ContentType.objects.get(app_label='participant', model='user')
|
||||
perm_6 = Permission.objects.get(content_type=ct_participant, codename='can_see_participant')
|
||||
perm_17 = Permission.objects.get(content_type=ct_participant, codename='can_see_participant')
|
||||
|
||||
ct_mediafile = ContentType.objects.get(app_label='mediafile', model='mediafile')
|
||||
perm_6a = Permission.objects.get(content_type=ct_mediafile, codename='can_see')
|
||||
perm_18 = Permission.objects.get(content_type=ct_mediafile, codename='can_see')
|
||||
|
||||
group_anonymous = Group.objects.create(name=ugettext_noop('Anonymous'), pk=1)
|
||||
group_anonymous.permissions.add(perm_1, perm_2, perm_3, perm_3a, perm_4, perm_5, perm_6, perm_6a)
|
||||
group_anonymous.permissions.add(perm_11, perm_12, perm_13, perm_14, perm_15, perm_16, perm_17, perm_18)
|
||||
group_registered = Group.objects.create(name=ugettext_noop('Registered'), pk=2)
|
||||
group_registered.permissions.add(perm_1, perm_2, perm_3, perm_3a, perm_4, perm_5, perm_6, perm_6a, can_speak)
|
||||
group_registered.permissions.add(perm_11, perm_12, perm_13, perm_14, perm_15, perm_16, perm_17, perm_18, can_speak)
|
||||
|
||||
# Delegates
|
||||
perm_7 = Permission.objects.get(content_type=ct_motion, codename='can_create_motion')
|
||||
perm_8 = Permission.objects.get(content_type=ct_motion, codename='can_support_motion')
|
||||
perm_9 = Permission.objects.get(content_type=ct_assignment, codename='can_nominate_other')
|
||||
perm_10 = Permission.objects.get(content_type=ct_assignment, codename='can_nominate_self')
|
||||
perm_10a = Permission.objects.get(content_type=ct_mediafile, codename='can_upload')
|
||||
# Delegates (pk 3)
|
||||
perm_31 = Permission.objects.get(content_type=ct_motion, codename='can_create_motion')
|
||||
perm_32 = Permission.objects.get(content_type=ct_motion, codename='can_support_motion')
|
||||
perm_33 = Permission.objects.get(content_type=ct_assignment, codename='can_nominate_other')
|
||||
perm_34 = Permission.objects.get(content_type=ct_assignment, codename='can_nominate_self')
|
||||
perm_35 = Permission.objects.get(content_type=ct_mediafile, codename='can_upload')
|
||||
|
||||
group_delegates = Group.objects.create(name=ugettext_noop('Delegates'), pk=3)
|
||||
group_delegates.permissions.add(perm_7, perm_8, perm_9, perm_10, perm_10a)
|
||||
group_delegates.permissions.add(perm_31, perm_32, perm_33, perm_34, perm_35)
|
||||
|
||||
# Staff
|
||||
perm_11 = Permission.objects.get(content_type=ct_agenda, codename='can_manage_agenda')
|
||||
perm_12 = Permission.objects.get(content_type=ct_motion, codename='can_manage_motion')
|
||||
perm_13 = Permission.objects.get(content_type=ct_assignment, codename='can_manage_assignment')
|
||||
perm_14 = Permission.objects.get(content_type=ct_participant, codename='can_manage_participant')
|
||||
perm_15 = Permission.objects.get(content_type=ct_core, codename='can_manage_projector')
|
||||
perm_15a = Permission.objects.get(content_type=ct_mediafile, codename='can_manage')
|
||||
# Staff (pk 4)
|
||||
perm_41 = Permission.objects.get(content_type=ct_agenda, codename='can_manage_agenda')
|
||||
perm_42 = Permission.objects.get(content_type=ct_motion, codename='can_manage_motion')
|
||||
perm_43 = Permission.objects.get(content_type=ct_assignment, codename='can_manage_assignment')
|
||||
perm_44 = Permission.objects.get(content_type=ct_participant, codename='can_manage_participant')
|
||||
perm_45 = Permission.objects.get(content_type=ct_core, codename='can_manage_projector')
|
||||
perm_46 = Permission.objects.get(content_type=ct_core, codename='can_use_chat')
|
||||
perm_47 = Permission.objects.get(content_type=ct_mediafile, codename='can_manage')
|
||||
|
||||
ct_config = ContentType.objects.get(app_label='config', model='configstore')
|
||||
perm_16 = Permission.objects.get(content_type=ct_config, codename='can_manage')
|
||||
perm_48 = Permission.objects.get(content_type=ct_config, codename='can_manage')
|
||||
|
||||
group_staff = Group.objects.create(name=ugettext_noop('Staff'), pk=4)
|
||||
group_staff.permissions.add(perm_7, perm_9, perm_10, perm_10a, perm_11, perm_12, perm_13, perm_14, perm_15, perm_15a, perm_16)
|
||||
group_staff.permissions.add(perm_6) # TODO: Remove this redundancy after cleanup of the permission system
|
||||
# add delegate permissions (without can_support_motion)
|
||||
group_staff.permissions.add(perm_31, perm_33, perm_34, perm_35)
|
||||
# add staff permissions
|
||||
group_staff.permissions.add(perm_41, perm_42, perm_43, perm_44, perm_45, perm_46, perm_47, perm_48)
|
||||
# add can_see_participant permission
|
||||
group_staff.permissions.add(perm_17) # TODO: Remove this redundancy after cleanup of the permission system
|
||||
|
||||
# Admin user
|
||||
create_or_reset_admin_user()
|
||||
|
@ -79,17 +79,20 @@ def run_tornado(addr, port, reload=False):
|
||||
url_string = 'http://%s:%s' % (addr, port)
|
||||
print _("Starting OpenSlides' tornado webserver listening to %(url_string)s") % {'url_string': url_string}
|
||||
|
||||
socket_js_router = SockJSRouter(ProjectorSocketHandler, '/projector/socket')
|
||||
|
||||
# Start the application
|
||||
# Setup WSGIContainer
|
||||
app = WSGIContainer(Django_WSGIHandler())
|
||||
tornado_app = Application(socket_js_router.urls + [
|
||||
|
||||
# Collect urls
|
||||
projectpr_socket_js_router = SockJSRouter(ProjectorSocketHandler, '/projector/socket')
|
||||
from openslides.core.chatbox import ChatboxSocketHandler
|
||||
chatbox_socket_js_router = SockJSRouter(ChatboxSocketHandler, '/core/chatbox')
|
||||
other_urls = [
|
||||
(r"%s(.*)" % settings.STATIC_URL, DjangoStaticFileHandler),
|
||||
(r'%s(.*)' % settings.MEDIA_URL, StaticFileHandler, {'path': settings.MEDIA_ROOT}),
|
||||
('.*', FallbackHandler, dict(fallback=app))
|
||||
], debug=reload)
|
||||
('.*', FallbackHandler, dict(fallback=app))]
|
||||
|
||||
# Start the application
|
||||
tornado_app = Application(projectpr_socket_js_router.urls + chatbox_socket_js_router.urls + other_urls, debug=reload)
|
||||
server = HTTPServer(tornado_app)
|
||||
server.listen(port=port,
|
||||
address=addr)
|
||||
server.listen(port=port, address=addr)
|
||||
IOLoop.instance().start()
|
||||
|
Loading…
Reference in New Issue
Block a user