Skip to content

Commit

Permalink
Cleaner chat model
Browse files Browse the repository at this point in the history
  • Loading branch information
dimbleby committed Aug 12, 2023
1 parent 2c29472 commit 6a2c59d
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 46 deletions.
61 changes: 33 additions & 28 deletions hunt/chat/consumers.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,44 @@
import json
from typing import TYPE_CHECKING

from asgiref.sync import sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from django.contrib.auth.models import User

from hunt.models import ChatMessage
from hunt.models import ChatMessage, Level

if TYPE_CHECKING:
from django.contrib.auth.models import User


class ChatConsumer(AsyncWebsocketConsumer): # type: ignore[misc]
async def connect(self) -> None:
room_name: str = self.scope["url_route"]["kwargs"]["room_name"]
room_team, _room_level = room_name.rsplit("_", 1)
self.room_name = room_name
self.room_group_name = f"chat_{room_name}"
self.team = room_team
def __init__(self) -> None:
super().__init__()
self.team: User | None = None
self.level: Level | None = None
self.room_group: str | None = None

# Verify that the user is authenticated and is allowed into this room.
async def connect(self) -> None:
user: User = self.scope["user"]
level: int = self.scope["url_route"]["kwargs"]["level"]

if not user.is_authenticated:
await self.close()
return

team = user.get_username()
if team != self.team:
await self.close()
return
self.team = user
self.level = await self.get_level(level)
self.room_group = f"{user.get_username()}_{level}"

# Join room group
await self.channel_layer.group_add(self.room_group_name, self.channel_name)
await self.channel_layer.group_add(self.room_group, self.channel_name)
await self.accept()

async def disconnect(
self,
code: int, # noqa: ARG002
) -> None:
# Leave room group
await self.channel_layer.group_discard(self.room_group_name, self.channel_name)
if self.room_group is not None:
await self.channel_layer.group_discard(self.room_group, self.channel_name)

# Receive message from WebSocket
async def receive(self, text_data: str) -> None:
Expand All @@ -46,8 +49,9 @@ async def receive(self, text_data: str) -> None:
await self.save_message(username, message)

# Send message to room group
assert self.room_group is not None
await self.channel_layer.group_send(
self.room_group_name,
self.room_group,
{"type": "chat_message", "message": message, "username": username},
)

Expand All @@ -63,14 +67,15 @@ async def chat_message(self, event: dict[str, str]) -> None:

@sync_to_async
def save_message(self, username: str, message: str) -> None:
try:
team_user = User.objects.get(username=self.team)
ChatMessage.objects.create(
name=username,
team=team_user,
room=self.room_name,
content=message,
)
except User.DoesNotExist:
# We don't know which team made this message, so don't save it
pass
chat_message = ChatMessage(
team=self.team,
level=self.level,
name=username,
content=message,
)
chat_message.full_clean()
chat_message.save()

@sync_to_async
def get_level(self, number: int) -> Level:
return Level.objects.get(number=number)
2 changes: 1 addition & 1 deletion hunt/chat/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
from hunt.chat import consumers

websocket_urlpatterns = [
path("ws/<str:room_name>/", consumers.ChatConsumer.as_asgi()),
path("level/<int:level>/", consumers.ChatConsumer.as_asgi()),
]
6 changes: 1 addition & 5 deletions hunt/levels.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ def maybe_load_level(request: AuthenticatedHttpRequest, level_num: int) -> str:
desc_paras = previous_level.description.splitlines()

template = loader.get_template("level.html")
chatroom_name = f"{request.user.get_username()}_{current_level.number}"
context = {
"team_level": team_level,
"level_number": current_level.number,
Expand All @@ -127,10 +126,7 @@ def maybe_load_level(request: AuthenticatedHttpRequest, level_num: int) -> str:
"latitude": previous_level.latitude,
"longitude": previous_level.longitude,
"is_last": is_last_level,
"chatroom": chatroom_name,
"messages": ChatMessage.objects.filter(
room=chatroom_name, team=request.user
),
"messages": ChatMessage.objects.filter(team=user, level=current_level),
}
else:
# Shouldn't be here. Show an error page.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Generated by Django 4.2.4 on 2023-08-12 17:56


import django.db.models.deletion
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor


def set_chat_message_levels(
apps: Apps, schema_editor: BaseDatabaseSchemaEditor
) -> None:
chat_message = apps.get_model("hunt", "ChatMessage")
level = apps.get_model("hunt", "Level")
for message in chat_message.objects.all().iterator():
_, number = message.room.rsplit("_", 1)
message.level = level.objects.get(number=number)
message.save()


class Migration(migrations.Migration):
dependencies = [
("hunt", "0004_chatmessage"),
]

operations = [
migrations.AddField(
model_name="chatmessage",
name="level",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="hunt.level",
),
preserve_default=False,
),
migrations.RunPython(set_chat_message_levels),
migrations.RemoveField(
model_name="chatmessage",
name="room",
),
migrations.AlterField(
model_name="chatmessage",
name="level",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="hunt.level",
),
preserve_default=False,
),
migrations.AlterField(
model_name="chatmessage",
name="name",
field=models.CharField(max_length=32),
),
]
14 changes: 11 additions & 3 deletions hunt/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ def __str__(self) -> str:


class ChatMessage(models.Model):
name = models.CharField(max_length=255)
team = models.ForeignKey(User, on_delete=models.CASCADE, related_name="+")
room = models.CharField(max_length=255)
level = models.ForeignKey(Level, on_delete=models.CASCADE, related_name="+")
name = models.CharField(max_length=32)
content = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)

Expand All @@ -133,4 +133,12 @@ class Meta:

@override
def __str__(self) -> str:
return f"Room: {self.room}, User: {self.name}, Message: {self.content}"
text = ", ".join(
[
f"{self.team.get_username()}",
f"{self.level}",
f"User: {self.name}",
f"Message: {self.content}",
]
)
return text
2 changes: 1 addition & 1 deletion hunt/templates/level.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ <h3>{{ latitude }}, {{ longitude }}</h3>
{% endif %}
{% endif %}
</div>
{% include "room.html" with room_name=chatroom username="Anonymous" %}
{% include "room.html" %}
{% endblock %}
15 changes: 7 additions & 8 deletions hunt/templates/room.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<div id="username">
<div class="field">
<div class="control">
<input class="input" type="text" placeholder="Anonymous" id="username-input">
<input class="input" type="text" placeholder="Username" id="username-input">
</div>
</div>

Expand All @@ -55,20 +55,15 @@
</div>
</div>

{{ room_name|json_script:"json-roomname" }}

<script>
const roomName = JSON.parse(document.getElementById('json-roomname').textContent);
var ws_scheme = window.location.protocol === "https:" ? "wss" : "ws";
var userName = "";

const chatSocket = new WebSocket(
ws_scheme
+ '://'
+ window.location.host
+ '/ws/'
+ roomName
+ '/'
+ '/level/{{ level_number }}/'
);

chatSocket.onclose = function(e) {
Expand Down Expand Up @@ -119,7 +114,11 @@
};

document.querySelector('#username-submit').onclick = function(e) {
userName = document.querySelector('#username-input').value;
const value = document.querySelector('#username-input').value;
if ((value.length === 0) || (value.length > 32)) {
return;
}
userName = value;
document.querySelector('#chat').removeAttribute("hidden");
document.querySelector('#username').setAttribute("hidden", true);
document.querySelector('#username-display').innerHTML = "Your username: " + userName
Expand Down

0 comments on commit 6a2c59d

Please sign in to comment.