diff --git a/osinaweb/db.sqlite3 b/osinaweb/db.sqlite3 index d6d1ef97..51dfbe3c 100644 Binary files a/osinaweb/db.sqlite3 and b/osinaweb/db.sqlite3 differ diff --git a/osinaweb/osichat/__pycache__/admin.cpython-310.pyc b/osinaweb/osichat/__pycache__/admin.cpython-310.pyc index 2d3ede8d..6bd5fecb 100644 Binary files a/osinaweb/osichat/__pycache__/admin.cpython-310.pyc and b/osinaweb/osichat/__pycache__/admin.cpython-310.pyc differ diff --git a/osinaweb/osichat/__pycache__/consumers.cpython-310.pyc b/osinaweb/osichat/__pycache__/consumers.cpython-310.pyc index 5888301d..b8032527 100644 Binary files a/osinaweb/osichat/__pycache__/consumers.cpython-310.pyc and b/osinaweb/osichat/__pycache__/consumers.cpython-310.pyc differ diff --git a/osinaweb/osichat/__pycache__/models.cpython-310.pyc b/osinaweb/osichat/__pycache__/models.cpython-310.pyc index 1eb2f9e3..dea9d81b 100644 Binary files a/osinaweb/osichat/__pycache__/models.cpython-310.pyc and b/osinaweb/osichat/__pycache__/models.cpython-310.pyc differ diff --git a/osinaweb/osichat/__pycache__/routing.cpython-310.pyc b/osinaweb/osichat/__pycache__/routing.cpython-310.pyc index 3b115dfd..b1481969 100644 Binary files a/osinaweb/osichat/__pycache__/routing.cpython-310.pyc and b/osinaweb/osichat/__pycache__/routing.cpython-310.pyc differ diff --git a/osinaweb/osichat/admin.py b/osinaweb/osichat/admin.py index c5adceef..d8ffa8ea 100644 --- a/osinaweb/osichat/admin.py +++ b/osinaweb/osichat/admin.py @@ -3,6 +3,7 @@ from .models import * # Register your models here. admin.site.register(Visitor) admin.site.register(VisitorLog) +admin.site.register(ChatConnection) admin.site.register(ChatRoom) admin.site.register(ChatRoomGuest) admin.site.register(ChatMember) diff --git a/osinaweb/osichat/api/__pycache__/views.cpython-310.pyc b/osinaweb/osichat/api/__pycache__/views.cpython-310.pyc index e19c7c4f..72b333d9 100644 Binary files a/osinaweb/osichat/api/__pycache__/views.cpython-310.pyc and b/osinaweb/osichat/api/__pycache__/views.cpython-310.pyc differ diff --git a/osinaweb/osichat/api/views.py b/osinaweb/osichat/api/views.py index 66125306..b040b999 100644 --- a/osinaweb/osichat/api/views.py +++ b/osinaweb/osichat/api/views.py @@ -109,7 +109,7 @@ def get_staffs(request): "first_name": staff.user.first_name, "last_name": staff.user.last_name, "image": staff.image.url, - "last_seen": staff.get_last_seen + "last_seen": get_chat_last_seen(staff.user) } staffs_data.append(staff_data) diff --git a/osinaweb/osichat/consumers.py b/osinaweb/osichat/consumers.py index 3c709c6d..4ebeede2 100644 --- a/osinaweb/osichat/consumers.py +++ b/osinaweb/osichat/consumers.py @@ -8,6 +8,7 @@ from django.forms.models import model_to_dict from django.core.serializers.json import DjangoJSONEncoder from django.db.models import Case, When, F, Max, DateTimeField from django.db import transaction +import threading @@ -55,21 +56,39 @@ class OsitcomVisitor(WebsocketConsumer): - - class Osichat(WebsocketConsumer): def connect(self): self.user = self.scope["user"] + existing_connection = ChatConnection.objects.filter(user=self.user).last() + if existing_connection: + self.connection = existing_connection + self.connection.online = True + self.connection.disconnected = False + self.connection.save() + else: + self.connection = ChatConnection.objects.create(user=self.user, online=True) async_to_sync(self.channel_layer.group_add)( 'osichat', self.channel_name ) self.accept() def disconnect(self, close_code): + self.last_seen = datetime.now() + self.connection.disconnected = True + self.connection.save() + timer_thread = threading.Timer(3, self.check_disconnect_status) + timer_thread.start() async_to_sync(self.channel_layer.group_discard)( 'osichat', self.channel_name ) + def check_disconnect_status(self): + connection = ChatConnection.objects.filter(user=self.user).last() + if connection.disconnected: + self.connection.last_seen = self.last_seen + self.connection.online = False + self.connection.save() + def receive(self, text_data): data = json.loads(text_data) event_type = data.get('event_type') @@ -471,6 +490,16 @@ class OsitcomChatRoom(WebsocketConsumer): self.group, event ) + if event_type == 'recording': + event = { + 'type': 'recording_handler', + 'user_id': text_data_json.get('user_id'), + 'recording_status': text_data_json.get('recording_status') + } + async_to_sync(self.channel_layer.group_send)( + self.group, 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')) @@ -764,6 +793,34 @@ class OsitcomChatRoom(WebsocketConsumer): })) + def recording_handler(self, event): + if event.get('recording_status') == 'recording': + if event.get('user_id'): + member = get_object_or_404(User, id=event.get('user_id')) + else: + member = None + + context = { + 'member': member, + 'chat_room': self.chat_room, + 'domain': self.domain + } + if self.client_type == 'mobile_admin': + member_data = None + if member: + member_data = model_to_dict(member) + member_data['image'] = member.staffprofile.image.url if member.staffprofile and member.staffprofile.image else None + self.send(text_data=json.dumps({ + 'event_type': 'recording', + 'member_data': member_data, + }, cls=DjangoJSONEncoder)) + + else: + self.send(text_data=json.dumps({ + 'event_type': 'stopped_recording', + })) + + def send_message_handler(self, event): chat_message = get_object_or_404(ChatMessage, id=event['chat_message_id']) context = { diff --git a/osinaweb/osichat/migrations/0033_chatconnection.py b/osinaweb/osichat/migrations/0033_chatconnection.py new file mode 100644 index 00000000..2da68df5 --- /dev/null +++ b/osinaweb/osichat/migrations/0033_chatconnection.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.5 on 2024-10-03 12:27 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('osichat', '0032_remove_chatnotification_users_chatnotification_user'), + ] + + operations = [ + migrations.CreateModel( + name='ChatConnection', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField(null=True)), + ('online', models.BooleanField(default=True)), + ('last_seen', models.DateTimeField(blank=True, null=True)), + ('disconnected', models.BooleanField(default=False)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/osinaweb/osichat/migrations/__pycache__/0033_chatconnection.cpython-310.pyc b/osinaweb/osichat/migrations/__pycache__/0033_chatconnection.cpython-310.pyc new file mode 100644 index 00000000..de4b7e70 Binary files /dev/null and b/osinaweb/osichat/migrations/__pycache__/0033_chatconnection.cpython-310.pyc differ diff --git a/osinaweb/osichat/models.py b/osinaweb/osichat/models.py index 5509fdcf..31b71442 100644 --- a/osinaweb/osichat/models.py +++ b/osinaweb/osichat/models.py @@ -64,7 +64,6 @@ def send_notification(notification): - # Create your models here. class ChatNotification(models.Model): TYPES = ( @@ -211,6 +210,36 @@ class VisitorLog(models.Model): ) + +class ChatConnection(models.Model): + date = models.DateTimeField(null=True) + user = models.OneToOneField(User, on_delete=models.CASCADE) + online = models.BooleanField(default=True) + last_seen = models.DateTimeField(null=True, blank=True) + disconnected = models.BooleanField(default=False) + + + +def get_chat_last_seen(user): + connection = ChatConnection.objects.filter(user=user).last() + if not connection: + return "Not seen yet" + + if connection.online: + return "Online" + last_seen_time = connection.last_seen + now = timezone.now() + time_diff = now - last_seen_time + if time_diff < timedelta(days=1): + if last_seen_time.date() == now.date(): + return f"last seen today at {last_seen_time.strftime('%I:%M %p')}" + else: + return f"last seen yesterday at {last_seen_time.strftime('%I:%M %p')}" + else: + return f"last seen on {last_seen_time.strftime('%b %d at %I:%M %p')}" + + + class ChatRoom(models.Model): name = models.CharField(max_length=300) created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, blank=True) diff --git a/osinaweb/osinacore/__pycache__/models.cpython-310.pyc b/osinaweb/osinacore/__pycache__/models.cpython-310.pyc index c7a34dbb..847a4c4f 100644 Binary files a/osinaweb/osinacore/__pycache__/models.cpython-310.pyc and b/osinaweb/osinacore/__pycache__/models.cpython-310.pyc differ diff --git a/osinaweb/osinacore/models.py b/osinaweb/osinacore/models.py index 16337aab..cafdfbfd 100644 --- a/osinaweb/osinacore/models.py +++ b/osinaweb/osinacore/models.py @@ -13,6 +13,7 @@ from channels.layers import get_channel_layer from datetime import timedelta + # Create your models here. @@ -60,6 +61,7 @@ class CustomerProfile(models.Model): new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.customer_id = current_year + new_id # Add 'p' prefix super(CustomerProfile, self).save(*args, **kwargs) + @property def get_last_seen(self): connection = Connection.objects.filter(user=self.user).last() @@ -78,7 +80,6 @@ class CustomerProfile(models.Model): return f"last seen yesterday at {last_seen_time.strftime('%I:%M %p')}" else: return f"last seen on {last_seen_time.strftime('%b %d at %I:%M %p')}" - @@ -149,6 +150,7 @@ class StaffProfile(models.Model): new_id = str(int(max_id[-4:]) + 1).zfill(4) if max_id else '0001' # If no existing records, start with '0001' self.staff_id = 'O' + current_year + new_id # Add 'p' prefix super(StaffProfile, self).save(*args, **kwargs) + @property def get_last_seen(self): connection = Connection.objects.filter(user=self.user).last() @@ -167,10 +169,14 @@ class StaffProfile(models.Model): return f"last seen yesterday at {last_seen_time.strftime('%I:%M %p')}" else: return f"last seen on {last_seen_time.strftime('%b %d at %I:%M %p')}" + @property def active(self): return self.staffposition_set.filter(end_date__isnull=True).exists() + + + class StaffPosition(models.Model):