diff --git a/chat_box/asgi.py b/chat_box/asgi.py deleted file mode 100644 index 6044bc8..0000000 --- a/chat_box/asgi.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -ASGI entrypoint. Configures Django and then runs the application -defined in the ASGI_APPLICATION setting. -""" - -import os -import django -from channels.routing import get_default_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dmoj.settings") -django.setup() -application = get_default_application() diff --git a/chat_box/routing.py b/chat_box/routing.py deleted file mode 100644 index a91c8ad..0000000 --- a/chat_box/routing.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.urls import re_path - -from . import consumers - -ASGI_APPLICATION = "chat_box.routing.application" -websocket_urlpatterns = [ - re_path(r'ws/chat/', consumers.ChatConsumer), -] diff --git a/chat_box/views.py b/chat_box/views.py index 486051c..68d1d11 100644 --- a/chat_box/views.py +++ b/chat_box/views.py @@ -1,26 +1,119 @@ from django.utils.translation import gettext as _ from django.views.generic import ListView -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest from django.core.paginator import Paginator +from django.core.exceptions import PermissionDenied from django.shortcuts import render from django.forms.models import model_to_dict from django.utils import timezone +from django.contrib.auth.decorators import login_required +import datetime +from judge import event_poster as event from judge.jinja2.gravatar import gravatar from .models import Message, Profile import json -def format_messages(messages): - msg_list = [{ - 'time': msg.time, - 'author': msg.author, - 'body': msg.body, - 'image': gravatar(msg.author, 32), - 'id': msg.id, - 'css_class': msg.author.css_class, - } for msg in messages] - return json.dumps(msg_list, default=str) + +class ChatView(ListView): + context_object_name = 'message' + template_name = 'chat/chat.html' + title = _('Chat Box') + paginate_by = 50 + messages = Message.objects.filter(hidden=False) + paginator = Paginator(messages, paginate_by) + + def get_queryset(self): + return self.messages + + def get(self, request, *args, **kwargs): + page = request.GET.get('page') + if page == None: + return super().get(request, *args, **kwargs) + + cur_page = self.paginator.get_page(page) + + return render(request, 'chat/message_list.html', { + 'object_list': cur_page.object_list, + }) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context['title'] = self.title + context['last_msg'] = event.last() + context['online_users'] = get_user_online_status() + context['admin_status'] = get_admin_online_status() + context['today'] = timezone.now().strftime("%d-%m-%Y") + return context + + +def delete_message(request): + ret = {'delete': 'done'} + + if request.method == 'GET': + return JsonResponse(ret) + + if request.user.is_staff: + try: + messid = int(request.POST.get('message')) + mess = Message.objects.get(id=messid) + except: + return HttpResponseBadRequest() + + mess.hidden = True + mess.save() + + return JsonResponse(ret) + + return JsonResponse(ret) + + +@login_required +def post_message(request): + ret = {'msg': 'posted'} + + if request.method == 'GET': + return JsonResponse(ret) + + new_message = Message(author=request.profile, + body=request.POST['body']) + new_message.save() + + event.post('chat', { + 'type': 'new_message', + 'message': new_message.id, + }) + + return JsonResponse(ret) + +@login_required +def chat_message_ajax(request): + if request.method != 'GET': + return HttpResponseBadRequest() + + try: + message_id = request.GET['message'] + except KeyError: + return HttpResponseBadRequest() + + try: + message = Message.objects.filter(hidden=False).get(id=message_id) + except Message.DoesNotExist: + return HttpResponseBadRequest() + return render(request, 'chat/message.html', { + 'message': message, + }) + + +def get_user_online_status(): + last_five_minutes = timezone.now()-timezone.timedelta(minutes=5) + return Profile.objects \ + .filter(display_rank='user', + last_access__gte = last_five_minutes)\ + .order_by('-rating') + def get_admin_online_status(): all_admin = Profile.objects.filter(display_rank='admin') @@ -35,63 +128,10 @@ def get_admin_online_status(): return ret -class ChatView(ListView): - model = Message - context_object_name = 'message' - template_name = 'chat/chat.html' - title = _('Chat Box') - paginate_by = 50 - paginator = Paginator(Message.objects.filter(hidden=False), paginate_by) - def get_queryset(self): - return Message.objects.filter(hidden=False) - - def get(self, request, *args, **kwargs): - page = request.GET.get('page') - if (page == None): - # return render(request, 'chat/chat.html', {'message': format_messages(Message.objects.all())}) - return super().get(request, *args, **kwargs) - - cur_page = self.paginator.get_page(page) - return HttpResponse(format_messages(cur_page.object_list)) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - - # hard code, should be fixed later - address = f'{self.request.get_host()}/ws/chat/' - if self.request.is_secure(): - context['ws_address'] = f'wss://{address}' - else: - context['ws_address'] = f'ws://{address}' - - context['title'] = self.title - last_five_minutes = timezone.now()-timezone.timedelta(minutes=5) - context['online_users'] = Profile.objects \ - .filter(display_rank='user', - last_access__gte = last_five_minutes)\ - .order_by('-rating') - context['admin_status'] = get_admin_online_status() - return context - -def delete_message(request): - ret = {'delete': 'done'} - - if request.method == 'GET': - return JsonResponse(ret) - - if request.user.is_staff: - messid = int(request.POST.get('messid')) - all_mess = Message.objects.all() - - for mess in all_mess: - if mess.id == messid: - mess.hidden = True - mess.save() - new_elt = {'time': mess.time, 'content': mess.body} - ret = new_elt - break - - return JsonResponse(ret) - - return JsonResponse(ret) +@login_required +def online_status_ajax(request): + return render(request, 'chat/online_status.html', { + 'online_users': get_user_online_status(), + 'admin_status': get_admin_online_status(), + }) \ No newline at end of file diff --git a/dmoj/routing.py b/dmoj/routing.py deleted file mode 100644 index 72e0379..0000000 --- a/dmoj/routing.py +++ /dev/null @@ -1,12 +0,0 @@ -from channels.auth import AuthMiddlewareStack -from channels.routing import ProtocolTypeRouter, URLRouter -import chat_box.routing - -application = ProtocolTypeRouter({ - # (http->django views is added by default) - 'websocket': AuthMiddlewareStack( - URLRouter( - chat_box.routing.websocket_urlpatterns - ) - ), -}) \ No newline at end of file diff --git a/dmoj/settings.py b/dmoj/settings.py index 90237ec..3b363fd 100644 --- a/dmoj/settings.py +++ b/dmoj/settings.py @@ -243,7 +243,6 @@ INSTALLED_APPS += ( 'impersonate', 'django_jinja', 'chat_box', - 'channels', 'newsletter', ) @@ -513,17 +512,6 @@ FILE_UPLOAD_PERMISSIONS = 0o644 MESSAGES_TO_LOAD = 15 -ASGI_APPLICATION = 'dmoj.routing.application' -CHANNEL_LAYERS = { - 'default': { - 'BACKEND': 'channels_redis.core.RedisChannelLayer', - 'CONFIG': { - "hosts": [('0.0.0.0', 6379)], - }, - }, -} - - NEWSLETTER_CONFIRM_EMAIL = False # Amount of seconds to wait between each email. Here 100ms is used. diff --git a/dmoj/urls.py b/dmoj/urls.py index 1573c4b..2801a51 100644 --- a/dmoj/urls.py +++ b/dmoj/urls.py @@ -1,4 +1,4 @@ -from chat_box.views import ChatView, delete_message +from chat_box.views import ChatView, delete_message, post_message, chat_message_ajax, online_status_ajax from django.conf import settings from django.conf.urls import include, url from django.contrib import admin @@ -372,8 +372,10 @@ urlpatterns = [ url(r'^$', login_required(ChatView.as_view()), name='chat'), - url(r'^delete/$', delete_message, name='delete_message') - + url(r'^delete/$', delete_message, name='delete_chat_message'), + url(r'^post/$', post_message, name='post_chat_message'), + url(r'^ajax$', chat_message_ajax, name='chat_message_ajax'), + url(r'^online_status/ajax$', online_status_ajax, name='online_status_ajax') ])), url(r'^notifications/', diff --git a/requirements.txt b/requirements.txt index e718308..ee3341e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,9 +30,6 @@ packaging celery -e git://github.com/DMOJ/ansi2html.git#egg=ansi2html sqlparse -channels==2.4.0 -channels-redis==2.4.2 -docker django-newsletter netaddr redis diff --git a/resources/chatbox.scss b/resources/chatbox.scss index 52eda9c..1cf0491 100644 --- a/resources/chatbox.scss +++ b/resources/chatbox.scss @@ -51,11 +51,14 @@ .clear { clear: both; } + .content-message { word-wrap: break-word; - white-space: pre-line; } +.content-message p { + margin: 0; +} #chat-area { height: 85vh; diff --git a/templates/chat/chat.html b/templates/chat/chat.html index 122ab2c..620cc5e 100644 --- a/templates/chat/chat.html +++ b/templates/chat/chat.html @@ -4,135 +4,106 @@ {% block title %} {{_('Chat Box')}} {% endblock %} {% block js_media %} - - + + {% endblock js_media %} {% block media %} - + {% endblock media %} {% block body %} @@ -244,6 +239,7 @@