Add chat
This commit is contained in:
parent
2b30e08381
commit
33d0a75775
@ -1,7 +1,8 @@
|
|||||||
import json
|
import json
|
||||||
from channels.generic.websocket import AsyncWebsocketConsumer
|
from channels.generic.websocket import AsyncWebsocketConsumer
|
||||||
from asgiref.sync import sync_to_async
|
from asgiref.sync import sync_to_async
|
||||||
from .views import page_talks, page_about, page_single_talk, page_results, page_profiles
|
from .views import page_talks, page_about, page_single_talk, page_results, page_profiles, page_chat
|
||||||
|
from .models import Message
|
||||||
|
|
||||||
|
|
||||||
class WebsiteConsumer(AsyncWebsocketConsumer):
|
class WebsiteConsumer(AsyncWebsocketConsumer):
|
||||||
@ -62,14 +63,6 @@ class WebsiteConsumer(AsyncWebsocketConsumer):
|
|||||||
self.room_group_name, {"type": "send_page_profiles"}
|
self.room_group_name, {"type": "send_page_profiles"}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Chat
|
|
||||||
if data["value"] == "chat":
|
|
||||||
await self.channel_layer.group_send(
|
|
||||||
self.room_group_name, {
|
|
||||||
"type": "send_page_chat",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# About
|
# About
|
||||||
if data["value"] == "about":
|
if data["value"] == "about":
|
||||||
await self.channel_layer.group_send(
|
await self.channel_layer.group_send(
|
||||||
@ -112,14 +105,6 @@ class WebsiteConsumer(AsyncWebsocketConsumer):
|
|||||||
html = await sync_to_async(self._get_profiles)()
|
html = await sync_to_async(self._get_profiles)()
|
||||||
await self.send(text_data=html)
|
await self.send(text_data=html)
|
||||||
|
|
||||||
def _get_chat(self):
|
|
||||||
return page_chat()
|
|
||||||
|
|
||||||
async def send_page_chat(self, event):
|
|
||||||
"""Send Chat page"""
|
|
||||||
html = await sync_to_async(self._get_chat)()
|
|
||||||
await self.send(text_data=html)
|
|
||||||
|
|
||||||
def _get_about(self):
|
def _get_about(self):
|
||||||
return page_about()
|
return page_about()
|
||||||
|
|
||||||
@ -138,3 +123,69 @@ class WebsiteConsumer(AsyncWebsocketConsumer):
|
|||||||
else:
|
else:
|
||||||
html = await sync_to_async(self._get_talks)()
|
html = await sync_to_async(self._get_talks)()
|
||||||
await self.send(text_data=html)
|
await self.send(text_data=html)
|
||||||
|
|
||||||
|
|
||||||
|
class ChatConsumer(AsyncWebsocketConsumer):
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
|
||||||
|
# Room
|
||||||
|
self.room_name = "general"
|
||||||
|
# Group for Redis
|
||||||
|
self.room_group_name = f"chat_{self.room_name}"
|
||||||
|
|
||||||
|
# Join room group
|
||||||
|
await self.channel_layer.group_add(self.room_group_name, self.channel_name)
|
||||||
|
|
||||||
|
await self.accept()
|
||||||
|
|
||||||
|
# Send chat page
|
||||||
|
await self.channel_layer.group_send(
|
||||||
|
self.room_group_name,
|
||||||
|
{
|
||||||
|
"type": "send_page_chat",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
async def disconnect(self, close_code):
|
||||||
|
# Leave room group
|
||||||
|
await self.channel_layer.group_discard(self.room_group_name, self.channel_name)
|
||||||
|
|
||||||
|
# Receive message from WebSocket
|
||||||
|
async def receive(self, text_data):
|
||||||
|
|
||||||
|
# Get data
|
||||||
|
text_data_json = json.loads(text_data)
|
||||||
|
new_username = text_data_json["new-username"]
|
||||||
|
new_text = text_data_json["new-text"]
|
||||||
|
|
||||||
|
# Save message
|
||||||
|
await self.save_message(new_username, new_text)
|
||||||
|
|
||||||
|
# Send new HTML
|
||||||
|
await self.channel_layer.group_send(
|
||||||
|
self.room_group_name,
|
||||||
|
{
|
||||||
|
"type": "send_page_chat",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
@sync_to_async
|
||||||
|
def instance_message(self, username, text):
|
||||||
|
return Message.objects.create(
|
||||||
|
username=username,
|
||||||
|
text=text,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def save_message(self, username, text):
|
||||||
|
return await self.instance_message(username, text)
|
||||||
|
|
||||||
|
# Pages
|
||||||
|
|
||||||
|
def _get_chat(self):
|
||||||
|
return page_chat()
|
||||||
|
|
||||||
|
async def send_page_chat(self, event):
|
||||||
|
"""Send Home page"""
|
||||||
|
html = await sync_to_async(self._get_chat)()
|
||||||
|
await self.send(text_data=html)
|
27
app/website/migrations/0006_message.py
Normal file
27
app/website/migrations/0006_message.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Generated by Django 3.2.9 on 2021-11-23 18:31
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('website', '0005_auto_20211121_0757'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Message',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('username', models.CharField(default='', max_length=100, verbose_name='Alias')),
|
||||||
|
('text', models.TextField(max_length=500)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Message',
|
||||||
|
'verbose_name_plural': 'Messages',
|
||||||
|
'ordering': ('-created_at',),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
@ -75,3 +75,18 @@ class Talk(models.Model):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
|
class Message(models.Model):
|
||||||
|
|
||||||
|
username = models.CharField(max_length=100, verbose_name="Alias", default="")
|
||||||
|
text = models.TextField(max_length=500)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ("-created_at",)
|
||||||
|
verbose_name = "Message"
|
||||||
|
verbose_name_plural = "Messages"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.text[:10] + "..."
|
@ -4,4 +4,5 @@ from . import consumers
|
|||||||
|
|
||||||
websocket_urlpatterns = [
|
websocket_urlpatterns = [
|
||||||
re_path(r"ws/pages/(?P<room_id>\w+)/$", consumers.WebsiteConsumer),
|
re_path(r"ws/pages/(?P<room_id>\w+)/$", consumers.WebsiteConsumer),
|
||||||
|
re_path(r"ws/chat/$", consumers.ChatConsumer),
|
||||||
]
|
]
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
{# To page Chat #}
|
{# To page Chat #}
|
||||||
{% #link action="page" value="chat" scroll-up="true" %}Chat{% /link %}
|
<a href="#" onclick="document.querySelector('#chat').classList.toggle('hidden')">Chat</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
{# To page About #}
|
{# To page About #}
|
||||||
@ -49,5 +49,8 @@
|
|||||||
</header>
|
</header>
|
||||||
<main id="main"></main>
|
<main id="main"></main>
|
||||||
</div>
|
</div>
|
||||||
|
<section hx-ws="connect:ws:{{ DOMAIN }}/ws/chat/">
|
||||||
|
<div id="chat" class="hidden"></div>
|
||||||
|
</section>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,3 +1,63 @@
|
|||||||
<main id="main" data-scroll-to-top="true">
|
{% load slippers %}
|
||||||
soy el chat
|
<div id="chat" data-scroll-to-top="false">
|
||||||
</main>
|
<style>
|
||||||
|
#chat {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 17rem;
|
||||||
|
height: 35rem;
|
||||||
|
border: 1px solid;
|
||||||
|
padding: 1rem;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
margin: 0;
|
||||||
|
transition: .5s
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
left: -17rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages {
|
||||||
|
height: 10rem;
|
||||||
|
overflow-y: scroll;
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<h1>Chat</h1>
|
||||||
|
<div class="messages" data-scroll-to-bottom="true">
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{% for message in messages %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ message.username }}</th>
|
||||||
|
<td>{{ message.text }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<form>
|
||||||
|
<input type="hidden" name="action" value="new-message">
|
||||||
|
<label>
|
||||||
|
<span>Username:</span>
|
||||||
|
<input
|
||||||
|
id="new-username"
|
||||||
|
type="text"
|
||||||
|
name="new-username"
|
||||||
|
value=""
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<span>Message:</span>
|
||||||
|
<input
|
||||||
|
id="new-text"
|
||||||
|
type="text"
|
||||||
|
name="new-text"
|
||||||
|
value=""
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<input type="button" hx-ws="send" hx-trigger="click" value="Send">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
id="search"
|
id="search"
|
||||||
type="search"
|
type="search"
|
||||||
name="search"
|
name="search"
|
||||||
|
autocomplete="off"
|
||||||
hx-ws="send"
|
hx-ws="send"
|
||||||
hx-trigger="keyup changed delay:1s"
|
hx-trigger="keyup changed delay:1s"
|
||||||
value="{{ search }}"
|
value="{{ search }}"
|
||||||
|
@ -2,7 +2,7 @@ from django.shortcuts import render
|
|||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from random import randint
|
from random import randint
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from .models import Talk, Profile
|
from .models import Talk, Profile, Message
|
||||||
from asgiref.sync import sync_to_async
|
from asgiref.sync import sync_to_async
|
||||||
|
|
||||||
|
|
||||||
@ -67,3 +67,12 @@ def page_results(search):
|
|||||||
"search": search,
|
"search": search,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def page_chat():
|
||||||
|
return render_to_string(
|
||||||
|
"pages/chat.html",
|
||||||
|
{
|
||||||
|
"messages": Message.objects.order_by("created_at").all(),
|
||||||
|
},
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user