diff --git a/flightmate/settings.py b/flightmate/settings.py index 08fd384e165249006ea27d370b0e029abea3b495..0ece708a14dff99b8c5152e8936ad8bd2ac34f07 100755 --- a/flightmate/settings.py +++ b/flightmate/settings.py @@ -23,7 +23,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SECRET_KEY = '#4h5=lswbghq65^otbpo16c^c1_@&winj16+nk+8naqc@dv-we' # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = False ALLOWED_HOSTS = ['*'] diff --git a/webapp/customers.py b/webapp/customers.py index 4634ce54184355615db6a1c68975112b0fc63335..cbd9d48c8e6d70f9b82d53e06e3f2edf42815b5a 100644 --- a/webapp/customers.py +++ b/webapp/customers.py @@ -1,29 +1,82 @@ -# 当接收到å‰ç«¯å‘æ¥çš„æ¶ˆæ¯æ—¶ï¼ŒåŽç«¯ä¼šè§¦å‘ws_message函数 +import re +import json +import logging from channels import Group -# def ws_message(message): -# # ASGI WebSocket packet-received and send-packet message types -# # both have a "text" key for their textual data. -# message.reply_channel.send({ -# "text": message.content['text'], -# }) - -# Connected to websocket.connect websocket连接的时候进行的æ“作 -def ws_add(message): - # Any user connecting to our app will be added to the “users†group and will receive messages sent by the server. - message.reply_channel.send({"accept": True}) - # Add to the chat group - Group("chat").add(message.reply_channel) - -# Connected to websocket.receive 收到消æ¯çš„æ—¶å€™è¿›è¡Œçš„æ“ä½œ -def ws_message(message): - Group("chat").send({ - "text": "[user] %s" % message.content['text'], - }) - -# Connected to websocket.disconnect å…³é—链接的时候进行的æ“作 -def ws_disconnect(message): - Group("chat").discard(message.reply_channel) - # When the client disconnects from our app, the channel is removed from the group, and the user will stop receiving messages. - # 这里利用了组的概念,在触å‘è¿žæŽ¥çš„æ—¶å€™ï¼ŒæŠŠå…¶åŠ å…¥chatç»„ï¼Œå½“æ”¶åˆ°æ¶ˆæ¯æ—¶å€™ï¼Œåœ¨ç»„内所有用户å‘é€ä¿¡æ¯ï¼Œæœ€åŽå…³é—连接的时候退出组。 +from channels.sessions import channel_session +from .models import Room + +log = logging.getLogger(__name__) + + +@channel_session +def ws_connect(message): + # Extract the room from the message. This expects message.path to be of the + # form /chat/{label}/, and finds a Room if the message path is applicable, + # and if the Room exists. Otherwise, bails (meaning this is a some othersort + # of websocket). So, this is effectively a version of _get_object_or_404. + try: + prefix, label = message['path'].decode('ascii').strip('/').split('/') + if prefix != 'chat': + log.debug('invalid ws path=%s', message['path']) + return + room = Room.objects.get(label=label) + except ValueError: + log.debug('invalid ws path=%s', message['path']) + return + except Room.DoesNotExist: + log.debug('ws room does not exist label=%s', label) + return + + log.debug('chat connect room=%s client=%s:%s', + room.label, message['client'][0], message['client'][1]) + + # Need to be explicit about the channel layer so that testability works + # This may be a FIXME? + Group('chat-' + label, channel_layer=message.channel_layer).add(message.reply_channel) + + message.channel_session['room'] = room.label + +@channel_session +def ws_receive(message): + # Look up the room from the channel session, bailing if it doesn't exist + try: + label = message.channel_session['room'] + room = Room.objects.get(label=label) + except KeyError: + log.debug('no room in channel_session') + return + except Room.DoesNotExist: + log.debug('recieved message, buy room does not exist label=%s', label) + return + + # Parse out a chat message from the content text, bailing if it doesn't + # conform to the expected message format. + try: + data = json.loads(message['text']) + except ValueError: + log.debug("ws message isn't json text=%s", text) + return + + if set(data.keys()) != set(('handle', 'message')): + log.debug("ws message unexpected format data=%s", data) + return + + if data: + log.debug('chat message room=%s handle=%s message=%s', + room.label, data['handle'], data['message']) + m = room.messages.create(**data) + + # See above for the note about Group + Group('chat-' + label, channel_layer=message.channel_layer).send({'text': json.dumps(m.as_dict())}) + + +@channel_session +def ws_disconnect(message): + try: + label = message.channel_session['room'] + room = Room.objects.get(label=label) + Group('chat-' + label, channel_layer=message.channel_layer).discard(message.reply_channel) + except (KeyError, Room.DoesNotExist): + pass diff --git a/webapp/models.py b/webapp/models.py index b73a104c7af9f90de4c910c7823d517cde3d4f81..516d5488da5642d57636248ca5a538dc5d3c6470 100755 --- a/webapp/models.py +++ b/webapp/models.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import uuid import datetime from django.db import models +from django.utils import timezone class FlightRecords(models.Model): frid = models.IntegerField(default=0) @@ -58,6 +59,30 @@ class FlightSeg(models.Model): self.full_clean() super(FlightSeg, self).save(*args, **kwargs) + +class Room(models.Model): + name = models.TextField() + label = models.SlugField(unique=True) + + def __unicode__(self): + return self.label + + +class Message(models.Model): + room = models.ForeignKey(Room, related_name='messages') + handle = models.TextField() + message = models.TextField() + timestamp = models.DateTimeField(default=timezone.now, db_index=True) + + def __unicode__(self): + return '[{timestamp}] {handle}: {message}'.format(**self.as_dict()) + + @property + def formatted_timestamp(self): + return self.timestamp.strftime('%b %-d %-I:%M %p') + + def as_dict(self): + return {'handle': self.handle, 'message': self.message, 'timestamp': self.formatted_timestamp} """ class Reserved(models.Model): user = models.ForeignKey(User, verbose_name='user_reserved', on_delete=models.CASCADE) diff --git a/webapp/urls.py b/webapp/urls.py index da724a760d84b4111c3af4635010daf9d97516d1..3b7ff3c66a5ba59a0598a5f2366eda92fd69e3fe 100644 --- a/webapp/urls.py +++ b/webapp/urls.py @@ -1,6 +1,6 @@ from django.conf.urls import include, url from webapp import views -from .views import user_list +from .views import log_in, log_out,sign_up, user_list urlpatterns = [ url(r'^$', views.index, name='index'), @@ -8,8 +8,11 @@ urlpatterns = [ url(r'^mobileapp$', views.mobileapp, name='mobileapp'), url(r'^account$', views.account, name='account'), url(r'^trip$', views.trip, name='trip'), - # link to user_list html + # link to user_list html, login and logout url(r'^$', user_list, name='user_list'), + url(r'^log_in/$', log_in, name='log_in'), + url(r'^log_out/$', log_out, name='log_out'), + url(r'^sign_up/$', sign_up, name='sign_up'), ] diff --git a/webapp/views.py b/webapp/views.py index 72262f18ed1316146ace2abfd73cb0ef83176824..7bf95dcc755c8521ba2cc2ac13b72f362d074bc3 100755 --- a/webapp/views.py +++ b/webapp/views.py @@ -6,11 +6,43 @@ from webapp.helper import updateModel, doHash, user_auth from django.contrib.sessions.backends.db import SessionStore from django.contrib.sessions.models import Session import json, datetime +from django.contrib.auth import login, logout +from django.contrib.auth.forms import AuthenticationForm +from django.core.urlresolvers import reverse +from django.shortcuts import render, redirect +from django.contrib.auth.forms import AuthenticationForm, UserCreationForm def user_list(request): return render(request, 'example/user_list.html') +def log_in(request): + form = AuthenticationForm() + if request.method == 'POST': + form = AuthenticationForm(data=request.POST) + if form.is_valid(): + login(request, form.get_user()) + return redirect(reverse('example:user_list')) + else: + print(form.errors) + return render(request, 'example/log_in.html', {'form': form}) + + +def log_out(request): + logout(request) + return redirect(reverse('example:log_in')) + +def sign_up(request): + form = UserCreationForm() + if request.method == 'POST': + form = UserCreationForm(data=request.POST) + if form.is_valid(): + form.save() + return redirect(reverse('example:log_in')) + else: + print(form.errors) + return render(request, 'example/sign_up.html', {'form': form}) + def trip(request): user = None token = request.GET.get("token", "") @@ -206,4 +238,44 @@ def query(request): return render(request, 'query.html', context) def mobileapp(request): - return render(request, 'mobileapp.html') \ No newline at end of file + return render(request, 'mobileapp.html') + +import random +import string +from django.db import transaction +from django.shortcuts import render, redirect +import haikunator +from .models import Room + +def about(request): + return render(request, "chat/about.html") + +def new_room(request): + """ + Randomly create a new room, and redirect to it. + """ + new_room = None + while not new_room: + with transaction.atomic(): + label = haikunator.haikunate() + if Room.objects.filter(label=label).exists(): + continue + new_room = Room.objects.create(label=label) + return redirect(chat_room, label=label) + +def chat_room(request, label): + """ + Room view - show the room, with latest messages. + The template for this view has the WebSocket business to send and stream + messages, so see the template for where the magic happens. + """ + # If the room with the given label doesn't exist, automatically create it + # upon first visit (a la etherpad). + room, created = Room.objects.get_or_create(label=label) + + # We want to show the last 50 messages, ordered most-recent-last + messages = reversed(room.messages.order_by('-timestamp')[:50]) + + return render(request, "chat/room.html", { + 'room': room, + 'messages': messages,