django-chelseru 2.0.5__py3-none-any.whl → 2.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-chelseru
3
- Version: 2.0.5
3
+ Version: 2.1.0
4
4
  Summary: Authentication system, online and real-time chat, SMS & BANK system for Iranian SMS services.
5
5
  Home-page: https://pipdjango.chelseru.com
6
6
  Author: Sobhan Bahman Rashnu
@@ -8,7 +8,7 @@ Author-email: bahmanrashnu@gmail.com
8
8
  Project-URL: Documentation, https://github.com/Chelseru/django-chelseru-lour/
9
9
  Project-URL: Telegram Group, https://t.me/bahmanpy
10
10
  Project-URL: Telegram Channel, https://t.me/ChelseruCom
11
- Keywords: djangochelseruchat djangochat drfchat online-chat online real-time chat iran chelseru lor lur bahman rashnu rashno lak lour sms djangoauth auth ywt otpauth otp authentication djangootp djangoiransms iransms djangosms djangokavenegar djangomelipayamak sobhan چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم
11
+ Keywords: djangochelseru chelseru djangochelseruchat djangochat drfchat online-chat online real-time chat iran chelseru lor lur bahman rashnu rashno lak lour sms djangoauth auth ywt otpauth otp authentication djangootp djangoiransms iransms djangosms djangokavenegar djangomelipayamak sobhan چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Framework :: Django
14
14
  Classifier: License :: OSI Approved :: MIT License
@@ -1,19 +1,19 @@
1
- django_chelseru-2.0.5.dist-info/licenses/LICENSE,sha256=VupU5KV4NteHaNQb-WH31G_WZWezxXoomjiCIAHoQJo,1089
1
+ django_chelseru-2.1.0.dist-info/licenses/LICENSE,sha256=VupU5KV4NteHaNQb-WH31G_WZWezxXoomjiCIAHoQJo,1089
2
2
  drfchelseru/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- drfchelseru/admin.py,sha256=uamcWPCCw9_dD00XL8Brp8A1NvfhB5FtUfF9DWQCK9c,1022
3
+ drfchelseru/admin.py,sha256=xKGZuzC-_VnMz0LbN31Owvi0pb4tDRd6dWKnkKyTPY0,4373
4
4
  drfchelseru/apps.py,sha256=hOTTzFGLXiTPZeN8p_LLcSECLtsR2Q0SUo8zJzgM-qQ,211
5
- drfchelseru/consumers.py,sha256=c8h9JYu5QUSKRREFrIrkjpkEQTzG5V8eg2lriaZODsc,2614
5
+ drfchelseru/consumers.py,sha256=uh_EJzkZI_eYBCY03kqaSFd9pvAuAihcQxsXuTlXt4g,2727
6
6
  drfchelseru/middlewares.py,sha256=Ej_9GTlVPzfzYAUqxUn7VHJRdlywQmrbSIW43yK5q5U,3818
7
- drfchelseru/models.py,sha256=jQ5IbS5q4GufZC9W_zgX1Qg8YU_f8V-Jusbh5hQYPhQ,11214
7
+ drfchelseru/models.py,sha256=8tiQ0TJo8kyaoIKAgfN2TiD0SewSQMOlXz43BcfAHlc,11683
8
8
  drfchelseru/routing.py,sha256=shAlgzcIwVuVPlvKeWBLCqr6PuBTHyIrWNgHEfnqrxg,165
9
- drfchelseru/serializers.py,sha256=I3kS2NhzIprY8-WWhjQPShAom6R7epg7do7RnDkpnys,1421
9
+ drfchelseru/serializers.py,sha256=yVc9PQHaoihatoJaDiYK7r3F9xQnv0zd6D5JPBbSGtI,2445
10
10
  drfchelseru/services.py,sha256=K-VzisPliuKv0BL6Z3U6Tz0ewiVwhUkxt7yn08pemCk,29024
11
11
  drfchelseru/settings.py,sha256=LhdRLmUJnNlET0JYnHqRdFzmBD_nEX18qU1C1j0qN0E,11466
12
- drfchelseru/signals.py,sha256=CI1mZR5RrdOddXBnPC1eMdt9iQkYFDypfgogtfTc2eQ,2714
12
+ drfchelseru/signals.py,sha256=2m4wR_ejGGhqoIZhewwcF0C7zn01OHz2FaKcI41mMzk,2769
13
13
  drfchelseru/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
14
- drfchelseru/urls.py,sha256=qD3As2gSCEaNDxgU0ejIADLUt9t2EvoaTmqeiV1LRSA,898
14
+ drfchelseru/urls.py,sha256=nT_rYVCeaBzRX_EboAssKGWfPtPHGixtNVeOUcWcy8U,1120
15
15
  drfchelseru/validators.py,sha256=jAJASfG4kPcqrGxxIcoR8VjS4L4n_EzZuxJtQ1g9qmo,480
16
- drfchelseru/views.py,sha256=a63NZzNsTZ-1bZJfXlP7V-eeYf_JDcMjvMAZ-dh0BcU,19849
16
+ drfchelseru/views.py,sha256=bdmdY-YuUGH1XxUWrQAjINtR1nI49ndC8riEZ8xlbdU,21139
17
17
  drfchelseru/migrations/0001_initial.py,sha256=LfkWAeQuPXNW3_igM-w_pyKafCeHQF3aReYgMXfMzEE,1034
18
18
  drfchelseru/migrations/0002_otpcode_session_user.py,sha256=c3oyBTQo2kjsKr5r_XQrqaq-66F7pui-4H4mEyAXgJk,3126
19
19
  drfchelseru/migrations/0003_rename_mobile_otpcode_mobile_number.py,sha256=eiD7t6etg6nOeT7BhJrSfEcR1yTPePXtATgtyu30520,377
@@ -37,7 +37,7 @@ drfchelseru/migrations/0020_payment_paid_at.py,sha256=H6cr-tfjJVjN3tCsCD8ecg9JGJ
37
37
  drfchelseru/migrations/0021_alter_payment_message.py,sha256=g5qIvQ-wecdXGcMf7ZhyfL2u85QpgMUOADHE7t4QHog,397
38
38
  drfchelseru/migrations/0022_payment_pay_mode_wallet.py,sha256=241lZITO1jQHqXkJKYm8DKUh7w9rmROh65LzNifP3BA,1521
39
39
  drfchelseru/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
- django_chelseru-2.0.5.dist-info/METADATA,sha256=hdAO3xXQWMbwS1Aux0o9Uxsm2kyo_sLXbadZCoAQn9Q,18242
41
- django_chelseru-2.0.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
- django_chelseru-2.0.5.dist-info/top_level.txt,sha256=fsaO1F03W3j4AYi0TfDGv5Cjb_Qrh6RSkwkWqfqaMns,12
43
- django_chelseru-2.0.5.dist-info/RECORD,,
40
+ django_chelseru-2.1.0.dist-info/METADATA,sha256=deqYHC9xLEUr5RxS6pUguGKzLoII_uuB5X0WUHO3SzI,18267
41
+ django_chelseru-2.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
42
+ django_chelseru-2.1.0.dist-info/top_level.txt,sha256=fsaO1F03W3j4AYi0TfDGv5Cjb_Qrh6RSkwkWqfqaMns,12
43
+ django_chelseru-2.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
drfchelseru/admin.py CHANGED
@@ -1,35 +1,120 @@
1
1
  from django.contrib import admin
2
- from .models import User, OTPCode, Session, MessageSMS, ChatRoom, MessageChat, ChatRoomPermissions, Organization, Payment, Wallet
2
+ from django.utils.html import format_html
3
+ from .models import (
4
+ User, OTPCode, Session, MessageSMS, Organization,
5
+ ChatRoomPermissions, ChatRoom, MessageChat, Wallet, Payment
6
+ )
3
7
 
8
+ # --- Inlines ---
9
+ class MessageChatInline(admin.TabularInline):
10
+ model = MessageChat
11
+ extra = 0
12
+ readonly_fields = ('timestamp',)
4
13
 
5
- @admin.register(User)
6
- class MobileAdmin(admin.ModelAdmin):
7
- list_display = ['id', 'user__id', 'user__username', 'mobile', 'user__is_active']
14
+ class WalletInline(admin.StackedInline):
15
+ model = Wallet
16
+ can_delete = False
17
+ verbose_name_plural = 'Wallet Info'
18
+
19
+ # --- Admins ---
8
20
 
21
+ @admin.register(User)
22
+ class UserAdmin(admin.ModelAdmin):
23
+ list_display = ('user', 'mobile', 'group')
24
+ search_fields = ('user__username', 'mobile')
25
+ list_filter = ('group',)
26
+ inlines = [WalletInline]
9
27
 
10
28
  @admin.register(OTPCode)
11
29
  class OTPCodeAdmin(admin.ModelAdmin):
12
- list_display = ['id', 'code', 'mobile_number', 'created_at']
13
- ordering = ('-created_at', )
14
-
30
+ list_display = ('mobile_number', 'code', 'created_at')
31
+ search_fields = ('mobile_number', 'code')
32
+ readonly_fields = ('created_at',)
15
33
 
16
34
  @admin.register(Session)
17
35
  class SessionAdmin(admin.ModelAdmin):
18
- list_display = ['id', 'user__id', 'user__username', 'ip_address', 'last_seen']
19
- ordering = ('-created_at', )
36
+ list_display = ('user', 'ip_address', 'device', 'browser', 'last_seen')
37
+ search_fields = ('user__username', 'ip_address', 'session_key')
38
+ list_filter = ('created_at', 'browser')
39
+ readonly_fields = ('created_at', 'last_seen')
20
40
 
21
41
  @admin.register(MessageSMS)
22
- class MessageAdmin(admin.ModelAdmin):
23
- list_display = ['id', 'mobile_number', 'message_text', 'status']
24
- ordering = ('-created_at', )
42
+ class MessageSMSAdmin(admin.ModelAdmin):
43
+ list_display = ('mobile_number', '_from', 'status', 'created_at')
44
+ list_filter = ('status', 'created_at')
45
+ search_fields = ('mobile_number', 'message_text')
46
+
47
+ @admin.register(Organization)
48
+ class OrganizationAdmin(admin.ModelAdmin):
49
+ list_display = ('name', 'uname', 'owner', 'created_at')
50
+ search_fields = ('name', 'uname', 'owner__username')
51
+
52
+ @admin.register(ChatRoomPermissions)
53
+ class ChatRoomPermissionsAdmin(admin.ModelAdmin):
54
+ list_display = ('get_users', 'access')
55
+ list_filter = ('access',)
56
+
57
+ def get_users(self, obj):
58
+ return ", ".join([u.username for u in obj.user.all()])
59
+ get_users.short_description = 'Users'
60
+
61
+ @admin.register(ChatRoom)
62
+ class ChatRoomAdmin(admin.ModelAdmin):
63
+ list_display = ('id', 'name', 'status', 'organization', 'created_at')
64
+ list_filter = ('status', 'created_at')
65
+ search_fields = ('name', 'descriptions')
66
+ filter_horizontal = ('users', 'pinned_for', 'permissions', 'banneds') # برای انتخاب راحت‌تر ManyToMany
67
+ inlines = [MessageChatInline]
25
68
 
69
+ @admin.register(MessageChat)
70
+ class MessageChatAdmin(admin.ModelAdmin):
71
+ list_display = ('sender', 'chat_room', 'short_text', 'timestamp')
72
+ list_filter = ('timestamp',)
73
+ search_fields = ('text', 'sender__username')
26
74
 
75
+ def short_text(self, obj):
76
+ return obj.text[:50] + '...' if len(obj.text) > 50 else obj.text
27
77
 
78
+ @admin.register(Wallet)
79
+ class WalletAdmin(admin.ModelAdmin):
80
+ list_display = ('user', 'amount', 'updated_at')
81
+ search_fields = ('user__username',)
82
+ readonly_fields = ('created_at', 'updated_at')
28
83
 
84
+ @admin.register(Payment)
85
+ class PaymentAdmin(admin.ModelAdmin):
86
+ list_display = ('order_id', 'user', 'colored_status', 'amount', 'gateway_title', 'created_at')
87
+ list_filter = ('status', 'pay_mode', 'gateway_title', 'created_at')
88
+ search_fields = ('order_id', 'authority', 'ref_id', 'user__username', 'mobile')
89
+ readonly_fields = ('created_at', 'updated_at', 'data', 'data_verify')
90
+
91
+ fieldsets = (
92
+ ('Basic Info', {
93
+ 'fields': ('status', 'user', 'pay_mode', 'amount', 'order_id', 'description')
94
+ }),
95
+ ('Contact Info', {
96
+ 'fields': ('mobile', 'email', 'callback_url')
97
+ }),
98
+ ('Gateway Info', {
99
+ 'fields': ('gateway_title', 'gateway_url', 'authority', 'ref_id', 'status_code', 'message')
100
+ }),
101
+ ('Card & Security', {
102
+ 'classes': ('collapse',), # این بخش به صورت تاشو نمایش داده می‌شود
103
+ 'fields': ('card_hash', 'card_pan', 'data', 'data_verify', 'paid_at')
104
+ }),
105
+ )
29
106
 
30
- admin.site.register(ChatRoom)
31
- admin.site.register(MessageChat)
32
- admin.site.register(ChatRoomPermissions)
33
- admin.site.register(Organization)
34
- admin.site.register(Payment)
35
- admin.site.register(Wallet)
107
+ def colored_status(self, obj):
108
+ """رنگی کردن وضعیت پرداخت برای تشخیص سریع‌تر"""
109
+ colors = {
110
+ 'paid': 'green',
111
+ 'unpaid': 'orange',
112
+ 'canceled': 'red',
113
+ 'refounded': 'blue',
114
+ }
115
+ return format_html(
116
+ '<b style="color:{};">{}</b>',
117
+ colors.get(obj.status, 'black'),
118
+ obj.status
119
+ )
120
+ colored_status.short_description = 'Status'
drfchelseru/consumers.py CHANGED
@@ -53,7 +53,6 @@ class ChatConsumer(AsyncWebsocketConsumer):
53
53
  text_data_json = json.loads(text_data)
54
54
  message = text_data_json['message']
55
55
  sender_id = self.scope['user'].id
56
- # sender_id = text_data_json['sender_id']
57
56
  sender = await sync_to_async(User.objects.get)(id=sender_id)
58
57
 
59
58
  # Save message to database
@@ -68,17 +67,19 @@ class ChatConsumer(AsyncWebsocketConsumer):
68
67
  self.room_group_name,
69
68
  {
70
69
  'type': 'chat_message',
70
+ 'id': chat_message.id,
71
71
  'message': chat_message.text,
72
- 'sender': sender.username
72
+ 'created_at': chat_message.created_at.isoformat(),
73
+ 'sender': {
74
+ 'id': sender.id,
75
+ 'username': sender.username,
76
+ },
77
+ 'chat_room': {
78
+ 'id': chat_message.chat_room.id
79
+ }
73
80
  }
74
81
  )
75
82
 
76
83
  async def chat_message(self, event):
77
- message = event['message']
78
- sender = event['sender']
79
-
80
84
  # Send message to WebSocket
81
- await self.send(text_data=json.dumps({
82
- 'message': message,
83
- 'sender': sender
84
- }))
85
+ await self.send(text_data=json.dumps(event))
drfchelseru/models.py CHANGED
@@ -149,8 +149,12 @@ class ChatRoom(models.Model):
149
149
  name = models.CharField(max_length=45, blank=True, null=True)
150
150
  descriptions = models.TextField(blank=True, null=True)
151
151
 
152
+ updated_at = models.DateTimeField(auto_now=True)
152
153
  created_at = models.DateTimeField(auto_now_add=True)
153
154
 
155
+ class Meta:
156
+ unique_together = ()
157
+
154
158
  def __str__(self):
155
159
  return f"ID: {self.id}"
156
160
 
@@ -163,6 +167,15 @@ class MessageChat(models.Model):
163
167
 
164
168
  created_at = models.DateTimeField(auto_now_add=True)
165
169
 
170
+ def save(self, *args, **kwargs):
171
+ # بررسی می‌کنیم که آیا این یک پیام جدید است یا ویرایش شده
172
+ is_new = self._state.adding
173
+ super().save(*args, **kwargs)
174
+
175
+ if is_new:
176
+ self.chat_room.updated_at = self.created_at
177
+ self.chat_room.save(update_fields=['updated_at'])
178
+
166
179
  def __str__(self):
167
180
  return f"iD: {self.id} | Message from {self.sender.username} at {self.timestamp} | Chatroom ID: {self.chat_room.id}"
168
181
 
@@ -1,10 +1,12 @@
1
- from rest_framework.serializers import ModelSerializer
1
+ from rest_framework.serializers import ModelSerializer, CharField, ValidationError
2
2
  from django.contrib.auth.models import User
3
+ from django.contrib.auth.password_validation import validate_password
4
+ from django.contrib.auth import get_user_model
3
5
  from .models import User as mobile, OTPCode, Session, MessageSMS, ChatRoom, MessageChat, Payment
4
6
 
5
7
  # from django.contrib.auth import get_user_model
6
8
 
7
- # UserGet = get_user_model()
9
+ UserGet = get_user_model()
8
10
 
9
11
  class DefaultUserSerializer(ModelSerializer):
10
12
  class Meta:
@@ -39,6 +41,8 @@ class MessageSerializer(ModelSerializer):
39
41
 
40
42
  class ChatRoomSerializer(ModelSerializer):
41
43
  user_1, user_2 = DefaultUserSerializer(read_only=True), DefaultUserSerializer(read_only=True)
44
+ users = DefaultUserSerializer(many=True, read_only=True)
45
+
42
46
  class Meta:
43
47
  model = ChatRoom
44
48
  fields = '__all__'
@@ -58,3 +62,27 @@ class PaymentSerializer(MobileSerializer):
58
62
  class Meta:
59
63
  model = Payment
60
64
  fields = '__all__'
65
+
66
+
67
+ # Authentication method : Passwd
68
+ class RegisterSerializer(ModelSerializer):
69
+ password = CharField(write_only=True, required=True, validators=[validate_password])
70
+ password2 = CharField(write_only=True, required=True)
71
+
72
+ class Meta:
73
+ model = UserGet
74
+ fields = ('username', 'password', 'password2', 'email')
75
+
76
+ def validate(self, attrs):
77
+ if attrs['password'] != attrs['password2']:
78
+ raise ValidationError({"password": "رمز عبور و تکرار آن یکسان نیستند."})
79
+ return attrs
80
+
81
+ def create(self, validated_data):
82
+ user = UserGet.objects.create(
83
+ username=validated_data['username'],
84
+ email=validated_data['email'],
85
+ )
86
+ user.set_password(validated_data['password'])
87
+ user.save()
88
+ return user
drfchelseru/signals.py CHANGED
@@ -1,9 +1,9 @@
1
1
  from django.contrib.auth.models import User as DefaultUser
2
- from .models import User, Payment, Wallet
2
+ from .models import User, Payment, Wallet, MessageChat, ChatRoom
3
3
  from django.db.models.signals import post_save, pre_save
4
4
  from django.dispatch import receiver
5
5
  import requests
6
-
6
+ from django.utils.timezone import now
7
7
  from urllib.parse import parse_qs
8
8
  from channels.middleware import BaseMiddleware
9
9
  from django.contrib.auth.models import AnonymousUser
@@ -38,7 +38,6 @@ def send_email_after_create(sender, instance, **kwargs):
38
38
  except:
39
39
  pass
40
40
 
41
-
42
41
 
43
42
 
44
43
  @sync_to_async
drfchelseru/urls.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from django.urls import path, include
2
2
  from rest_framework.routers import DefaultRouter
3
- from .views import MessageSend, OTPCodeSend ,Authentication, SessionList, MessageViewSet, ChatRoomViewSet, PaymentCreate, PaymentCallback
3
+ from rest_framework_simplejwt.views import TokenObtainPairView
4
+
5
+ from .views import MessageSend, OTPCodeSend ,Authentication, SessionList, MessageViewSet, ChatRoomViewSet, PaymentCreate, PaymentCallback, RegisterView
4
6
 
5
7
  app_name = 'drfchelseru'
6
8
 
@@ -14,6 +16,9 @@ urlpatterns = [
14
16
  path('otp/send/', OTPCodeSend.as_view(), name='otp-send'),
15
17
  path('authenticate/', Authentication.as_view(), name='auth'),
16
18
 
19
+ path('register/', RegisterView.as_view(), name='register-passwd'),
20
+ path('login/', TokenObtainPairView.as_view(), name='login-passwd'),
21
+
17
22
  path('sessions/', SessionList.as_view(), name='sessions'),
18
23
 
19
24
  path('payment/create/', PaymentCreate.as_view(), name='payment-create'),
drfchelseru/views.py CHANGED
@@ -1,21 +1,26 @@
1
1
  from rest_framework.viewsets import ModelViewSet
2
2
  from rest_framework.views import APIView
3
3
  from rest_framework.permissions import AllowAny, IsAuthenticated
4
- from rest_framework.generics import ListAPIView
4
+ from rest_framework.generics import ListAPIView, CreateAPIView
5
5
  from rest_framework.response import Response
6
6
  from rest_framework.status import HTTP_200_OK, HTTP_204_NO_CONTENT, HTTP_500_INTERNAL_SERVER_ERROR, HTTP_502_BAD_GATEWAY, HTTP_401_UNAUTHORIZED, HTTP_400_BAD_REQUEST, HTTP_409_CONFLICT, HTTP_404_NOT_FOUND
7
7
  from rest_framework.exceptions import NotFound, ValidationError
8
8
  from rest_framework import status
9
+ from rest_framework.pagination import PageNumberPagination
10
+ from rest_framework.pagination import CursorPagination
9
11
 
10
12
  from django.contrib.auth.models import User as UserDefault
13
+ from django.contrib.auth import get_user_model
11
14
 
12
15
  from .services import send_message, create_payment, verify_payment
13
16
  from .settings import sms_init_check, auth_init_check
14
17
  from .validators import mobile_number as mobile_validator
15
- from .serializers import MessageSerializer, OTPCodeSerializer, SessionSerializer, ChatRoomSerializer, MessageChatSerializer, PaymentSerializer
18
+ from .serializers import MessageSerializer, OTPCodeSerializer, SessionSerializer, ChatRoomSerializer, MessageChatSerializer, PaymentSerializer, RegisterSerializer
16
19
  from .models import User, ChatRoom
17
20
  from django.utils.timezone import now, timedelta
18
21
  from django.db import transaction, IntegrityError, OperationalError
22
+ from django.db.models import Count
23
+ from django.db.models import Q
19
24
 
20
25
  from django.conf import settings
21
26
  from django.core.exceptions import ImproperlyConfigured
@@ -24,6 +29,7 @@ import traceback
24
29
  import time
25
30
  import logging
26
31
 
32
+ UserGet = get_user_model()
27
33
 
28
34
  logger = logging.getLogger(__name__)
29
35
 
@@ -253,48 +259,85 @@ class SessionList(ListAPIView):
253
259
  class ChatRoomViewSet(ModelViewSet):
254
260
  serializer_class = ChatRoomSerializer
255
261
  permission_classes = [IsAuthenticated]
256
- model = serializer_class.Meta.model
262
+ queryset = ChatRoom.objects.all()
257
263
 
258
264
  def get_queryset(self):
259
- return self.model.objects.filter(user_1=self.request.user) | self.model.objects.filter(user_2=self.request.user)
265
+ return self.queryset.filter(users=self.request.user)
260
266
 
261
267
  def perform_create(self, serializer):
262
- user = self.request.user
268
+ user_1 = self.request.user
269
+ user_id = self.request.data.get("user_id")
270
+
271
+ if not user_id:
272
+ raise NotFound("user_id ارسال نشده است.")
263
273
 
264
- user_id = self.request.data.get('user', None)
265
- user_2 = UserDefault.objects.filter(id=user_id).first()
274
+ user_2 = UserGet.objects.filter(id=user_id).first()
266
275
  if not user_2:
267
- raise NotFound("کاربر مورد نظر با آی دی فرستاده شده یافت نشد.")
268
-
269
- chat_room = serializer.save(user_1=user, user_2=user_2)
270
-
276
+ raise NotFound("کاربر مورد نظر یافت نشد.")
277
+
278
+ # 🔒 جلوگیری از ساخت چت تکراری
279
+ existing_room = (
280
+ ChatRoom.objects
281
+ .filter(users=user_1)
282
+ .filter(users=user_2)
283
+ )
284
+ print(existing_room)
285
+
286
+ if existing_room:
287
+ self.instance = existing_room
288
+ return
289
+
290
+ # 🆕 ساخت چت جدید
291
+ chat_room = serializer.save()
292
+ chat_room.users.add(user_1, user_2)
293
+ chat_room.save()
294
+
295
+ self.instance = chat_room
296
+
297
+
298
+ # class MessagePagination(PageNumberPagination):
299
+ # page_size = 30
300
+
301
+
302
+ class MessageCursorPagination(CursorPagination):
303
+ page_size = 30
304
+ # مرتب‌سازی بر اساس زمان ایجاد (نزولی)
305
+ # این باعث می‌شود همیشه در اولین درخواست، ۳۰ پیام آخر ارسال شود
306
+ ordering = '-created_at'
271
307
 
272
308
  class MessageViewSet(ModelViewSet):
273
309
  serializer_class = MessageChatSerializer
274
310
  permission_classes = [IsAuthenticated]
311
+ pagination_class = MessageCursorPagination
275
312
 
276
- def get_queryset(self):
277
- user = self.request.user
278
313
 
279
- queryset = self.serializer_class.Meta.model.objects.all()
314
+ def get_queryset(self):
280
315
  chat_room_id = self.request.query_params.get('chat_room')
281
- if chat_room_id:
282
- queryset = queryset.filter(chat_room_id=chat_room_id)
283
- return queryset
316
+
317
+ if not chat_room_id:
318
+ return self.serializer_class.Meta.model.objects.none()
319
+
320
+ return (
321
+ self.serializer_class.Meta.model.objects
322
+ .filter(chat_room_id=chat_room_id)
323
+ .select_related("sender", "chat_room")
324
+ )
284
325
 
285
326
  def perform_create(self, serializer):
286
327
  chat_room_id = self.request.data.get('chat_room')
328
+
287
329
  if not chat_room_id:
288
- raise ValidationError("فیلد chat_room اجباریه.")
330
+ raise ValidationError("فیلد chat_room اجباری است.")
289
331
 
290
332
  try:
291
333
  chat = ChatRoom.objects.get(id=chat_room_id)
292
334
  except ChatRoom.DoesNotExist:
293
335
  raise NotFound("چت‌روم پیدا نشد.")
294
336
 
295
- message = serializer.save(sender=self.request.user, chat_room=chat)
296
- chat = message.chat_room
297
- chat.save()
337
+ serializer.save(
338
+ sender=self.request.user,
339
+ chat_room=chat
340
+ )
298
341
 
299
342
 
300
343
 
@@ -435,4 +478,10 @@ class PaymentCallback(APIView):
435
478
 
436
479
  except self.model.DoesNotExist:
437
480
  return Response({'error': 'payment not found.'}, status=HTTP_404_NOT_FOUND)
438
- return Response({})
481
+ return Response({})
482
+
483
+
484
+ # Authentication method : Passwd
485
+ class RegisterView(CreateAPIView):
486
+ queryset = UserGet.objects.all()
487
+ serializer_class = RegisterSerializer