From 17573e1a76f05180425d8a4a7eb4f87e8dee69b6 Mon Sep 17 00:00:00 2001 From: Egor Matveev Date: Sun, 19 Dec 2021 23:15:19 +0300 Subject: [PATCH] chats --- Main/migrations/0009_auto_20211219_1958.py | 41 +++++++++++++++++++++ Main/models/__init__.py | 2 + Main/models/chat.py | 8 ++++ Main/models/message.py | 13 +++++++ Main/models/userinfo.py | 1 + Main/views/ChatView.py | 39 ++++++++++++++++++++ Main/views/ChatWithView.py | 30 +++++++++++++++ Main/views/MessagesView.py | 24 ++++++++++++ Main/views/__init__.py | 3 ++ templates/account.html | 10 ++++- templates/chat.html | 43 ++++++++++++++++++++++ templates/messages.html | 33 +++++++++++++++++ 12 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 Main/migrations/0009_auto_20211219_1958.py create mode 100644 Main/models/chat.py create mode 100644 Main/models/message.py create mode 100644 Main/views/ChatView.py create mode 100644 Main/views/ChatWithView.py create mode 100644 Main/views/MessagesView.py create mode 100644 templates/chat.html create mode 100644 templates/messages.html diff --git a/Main/migrations/0009_auto_20211219_1958.py b/Main/migrations/0009_auto_20211219_1958.py new file mode 100644 index 0000000..6571ece --- /dev/null +++ b/Main/migrations/0009_auto_20211219_1958.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.4 on 2021-12-19 16:58 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('Main', '0008_userinfo_notification_friends'), + ] + + operations = [ + migrations.CreateModel( + name='Chat', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('from_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='from_chat', to=settings.AUTH_USER_MODEL)), + ('to_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='to_chat', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddField( + model_name='userinfo', + name='notification_messages', + field=models.BooleanField(default=False), + ), + migrations.CreateModel( + name='Message', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField()), + ('read', models.BooleanField(default=False)), + ('time_sent', models.DateTimeField(default=django.utils.timezone.now)), + ('chat', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Main.chat')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/Main/models/__init__.py b/Main/models/__init__.py index fd4e376..53191ee 100644 --- a/Main/models/__init__.py +++ b/Main/models/__init__.py @@ -9,3 +9,5 @@ from Main.models.extrafile import ExtraFile from Main.models.progress import Progress from Main.models.solution_file import SolutionFile from Main.models.friendship import Friendship +from Main.models.chat import Chat +from Main.models.message import Message diff --git a/Main/models/chat.py b/Main/models/chat.py new file mode 100644 index 0000000..3c3c6df --- /dev/null +++ b/Main/models/chat.py @@ -0,0 +1,8 @@ +from django.contrib.auth.models import User +from django.db import models + + +class Chat(models.Model): + from_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="from_chat") + to_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="to_chat") + user = None diff --git a/Main/models/message.py b/Main/models/message.py new file mode 100644 index 0000000..c77f3cf --- /dev/null +++ b/Main/models/message.py @@ -0,0 +1,13 @@ +from django.contrib.auth.models import User +from django.db import models +from django.utils import timezone + +from Main.models.chat import Chat + + +class Message(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + chat = models.ForeignKey(Chat, on_delete=models.CASCADE) + text = models.TextField() + read = models.BooleanField(default=False) + time_sent = models.DateTimeField(default=timezone.now) diff --git a/Main/models/userinfo.py b/Main/models/userinfo.py index 7336160..bc92554 100644 --- a/Main/models/userinfo.py +++ b/Main/models/userinfo.py @@ -26,6 +26,7 @@ class UserInfo(models.Model): telegram_chat_id = models.TextField(default="") notification_solution_result = models.BooleanField(default=False) notification_friends = models.BooleanField(default=False) + notification_messages = models.BooleanField(default=False) code = models.IntegerField(null=True) verified = models.BooleanField(default=False) diff --git a/Main/views/ChatView.py b/Main/views/ChatView.py new file mode 100644 index 0000000..c7c8c5e --- /dev/null +++ b/Main/views/ChatView.py @@ -0,0 +1,39 @@ +from typing import Optional + +from django.utils import timezone + +from Main.management.commands.bot import bot +from Main.models import Chat, Message +from Sprint.settings import CONSTS +from SprintLib.BaseView import BaseView + + +class ChatView(BaseView): + endpoint = "chat" + required_login = True + view_file = "chat.html" + chat: Optional[Chat] = None + + def pre_handle(self): + if self.entities.chat.from_user == self.request.user: + self.entities.chat.user = self.entities.chat.to_user + else: + self.entities.chat.user = self.entities.chat.from_user + + def post(self): + Message.objects.create( + user=self.request.user, + chat=self.entities.chat, + text=self.request.POST["text"], + time_sent=timezone.now(), + ) + if ( + self.entities.chat.user.userinfo.activity_status != CONSTS["online_status"] + and self.entities.chat.user.userinfo.notification_messages + ): + bot.send_message( + self.entities.chat.user.userinfo.telegram_chat_id, + f"Пользователь {self.request.user.username} отправил сообщение:\n" + f"{self.request.POST['text']}", + ) + return "/chat?chat_id" + str(self.entities.chat.id) diff --git a/Main/views/ChatWithView.py b/Main/views/ChatWithView.py new file mode 100644 index 0000000..844343b --- /dev/null +++ b/Main/views/ChatWithView.py @@ -0,0 +1,30 @@ +from django.contrib.auth.models import User +from django.db.models import Q + +from Main.models import Chat +from SprintLib.BaseView import BaseView, AccessError + + +class ChatWithView(BaseView): + required_login = True + endpoint = "chat_with" + chat = None + + def pre_handle(self): + if "username" not in self.request.GET: + raise AccessError() + + def get(self): + chat = Chat.objects.filter( + Q( + from_user=self.request.user, + to_user__username=self.request.GET["username"], + ) + | Q( + to_user=self.request.user, + from_user__username=self.request.GET["username"], + ) + ).first() + if chat is None: + chat = Chat.objects.create(from_user=self.request.user, to_user=User.objects.get(username=self.request.GET['username'])) + return "/chat?chat_id=" + str(chat.id) diff --git a/Main/views/MessagesView.py b/Main/views/MessagesView.py new file mode 100644 index 0000000..1f65d35 --- /dev/null +++ b/Main/views/MessagesView.py @@ -0,0 +1,24 @@ +from Main.models import Message +from SprintLib.BaseView import BaseView, AccessError + + +class MessagesView(BaseView): + required_login = True + view_file = "messages.html" + endpoint = "messages" + page_size = 20 + + def pre_handle(self): + if not hasattr(self.entities, "chat") or 'page' not in self.request.GET: + raise AccessError() + if self.entities.chat.from_user != self.request.user and self.entities.chat.to_user != self.request.user: + raise AccessError() + + def get(self): + offset = (int(self.request.GET["page"]) - 1) * self.page_size + limit = self.page_size + messages = Message.objects.filter(chat=self.entities.chat).order_by("-time_sent") + messages.update(read=True) + self.context["messages"] = messages[offset:offset + limit] + self.context["count_pages"] = range(1, (len(messages) - 1) // self.page_size + 2) + self.context["need_pagination"] = len(self.context["count_pages"]) > 1 diff --git a/Main/views/__init__.py b/Main/views/__init__.py index d1d6d1a..84afa55 100644 --- a/Main/views/__init__.py +++ b/Main/views/__init__.py @@ -15,3 +15,6 @@ from Main.views.SendCodeView import SendCodeView from Main.views.SetSettingsView import SetSettingsView from Main.views.UsersView import UsersView from Main.views.SolutionsView import SolutionsView +from Main.views.ChatView import ChatView +from Main.views.ChatWithView import ChatWithView +from Main.views.MessagesView import MessagesView diff --git a/templates/account.html b/templates/account.html index 179d811..8c6e380 100644 --- a/templates/account.html +++ b/templates/account.html @@ -23,7 +23,7 @@

{{ account.userinfo.surname }} {{ account.userinfo.name }} - {{ account.userinfo.activity_status }} + {{ account.userinfo.activity_status }} {% if not owner %}
{% csrf_token %} @@ -133,6 +133,14 @@ + + + Сообщения в оффлайн + + + + + diff --git a/templates/chat.html b/templates/chat.html new file mode 100644 index 0000000..9cf0c75 --- /dev/null +++ b/templates/chat.html @@ -0,0 +1,43 @@ +{% extends 'base_main.html' %} + +{% block scripts %} + var page = 1; + function setPage(number) { + page = number; + } + function doPoll() { + jQuery.get('/messages?chat_id={{ chat.id }}&page=' + page.toString(), function(data) { + var e = document.getElementById('messages'); + if (e.innerHTML !== data) + e.innerHTML = data; + const name = "page_num_" + page.toString(); + elem = document.getElementById(name); + if (elem) { + elem.className = "btn btn-dark"; + } + setTimeout(function() {doPoll()}, 2000); + }) + } +{% endblock %} + +{% block onload %}doPoll(){% endblock %} + +{% block main %} +
+
+ +
+
+ +
+
+

{{ chat.user.username }}

+
+
+ + {% csrf_token %} + + +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/messages.html b/templates/messages.html new file mode 100644 index 0000000..b5cce9c --- /dev/null +++ b/templates/messages.html @@ -0,0 +1,33 @@ +{% if need_pagination %} +
+ + + {% for num in count_pages %} + + {% endfor %} + +
+
+{% endif %} +
+ {% for message in messages %} +
+ {% if message.user == user %} +
+
+ {% else %} +
+ {% endif %} +

{{ message.text }}

+ {% if message.user == user %} +
+ {% else %} +
+
+ +
+ {% endif %} + +
+ {% endfor %} +
\ No newline at end of file