Skip to content

Commit 18ffcc1

Browse files
authored
Merge pull request #6 from josnin/featureLoadSave
save chat message using tortoise ORM
2 parents 22af504 + 126f31b commit 18ffcc1

File tree

12 files changed

+169
-9
lines changed

12 files changed

+169
-9
lines changed

chat/consumers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import json
22
from channels.generic.websocket import AsyncWebsocketConsumer
33
#from asgiref.sync import await_to_sync
4+
from chat.services import chat_save_message
5+
6+
47

58
class ChatConsumer(AsyncWebsocketConsumer):
69
""" handshake websocket front end """
@@ -20,6 +23,7 @@ async def connect(self):
2023

2124
await self.accept()
2225

26+
2327
async def disconnect(self, code):
2428
# Leave room group
2529
if self.room_group_name and self.channel_name:
@@ -47,6 +51,15 @@ async def receive(self, text_data=None, bytes_data=None):
4751
}
4852
)
4953

54+
await chat_save_message(
55+
username=self.scope['user'].username.title(),
56+
room_id=self.room_name,
57+
message=message,
58+
message_type=message_type,
59+
image_caption=image_caption
60+
)
61+
62+
5063
# Receive message from room group
5164
async def chat_message(self, event):
5265
""" exhange message here """

chat/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from django.db import models
22
from django.contrib.auth.models import Group
33

4+
5+
46
# Create your models here.
57
class ChatGroup(Group):
68
""" extend Group model to add extra info"""

chat/services.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
from tortoise import Tortoise, run_async
3+
from django.conf import settings
4+
from .tortoise_models import ChatMessage
5+
6+
async def chat_save_message(username, room_id, message, message_type, image_caption):
7+
8+
""" function to store chat message in sqlite """
9+
10+
await Tortoise.init(**settings.TORTOISE_INIT)
11+
await Tortoise.generate_schemas()
12+
13+
await ChatMessage.create(room_id=room_id,
14+
username=username,
15+
message=message,
16+
message_type=message_type,
17+
image_caption=image_caption
18+
)
19+
20+
await Tortoise.close_connections()

chat/static/chat/style.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,14 @@ svg {
581581
font-size: .93rem;
582582
}
583583

584+
.date_weekday {
585+
display: grid;
586+
justify-self: center;
587+
padding: 5px 12px 6px;
588+
font-size: 0.78rem;
589+
background-color: #e1f3faff;
590+
border-radius: 7.5px;
591+
width: fit-content;
592+
box-shadow: 0 1px .5px rgba(0,0,0,.13);
593+
line-height: 21px;
594+
}

chat/templates/chat/room.html

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
<script>
8585

8686
const roomId = '{{chatgroup.id}}'
87+
var tempDaysWeekdays = [];
8788

8889
const chatSocket = new WebSocket(
8990
`ws://${window.location.host}/ws/chat/${roomId}/`
@@ -116,7 +117,6 @@
116117

117118
document.querySelector('#chat-message-input').onpaste = function(e) {
118119
let item = e.clipboardData.items[0];
119-
console.log(item);
120120
if (item.type.includes('image')) {
121121
let blob = item.getAsFile();
122122

@@ -139,18 +139,27 @@
139139
msgbox.scrollTop = msgbox.scrollHeight
140140
}
141141

142-
function getTime() {
143-
let today = new Date();
142+
function getTime(msg_time) {
143+
if (msg_time) {
144+
// define as Date so we can convert to acceptable date time format (with out letter T, ex. 2020-10-10T06:50:14.751 )
145+
temp = new Date(msg_time);
146+
147+
// suffix UTC so it will render as local time when it use toLocalString
148+
var today = new Date(`${temp.toLocaleString()} UTC`);
149+
} else {
150+
var today = new Date();
151+
}
152+
153+
// format & render to local time
144154
let time = today.toLocaleString([], { hour: '2-digit', minute: '2-digit' });
145155
return time
146156

147157
}
148158

149-
function broadcastMessage(msg, user, msg_type, img_caption) {
159+
function broadcastMessage(msg, user, msg_type, img_caption, msg_time) {
150160
// create a new div element
151161
let newDiv = document.createElement("div");
152162
// and give it some content
153-
console.log(msg_type, 'broadcastMessage')
154163
if (msg_type == 'image') {
155164
msg = `<img src="${msg}"> <br/> ${img_caption}`;
156165
}
@@ -159,7 +168,7 @@
159168
var msg1 = `<div class="right-msg-container">
160169
<div class="s-message">
161170
<div class="s-msg">${msg}</div>
162-
<div class="s-time">${getTime()}</div>
171+
<div class="s-time">${getTime(msg_time)}</div>
163172
</div>
164173
<div class="s-tail"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 13" preserveAspectRatio="none" width="8" height="13"><path opacity=".5" d="M5.188 1H0v11.193l6.467-8.625C7.526 2.156 6.958 1 5.188 1z"></path><path fill="#dcf8c6ff" d="M5.188 0H0v11.193l6.467-8.625C7.526 1.156 6.958 0 5.188 0z"></path></svg></div>
165174
</div>`
@@ -169,10 +178,16 @@
169178
<div class="r-message" >
170179
<div class="r-user"><a href="#">${user}</a></div>
171180
<div class="r-msg">${msg}</div>
172-
<div class="r-time">${getTime()}</div>
181+
<div class="r-time">${getTime(msg_time)}</div>
173182
</div>
174183
</div>`
175184
}
185+
186+
if (msg_time) {
187+
showDatesWeekDays(msg_time)
188+
} else {
189+
showDatesWeekDays(new Date())
190+
}
176191

177192
newDiv.innerHTML = msg1;
178193

@@ -232,5 +247,56 @@
232247
}));
233248
}
234249

250+
251+
function showDatesWeekDays(date_created) {
252+
// add the newly created element and its content into the DOM
253+
254+
dt = new Date(date_created)
255+
256+
if (!tempDaysWeekdays.includes(dt.toLocaleDateString())) {
257+
let newDiv = document.createElement("div");
258+
let currentDiv = document.getElementById("new-message-chat");
259+
let parentDiv = currentDiv.parentNode;
260+
let days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
261+
262+
if (dt.toDateString() == new Date().toDateString()) {
263+
// display TODAY in message
264+
date_weekday = 'TODAY';
265+
} else if(dt > getDateBefore()) {
266+
// display week day in message
267+
date_weekday = days[dt.getDay()].toUpperCase()
268+
} else {
269+
// display date in message
270+
date_weekday = dt.toLocaleDateString();
271+
}
272+
273+
newDiv.style.display = "grid";
274+
newDiv.innerHTML = `<div class="date_weekday">${date_weekday}</div>`
275+
parentDiv.insertBefore(newDiv, currentDiv);
276+
277+
tempDaysWeekdays.push(dt.toLocaleDateString())
278+
}
279+
280+
}
281+
282+
function getDateBefore(days=7) {
283+
// calculate the last 7 days date
284+
// 7 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) * 1000 (milliseconds ) = 604800000 or 7 days in milliseconds.
285+
daysInMs= days * 24 * 60 * 60 * 1000
286+
return new Date(Date.now() - daysInMs)
287+
}
288+
289+
function loadMessage() {
290+
fetch("{% url 'chat:history' chatgroup.id %}")
291+
.then( response => response.json() )
292+
.then( data => {
293+
for (let msg of data) {
294+
broadcastMessage(msg.message, msg.username, msg.message_type, msg.image_caption, msg.date_created)
295+
}
296+
scrollBottom()
297+
})
298+
}
299+
loadMessage()
300+
235301
</script>
236302
{% endblock content %}

chat/tortoise_models.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
from tortoise import fields
3+
from tortoise.models import Model
4+
5+
class ChatMessage(Model):
6+
""" use to store chat history message
7+
make used of tortoise ORM since its support asyncio ORM
8+
"""
9+
id = fields.IntField(pk=True)
10+
room_id = fields.IntField(null=True)
11+
username = fields.CharField(max_length=50, null=True)
12+
message = fields.TextField()
13+
message_type = fields.CharField(max_length=50, null=True)
14+
image_caption = fields.CharField(max_length=50, null=True)
15+
date_created = fields.DatetimeField(null=True, auto_now_add=True)
16+
17+
class Meta:
18+
table = 'chat_chatmessage'
19+
20+
def __str__(self):
21+
return self.message

chat/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
urlpatterns = [
99
path('', views.index, name='index'),
10+
path('history/<str:room_id>/', views.history, name='history'),
1011
path('unauthorized/', views.unauthorized, name='unauthorized'),
1112
path('<str:group_id>/', views.room, name='room'),
1213
]

chat/views.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
from django.shortcuts import render
22
from django.contrib.auth.decorators import login_required
33
from django.urls import reverse
4-
from django.http import HttpResponseRedirect
4+
from django.http import HttpResponseRedirect, JsonResponse
5+
from asgiref.sync import sync_to_async
6+
from tortoise import Tortoise
7+
from django.conf import settings
58

69
# Create your views here.
710

811
# chat/views.py
912
from django.shortcuts import render
1013
from .models import ChatGroup
14+
from .tortoise_models import ChatMessage
1115

1216
@login_required
1317
def index(request):
@@ -46,4 +50,13 @@ def room(request, group_id):
4650

4751
@login_required
4852
def unauthorized(request):
49-
return render(request, 'chat/unauthorized.html', {})
53+
return render(request, 'chat/unauthorized.html', {})
54+
55+
56+
async def history(request, room_id):
57+
58+
await Tortoise.init(**settings.TORTOISE_INIT)
59+
chat_message = await ChatMessage.filter(room_id=room_id).order_by('date_created').values()
60+
await Tortoise.close_connections()
61+
62+
return await sync_to_async(JsonResponse)(chat_message, safe=False)

db.sqlite3.tortoise

12 KB
Binary file not shown.

django_channel_tutorial/settings.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,11 @@
134134

135135
MEDIA_URL = '/media/'
136136
MEDIA_ROOT = os.path.join(BASE_DIR, 'django_channel_tutorial/media')
137+
138+
139+
TORTOISE_INIT = {
140+
"db_url": "sqlite://db.sqlite3.tortoise",
141+
"modules" : {
142+
"models": ["chat.tortoise_models"]
143+
}
144+
}

0 commit comments

Comments
 (0)