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 @@
+ {% endfor %} + |
{{ message.text }}
+ {% if message.user == user %} +