from channels.generic.websocket import WebsocketConsumer from django.shortcuts import get_object_or_404 from .models import * import json from django.template.loader import render_to_string from asgiref.sync import async_to_sync from channels.generic.websocket import WebsocketConsumer from django.shortcuts import get_object_or_404 from customercore.models import * import json from django.template.loader import render_to_string from asgiref.sync import async_to_sync from channels.generic.websocket import AsyncWebsocketConsumer from django.shortcuts import get_object_or_404 from datetime import datetime from asgiref.sync import sync_to_async import json class TicketRoomConsumer(AsyncWebsocketConsumer): async def connect(self): self.user = self.scope['user'] self.ticket_id = self.scope['url_route']['kwargs']['ticket_id'] self.ticket = await sync_to_async(get_object_or_404)(Ticket, id=self.ticket_id) self.ticket_number = self.ticket.ticket_number await sync_to_async(TicketConnection.objects.filter(ticket=self.ticket, user=self.user, terminated_at__isnull=True).delete)() await sync_to_async(TicketConnection.objects.create)( ticket=self.ticket, user=self.user, date=datetime.now() ) staff_profile = await sync_to_async(StaffProfile.objects.filter(user=self.user).first)() if staff_profile: if not await sync_to_async(TicketStaff.objects.filter(staff=staff_profile, ticket=self.ticket).exists)(): await sync_to_async(TicketStaff.objects.create)( staff=staff_profile, ticket=self.ticket, date_added=datetime.now() ) await self.channel_layer.group_add(self.ticket_number, self.channel_name) await self.accept() await self.modify_online_user() async def disconnect(self, close_code): await sync_to_async(TicketConnection.objects.filter(ticket=self.ticket, user=self.user).update)(terminated_at=datetime.now()) await self.channel_layer.group_discard(self.ticket_number, self.channel_name) await self.modify_online_user() async def receive(self, text_data): text_data_json = json.loads(text_data) event_type = text_data_json.get('event_type') if event_type == 'typing': event = { 'type': 'typing_handler', 'user': self.scope['user'] } await self.channel_layer.group_send(self.ticket_number, event) elif event_type == 'stop_typing': event = { 'type': 'stop_typing_handler', } await self.channel_layer.group_send(self.ticket_number, event) elif event_type == 'update_reaction': reaction = text_data_json['reaction'] update_id = text_data_json['update_id'] event = { 'type': 'reaction_handler', 'update_id': update_id, 'reaction': reaction, 'user': self.scope['user'] } await self.channel_layer.group_send(self.ticket_number, event) else: body = text_data_json['description'] file_paths = text_data_json['filePath'] ticketupdate = await sync_to_async(TicketUpdate.objects.create)( added_by=self.user, description=body, ticket=self.ticket, date_added=datetime.now() ) for file_path in file_paths: ticket_attachment = TicketAttachment( ticket_update=ticketupdate, file_path=file_path ) await sync_to_async(ticket_attachment.save)() event = { 'type': 'update_handler', 'update_id': ticketupdate.id } await self.channel_layer.group_send(self.ticket_number, event) async def update_handler(self, event): update_id = event['update_id'] update = await sync_to_async(TicketUpdate.objects.get)(id=update_id) context = { 'update': update, 'user': self.user } html = await sync_to_async(render_to_string)("details_templates/partials/new-ticket-message.html", context=context) await self.send(text_data=json.dumps({ 'event_type': 'update', 'html': html })) async def typing_handler(self, event): context = { 'user': event['user'] } html = await sync_to_async(render_to_string)("details_templates/partials/typing-message.html", context=context) await self.send(text_data=json.dumps({ 'event_type': 'typing', 'html': html })) async def stop_typing_handler(self, event): await self.send(text_data=json.dumps({ 'event_type': 'stop_typing' })) async def reaction_handler(self, event): update_id = event['update_id'] reaction = event['reaction'] user = self.user update = await sync_to_async(TicketUpdate.objects.get)(id=update_id) existing_reaction = await sync_to_async(TicketUpdateReaction.objects.filter)(ticket_update=update, customer=user).first() new_reaction = None if existing_reaction: if existing_reaction.reaction == reaction: await sync_to_async(existing_reaction.delete)() else: await sync_to_async(TicketUpdateReaction.objects.filter)(ticket_update=update, customer=user).delete() new_reaction = await sync_to_async(TicketUpdateReaction.objects.create)( ticket_update=update, reaction=reaction, customer=user ) else: new_reaction = await sync_to_async(TicketUpdateReaction.objects.create)( ticket_update=update, reaction=reaction, customer=user ) await self.send(text_data=json.dumps({ 'event_type': 'reaction', 'update_id': update_id, 'reaction': new_reaction.reaction if new_reaction else None })) async def modify_online_user(self): connections = await sync_to_async(TicketConnection.objects.filter)(ticket=self.ticket, terminated_at__isnull=True) event = { 'type': 'user_connection_handler', 'user': self.user, 'connections': connections, } await self.channel_layer.group_send(self.ticket_number, event) async def user_connection_handler(self, event): context = { 'connections': event['connections'], 'user': event['user'] } html = await sync_to_async(render_to_string)("details_templates/partials/ticket-online-users.html", context=context) await self.send(text_data=json.dumps({ 'event_type': 'user_status', 'html': html })) class NewTicketConsumer(WebsocketConsumer): def connect(self): self.user = self.scope['user'] async_to_sync(self.channel_layer.group_add)( "new_ticket_group", self.channel_name ) self.accept() def disconnect(self, close_code): async_to_sync(self.channel_layer.group_discard)( "new_ticket_group", self.channel_name ) def new_ticket_event(self, event): ticket_id = event['ticket_id'] ticket = Ticket.objects.get(id=ticket_id) is_ticketstaff_member = ( hasattr(self.user, 'staffprofile') and (self.user.staffprofile in ticket.get_all_ticket_staff() or self.user.is_superuser) ) is_ticket_customer = ( hasattr(self.user, 'customerprofile') and (self.user.customerprofile == ticket.customer)) if is_ticketstaff_member or is_ticket_customer: context = {'ticket': ticket, 'new': True} if is_ticketstaff_member: html = render_to_string("details_templates/partials/staff-ticket-display.html", context) else: html = render_to_string("details_templates/partials/customer-ticket-display.html", context) self.send(text_data=json.dumps({ 'event_type': 'new_ticket', 'html': html, 'ticket_id': ticket_id })) class NewTicketUpdateConsumer(WebsocketConsumer): def connect(self): self.user = self.scope['user'] async_to_sync(self.channel_layer.group_add)( "new_ticket_update_group", self.channel_name ) self.accept() def disconnect(self, close_code): async_to_sync(self.channel_layer.group_discard)( "new_ticket_update_group", self.channel_name ) def new_ticket_update_event(self, event): ticket_update_id = event['ticket_update_id'] ticket_update = TicketUpdate.objects.get(id=ticket_update_id) ticket = ticket_update.ticket ticket_id = ticket.id unread_updates_count = 0 for ticket_update in ticket.ticketupdate_set.exclude(added_by=self.user): if not TicketRead.objects.filter(ticket_update=ticket_update, user=self.user, read=True).exists(): unread_updates_count += 1 ticket.unread_updates_count = unread_updates_count is_ticketstaff_member = ( hasattr(self.user, 'staffprofile') and (self.user.staffprofile in ticket.get_all_ticket_staff() or self.user.is_superuser) ) is_ticket_customer = ( hasattr(self.user, 'customerprofile') and (self.user.customerprofile == ticket.customer)) if is_ticketstaff_member or is_ticket_customer: context = {'ticket': ticket, 'new': True} if is_ticketstaff_member: html = render_to_string("details_templates/partials/staff-ticket-display.html", context) else: html = render_to_string("details_templates/partials/customer-ticket-display.html", context) self.send(text_data=json.dumps({ 'event_type': 'new_ticket_update_group', 'html': html, 'ticket_id': ticket_id }))