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.progress import Progress
from Main.models.solution_file import SolutionFile from Main.models.solution_file import SolutionFile
from Main.models.friendship import Friendship 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="") telegram_chat_id = models.TextField(default="")
notification_solution_result = models.BooleanField(default=False) notification_solution_result = models.BooleanField(default=False)
notification_friends = models.BooleanField(default=False) notification_friends = models.BooleanField(default=False)
notification_messages = models.BooleanField(default=False)
code = models.IntegerField(null=True) code = models.IntegerField(null=True)
verified = models.BooleanField(default=False) 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.SetSettingsView import SetSettingsView
from Main.views.UsersView import UsersView from Main.views.UsersView import UsersView
from Main.views.SolutionsView import SolutionsView 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"> <div class="col-9">
<h3> <h3>
{{ account.userinfo.surname }} {{ account.userinfo.name }} {{ 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 %} {% if not owner %}
<form method="POST"> <form method="POST">
{% csrf_token %} {% csrf_token %}
@ -133,6 +133,14 @@
<input type="checkbox" name="notification_friends" {% if user.userinfo.notification_friends %}checked{% endif %}> <input type="checkbox" name="notification_friends" {% if user.userinfo.notification_friends %}checked{% endif %}>
</td> </td>
</tr> </tr>
<tr>
<td style="width: 200px;">
Сообщения в оффлайн
</td>
<td>
<input type="checkbox" name="notification_messages" {% if user.userinfo.notification_messages %}checked{% endif %}>
</td>
</tr>
</table> </table>
<button type="submit" class="btn btn-light" style="margin-top: 15px;"><i class="fa fa-save"></i> Сохранить</button> <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>