Skip to content

Commit

Permalink
add real-time to chat
Browse files Browse the repository at this point in the history
using web hooks the chat now pulls messages in real time. yet to add send message function.
  • Loading branch information
Taseen18 committed Mar 30, 2024
1 parent 09a49ee commit f48f0f8
Show file tree
Hide file tree
Showing 3,464 changed files with 614,599 additions and 9 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
Binary file added backend/backend/__pycache__/asgi.cpython-311.pyc
Binary file not shown.
Binary file modified backend/backend/__pycache__/settings.cpython-311.pyc
Binary file not shown.
13 changes: 11 additions & 2 deletions backend/backend/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,18 @@
"""

import os

from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import chat.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')

application = get_asgi_application()
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns
)
),
})
16 changes: 15 additions & 1 deletion backend/backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@
# Application definition

INSTALLED_APPS = [
'to_do_list',
"daphne",
'rest_framework',
'corsheaders',
'channels',
'to_do_list',
'chat',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand All @@ -43,6 +46,8 @@
'django.contrib.staticfiles',
]

ASGI_APPLICATION = 'backend.asgi.application'

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
Expand Down Expand Up @@ -151,6 +156,15 @@
}
'''

CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)], # Update this if your Redis isn't running on the default settings
},
},
}

SUPABASE_URL = 'https://yltkxqmckodbklfqdecl.supabase.co'
#DELETE THE BELOW KEYS WHEN COMMITTING TO GIT
SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlsdGt4cW1ja29kYmtsZnFkZWNsIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxMDIxNzE0NCwiZXhwIjoyMDI1NzkzMTQ0fQ.S_B9DjQveoPczkfqdZ4g1NANnRvqstuLdNaIX5bg4ds'
Expand Down
1 change: 1 addition & 0 deletions backend/chat/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default_app_config = 'chat.apps.ChatConfig'
Binary file modified backend/chat/__pycache__/__init__.cpython-311.pyc
Binary file not shown.
Binary file added backend/chat/__pycache__/admin.cpython-311.pyc
Binary file not shown.
Binary file added backend/chat/__pycache__/apps.cpython-311.pyc
Binary file not shown.
Binary file not shown.
Binary file added backend/chat/__pycache__/models.cpython-311.pyc
Binary file not shown.
Binary file added backend/chat/__pycache__/routing.cpython-311.pyc
Binary file not shown.
Binary file added backend/chat/__pycache__/signals.cpython-311.pyc
Binary file not shown.
Binary file modified backend/chat/__pycache__/views.cpython-311.pyc
Binary file not shown.
10 changes: 9 additions & 1 deletion backend/chat/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
from django.contrib import admin
from .models import Message, Chat

# Register your models here.
@admin.register(Message)
class MessageAdmin(admin.ModelAdmin):
list_display = ('content', 'sender', 'receiver', 'sent_at', 'chat_id')
search_fields = ('content', 'sender__username')

@admin.register(Chat)
class ChatAdmin(admin.ModelAdmin):
list_display = ('chat_id', 'last_message_at', 'employee_id', 'mhp_id')
3 changes: 3 additions & 0 deletions backend/chat/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
class ChatConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'chat'

def ready(self):
import chat.signals
61 changes: 61 additions & 0 deletions backend/chat/consumers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from channels.generic.websocket import AsyncWebsocketConsumer
import json
from .models import Message
from asgiref.sync import sync_to_async

class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
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()
print("webhook accepted")

recent_messages = await fetch_recent_messages(self.room_name)
for message in recent_messages:
await self.send_chat_message(message)


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 (not used here but included for completeness)
async def receive(self, text_data):
pass

async def chat_message(self, event):
await self.send(text_data=json.dumps({
'message': event['message']
}))

# Method to send chat messages to WebSocket
async def send_chat_message(self, message):
# Directly send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))

@sync_to_async
def fetch_recent_messages(room_name, limit=10):
print("Connecting to room:", room_name)
messages = Message.objects.filter(chat_id=room_name).order_by('sent_at')[:limit]
recent_messages = [{
"content": message.content,
"sender": message.sender.username,
"receiver": message.receiver.username,
"sent_at": message.sent_at.strftime("%Y-%m-%d %H:%M:%S")
} for message in messages]
print("Fetched messages:", recent_messages) # Debug print
return recent_messages

30 changes: 30 additions & 0 deletions backend/chat/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.0.2 on 2024-03-30 12:44

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Message',
fields=[
('message_id', models.AutoField(primary_key=True, serialize=False)),
('content', models.TextField()),
('sent_at', models.DateTimeField(auto_now_add=True)),
('receiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to=settings.AUTH_USER_MODEL)),
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['sent_at'],
},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.0.2 on 2024-03-30 12:47

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('chat', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AlterField(
model_name='message',
name='receiver',
field=models.ForeignKey(db_column='receiver_username', on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to=settings.AUTH_USER_MODEL, to_field='username'),
),
migrations.AlterField(
model_name='message',
name='sender',
field=models.ForeignKey(db_column='sender_username', on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL, to_field='username'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 5.0.2 on 2024-03-30 13:05

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('chat', '0002_alter_message_receiver_alter_message_sender'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AlterField(
model_name='message',
name='receiver',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to=settings.AUTH_USER_MODEL, to_field='username'),
),
migrations.AlterField(
model_name='message',
name='sender',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL, to_field='username'),
),
migrations.CreateModel(
name='Chat',
fields=[
('chat_id', models.AutoField(primary_key=True, serialize=False)),
('last_message_at', models.DateTimeField(auto_now=True)),
('employee_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='employee', to=settings.AUTH_USER_MODEL, to_field='username')),
('mhp_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mhp', to=settings.AUTH_USER_MODEL, to_field='username')),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Generated by Django 5.0.2 on 2024-03-30 13:14

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('chat', '0003_alter_message_receiver_alter_message_sender_chat'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.RemoveField(
model_name='chat',
name='employee_id',
),
migrations.RemoveField(
model_name='chat',
name='mhp_id',
),
migrations.AddField(
model_name='chat',
name='employee',
field=models.ForeignKey(default=55, on_delete=django.db.models.deletion.CASCADE, related_name='employee_id', to=settings.AUTH_USER_MODEL, to_field='username'),
preserve_default=False,
),
migrations.AddField(
model_name='chat',
name='mhp',
field=models.ForeignKey(default=56, on_delete=django.db.models.deletion.CASCADE, related_name='mhp_id', to=settings.AUTH_USER_MODEL, to_field='username'),
preserve_default=False,
),
migrations.AddField(
model_name='message',
name='chat',
field=models.ForeignKey(default=57, on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='chat.chat'),
preserve_default=False,
),
migrations.AlterField(
model_name='message',
name='receiver',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='receiver_id', to=settings.AUTH_USER_MODEL, to_field='username'),
),
migrations.AlterField(
model_name='message',
name='sender',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sender_id', to=settings.AUTH_USER_MODEL, to_field='username'),
),
]
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
18 changes: 17 additions & 1 deletion backend/chat/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
from django.db import models
from django.contrib.auth.models import User

# Create your models here.
class Message(models.Model):
message_id = models.AutoField(primary_key=True)
chat = models.ForeignKey('Chat', related_name='messages', on_delete=models.CASCADE)
content = models.TextField()
sender = models.ForeignKey(User, related_name='sender_id', on_delete=models.CASCADE, to_field='username')
receiver = models.ForeignKey(User, related_name='receiver_id', on_delete=models.CASCADE, to_field='username')
sent_at = models.DateTimeField(auto_now_add=True)

class Meta:
ordering = ['sent_at']

class Chat(models.Model):
chat_id = models.AutoField(primary_key=True)
employee = models.ForeignKey(User, related_name='employee_id', on_delete=models.CASCADE, to_field='username')
mhp = models.ForeignKey(User, related_name='mhp_id', on_delete=models.CASCADE, to_field='username')
last_message_at = models.DateTimeField(auto_now=True)
6 changes: 6 additions & 0 deletions backend/chat/routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.urls import path
from . import consumers

websocket_urlpatterns = [
path('ws/chat/<str:room_name>/', consumers.ChatConsumer.as_asgi()),
]
29 changes: 29 additions & 0 deletions backend/chat/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Message
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

@receiver(post_save, sender=Message)
def send_message_update(sender, instance, created, **kwargs):
if created:
channel_layer = get_channel_layer()
room_group_name = f'chat_{instance.chat_id}'

# Prepare the message content
message_content = {
'type': 'chat_message', # This should match the method name in your consumer
'message': {
'content': instance.content,
'sender': instance.sender.username,
"receiver": instance.receiver.username,
'sent_at': instance.sent_at.strftime("%Y-%m-%d %H:%M:%S") # Format datetime as string
}
}

# Send message to room group
async_to_sync(channel_layer.group_send)(
room_group_name,
message_content
)

4 changes: 3 additions & 1 deletion backend/chat/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, render
from .db_service import fetch_chats, fetch_messages
from django.contrib.auth.models import User



class GetChats(APIView):
permission_classes = [IsAuthenticated]

Expand Down
Binary file added backend/dump.rdb
Binary file not shown.
10 changes: 10 additions & 0 deletions venv/bin/automat-visualize
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
'''exec' "/Users/taseen/Library/Mobile Documents/com~apple~CloudDocs/QMUL/Year 2/Semester 2/SE Project/Prototype/Serenity/venv/bin/python" "$0" "$@"
' '''
# -*- coding: utf-8 -*-
import re
import sys
from automat._visualize import tool
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(tool())
10 changes: 10 additions & 0 deletions venv/bin/cftp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
'''exec' "/Users/taseen/Library/Mobile Documents/com~apple~CloudDocs/QMUL/Year 2/Semester 2/SE Project/Prototype/Serenity/venv/bin/python" "$0" "$@"
' '''
# -*- coding: utf-8 -*-
import re
import sys
from twisted.conch.scripts.cftp import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run())
10 changes: 10 additions & 0 deletions venv/bin/ckeygen
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
'''exec' "/Users/taseen/Library/Mobile Documents/com~apple~CloudDocs/QMUL/Year 2/Semester 2/SE Project/Prototype/Serenity/venv/bin/python" "$0" "$@"
' '''
# -*- coding: utf-8 -*-
import re
import sys
from twisted.conch.scripts.ckeygen import run
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run())
Loading

0 comments on commit f48f0f8

Please sign in to comment.