from channels.generic.websocket import WebsocketConsumer from .models import * import json from django.template.loader import render_to_string from asgiref.sync import async_to_sync from django.shortcuts import get_object_or_404 import requests from django.forms.models import model_to_dict from django.core.serializers.json import DjangoJSONEncoder class OsitcomVisitor(WebsocketConsumer): def connect(self): async_to_sync(self.channel_layer.group_add)( 'ositcom_visitors', self.channel_name ) self.accept() self.visitor = None def disconnect(self, close_code): if self.visitor: self.current_log.left_date = datetime.now() self.current_log.save() async_to_sync(self.channel_layer.group_discard)( 'ositcom_visitors', self.channel_name ) def receive(self, text_data): text_data_json = json.loads(text_data) event_type = text_data_json.get('event_type') if event_type == 'visitor_ping': session_id = text_data_json.get('session_id') if Visitor.objects.filter(session_id=session_id).last(): self.visitor = Visitor.objects.filter(session_id=session_id).last() else: self.visitor = Visitor.objects.create( session_id = session_id, ip_address = text_data_json.get('client_ip'), country = text_data_json.get('country'), ) self.current_log = VisitorLog.objects.create( visitor = self.visitor, referrer = text_data_json.get('referrer'), url = text_data_json.get('url'), visit_date = datetime.now() ) class OsitcomChatRoom(WebsocketConsumer): def connect(self): self.session_id = self.scope['url_route']['kwargs']['session_id'] async_to_sync(self.channel_layer.group_add)( self.session_id, self.channel_name ) self.accept() self.visitor = Visitor.objects.filter(session_id=self.session_id).last() chat_room_guest = ChatRoomGuest.objects.filter(visitor=self.visitor).last() if chat_room_guest: chat_room = chat_room_guest.room self.chat_room = chat_room else: self.chat_room = None def disconnect(self, close_code): async_to_sync(self.channel_layer.group_discard)( self.session_id, self.channel_name ) def receive(self, text_data): text_data_json = json.loads(text_data) event_type = text_data_json.get('event_type') if event_type == 'load_chat': self.client_type = text_data_json.get('client_type') event = { 'reconnecting' : text_data_json.get('reconnecting') } self.load_chat_handler(event) if event_type == 'start_conversation': chat_room = ChatRoom.objects.create( name=f"Support: {self.session_id}", date_created = datetime.now() ) if text_data_json.get('guest_name'): self.visitor.name = text_data_json.get('guest_name') self.visitor.save() if text_data_json.get('guest_mobile_number'): self.visitor.mobile_number = text_data_json.get('guest_mobile_number') self.visitor.save() chat_room_guest = ChatRoomGuest.objects.create( room=chat_room, visitor=self.visitor ) self.chat_room = chat_room event = { 'type': 'start_conversation_handler', 'chat_room_id': chat_room.id } async_to_sync(self.channel_layer.group_send)( self.session_id, event ) if event_type == 'typing': event = { 'type': 'typing_handler', 'user_id': text_data_json.get('user_id'), 'typing_status': text_data_json.get('typing_status') } async_to_sync(self.channel_layer.group_send)( self.session_id, event ) if event_type == 'send_message': if text_data_json.get('user_id'): member = get_object_or_404(User, id=text_data_json.get('user_id')) else: member = None chat_message = ChatMessage.objects.create( member = member, room = self.chat_room, content= text_data_json.get('message'), date_sent = datetime.now() ) event = { 'type': 'send_message_handler', 'chat_message_id': chat_message.id } async_to_sync(self.channel_layer.group_send)( self.session_id, event ) if event_type == 'uploaded_file': if text_data_json.get('user_id'): member = get_object_or_404(User, id=text_data_json.get('user_id')) else: member = None message = ChatMessage.objects.create( member = member, room = self.chat_room, date_sent = datetime.now() ) message_attachment = ChatMessageAttachment.objects.create( message = message, attachment = text_data_json.get('path'), ) event = { 'type': 'uploaded_file_handler', 'message_attachment_id': message_attachment.id, 'file_type': text_data_json.get('file_type'), 'file_name': text_data_json.get('file_name'), } async_to_sync(self.channel_layer.group_send)( self.session_id, event ) if event_type == 'update_read_messages' and self.chat_room: latest_unread_message = None number_of_unread = 0 if text_data_json.get('user_id'): member = get_object_or_404(User, id=text_data_json.get('user_id')) guest = None if text_data_json.get('chat_state') == 'open': messages = ChatMessage.objects.filter(room=self.chat_room).exclude(member=member) for message in messages: seen_message = ChatMessageSeen.objects.filter( message=message, member=member ).exists() if not seen_message: ChatMessageSeen.objects.create( message=message, member=member, seen_date = datetime.now() ) number_of_unread = 0 else: number_of_unread = ChatMessage.objects.filter(room=self.chat_room).exclude(member = member, chatmessageseen__member=member).count() latest_unread_message = ChatMessage.objects.filter(room=self.chat_room).exclude(chatmessageseen__member=member).last() else: member = None guest = self.chat_room.chatroomguest if text_data_json.get('chat_state') == 'open': messages = ChatMessage.objects.filter(room=self.chat_room).exclude(member=None) for message in messages: seen_message = ChatMessageSeen.objects.filter( message=message, guest=guest ).exists() if not seen_message: ChatMessageSeen.objects.create( message=message, guest=guest, seen_date = datetime.now() ) number_of_unread = 0 else: number_of_unread = ChatMessage.objects.filter(room=self.chat_room, member__isnull=False).exclude(chatmessageseen__guest=guest).count() latest_unread_message = ChatMessage.objects.filter(room=self.chat_room, member__isnull=False).exclude(chatmessageseen__guest=guest).last() event = { 'type': 'update_read_messages_handler', 'number_of_unread': number_of_unread, 'latest_unread_message_id': latest_unread_message.id if latest_unread_message else None } self.update_read_messages_handler(event) if event_type == 'end_chat': event = { 'type': 'end_chat_handler', 'user_id': text_data_json.get('user_id') } async_to_sync(self.channel_layer.group_send)( self.session_id, event ) def load_chat_handler(self, event): if self.chat_room: chat_room = self.chat_room chat_room_messages = ChatMessage.objects.filter(room=chat_room).order_by('date_sent') else: chat_room = None chat_room_messages = None context = { 'chat_room': chat_room, 'chat_room_messages': chat_room_messages, } if self.client_type == 'mobile_admin': chat_room_data = model_to_dict(chat_room) chat_room_messages_data = [] for message in chat_room_messages: message_data = model_to_dict(message) attachment = getattr(message, 'chatmessageattachment', None) if attachment: message_data['attachment'] = { 'attachment': attachment.attachment, 'is_image': attachment.is_image(), 'file_name': attachment.file_name, } else: message_data['attachment'] = None chat_room_messages_data.append(message_data) self.send(text_data=json.dumps({ 'event_type': 'load_chat', 'chat_room_data': chat_room_data, 'chat_room_messages_data': chat_room_messages_data, }, cls=DjangoJSONEncoder)) elif self.client_type == 'website_admin': html = render_to_string("chat_templates/chat-widget.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'load_chat', 'html': html, })) else: if event.get('reconnecting') == 'False': #Connecting for the first time html = render_to_string("chat-widget.html", context=context) else: if chat_room: if chat_room.date_terminated: html = render_to_string("ended-chat.html", context=context) else: html = render_to_string("chat-room.html", context=context) else: html = render_to_string("start-chat.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'load_chat', 'html': html, })) def start_conversation_handler(self, event): chat_room = get_object_or_404(ChatRoom, id=event['chat_room_id']) context = { 'chat_room': chat_room, 'session_id':self.session_id } if self.client_type == 'mobile_admin': self.send(text_data=json.dumps({ 'event_type': 'start_conversation', 'context': context, })) else: html = render_to_string("chat-room.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'start_conversation', 'html': html, })) def typing_handler(self, event): if event.get('typing_status') == 'typing': if event.get('user_id'): member = get_object_or_404(User, id=event.get('user_id')) else: member = None context = { 'member': member, } html = render_to_string("partials/typing.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'typing', 'html': html, })) else: self.send(text_data=json.dumps({ 'event_type': 'stopped_typing', })) def send_message_handler(self, event): chat_message = get_object_or_404(ChatMessage, id=event['chat_message_id']) context = { 'chat_message': chat_message, } if self.client_type == 'mobile_admin': chat_message_data = model_to_dict(chat_message) self.send(text_data=json.dumps({ 'event_type': 'send_message', 'chat_message_data': chat_message_data, },cls=DjangoJSONEncoder)) elif self.client_type == 'website_admin': html = render_to_string("chat_templates/message.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'send_message', 'html': html, })) else: html = render_to_string("partials/message.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'send_message', 'user': chat_message.member.id if chat_message.member else None, 'html': html, })) def uploaded_file_handler(self, event): message_attachment = get_object_or_404(ChatMessageAttachment, id=event['message_attachment_id']) context = { 'message_attachment': message_attachment, 'file_type': event['file_type'] } if self.client_type == 'mobile_admin': message_attachment_data = model_to_dict(message_attachment) self.send(text_data=json.dumps({ 'event_type': 'uploaded_file', 'message_attachment_data': message_attachment_data, 'user': message_attachment.message.member.id if message_attachment.message.member else None, 'file_type': event['file_type'] },cls=DjangoJSONEncoder)) else: html = render_to_string("partials/message-attachment.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'uploaded_file', 'file_name': event['file_name'], 'user': message_attachment.message.member.id if message_attachment.message.member else None, 'html': html, })) def update_read_messages_handler(self, event): latest_unread_message_id = event.get('latest_unread_message_id') if latest_unread_message_id: latest_unread_message = get_object_or_404(ChatMessage, id=latest_unread_message_id) context = { 'number_of_unread' : event['number_of_unread'], 'latest_unread_message': latest_unread_message } html = render_to_string("partials/unread-messages.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'update_read_messages', 'html': html, })) else: latest_unread_message = None def end_chat_handler(self, event): if event['user_id']: member = get_object_or_404(User, id=event['user_id']) else: member = None self.chat_room.date_terminated = datetime.now() self.chat_room.terminated_by = member self.chat_room.save() context = { 'chat_room': self.chat_room, 'chat_room_messages': ChatMessage.objects.filter(room=self.chat_room).order_by('date_sent'), } html = render_to_string("ended-chat.html", context=context) self.send(text_data=json.dumps({ 'event_type': 'ended_chat', 'html': html, }))