This commit is contained in:
Egor Matveev 2021-12-19 23:15:19 +03:00
parent 014ab7a6b8
commit 17573e1a76
12 changed files with 246 additions and 1 deletions

View File

@ -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)),
],
),
]

View File

@ -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

8
Main/models/chat.py Normal file
View File

@ -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

13
Main/models/message.py Normal file
View File

@ -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)

View File

@ -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)

39
Main/views/ChatView.py Normal file
View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -23,7 +23,7 @@
<div class="col-9">
<h3>
{{ account.userinfo.surname }} {{ account.userinfo.name }}
<span style="margin-left: 15px; margin-bottom: 20px;" class="badge badge-{% if account.userinfo.activity_status == online_status %}success{% else %}secondary{% endif %}">{{ account.userinfo.activity_status }}</span>
<span style="margin-left: 15px; margin-bottom: 20px;" class="badge badge-{% if account.userinfo.activity_status == online_status %}success{% else %}secondary{% endif %}">{{ account.userinfo.activity_status }}</span> <a href="/chat_with?username={{ account.username }}"><i class="fa fa-comments"></i></a>
{% if not owner %}
<form method="POST">
{% csrf_token %}
@ -133,6 +133,14 @@
<input type="checkbox" name="notification_friends" {% if user.userinfo.notification_friends %}checked{% endif %}>
</td>
</tr>
<tr>
<td style="width: 200px;">
Сообщения в оффлайн
</td>
<td>
<input type="checkbox" name="notification_messages" {% if user.userinfo.notification_messages %}checked{% endif %}>
</td>
</tr>
</table>
<button type="submit" class="btn btn-light" style="margin-top: 15px;"><i class="fa fa-save"></i> Сохранить</button>

43
templates/chat.html Normal file
View File

@ -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 %}
<div class="row">
<div class="col">
<a href="/account?username={{ chat.user.username }}" style="font-size: 40px;"><i class="fa fa-arrow-left"></i></a>
</div>
<div class="col">
<img src="{{ chat.user.userinfo.profile_pic_url }}" width="50px" height="50px" style="border-radius: 50%; margin-right: 10px;">
</div>
<div class="col-10">
<p style="font-size: 40px;">{{ chat.user.username }}</p>
</div>
</div>
<form method="POST">
{% csrf_token %}
<textarea name="text" style="width: 100%; height: 100px;"></textarea>
<button type="submit" class="btn btn-dark">Отправить</button>
</form>
<div id="messages"></div>
{% endblock %}

33
templates/messages.html Normal file
View File

@ -0,0 +1,33 @@
{% if need_pagination %}
<div style="display: flex; justify-content: flex-end">
<table>
<tr>
{% for num in count_pages %}
<td><button class="btn btn-light" id="page_num_{{ num }}" onclick="setPage({{ num }})">{{ num }}</button></td>
{% endfor %}
</tr>
</table>
</div>
{% endif %}
<div class="container">
{% for message in messages %}
<div class="row" style="margin-bottom: 15px;">
{% if message.user == user %}
<div class="col-8"></div>
<div class="col-4" style="text-align: end; background-color: #b5deec; border-radius: 25px;">
{% else %}
<div class="col-4" style="background-color: #8ccde2; border-radius: 25px;">
{% endif %}
<p style="align-self: end; word-wrap: break-word;">{{ message.text }}</p>
{% if message.user == user %}
</div>
{% else %}
</div>
<div class="col-8">
</div>
{% endif %}
</div>
{% endfor %}
</div>