Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

app refactored and redesigned

handlers class created
static dir included
  • Loading branch information...
commit 81d5e5ee9a8c8cdf59e81f8ba6144d4ed2c5bba4 1 parent 4450109
@qubird authored
View
BIN  .DS_Store
Binary file not shown
View
1  .gitignore
@@ -1 +1,2 @@
*.py[co]
+.DS_Store
View
6 chatrooms.egg-info/SOURCES.txt
@@ -2,9 +2,10 @@ README.txt
setup.cfg
setup.py
chatrooms/__init__.py
+chatrooms/__views.py
chatrooms/admin.py
chatrooms/models.py
-chatrooms/test_urls.py
+chatrooms/signals.py
chatrooms/tests.py
chatrooms/urls.py
chatrooms/views.py
@@ -24,4 +25,5 @@ chatrooms/management/commands/__init__.py
chatrooms/management/commands/test_gevent.py
chatrooms/utils/__init__.py
chatrooms/utils/auth.py
-chatrooms/utils/decorators.py
+chatrooms/utils/decorators.py
+chatrooms/utils/examples.py
View
BIN  chatrooms/.DS_Store
Binary file not shown
View
79 chatrooms/ajax/chat.py
@@ -6,27 +6,27 @@
from collections import deque
from django.conf import settings
-from django.contrib.auth.models import User
-from django.db.models import Max
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.http import (HttpResponse,
HttpResponseNotFound,
HttpResponseBadRequest)
+from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from gevent.event import Event
-from ..models import Room, Message
+from ..models import Room
from ..signals import chat_message_received
from ..utils.auth import check_user_passes_test
from ..utils.decorators import ajax_user_passes_test_or_403
from ..utils.decorators import ajax_login_required
+from ..utils.handlers import MessageHandlerFactory
TIME_FORMAT = '%Y-%m-%dT%H:%M:%S:%f'
-TIMEOUT = 20
+TIMEOUT = 30
if settings.DEBUG:
TIMEOUT = 3
@@ -57,20 +57,26 @@ def get_messages(self, request):
"""
try:
room_id = int(request.GET['room_id'])
- latest_id = int(request.GET['latest_id'])
+ latest_msg_id = int(request.GET['latest_message_id'])
except:
- return HttpResponseNotFound('not found', mimetype="text/plain")
- room = Room.objects.get(id=room_id)
+ return HttpResponseBadRequest(
+ "Parameters missing or bad parameters. "
+ "Expected a GET request with 'room_id' and 'latest_message_id' "
+ "parameters")
+ room = get_object_or_404(Room, id=room_id)
# wait for new messages
self.new_message_events[room.id].wait(TIMEOUT)
- messages = self.messages[room.id]
+
+ handler = MessageHandlerFactory()
+ messages = handler.retrieve_messages(self, room_id)
+
to_jsonify = [
{"message_id": msg_id,
"username": message.user.username,
"date": message.date.strftime(TIME_FORMAT),
- "content": message.message}
+ "content": message.content}
for msg_id, message in messages
- if msg_id > latest_id
+ if msg_id > latest_msg_id
]
return HttpResponse(json.dumps(to_jsonify),
mimetype="application/json")
@@ -87,19 +93,19 @@ def send_message(self, request):
message = request.POST['message']
date = datetime.now()
except:
- return HttpResponseBadRequest()
+ return HttpResponseBadRequest(
+ "Parameters missing or bad parameters"
+ "Expected a POST request with 'room_id' and 'message' parameters")
+ room = get_object_or_404(Room, id=room_id)
user = request.user
-
foo, response = chat_message_received.send(
sender=self,
- room_id=room_id,
+ room_id=room.id,
user=user,
message=message,
date=date)[0]
- msg_number = self.counters[room_id].next()
- self.messages[room_id].append((msg_number, response))
- return HttpResponse(json.dumps(
- {'id': msg_number,
+
+ return HttpResponse(json.dumps({
'timestamp': date.strftime(TIME_FORMAT), }
))
@@ -109,14 +115,14 @@ def notify_users_list(self, request):
"""Updates user time into connected users dictionary
"""
try:
- room_id = request.POST['room_id']
- except KeyError:
- return HttpResponseNotFound('not found', mimetype="text/plain")
+ room_id = int(request.POST['room_id'])
+ except:
+ return HttpResponseBadRequest(
+ "Parameters missing or bad parameters"
+ "Expected a POST request with 'room_id'")
- # if request.user.is_authenticated():
- room_id = long(room_id)
user = request.user
- room = Room.objects.get(id=room_id)
+ room = get_object_or_404(Room, id=room_id)
date = datetime.today()
self.connected_users[room.id].update({user.username: date})
self.new_connected_user_event[room_id].set()
@@ -130,12 +136,14 @@ def get_users_list(self, request):
"""
REFRESH_TIME = 8
try:
- room_id = request.GET['room_id']
- except KeyError:
- return HttpResponseBadRequest()
- room_id = int(room_id)
- room = Room.objects.get(id=room_id)
- user = User.objects.get(username=request.user.username)
+ room_id = int(request.GET['room_id'])
+ except:
+ return HttpResponseBadRequest(
+ "Parameters missing or bad parameters"
+ "Expected a POST request with 'room_id'")
+
+ room = get_object_or_404(Room, id=room_id)
+ user = request.user
self.connected_users[room.id].update({
user.username: datetime.today()
})
@@ -158,7 +166,7 @@ def get_users_list(self, request):
@method_decorator(ajax_login_required)
@method_decorator(ajax_user_passes_test_or_403(check_user_passes_test))
- def get_last_message_id(self, request):
+ def get_latest_message_id(self, request):
"""
Dumps the id of the latest message sent
"""
@@ -188,16 +196,7 @@ def _clean_connected_users(self, room_id, seconds=60):
get_messages = chat.get_messages
get_users_list = chat.get_users_list
notify_users_list = chat.notify_users_list
-get_last_message_id = chat.get_last_message_id
-
-
-def get_date(request):
- """dumps the current date """
- response = {
- "date": "%s" % datetime.today().strftime(TIME_FORMAT)
- }
- return HttpResponse(json.dumps(response),
- mimetype="application/json")
+get_latest_message_id = chat.get_latest_message_id
@receiver(post_save, sender=Room)
View
15 chatrooms/models.py
@@ -7,19 +7,22 @@
class Room(PolymorphicModel):
- name = models.CharField(max_length=64)
+ name = models.CharField(max_length=64, unique=True)
slug = models.SlugField()
- subscribers = models.ManyToManyField(User)
- private = models.BooleanField()
- password = models.CharField(max_length=32)
+ subscribers = models.ManyToManyField(User, blank=True)
+ private = models.NullBooleanField()
+ password = models.CharField(max_length=32, blank=True)
+
+ def __unicode__(self):
+ return u"%s" % self.name
@models.permalink
def get_absolute_url(self):
- return ('room_view', [str(self.id)])
+ return ('room_view', [self.slug])
class Message(PolymorphicModel):
user = models.ForeignKey(User)
date = models.DateTimeField(['%Y-%m-%d %H:%M:%S:%f'])
room = models.ForeignKey(Room)
- message = models.CharField(max_length=5000)
+ content = models.CharField(max_length=5000)
View
58 chatrooms/signals.py
@@ -1,11 +1,6 @@
-from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
+from utils.handlers import MessageHandlerFactory # get_message_received_handler
from django.dispatch import Signal
-from django_load.core import load_object
-
-from .models import Room, Message
-
chat_message_received = Signal(
providing_args=[
@@ -15,53 +10,6 @@
"date",
])
+handler = MessageHandlerFactory()
-def set_new_message_chatroom_event(chatobj, room_id):
- """
- Set event indexed by the given room_id on the ChatView object
- """
- event = chatobj.new_message_event[room_id]
- event.set()
- event.clear()
-
-
-def db_message_received_handler(signal, sender, room_id, user, message, date):
- """
- Default handler for the message_received signal.
- 1 - Saves an instance of message to db
- 2 - Returns the created message
-
- A handler is a function accepting the following arguments:
- signal, sender, room_id, user, message, date
- It must return an object containing the following attributes:
- user, room, date, message
- Whatever the things you do with the message (store to db, queueing
- it to RabbitMQ or anything you like), you have to return
- an object with the former attributes.
- """
- room = Room.objects.get(id=room_id)
- new_message = Message(user=user,
- room=room,
- date=date,
- message=message)
- new_message.save()
- return new_message
-
-
-def get_message_received_handler():
- """
- Returns the function defined as settings.CHATROOMS_MESSAGE_RECEIVED_HANDLER
- if any, else returns the db_message_received_handler
- """
- if hasattr(settings, 'CHATROOMS_MESSAGE_RECEIVED_HANDLER'):
- try:
- return load_object(settings.CHATROOMS_MESSAGE_RECEIVED_HANDLER)
- except (ImportError, TypeError):
- raise ImproperlyConfigured(
- "The variable set as settings.CHATROOMS_MESSAGE_RECEIVED_HANDLER "
- "is not a module or the path is not correct"
- )
- return db_message_received_handler
-
-
-chat_message_received.connect(get_message_received_handler())
+chat_message_received.connect(handler.handle_received_message)
View
160 chatrooms/static/css/room.css
@@ -0,0 +1,160 @@
+body{
+ background-color: #EDF0F0;
+ font-family: Helvetica, Arial, "MS Trebuchet", sans-serif;
+}
+
+#nav-menu li {
+ list-style-type: none;
+ display: inline;
+ margin-right: 20px;
+}
+
+.button {
+ border-top: 1px solid #737373;
+ background: #abb3b8;
+ background: -webkit-gradient(linear, left top, left bottom, from(#000000), to(#abb3b8));
+ background: -webkit-linear-gradient(top, #000000, #abb3b8);
+ background: -moz-linear-gradient(top, #000000, #abb3b8);
+ background: -ms-linear-gradient(top, #000000, #abb3b8);
+ background: -o-linear-gradient(top, #000000, #abb3b8);
+ padding: 4px 8px;
+ -webkit-border-radius: 8px;
+ -moz-border-radius: 8px;
+ border-radius: 8px;
+ -webkit-box-shadow: rgba(0,0,0,1) 0 1px 0;
+ -moz-box-shadow: rgba(0,0,0,1) 0 1px 0;
+ box-shadow: rgba(0,0,0,1) 0 1px 0;
+ text-shadow: rgba(0,0,0,.4) 0 1px 0;
+ color: white;
+ font-size: 14px;
+ font-family: 'Lucida Grande', Helvetica, Arial, Sans-Serif;
+ text-decoration: none;
+ vertical-align: middle;
+}
+.button:hover {
+ border-top-color: #ffffff;
+ background: #ffffff;
+ color: #000000;
+}
+.button:active {
+ border-top-color: #93979c;
+ background: #93979c;
+}
+
+#header {
+ position: static;
+ left: 0px;
+ top: 0px;
+ background-color: #EBECE4;
+ text-align: center;
+ font-family: Helvetica, Arial, "MS Trebuchet", sans-serif;
+ height: 40px;
+}
+
+#video {
+ float: left;
+ display: inline;
+ position: relative;
+ box-shadow: inset 2px 2px 1px #888888;
+}
+
+#chat {
+ width: 35%;
+ display: inline;
+ float: left;
+ background-color: #C9C9C9;
+ box-shadow: inset 2px 2px 1px #888888;
+}
+
+#chatText {
+ overflow: auto;
+ position: relative;
+ height: 70%;
+ width: 100%;
+}
+
+#chatInput input{
+}
+
+#chatSendText {
+ border:none;
+ position: relative;
+ float: left;
+ height: 32px;
+ width: 80%;
+ font-size: 18px;
+ padding-top: 9px;
+ padding-left: 4px;
+ outline-style:none;
+ font-family: Helvetica, Arial, "MS Trebuchet", sans-serif;
+ color: #5a5a5a;
+ -webkit-box-shadow: inset 2px 2px 1px #888888; /* Safari and Chrome */
+ box-shadow: inset 2px 2px 1px #888888;
+}
+
+#chatSendButton{
+ border:none;
+ position: relative;
+ float: left;
+ height: 32px;
+ width: 20%;
+ font-size: 18px;
+ font-family: Helvetica, Arial, "MS Trebuchet", sans-serif;
+ -webkit-box-shadow: 2px 2px 1px #888888; /* Safari and Chrome */
+ box-shadow: 2px 2px 1px #888888;
+}
+
+#chatSendButton:active, #chatSendButton.pressed{
+ border:none;
+ position: relative;
+ float: left;
+ height: 32px;
+ width: 20%;
+ font-size: 18px;
+ font-family: Helvetica, Arial, "MS Trebuchet", sans-serif;
+ box-shadow: inset 2px 2px 1px #888888;
+}
+
+
+.chatMessage {
+ background-color: #999999;
+ color: white;
+ display: block;
+ margin-left: 2px;
+}
+
+.myMessage {
+ background-color: #F4F4F4;
+ color: black;
+ display: block;
+ margin-left: 2px;
+}
+
+#connectedUsers{
+ overflow: auto;
+ position: relative;
+ height: 70%;
+ list-style-type: none;
+ float: left;
+ box-shadow: 1px 1px 3px #888888;
+}
+
+#connectedUsersList{
+ list-style-type: none;
+ margin-left: 0px;
+ padding-left: 0px;
+ margin-top: 0px;
+}
+
+#connectedUsersTitle{
+ font-size: 10px;
+}
+.messageDate, .messageUsername{
+ display: inline;
+ font-size: 10px;
+}
+
+.messageContent{
+ font-style: oblique;
+ font-size: 12px;
+}
View
36 chatrooms/static/js/jquery_csrf_ajax.js
@@ -0,0 +1,36 @@
+$(document).ajaxSend(function(event, xhr, settings) {
+ function getCookie(name) {
+ var cookieValue = null;
+ if (document.cookie && document.cookie != '') {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = jQuery.trim(cookies[i]);
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
+ }
+ }
+ return cookieValue;
+ }
+ function sameOrigin(url) {
+ // url could be relative or scheme relative or absolute
+ var host = document.location.host; // host + port
+ var protocol = document.location.protocol;
+ var sr_origin = '//' + host;
+ var origin = protocol + sr_origin;
+ // Allow absolute or scheme relative URLs to same origin
+ return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
+ (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
+ // or any other URL that isn't scheme relative or absolute i.e relative.
+ !(/^(\/\/|http:|https:).*/.test(url));
+ }
+ function safeMethod(method) {
+ return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+ }
+
+ if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
+ xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
+ }
+});
View
192 chatrooms/static/js/room.js
@@ -0,0 +1,192 @@
+/* jQuery client side script to make the chatrooms app work out of the box
+*/
+
+$(function(){
+ var Context = getContext();
+ var latest_message_id;
+
+ $.ajax({
+ url: "/chat/get_latest_msg_id/",
+ async: false,
+ dataType: 'json',
+ data: {'room_id': Context.room_id},
+ success: function(data) {
+ latest_message_id = data.id;
+ }
+ });
+
+ var getEscapedText = function(text_to_escape){
+ return $('<dummy>').text(text_to_escape).html();
+ };
+
+ var compareDates = function(dateObj1, dateObj2){
+ /*returns True if dateObj1 >= dateObj2 */
+ if ((dateObj1.hour >= dateObj2.hour &&
+ dateObj1.minute >= dateObj2.minute &&
+ dateObj1.second == dateObj2.second &&
+ dateObj1.microsecond > dateObj2.microsecond)
+ ||
+ (dateObj1.hour >= dateObj2.hour &&
+ dateObj1.minute >= dateObj2.minute &&
+ dateObj1.second > dateObj2.second)){
+ return 1;
+ }
+ };
+
+
+ var parseDateTime = function(timeString){
+ //capture time string fields thru regexp 2010-10-01T12:07:31:768227
+ var parse_time = /([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2}):([0-9]*)/;
+ var resultsArr = parse_time.exec(timeString);
+ var resultsObj;
+ if(resultsArr.length === 8){
+ resultsObj = {
+ fullString: resultsArr[0],
+ year: resultsArr[1],
+ month:resultsArr[2],
+ day: resultsArr[3],
+ hour: resultsArr[4],
+ minute: resultsArr[5],
+ second: resultsArr[6],
+ microsecond: resultsArr[7]
+ };
+ return resultsObj;
+ }else return undefined;
+ };
+
+ var chatSendAction = function (event) {
+ if($('#chatSendText').val() !== ""){
+ var data_to_send = {
+ "username": Context.username,
+ "room_id": Context.room_id,
+ //escape quotes and special chars to avoid html injection
+ "message": escape(getEscapedText($('#chatSendText').val()))
+ };
+ $.post('/chat/send_message/', data_to_send, function(data){
+ $('#chatSendText').attr('value', "");
+ });
+ }
+ };
+
+ var getChatText = function(data){
+ var to_append = [];
+ for (var i = 0; i < data.length; i++){
+ if (latest_message_id < data[i].message_id){
+ latest_message_id = data[i].message_id;
+
+ var msgTime = parseDateTime(data[i].date);
+
+ if (Context.username === data[i].username){
+ to_append.push(
+ '<div class="chatMessage myMessage"><div class="messageDate">');
+ }
+ else {
+ to_append.push(
+ '<div class="chatMessage"><div class="messageDate">');
+ }
+
+ to_append.push(msgTime.hour + ':' + msgTime.minute +
+ ':' + msgTime.second);
+ to_append.push('</div> <div class="messageUsername">');
+ if (Context.username === data[i].username){
+ to_append.push('You wrote:');
+ }
+ else {
+ to_append.push(data[i].username + ' wrote:');
+ }
+
+ to_append.push('</div><div class="messageContent">');
+ to_append.push(unescape(data[i].content));
+ to_append.push('</div>' + '</div>');
+ }
+ }
+ return to_append.join("");
+ };
+
+ var chatGetMessages = function(){
+ $.ajax({
+ url: "/chat/get_messages/",
+ cache: false,
+ dataType: "json",
+ data: {'room_id': Context.room_id,
+ 'latest_message_id': latest_message_id},
+ type: "GET",
+ success: function(data) {
+ var chatText = getChatText(data)
+ $('#chatText').append(chatText);
+ $("#chatText").attr({
+ scrollTop: $("#chatText").attr("scrollHeight")});
+ window.setTimeout(chatGetMessages, 0);
+ }});
+ };
+ var notifyConnection = function(){
+ $.ajax({
+ url: "/chat/notify_users_list/",
+ cache: false,
+ data: {'room_id': Context.room_id},
+ type: 'POST',
+ success: function(data){
+ // window.setTimeout(usersListGet, 0);
+ }
+
+ });
+ };
+
+ var usersListGet = function(){
+ $.ajax({
+ url: "/chat/get_users_list/",
+ cache: false,
+ dataType: "json",
+ data: {'room_id': Context.room_id},
+ type: "GET",
+ success: function(data){
+ $('#connectedUsersList').empty();
+ var now = parseDateTime(data.now);
+ var date = new Date(now.year, now.month, now.day,
+ now.hour, now.minute, now.second);
+ $('#connectedUsersList').empty();
+ date = date.valueOf();
+ var users = data.users;
+ for (var i = 0; i < users.length; i++){
+ var userdate = parseDateTime(users[i].date);
+ var userJsDate = new Date(
+ userdate.year,
+ userdate.month,
+ userdate.day,
+ userdate.hour,
+ userdate.minute,
+ userdate.second);
+ userJsDate = userJsDate.valueOf();
+ if ( date - userJsDate < (data.refresh * 2) * 1000){
+ if (Context.username == users[i].username){
+ $('#connectedUsersList').append(
+ '<li>You</li>');
+ } else{
+ $('#connectedUsersList').append(
+ '<li>'+ users[i].username + '</li>');}
+ }
+ }
+ window.setTimeout(usersListGet, 0);
+ }
+ });
+ };
+
+ $('#chatSendButton').bind("click", chatSendAction);
+
+ $('#chatSendText').keydown(function(e){
+ if(e.keyCode == '13'){
+ $('#chatSendButton').addClass("pressed");
+ }
+ });
+ $('#chatSendText').keyup(function(e){
+ if(e.keyCode == '13'){
+ $('#chatSendButton').removeClass("pressed");
+ $('#chatSendButton').click();
+ }
+ });
+
+
+ window.setTimeout(chatGetMessages, 0);
+ window.setTimeout(usersListGet, 0);
+ window.setTimeout(notifyConnection, 0);
+});
View
15 chatrooms/templates/chatrooms/base.html
@@ -0,0 +1,15 @@
+<html>
+ <head>
+ <title></title>
+ <script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
+ <script type="text/javascript" charset="utf-8"
+ src="{{STATIC_URL}}js/jquery_csrf_ajax.js">
+ </script>
+ {% block extra_headers %}
+ {% endblock %}
+ </head>
+ <body>
+ {% block content %}
+ {% endblock %}
+ </body>
+</html>
View
33 chatrooms/templates/chatrooms/room.html
@@ -0,0 +1,33 @@
+{% extends "chatrooms/base.html" %}
+
+{% block extra_headers %}
+ <!-- <link rel="stylesheet" type="text/css" href="{{STATIC_URL}}/css/room_page.css"> -->
+ <script type="text/javascript">
+ getContext = function(){
+ return {
+ "username": "{{ user.username }}",
+ "room_id": {{ room.id }},
+ }
+ }
+ </script>
+ <script type="text/javascript" src="{{ STATIC_URL }}/js/room.js"></script>
+ <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}/css/room.css">
+{% endblock %}
+
+
+{% block content %}
+ <div id="content">
+ <div id="chat">
+ <div id="chatText"></div>
+ <div id="chatInput">
+ <input id="chatSendText" name="chatSendText" type="text" >
+ <input id="chatSendButton" type="button" value="Send">
+ </div>
+ </div>
+ <div id="connectedUsers">
+ <p id="connectedUsersTitle">Connected users</p>
+ <ol id="connectedUsersList">
+ </ol>
+ </div>
+ </div>
+{% endblock %}
View
32 chatrooms/templates/chatrooms/rooms_list.html
@@ -0,0 +1,32 @@
+{% extends "chatrooms/base.html" %}
+{% block content %}
+ <div id="rooms-list">
+ <ul>
+ {% for room in rooms%}
+ <li><a href={{ room.get_absolute_url }}>{{ room.name }}</a></li>
+ {% endfor %}
+ </ul>
+ </div>
+
+ <div class="pagination">
+ <span class="current">
+ Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
+ </span>
+
+ <span class="step-links">
+ {% if page_obj.has_previous %}
+ <a href="?page={{ page_obj.previous_page_number }}"><</a>
+ {% endif %}
+
+ {% for page_num in page_obj.paginator.page_range %}
+ {% if page_num != page_obj.number %}
+ <a href="?page={{ page_num }}">{{ page_num }}</a>
+ {% endif %}
+ {% endfor %}
+
+ {% if page_obj.has_next %}
+ <a href="?page={{ page_obj.next_page_number }}">></a>
+ {% endif %}
+ </span>
+ </div>
+{% endblock content %}
View
9 chatrooms/test_urls.py
@@ -1,9 +0,0 @@
-from django.conf.urls.defaults import *
-
-# URL test patterns for django.chatrooms. Use this file to ensure a consistent
-# set of URL patterns are used when running unit tests. This test_urls
-# module should be referred to by your test class.
-
-urlpatterns = patterns('django.chatrooms.views',
- # Add url patterns here
-)
View
23 chatrooms/urls.py
@@ -1,10 +1,23 @@
+#encoding=utf8
+
from django.conf.urls.defaults import *
+from django.contrib.auth.decorators import login_required
-# URL patterns for django.chatrooms
+from . import views
urlpatterns = patterns('chatrooms',
- # Add url patterns here
- url(r'^get_messages/', 'ajax.chat.chat_get'),
- url(r'^send_message/', 'ajax.chat.chat_send'),
- url(r'^get_last_msg_id/', 'ajax.chat.get_last_message_id'),
+ # room views
+ url(r'^rooms/$',
+ login_required(views.RoomsListView.as_view()),
+ name="rooms_list"),
+ url(r'^room/(?P<slug>[-\w\d]+)/$',
+ login_required(views.RoomView.as_view()),
+ name="room_view"),
+
+ # ajax requests
+ url(r'^get_messages/', 'ajax.chat.get_messages'),
+ url(r'^send_message/', 'ajax.chat.send_message'),
+ url(r'^get_latest_msg_id/', 'ajax.chat.get_latest_message_id'),
+ url(r'^get_users_list/$', 'ajax.chat.get_users_list'),
+ url(r'^notify_users_list/$', 'ajax.chat.notify_users_list')
)
View
10 chatrooms/utils/decorators.py
@@ -1,25 +1,21 @@
#encoding=utf8
-try:
- from functools import wraps
-except ImportError:
- from django.utils.functional import wraps # Python 2.4 fallback.
-
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.decorators import available_attrs
+from django.utils.functional import wraps
def ajax_user_passes_test_or_403(test_func, message="Access denied"):
"""
- Decorator for views that checks that the user passes the given test,
+ Decorator for views that checks the user passes the given test,
raising 403 if user does not pass test.
If the request is ajax returns a 403 response with a message,
else renders a 403.html template.
- The test should be a callable that takes the user object and
+ The test should be a callable which takes the user object and
returns True if the user passes.
"""
View
89 chatrooms/utils/handlers.py
@@ -0,0 +1,89 @@
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django_load.core import load_object
+
+from ..models import Room, Message
+
+
+class MessageHandler(object):
+ """
+ Class which implements two methods:
+ - handle_received_message
+ is designated to handle the "chat_message_received" signal
+ - retrieve_messages
+ is designated to return the list of messages sent into a chat room
+ up to now
+
+ 'handle_received_message' method is designed to perform operations
+ with the received message such that 'retrieve_messages' will be able to
+ retrieve it afterwards
+
+ The handlers can be customized extending this class
+ and setting the full path name of the extending class
+ into settings.CHATROOMS_HANDLERS_CLASS
+ """
+
+ def handle_received_message(self,
+ sender, room_id, user, message, date, **kwargs):
+ """
+ Default handler for the message_received signal.
+ 1 - Saves an instance of message to db
+ 2 - Appends a tuple (message_id, message_obj)
+ to the sender.messages queue
+ 3 - Signals the "New message" event on the sender
+ 4 - Returns the created message
+
+ A handler is a method accepting the following arguments:
+ signal, sender, room_id, user, message, date
+ """
+ room = Room.objects.get(id=room_id)
+ new_message = Message(user=user,
+ room=room,
+ date=date,
+ content=message)
+ new_message.save()
+ msg_number = sender.counters[room_id].next()
+ sender.messages[room_id].append((msg_number, new_message))
+
+ event = sender.new_message_events[room_id]
+ event.set()
+ event.clear()
+ return new_message
+
+ def retrieve_messages(self,
+ chatobj, room_id, *args, **kwargs):
+ """
+ Returns a list of tuples like:
+ [(message_id, message_obj), ...]
+ Where message_obj is an instance of Message or an object with
+ the attributes 'username', 'date' and 'content' at least
+
+ In this case, returns the queue of messages stored in
+ the ChatView.message dictionary by self.handle_received_message
+ """
+ return chatobj.messages[room_id]
+
+
+class MessageHandlerFactory(object):
+ """
+ Returns a (singleton) instance of the class set as
+ settings.CHATROOMS_HANDLERS_CLASS
+ if any, else returns an instance of MessageHandler
+ """
+ _instance = None
+
+ def __new__(cls):
+ klass = MessageHandler
+ if hasattr(settings, 'CHATROOMS_HANDLERS_CLASS'):
+ try:
+ klass = load_object(settings.CHATROOMS_HANDLERS_CLASS)
+ except (ImportError, TypeError):
+ raise ImproperlyConfigured(
+ "The class set as "
+ "settings.CHATROOMS_MESSAGES_RETRIEVING_FUNCTION "
+ "does not exists"
+ )
+
+ if not cls._instance:
+ cls._instance = klass()
+ return cls._instance
View
189 chatrooms/views.py
@@ -1,164 +1,25 @@
-# Create your views here.
-
-from django.http import HttpResponseForbidden, HttpResponseNotFound
-from django.shortcuts import render_to_response
-from django.contrib.auth.views import (
- login as django_login,
- logout as django_logout,
- logout_then_login,
- )
-
-from django.template import RequestContext
-from django.contrib.auth.decorators import login_required
-
-from livelessions.models import (
- DocenteCorso,
- Utente,
- Room,
- Iscritto)
-
-
-def main_page(request):
- return render_to_response(
- 'mainpage.html',
- {"title" : "main page",
- })
-
-
-def login(request):
- """Check if user is authenticated and signed in FAD,
- shows user page or login form
- """
- if request.user and request.user.is_authenticated():
- # check is user is a Docente or a Studente and shows respecting page
- username = request.user.username
- # looks up Utente primary key to match
- try:
- pk_utente = Utente.objects.get(username=username).pk
- except Utente.DoesNotExist:
- # user not signed in FAD Backend
- return not_a_fad_user(request)
- if DocenteCorso.objects.filter(fk_utente=pk_utente).exists():
- # set is_a_doc flag to true for future authentication
- request.user.is_a_doc = True
- request.user.fad_id_utente = pk_utente
- return doc_page(request)
- elif Iscritto.objects.filter(fk_utente=pk_utente).exists():
- # check is utente is signed on any catalogo corso
- # set is_a_doc to false for future authentication
- request.user.is_a_doc = False
- return student_page(request)
- else:
- # utente is neither a studente nor a docente
- return not_any_course(request)
- else:
- #return django.contrib.auth.views.login function
- return django_login(request)
-
-
-@login_required
-def doc_page(request):
- """"""
- utente_id = request.user.fad_id_utente
- # retrieve utente object and rooms
- utente = Utente.objects.get(pk_utente=utente_id)
- rooms = utente.rooms_as_publisher_set.all()
-
- # retrieve corsi docente
- corsi = utente.corsi_as_docente.all()
- schede_corsi = []
- for c in corsi:
- if c.get_scheda_corso not in schede_corsi:
- schede_corsi.append(c.get_scheda_corso)
- context = {
- 'username': request.user.username,
- 'active_rooms': rooms,
- 'schede_corsi': schede_corsi,
- }
- return render_to_response(
- "docpage.html",
- context,
- context_instance=RequestContext(request)
- )
-
-
-@login_required
-def student_page(request):
- utente = Utente.objects.get(username=request.user.username)
- corsi = utente.corsi_as_studente.all().values_list('pk', flat=True)
- rooms = Room.objects.filter(corso__in=corsi).order_by('corso')
- context = {
- "username": request.user.username,
- "active_rooms": rooms,
- }
- return render_to_response(
- "studentpage.html",
- context,
- context_instance=RequestContext(request)
- )
-
-
-def not_a_fad_user(request):
- """
- Logs out an user existing in auth_user table but not signed on FAD backend
- """
- return django_logout(
- request,
- template_name='registration/not_a_fad_user.html'
- )
-
-
-def not_any_course(request):
- return django_logout(
- request,
- template_name='registration/not_any_course.html'
- )
-
-
-def logout(request):
- """
- if request.user and request.user.is_authenticated():
- django_logout(request)
- return login(request)
- else:
- return login(request)
- """
- return logout_then_login(request, '/')
-
-
-@login_required
-def room_view(request, room_id):
- """"""
- try:
- room = Room.objects.get(pk=room_id)
- except Room.DoesNotExist:
- return HttpResponseNotFound('Room not found!!')
- utente = Utente.objects.get(username=request.user.username)
-
- context = {
- 'utente': request.user,
- 'room': room
- }
- if utente.is_publisher(room_id):
- template = 'broadcaster.html'
- else:
- # user is either a subscriber or not authorised
- if utente.is_subscriber(room_id):
- template = 'subscriber.html'
- else:
- # utente iscritto al corso
- room = Room.objects.get(pk=room_id)
- corso = room.corso
-
- if utente.corsi_as_studente.filter(pk=corso.pk).exists():
- room.subscribers.add(utente)
- room.save()
- template = 'subscriber.html'
- else:
- return HttpResponseForbidden('Forbidden resource')
- return render_to_response(
- template,
- context,
- context_instance=RequestContext(request)
- )
-
+#encoding=utf8
+
+from django.template import RequestContext
+from django.views.generic import ListView, DetailView
+
+from .models import Room
+
+
+class RoomsListView(ListView):
+ """
+ View to show the list of rooms available
+ """
+ context_object_name = "rooms"
+ queryset = Room.objects.all()
+ template_name = "chatrooms/rooms_list.html"
+ paginate_by = 2
+
+
+class RoomView(DetailView):
+ """
+ View for the single room
+ """
+ model = Room
+ context_object_name = 'room'
+ template_name = "chatrooms/room.html"
Please sign in to comment.
Something went wrong with that request. Please try again.