django-chelseru 1.0.8__tar.gz → 1.1.0__tar.gz
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.
- {django_chelseru-1.0.8/django_chelseru.egg-info → django_chelseru-1.1.0}/PKG-INFO +3 -3
- {django_chelseru-1.0.8 → django_chelseru-1.1.0/django_chelseru.egg-info}/PKG-INFO +3 -3
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/django_chelseru.egg-info/SOURCES.txt +5 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/admin.py +2 -1
- django_chelseru-1.1.0/drfchelseru/middlewares.py +111 -0
- django_chelseru-1.1.0/drfchelseru/migrations/0012_payment.py +30 -0
- django_chelseru-1.1.0/drfchelseru/migrations/0013_payment_authority_payment_data_payment_status_code.py +28 -0
- django_chelseru-1.1.0/drfchelseru/migrations/0014_payment_gateway_title_payment_gateway_url.py +23 -0
- django_chelseru-1.1.0/drfchelseru/migrations/0015_payment_message.py +18 -0
- django_chelseru-1.1.0/drfchelseru/migrations/0016_payment_card_hash_payment_card_pan_and_more.py +33 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/models.py +115 -1
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/serializers.py +8 -2
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/services.py +197 -1
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/settings.py +65 -1
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/urls.py +4 -1
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/views.py +84 -3
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/setup.py +3 -3
- django_chelseru-1.0.8/drfchelseru/middlewares.py +0 -80
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/LICENSE +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/MANIFEST.in +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/README.md +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/README_PA.md +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/django_chelseru.egg-info/dependency_links.txt +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/django_chelseru.egg-info/requires.txt +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/django_chelseru.egg-info/top_level.txt +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/__init__.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/apps.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/consumers.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0001_initial.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0002_otpcode_session_user.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0003_rename_mobile_otpcode_mobile_number.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0004_rename_message_message_sms.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0005_rename_message_sms_messagesms_chatroom_messagechat.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0006_alter_chatroom_user_1_alter_chatroom_user_2_and_more.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0007_chatroom_pinned_for_chatroom_status_chatroom_users_and_more.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0008_alter_chatroompermissions_user.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0009_alter_chatroom_status.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0010_chatroom_banneds_chatroom_descriptions_chatroom_name_and_more.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0011_alter_chatroom_user_1_alter_chatroom_user_2.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/__init__.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/routing.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/signals.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/tests.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/validators.py +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/pyproject.toml +0 -0
- {django_chelseru-1.0.8 → django_chelseru-1.1.0}/setup.cfg +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-chelseru
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Authentication system, online and real-time chat, SMS system for Iranian SMS services.
|
|
5
5
|
Home-page: https://pipdjango.chelseru.com
|
|
6
|
-
Author: Sobhan Bahman
|
|
6
|
+
Author: Sobhan Bahman Rashnu
|
|
7
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 lour sms djangoauth auth ywt otpauth otp authentication djangootp djangoiransms iransms djangosms djangokavenegar djangomelipayamak sobhan چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم
|
|
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 چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
13
|
Classifier: Framework :: Django
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-chelseru
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Authentication system, online and real-time chat, SMS system for Iranian SMS services.
|
|
5
5
|
Home-page: https://pipdjango.chelseru.com
|
|
6
|
-
Author: Sobhan Bahman
|
|
6
|
+
Author: Sobhan Bahman Rashnu
|
|
7
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 lour sms djangoauth auth ywt otpauth otp authentication djangootp djangoiransms iransms djangosms djangokavenegar djangomelipayamak sobhan چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم
|
|
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 چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
13
|
Classifier: Framework :: Django
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -35,4 +35,9 @@ drfchelseru/migrations/0008_alter_chatroompermissions_user.py
|
|
|
35
35
|
drfchelseru/migrations/0009_alter_chatroom_status.py
|
|
36
36
|
drfchelseru/migrations/0010_chatroom_banneds_chatroom_descriptions_chatroom_name_and_more.py
|
|
37
37
|
drfchelseru/migrations/0011_alter_chatroom_user_1_alter_chatroom_user_2.py
|
|
38
|
+
drfchelseru/migrations/0012_payment.py
|
|
39
|
+
drfchelseru/migrations/0013_payment_authority_payment_data_payment_status_code.py
|
|
40
|
+
drfchelseru/migrations/0014_payment_gateway_title_payment_gateway_url.py
|
|
41
|
+
drfchelseru/migrations/0015_payment_message.py
|
|
42
|
+
drfchelseru/migrations/0016_payment_card_hash_payment_card_pan_and_more.py
|
|
38
43
|
drfchelseru/migrations/__init__.py
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from django.contrib import admin
|
|
2
|
-
from .models import User, OTPCode, Session, MessageSMS, ChatRoom, MessageChat, ChatRoomPermissions, Organization
|
|
2
|
+
from .models import User, OTPCode, Session, MessageSMS, ChatRoom, MessageChat, ChatRoomPermissions, Organization, Payment
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
@admin.register(User)
|
|
@@ -31,3 +31,4 @@ admin.site.register(ChatRoom)
|
|
|
31
31
|
admin.site.register(MessageChat)
|
|
32
32
|
admin.site.register(ChatRoomPermissions)
|
|
33
33
|
admin.site.register(Organization)
|
|
34
|
+
admin.site.register(Payment)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from django.utils.timezone import datetime
|
|
2
|
+
from .models import Session
|
|
3
|
+
import user_agents
|
|
4
|
+
|
|
5
|
+
from urllib.parse import parse_qs
|
|
6
|
+
from channels.middleware import BaseMiddleware
|
|
7
|
+
from django.contrib.auth.models import AnonymousUser
|
|
8
|
+
from rest_framework_simplejwt.tokens import AccessToken
|
|
9
|
+
from django.contrib.auth import get_user_model
|
|
10
|
+
from asgiref.sync import sync_to_async
|
|
11
|
+
|
|
12
|
+
from .settings import auth_init_check, AUTH_SERVICE_DJSESSION, AUTH_SERVICE_DJSESSION
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TakeUserSessionMiddlaware:
|
|
16
|
+
def __init__(self, get_response):
|
|
17
|
+
self.get_response = get_response
|
|
18
|
+
|
|
19
|
+
def __call__(self, request):
|
|
20
|
+
response = self.get_response(request)
|
|
21
|
+
|
|
22
|
+
if request.user.is_authenticated:
|
|
23
|
+
user_agent = request.META.get('HTTP_USER_AGENT', '')
|
|
24
|
+
ip = self.get_client_ip(request)
|
|
25
|
+
|
|
26
|
+
icheck = auth_init_check()
|
|
27
|
+
session = None
|
|
28
|
+
|
|
29
|
+
if icheck['AUTH_SERVICE'] == AUTH_SERVICE_DJSESSION:
|
|
30
|
+
if not request.session.session_key:
|
|
31
|
+
request.session.create()
|
|
32
|
+
session_key = request.session.session_key
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
# get session
|
|
36
|
+
session = Session.objects.get(session_key=session_key)
|
|
37
|
+
|
|
38
|
+
except Session.DoesNotExist:
|
|
39
|
+
# create
|
|
40
|
+
session = Session.objects.create(
|
|
41
|
+
user = request.user,
|
|
42
|
+
session_key = session_key,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
elif icheck['AUTH_SERVICE'] == AUTH_SERVICE_JWT:
|
|
46
|
+
try:
|
|
47
|
+
session = Session.objects.get(user=request.user)
|
|
48
|
+
except Session.DoesNotExist:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
if session:
|
|
52
|
+
session.user_agent = user_agent
|
|
53
|
+
session.ip_address = ip_address
|
|
54
|
+
session.device = user_agents.parse(user_agent).device.family
|
|
55
|
+
session.browser = user_agents.parse(user_agent).browser.family
|
|
56
|
+
session.last_seen = datetime.now()
|
|
57
|
+
|
|
58
|
+
session.save()
|
|
59
|
+
|
|
60
|
+
# session, created = Session.objects.get_or_create(
|
|
61
|
+
# user = request.user,
|
|
62
|
+
# session_key = session_key,
|
|
63
|
+
# defaults = {
|
|
64
|
+
# 'user_agent': user_agent,
|
|
65
|
+
# 'ip_address': ip,
|
|
66
|
+
# 'device': user_agents.parse(user_agent).device.family,
|
|
67
|
+
# 'browser': user_agents.parse(user_agent).browser.family,
|
|
68
|
+
# }
|
|
69
|
+
# )
|
|
70
|
+
|
|
71
|
+
# session.user_agent = user_agent
|
|
72
|
+
# session.ip_address = ip
|
|
73
|
+
# session.last_seen = datetime.now()
|
|
74
|
+
# session.save()
|
|
75
|
+
|
|
76
|
+
return response
|
|
77
|
+
|
|
78
|
+
def get_client_ip(self, request):
|
|
79
|
+
x_forwarded_for = request.META.get('X_FORWARDED_FOR')
|
|
80
|
+
if x_forwarded_for:
|
|
81
|
+
return x_forwarded_for.split(',')[0]
|
|
82
|
+
return request.META.get('REMOTE_ADDR')
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
User = get_user_model()
|
|
87
|
+
|
|
88
|
+
@sync_to_async
|
|
89
|
+
def get_user(validated_token):
|
|
90
|
+
try:
|
|
91
|
+
user_id = validated_token["user_id"]
|
|
92
|
+
return User.objects.get(id=user_id)
|
|
93
|
+
except User.DoesNotExist:
|
|
94
|
+
return AnonymousUser()
|
|
95
|
+
|
|
96
|
+
class JWTAuthMiddleware(BaseMiddleware):
|
|
97
|
+
async def __call__(self, scope, receive, send):
|
|
98
|
+
query_string = scope.get("query_string", b"").decode()
|
|
99
|
+
query_params = parse_qs(query_string)
|
|
100
|
+
token = query_params.get("token")
|
|
101
|
+
|
|
102
|
+
if token:
|
|
103
|
+
try:
|
|
104
|
+
access_token = AccessToken(token[0])
|
|
105
|
+
scope["user"] = await get_user(access_token)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
scope["user"] = AnonymousUser()
|
|
108
|
+
else:
|
|
109
|
+
scope["user"] = AnonymousUser()
|
|
110
|
+
|
|
111
|
+
return await super().__call__(scope, receive, send)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-25 20:12
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('drfchelseru', '0011_alter_chatroom_user_1_alter_chatroom_user_2'),
|
|
12
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name='Payment',
|
|
18
|
+
fields=[
|
|
19
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
20
|
+
('order_id', models.CharField(max_length=20)),
|
|
21
|
+
('amount', models.FloatField()),
|
|
22
|
+
('description', models.TextField()),
|
|
23
|
+
('callback_url', models.SlugField()),
|
|
24
|
+
('mobile', models.CharField(blank=True, max_length=11, null=True)),
|
|
25
|
+
('email', models.EmailField(blank=True, max_length=254, null=True)),
|
|
26
|
+
('currency', models.CharField(blank=True, max_length=20, null=True)),
|
|
27
|
+
('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)),
|
|
28
|
+
],
|
|
29
|
+
),
|
|
30
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-26 19:35
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('drfchelseru', '0012_payment'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='payment',
|
|
15
|
+
name='authority',
|
|
16
|
+
field=models.TextField(blank=True, null=True),
|
|
17
|
+
),
|
|
18
|
+
migrations.AddField(
|
|
19
|
+
model_name='payment',
|
|
20
|
+
name='data',
|
|
21
|
+
field=models.TextField(blank=True, null=True),
|
|
22
|
+
),
|
|
23
|
+
migrations.AddField(
|
|
24
|
+
model_name='payment',
|
|
25
|
+
name='status_code',
|
|
26
|
+
field=models.IntegerField(blank=True, null=True),
|
|
27
|
+
),
|
|
28
|
+
]
|
django_chelseru-1.1.0/drfchelseru/migrations/0014_payment_gateway_title_payment_gateway_url.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-26 20:22
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('drfchelseru', '0013_payment_authority_payment_data_payment_status_code'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='payment',
|
|
15
|
+
name='gateway_title',
|
|
16
|
+
field=models.CharField(blank=True, max_length=25, null=True),
|
|
17
|
+
),
|
|
18
|
+
migrations.AddField(
|
|
19
|
+
model_name='payment',
|
|
20
|
+
name='gateway_url',
|
|
21
|
+
field=models.SlugField(blank=True, null=True),
|
|
22
|
+
),
|
|
23
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-26 21:06
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('drfchelseru', '0014_payment_gateway_title_payment_gateway_url'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='payment',
|
|
15
|
+
name='message',
|
|
16
|
+
field=models.CharField(blank=True, max_length=25, null=True),
|
|
17
|
+
),
|
|
18
|
+
]
|
django_chelseru-1.1.0/drfchelseru/migrations/0016_payment_card_hash_payment_card_pan_and_more.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Generated by Django 5.1.6 on 2025-08-26 21:10
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('drfchelseru', '0015_payment_message'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='payment',
|
|
15
|
+
name='card_hash',
|
|
16
|
+
field=models.TextField(blank=True, null=True),
|
|
17
|
+
),
|
|
18
|
+
migrations.AddField(
|
|
19
|
+
model_name='payment',
|
|
20
|
+
name='card_pan',
|
|
21
|
+
field=models.TextField(blank=True, null=True),
|
|
22
|
+
),
|
|
23
|
+
migrations.AddField(
|
|
24
|
+
model_name='payment',
|
|
25
|
+
name='data_verify',
|
|
26
|
+
field=models.TextField(blank=True, null=True),
|
|
27
|
+
),
|
|
28
|
+
migrations.AddField(
|
|
29
|
+
model_name='payment',
|
|
30
|
+
name='ref_id',
|
|
31
|
+
field=models.IntegerField(blank=True, null=True),
|
|
32
|
+
),
|
|
33
|
+
]
|
|
@@ -164,4 +164,118 @@ class MessageChat(models.Model):
|
|
|
164
164
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
165
165
|
|
|
166
166
|
def __str__(self):
|
|
167
|
-
return f"iD: {self.id} | Message from {self.sender.username} at {self.timestamp} | Chatroom ID: {self.chat_room.id}"
|
|
167
|
+
return f"iD: {self.id} | Message from {self.sender.username} at {self.timestamp} | Chatroom ID: {self.chat_room.id}"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class Payment(models.Model):
|
|
171
|
+
user = models.ForeignKey(default_user, models.DO_NOTHING)
|
|
172
|
+
order_id = models.CharField(max_length=20)
|
|
173
|
+
amount = models.FloatField()
|
|
174
|
+
description = models.TextField()
|
|
175
|
+
callback_url = models.SlugField()
|
|
176
|
+
mobile = models.CharField(max_length=11, blank=True, null=True)
|
|
177
|
+
email = models.EmailField(blank=True, null=True)
|
|
178
|
+
currency = models.CharField(max_length=20, blank=True, null=True)
|
|
179
|
+
|
|
180
|
+
gateway_title = models.CharField(max_length=25, blank=True, null=True)
|
|
181
|
+
gateway_url = models.SlugField(blank=True, null=True)
|
|
182
|
+
authority = models.TextField(blank=True, null=True)
|
|
183
|
+
status_code = models.IntegerField(blank=True, null=True)
|
|
184
|
+
message = models.CharField(max_length=25, blank=True, null=True)
|
|
185
|
+
card_hash = models.TextField(blank=True, null=True)
|
|
186
|
+
card_pan = models.TextField(blank=True, null=True)
|
|
187
|
+
ref_id = models.IntegerField(blank=True, null=True)
|
|
188
|
+
|
|
189
|
+
data = models.TextField(blank=True, null=True)
|
|
190
|
+
data_verify = models.TextField(blank=True, null=True)
|
|
191
|
+
|
|
192
|
+
def __str__(self):
|
|
193
|
+
return f'payment id: {self.id} - order id: {self.order_id} amount: {self.amount}'
|
|
194
|
+
|
|
195
|
+
def set_request_data(self, **kwargs: dict):
|
|
196
|
+
'''
|
|
197
|
+
inputs:
|
|
198
|
+
currency
|
|
199
|
+
gateway_title
|
|
200
|
+
gateway_url
|
|
201
|
+
callback_url
|
|
202
|
+
authority
|
|
203
|
+
status_code
|
|
204
|
+
message
|
|
205
|
+
data
|
|
206
|
+
'''
|
|
207
|
+
currency = kwargs.get('currency')
|
|
208
|
+
gateway_title = kwargs.get('gateway_title')
|
|
209
|
+
gateway_url = kwargs.get('gateway_url')
|
|
210
|
+
callback_url = kwargs.get('callback_url')
|
|
211
|
+
authority = kwargs.get('authority')
|
|
212
|
+
status_code = kwargs.get('status_code')
|
|
213
|
+
message = kwargs.get('message')
|
|
214
|
+
data = kwargs.get('data')
|
|
215
|
+
|
|
216
|
+
if not callback_url:
|
|
217
|
+
return False
|
|
218
|
+
|
|
219
|
+
self.callback_url = callback_url
|
|
220
|
+
|
|
221
|
+
if currency is not None:
|
|
222
|
+
self.currency = currency
|
|
223
|
+
|
|
224
|
+
if gateway_title is not None:
|
|
225
|
+
self.gateway_title = gateway_title
|
|
226
|
+
|
|
227
|
+
if gateway_url is not None:
|
|
228
|
+
self.gateway_url = gateway_url
|
|
229
|
+
|
|
230
|
+
if authority is not None:
|
|
231
|
+
self.authority = authority
|
|
232
|
+
|
|
233
|
+
if status_code is not None:
|
|
234
|
+
self.status_code = status_code
|
|
235
|
+
|
|
236
|
+
if message is not None:
|
|
237
|
+
self.message = message
|
|
238
|
+
|
|
239
|
+
if data is not None:
|
|
240
|
+
self.data = data
|
|
241
|
+
|
|
242
|
+
self.save()
|
|
243
|
+
|
|
244
|
+
def set_verify_data(self, **kwargs: dict):
|
|
245
|
+
'''
|
|
246
|
+
inputs:
|
|
247
|
+
status_code
|
|
248
|
+
message
|
|
249
|
+
card_hash
|
|
250
|
+
card_pan
|
|
251
|
+
ref_id
|
|
252
|
+
data_verify
|
|
253
|
+
'''
|
|
254
|
+
status_code = kwargs.get('status_code')
|
|
255
|
+
message = kwargs.get('message')
|
|
256
|
+
card_hash = kwargs.get('card_hash')
|
|
257
|
+
card_pan = kwargs.get('card_pan')
|
|
258
|
+
ref_id = kwargs.get('ref_id')
|
|
259
|
+
data_verify = kwargs.get('data_verify')
|
|
260
|
+
|
|
261
|
+
if status_code is not None:
|
|
262
|
+
self.status_code = status_code
|
|
263
|
+
|
|
264
|
+
if message is not None:
|
|
265
|
+
self.message = message
|
|
266
|
+
|
|
267
|
+
if card_hash is not None:
|
|
268
|
+
self.card_hash = card_hash
|
|
269
|
+
|
|
270
|
+
if card_pan is not None:
|
|
271
|
+
self.card_pan = card_pan
|
|
272
|
+
|
|
273
|
+
if ref_id is not None:
|
|
274
|
+
self.ref_id = ref_id
|
|
275
|
+
|
|
276
|
+
if data_verify is not None:
|
|
277
|
+
self.data_verify = data_verify
|
|
278
|
+
|
|
279
|
+
self.save()
|
|
280
|
+
pass
|
|
281
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from rest_framework.serializers import ModelSerializer
|
|
2
2
|
from django.contrib.auth.models import User
|
|
3
|
-
from .models import User as mobile, OTPCode, Session, MessageSMS, ChatRoom, MessageChat
|
|
3
|
+
from .models import User as mobile, OTPCode, Session, MessageSMS, ChatRoom, MessageChat, Payment
|
|
4
4
|
|
|
5
5
|
# from django.contrib.auth import get_user_model
|
|
6
6
|
|
|
@@ -51,4 +51,10 @@ class MessageChatSerializer(ModelSerializer):
|
|
|
51
51
|
class Meta:
|
|
52
52
|
model = MessageChat
|
|
53
53
|
fields = '__all__'
|
|
54
|
-
depth = 1
|
|
54
|
+
depth = 1
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class PaymentSerializer(MobileSerializer):
|
|
58
|
+
class Meta:
|
|
59
|
+
model = Payment
|
|
60
|
+
fields = '__all__'
|
|
@@ -5,7 +5,8 @@ from zeep import Client
|
|
|
5
5
|
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
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
from .settings import sms_init_check
|
|
8
|
+
from .settings import sms_init_check, bank_init_check, GATEWAY_ZARINPAL
|
|
9
|
+
from .models import Payment
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class ParsianWebcoIr:
|
|
@@ -237,3 +238,198 @@ def send_message(mobile_number, message_text, data=None, template_id=None):
|
|
|
237
238
|
return False, {'details': 'Invalid response structure.', 'error': str(e)}
|
|
238
239
|
|
|
239
240
|
return response_bool, {'data': response_data, 'obj_status': obj_status, 'status': response_status_code}
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class ZarinpalCom:
|
|
246
|
+
"""
|
|
247
|
+
merchant_id
|
|
248
|
+
currency
|
|
249
|
+
"""
|
|
250
|
+
def __init__(self, merchant_id):
|
|
251
|
+
self.merchant_id = merchant_id
|
|
252
|
+
|
|
253
|
+
def create_payment(self, amount, callback_url, description, order_id=None, mobile=None, email=None, currency=None, **metadata):
|
|
254
|
+
'''
|
|
255
|
+
curl -X POST \
|
|
256
|
+
https://payment.zarinpal.com/pg/v4/payment/request.json \
|
|
257
|
+
-H 'accept: application/json' \
|
|
258
|
+
-H 'content-type: application/json' \
|
|
259
|
+
-d '{
|
|
260
|
+
"merchant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
|
261
|
+
"amount": 1000,
|
|
262
|
+
"callback_url": "http://your-site.com/verify",
|
|
263
|
+
"description": "Transaction description.",
|
|
264
|
+
"metadata": {"mobile": "09121234567","email": "info.test@gmail.com"}
|
|
265
|
+
}
|
|
266
|
+
___
|
|
267
|
+
|
|
268
|
+
{
|
|
269
|
+
"data": {
|
|
270
|
+
"code": 100,
|
|
271
|
+
"message": "Success",
|
|
272
|
+
"authority": "A0000000000000000000000000000wwOGYpd",
|
|
273
|
+
"fee_type": "Merchant",
|
|
274
|
+
"fee": 100
|
|
275
|
+
},
|
|
276
|
+
"errors": []
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
merchant_id String بله كد ۳۶ كاراكتری اختصاصی پذیرنده
|
|
281
|
+
amount Integer بله مبلغ تراكنش
|
|
282
|
+
currency String خیر تعیین واحد پولی ریال (IRR) یا تومان(IRT)
|
|
283
|
+
description String بله توضیحات مربوط به تراکنش
|
|
284
|
+
callback_url String بله صفحه بازگشت مشتري، پس از انجام عمل پرداخت
|
|
285
|
+
metadata Array دارای مقدار های mobile و email و order_id
|
|
286
|
+
mobile String خیر شماره تماس خریدار
|
|
287
|
+
email String خیر ایمیل خریدار
|
|
288
|
+
order_id String خیر شماره سفارش
|
|
289
|
+
'''
|
|
290
|
+
url = 'https://payment.zarinpal.com/pg/v4/payment/request.json'
|
|
291
|
+
headers = {
|
|
292
|
+
'accept': 'application/json',
|
|
293
|
+
'content-type': 'application/json'
|
|
294
|
+
}
|
|
295
|
+
try:
|
|
296
|
+
data = metadata
|
|
297
|
+
data['merchant_id'] = self.merchant_id
|
|
298
|
+
data['amount'] = amount
|
|
299
|
+
data['callback_url'] = callback_url
|
|
300
|
+
data['description'] = description
|
|
301
|
+
if order_id:
|
|
302
|
+
data['order_id'] = order_id
|
|
303
|
+
|
|
304
|
+
if mobile:
|
|
305
|
+
data['mobile'] = mobile
|
|
306
|
+
|
|
307
|
+
if email:
|
|
308
|
+
data['email'] = email
|
|
309
|
+
|
|
310
|
+
if currency:
|
|
311
|
+
data['currency'] = currency
|
|
312
|
+
|
|
313
|
+
response = requests.post(url=url, data=data)
|
|
314
|
+
return response.json()
|
|
315
|
+
|
|
316
|
+
except:
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def verify_payment(self, authority, amount):
|
|
321
|
+
'''
|
|
322
|
+
curl -X POST \
|
|
323
|
+
https://payment.zarinpal.com/pg/v4/payment/verify.json \
|
|
324
|
+
-H 'accept: application/json' \
|
|
325
|
+
-H 'content-type: application/json' \
|
|
326
|
+
-d '{
|
|
327
|
+
"merchant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
|
328
|
+
"amount": 1000,
|
|
329
|
+
"authority": "A0000000000000000000000000000wwOGYpd"
|
|
330
|
+
}'
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
{
|
|
334
|
+
"data": {
|
|
335
|
+
"code": 100,
|
|
336
|
+
"message": "Verified",
|
|
337
|
+
"card_hash": "1EBE3EBEBE35C7EC0F8D6EE4F2F859107A87822CA179BC9528767EA7B5489B69",
|
|
338
|
+
"card_pan": "502229******5995",
|
|
339
|
+
"ref_id": 201,
|
|
340
|
+
"fee_type": "Merchant",
|
|
341
|
+
"fee": 0
|
|
342
|
+
},
|
|
343
|
+
"errors": []
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
code Integer عددی كه نشان دهنده موفق بودن یا موفق نبودن پرداخت است.
|
|
348
|
+
ref_id Integer در صورتی كه پرداخت موفق باشد، شماره تراكنش پرداخت انجام شده را بر میگرداند.
|
|
349
|
+
card_pan String شماره کارت به صورت Mask
|
|
350
|
+
card_hash String هش کارت به صورت SHA256
|
|
351
|
+
fee_type String پرداخت کننده کارمزد: که در پنل کاربری میان خریدار یا خود پذیرنده قابل انتخاب است.
|
|
352
|
+
fee Integer کارمزد
|
|
353
|
+
'''
|
|
354
|
+
url = 'https://payment.zarinpal.com/pg/v4/payment/verify.json'
|
|
355
|
+
headers = {
|
|
356
|
+
'accept': 'application/json',
|
|
357
|
+
'content-type': 'application/json'
|
|
358
|
+
}
|
|
359
|
+
data = {
|
|
360
|
+
'merchant_id': self.merchant_id,
|
|
361
|
+
'amount': int(amount),
|
|
362
|
+
'authority': authority
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
print(data)
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
response = requests.post(url=url, data=data).json()
|
|
369
|
+
return response
|
|
370
|
+
except:
|
|
371
|
+
return False
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def create_payment(amount, description, merchant_id=None, callback_url=None, order_id=None, mobile=None, email=None, currency=None, **kwargs):
|
|
376
|
+
try:
|
|
377
|
+
ickeck = bank_init_check()
|
|
378
|
+
gateway = ickeck['gateway']
|
|
379
|
+
if not merchant_id:
|
|
380
|
+
merchant_id = ickeck['settings'].get('merchant_id')
|
|
381
|
+
if not callback_url:
|
|
382
|
+
callback_url = ickeck['settings'].get('callback_url')
|
|
383
|
+
if not currency:
|
|
384
|
+
currency = ickeck['settings'].get('currency')
|
|
385
|
+
|
|
386
|
+
callback_url = callback_url + '/payment/callback/' if callback_url[-1] != '/' else callback_url + 'payment/callback/'
|
|
387
|
+
|
|
388
|
+
response = None
|
|
389
|
+
match gateway:
|
|
390
|
+
case GATEWAY_ZARINPAL:
|
|
391
|
+
gw = ZarinpalCom(merchant_id=merchant_id)
|
|
392
|
+
_response = gw.create_payment(amount, callback_url, description, order_id, mobile, email, currency)
|
|
393
|
+
response = {
|
|
394
|
+
'currency': currency,
|
|
395
|
+
'gateway_title': GATEWAY_ZARINPAL,
|
|
396
|
+
'gateway_url': f'https://payment.zarinpal.com/pg/StartPay/{_response['data'].get('authority')}',
|
|
397
|
+
'callback_url': callback_url,
|
|
398
|
+
'authority': _response['data'].get('authority'),
|
|
399
|
+
'status_code': _response['data'].get('code'),
|
|
400
|
+
'message': _response['data'].get('message'),
|
|
401
|
+
'data': _response['data']
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if response is not None:
|
|
405
|
+
return response
|
|
406
|
+
except ImproperlyConfigured as e:
|
|
407
|
+
raise
|
|
408
|
+
except:
|
|
409
|
+
pass
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def verify_payment(authority, amount, merchant_id=None):
|
|
413
|
+
try:
|
|
414
|
+
ickeck = bank_init_check()
|
|
415
|
+
gateway = ickeck['gateway']
|
|
416
|
+
if not merchant_id:
|
|
417
|
+
merchant_id = ickeck['settings'].get('merchant_id')
|
|
418
|
+
response = None
|
|
419
|
+
match gateway:
|
|
420
|
+
case GATEWAY_ZARINPAL:
|
|
421
|
+
gw = ZarinpalCom(merchant_id=merchant_id)
|
|
422
|
+
_response = gw.verify_payment(authority, amount)
|
|
423
|
+
response = {
|
|
424
|
+
'status_code': _response['data'].get('status_code'),
|
|
425
|
+
'message': _response['data'].get('message'),
|
|
426
|
+
'card_hash': _response['data'].get('card_hash'),
|
|
427
|
+
'card_pan': _response['data'].get('card_pan'),
|
|
428
|
+
'ref_id': _response['data'].get('ref_id'),
|
|
429
|
+
'data_verify': _response['data'],
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if response is not None:
|
|
433
|
+
return response
|
|
434
|
+
except ImproperlyConfigured as e:
|
|
435
|
+
raise
|
|
@@ -29,6 +29,14 @@ DJANGO_CHELSERU = {
|
|
|
29
29
|
'T7': 7,
|
|
30
30
|
'T8': 8,
|
|
31
31
|
'T9': 9,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
'BANK': {
|
|
35
|
+
'GATEWAY': 'ZARINPAL_COM',
|
|
36
|
+
'SETTINGS': {
|
|
37
|
+
'MERCHANT_ID': '',
|
|
38
|
+
'CALLBACK_URL': '',
|
|
39
|
+
'CURRENCY': 'IRT', # IRR, IRT
|
|
32
40
|
}
|
|
33
41
|
}
|
|
34
42
|
}
|
|
@@ -39,10 +47,18 @@ from django.core.exceptions import ImproperlyConfigured
|
|
|
39
47
|
|
|
40
48
|
SERVICE_NAME = 'DJANGO_CHELSERU'
|
|
41
49
|
|
|
50
|
+
AUTH_SERVICE_JWT = 'rest_framework_simplejwt'
|
|
51
|
+
AUTH_SERVICE_DJSESSION = 'django_session'
|
|
52
|
+
|
|
42
53
|
AUTH_METHOD = [(0, 'OTP'), (1, 'PASSWD')]
|
|
43
|
-
AUTH_SERVICES = [(0,
|
|
54
|
+
AUTH_SERVICES = [(0, AUTH_SERVICE_JWT)]
|
|
44
55
|
SMS_SERVICES = [(0, 'PARSIAN_WEBCO_IR'),(1, 'MELI_PAYAMAK_COM') ,(2, 'KAVENEGAR_COM')]
|
|
45
56
|
|
|
57
|
+
GATEWAY_ZARINPAL = 'ZARINPAL_COM'
|
|
58
|
+
GATEWAYS = ((0, GATEWAY_ZARINPAL),)
|
|
59
|
+
CURRENCIES = ((0, 'IRT'), (1, 'IRR'))
|
|
60
|
+
|
|
61
|
+
|
|
46
62
|
def auth_init_check():
|
|
47
63
|
try:
|
|
48
64
|
auth_mode = 'OTP'
|
|
@@ -185,3 +201,51 @@ def sms_init_check():
|
|
|
185
201
|
return False
|
|
186
202
|
|
|
187
203
|
|
|
204
|
+
def bank_init_check():
|
|
205
|
+
gateway = None
|
|
206
|
+
options = {
|
|
207
|
+
'currency': 'IRT',
|
|
208
|
+
}
|
|
209
|
+
try:
|
|
210
|
+
if not hasattr(settings, SERVICE_NAME):
|
|
211
|
+
raise ImproperlyConfigured(f'{SERVICE_NAME} must be defined in settings.py.')
|
|
212
|
+
|
|
213
|
+
else:
|
|
214
|
+
bank = getattr(settings, SERVICE_NAME).get('BANK')
|
|
215
|
+
if not bank:
|
|
216
|
+
raise ImproperlyConfigured(f'BANK key must be defined in {SERVICE_NAME}')
|
|
217
|
+
else:
|
|
218
|
+
gateway = bank.get('GATEWAY')
|
|
219
|
+
if gateway not in list(map(lambda x: x[1], GATEWAYS)):
|
|
220
|
+
raise ImproperlyConfigured(f'GATEWAY must be choice between {list(map(lambda x:x[1], GATEWAYS))}.')
|
|
221
|
+
|
|
222
|
+
else:
|
|
223
|
+
_settings = bank.get('SETTINGS')
|
|
224
|
+
if not _settings:
|
|
225
|
+
raise ImproperlyConfigured(f'SETTINGS key must be defined in BANK')
|
|
226
|
+
else:
|
|
227
|
+
_merchant_id = _settings.get('MERCHANT_ID')
|
|
228
|
+
_callback_url = _settings.get('CALLBACK_URL')
|
|
229
|
+
_currency = _settings.get('CORRENCY')
|
|
230
|
+
|
|
231
|
+
if not _merchant_id:
|
|
232
|
+
raise ImproperlyConfigured(f'MERCHANT_ID key must be defined in SETTINGS.')
|
|
233
|
+
if not _callback_url:
|
|
234
|
+
raise ImproperlyConfigured(f'CALLBACK_URL key must be defined in SETTINGS.')
|
|
235
|
+
|
|
236
|
+
options['merchant_id'] = _merchant_id
|
|
237
|
+
options['callback_url'] = _callback_url
|
|
238
|
+
|
|
239
|
+
if _currency:
|
|
240
|
+
options['currency'] = _currency
|
|
241
|
+
|
|
242
|
+
return {'gateway': gateway, 'settings': options}
|
|
243
|
+
except ImproperlyConfigured as e:
|
|
244
|
+
print(f"Configuration Error: {e}")
|
|
245
|
+
raise
|
|
246
|
+
except:
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
return False
|
|
250
|
+
|
|
251
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
3
|
+
from .views import MessageSend, OTPCodeSend ,Authentication, SessionList, MessageViewSet, ChatRoomViewSet, PaymentCreate, PaymentCallback
|
|
4
4
|
|
|
5
5
|
app_name = 'drfchelseru'
|
|
6
6
|
|
|
@@ -13,4 +13,7 @@ urlpatterns = [
|
|
|
13
13
|
path('otp/send/', OTPCodeSend.as_view(), name='otp-send'),
|
|
14
14
|
path('authenticate/', Authentication.as_view(), name='auth'),
|
|
15
15
|
path('sessions/', SessionList.as_view(), name='sessions'),
|
|
16
|
+
|
|
17
|
+
path('payment/create/', PaymentCreate.as_view(), name='payment-create'),
|
|
18
|
+
path('payment/callback/', PaymentCallback.as_view(), name='payment-callback'),
|
|
16
19
|
] + [path('chat/', include(router.urls)),]
|
|
@@ -3,14 +3,14 @@ from rest_framework.views import APIView
|
|
|
3
3
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
|
4
4
|
from rest_framework.generics import ListAPIView
|
|
5
5
|
from rest_framework.response import Response
|
|
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
|
|
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 django.contrib.auth.models import User as UserDefault
|
|
9
9
|
|
|
10
|
-
from .services import send_message
|
|
10
|
+
from .services import send_message, create_payment, verify_payment
|
|
11
11
|
from .settings import sms_init_check, auth_init_check
|
|
12
12
|
from .validators import mobile_number as mobile_validator
|
|
13
|
-
from .serializers import MessageSerializer, OTPCodeSerializer, SessionSerializer, ChatRoomSerializer, MessageChatSerializer
|
|
13
|
+
from .serializers import MessageSerializer, OTPCodeSerializer, SessionSerializer, ChatRoomSerializer, MessageChatSerializer, PaymentSerializer
|
|
14
14
|
from .models import User, ChatRoom
|
|
15
15
|
from django.utils.timezone import now, timedelta
|
|
16
16
|
from django.db import transaction
|
|
@@ -263,3 +263,84 @@ class MessageViewSet(ModelViewSet):
|
|
|
263
263
|
chat = message.chat_room
|
|
264
264
|
chat.save()
|
|
265
265
|
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class PaymentCreate(APIView):
|
|
269
|
+
permission_classes = (AllowAny, )
|
|
270
|
+
serializer_class = PaymentSerializer
|
|
271
|
+
model = serializer_class.Meta.model
|
|
272
|
+
|
|
273
|
+
def post(self, request):
|
|
274
|
+
'''
|
|
275
|
+
order_id str
|
|
276
|
+
amount float
|
|
277
|
+
description str
|
|
278
|
+
callback_url str
|
|
279
|
+
mobile str
|
|
280
|
+
email str
|
|
281
|
+
currency str
|
|
282
|
+
'''
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
assert 'order_id' in self.request.data, 'order_id is required.'
|
|
286
|
+
assert 'amount' in self.request.data, 'amount is required.'
|
|
287
|
+
assert 'description' in self.request.data, 'description is required.'
|
|
288
|
+
|
|
289
|
+
data = {
|
|
290
|
+
'order_id': self.request.data['order_id'],
|
|
291
|
+
'amount': self.request.data['amount'],
|
|
292
|
+
'description': self.request.data['description'],
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
obj = self.model.objects.create(user=request.user, order_id=data['order_id'],
|
|
296
|
+
amount=data['amount'], description=data['description'])
|
|
297
|
+
|
|
298
|
+
if 'callback_url' in request.data:
|
|
299
|
+
data['callback_url'] = request.data['callback_url']
|
|
300
|
+
obj.callback_url = data['callback_url']
|
|
301
|
+
|
|
302
|
+
if 'mobile' in self.request.data:
|
|
303
|
+
data['mobile'] = self.request.data['mobile']
|
|
304
|
+
obj.mobile = data['mobile']
|
|
305
|
+
|
|
306
|
+
if 'email' in self.request.data:
|
|
307
|
+
data['email'] = self.request.data['email']
|
|
308
|
+
obj.email = data['email']
|
|
309
|
+
|
|
310
|
+
if 'currency' in self.request.data:
|
|
311
|
+
data['currency'] = self.request.data['currency']
|
|
312
|
+
obj.currency = data['currency']
|
|
313
|
+
|
|
314
|
+
obj.save()
|
|
315
|
+
response = create_payment(**data)
|
|
316
|
+
obj.set_request_data(**response)
|
|
317
|
+
|
|
318
|
+
return Response({'details': response}, status=HTTP_200_OK)
|
|
319
|
+
except AssertionError as e:
|
|
320
|
+
return Response({'error': str(e)}, status=HTTP_400_BAD_REQUEST)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class PaymentCallback(APIView):
|
|
324
|
+
permission_classes = (AllowAny, )
|
|
325
|
+
serializer_class = PaymentSerializer
|
|
326
|
+
model = serializer_class.Meta.model
|
|
327
|
+
|
|
328
|
+
def get(self, request):
|
|
329
|
+
'''
|
|
330
|
+
query params:
|
|
331
|
+
Authority
|
|
332
|
+
Status (OK, NOK)
|
|
333
|
+
'''
|
|
334
|
+
authority = request.GET.get('Authority')
|
|
335
|
+
status = request.GET.get('Status')
|
|
336
|
+
|
|
337
|
+
if status and status == 'OK' and authority:
|
|
338
|
+
try:
|
|
339
|
+
obj = self.model.objects.get(authority=authority)
|
|
340
|
+
response = verify_payment(authority=authority, amount=obj.amount)
|
|
341
|
+
obj.set_verify_data(**response)
|
|
342
|
+
return Response({'details': response}, status=HTTP_200_OK)
|
|
343
|
+
except self.model.DoesNotExist:
|
|
344
|
+
return Response({'error': 'payment not found.'}, status=HTTP_404_NOT_FOUND)
|
|
345
|
+
|
|
346
|
+
return Response({'error': 'The transaction was unsuccessful or canceled.'}, status=HTTP_400_BAD_REQUEST)
|
|
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
|
|
|
3
3
|
|
|
4
4
|
setup(
|
|
5
5
|
name='django-chelseru',
|
|
6
|
-
version='1.0
|
|
6
|
+
version='1.1.0',
|
|
7
7
|
packages=find_packages(),
|
|
8
8
|
include_package_data=True,
|
|
9
9
|
install_requires=[
|
|
@@ -16,7 +16,7 @@ setup(
|
|
|
16
16
|
'zeep==4.3.1',
|
|
17
17
|
'user-agents==2.2.0'
|
|
18
18
|
],
|
|
19
|
-
author='Sobhan Bahman
|
|
19
|
+
author='Sobhan Bahman Rashnu',
|
|
20
20
|
author_email='bahmanrashnu@gmail.com',
|
|
21
21
|
description='Authentication system, online and real-time chat, SMS system for Iranian SMS services.',
|
|
22
22
|
long_description=open('README.md').read(),
|
|
@@ -34,5 +34,5 @@ setup(
|
|
|
34
34
|
'Operating System :: OS Independent',
|
|
35
35
|
],
|
|
36
36
|
python_requires='>=3.11',
|
|
37
|
-
keywords="djangochelseruchat djangochat drfchat online-chat online real-time chat iran chelseru lor lur bahman rashnu lour sms djangoauth auth ywt otpauth otp authentication djangootp djangoiransms iransms djangosms djangokavenegar djangomelipayamak sobhan چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم",
|
|
37
|
+
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 چت سبحان بهمن رشنو چلسرو جنگو پایتون لر لور آنلاین ریل تایم",
|
|
38
38
|
)
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
from django.utils.timezone import datetime
|
|
2
|
-
from .models import Session
|
|
3
|
-
import user_agents
|
|
4
|
-
|
|
5
|
-
from urllib.parse import parse_qs
|
|
6
|
-
from channels.middleware import BaseMiddleware
|
|
7
|
-
from django.contrib.auth.models import AnonymousUser
|
|
8
|
-
from rest_framework_simplejwt.tokens import AccessToken
|
|
9
|
-
from django.contrib.auth import get_user_model
|
|
10
|
-
from asgiref.sync import sync_to_async
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class TakeUserSessionMiddlaware:
|
|
14
|
-
def __init__(self, get_response):
|
|
15
|
-
self.get_response = get_response
|
|
16
|
-
|
|
17
|
-
def __call__(self, request):
|
|
18
|
-
response = self.get_response(request)
|
|
19
|
-
|
|
20
|
-
if request.user.is_authenticated:
|
|
21
|
-
user_agent = request.META.get('HTTP_USER_AGENT', '')
|
|
22
|
-
ip = self.get_client_ip(request)
|
|
23
|
-
|
|
24
|
-
if not request.session.session_key:
|
|
25
|
-
request.session.create()
|
|
26
|
-
|
|
27
|
-
session_key = request.session.session_key
|
|
28
|
-
|
|
29
|
-
session, created = Session.objects.get_or_create(
|
|
30
|
-
user = request.user,
|
|
31
|
-
session_key = session_key,
|
|
32
|
-
defaults = {
|
|
33
|
-
'user_agent': user_agent,
|
|
34
|
-
'ip_address': ip,
|
|
35
|
-
'device': user_agents.parse(user_agent).device.family,
|
|
36
|
-
'browser': user_agents.parse(user_agent).browser.family,
|
|
37
|
-
}
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
session.user_agent = user_agent
|
|
41
|
-
session.ip_address = ip
|
|
42
|
-
session.last_seen = datetime.now()
|
|
43
|
-
session.save()
|
|
44
|
-
|
|
45
|
-
return response
|
|
46
|
-
|
|
47
|
-
def get_client_ip(self, request):
|
|
48
|
-
x_forwarded_for = request.META.get('X_FORWARDED_FOR')
|
|
49
|
-
if x_forwarded_for:
|
|
50
|
-
return x_forwarded_for.split(',')[0]
|
|
51
|
-
return request.META.get('REMOTE_ADDR')
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
User = get_user_model()
|
|
56
|
-
|
|
57
|
-
@sync_to_async
|
|
58
|
-
def get_user(validated_token):
|
|
59
|
-
try:
|
|
60
|
-
user_id = validated_token["user_id"]
|
|
61
|
-
return User.objects.get(id=user_id)
|
|
62
|
-
except User.DoesNotExist:
|
|
63
|
-
return AnonymousUser()
|
|
64
|
-
|
|
65
|
-
class JWTAuthMiddleware(BaseMiddleware):
|
|
66
|
-
async def __call__(self, scope, receive, send):
|
|
67
|
-
query_string = scope.get("query_string", b"").decode()
|
|
68
|
-
query_params = parse_qs(query_string)
|
|
69
|
-
token = query_params.get("token")
|
|
70
|
-
|
|
71
|
-
if token:
|
|
72
|
-
try:
|
|
73
|
-
access_token = AccessToken(token[0])
|
|
74
|
-
scope["user"] = await get_user(access_token)
|
|
75
|
-
except Exception as e:
|
|
76
|
-
scope["user"] = AnonymousUser()
|
|
77
|
-
else:
|
|
78
|
-
scope["user"] = AnonymousUser()
|
|
79
|
-
|
|
80
|
-
return await super().__call__(scope, receive, send)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_chelseru-1.0.8 → django_chelseru-1.1.0}/django_chelseru.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0002_otpcode_session_user.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_chelseru-1.0.8 → django_chelseru-1.1.0}/drfchelseru/migrations/0009_alter_chatroom_status.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|