This commit is contained in:
Haydar Ghasemi 2026-05-25 17:31:24 +03:30
commit 55dadd67f4
10 changed files with 66 additions and 42 deletions

1
.gitignore vendored
View file

@ -6,4 +6,5 @@ delme*.py
.env
/venv/
oidc.key
/log/
/logs/*.log

View file

@ -160,9 +160,6 @@ class User(AbstractUser):
return state.get_province_by_id(self.province)
def set_otp(self):
if self.otp_expire and (self.otp_expire + timedelta(seconds=MAX_OTP_VALID_DURATION)) > timezone.now():
raise Exception(_('otp expire time not reached.'))
if not settings.SMS_SEND:
self._otp = '77501'
elif self.phone_number in settings.TEST_PHONENUMBERS:

View file

@ -76,16 +76,9 @@ class RequestOTPSerializer(serializers.ModelSerializer):
user = User.objects.create_user(**validated_data)
if not user.otp_is_valid():
try:
user.set_otp()
except Exception as e:
raise UnprocessableEntity(_('otp expire time not reached'))
user.send_otp()
else:
raise UnprocessableEntity(_('otp expire time not reached yet'))
self.instance = user
return user

View file

@ -21,7 +21,7 @@ from apps.users.models import User
from apps.users.provinces_and_cities import State
from apps.users.serializers import PublicUserSerializer, AccountSerializer, RequestOTPSerializer, RequestOTTSerializer, \
ChangePasswordSerializer, UserInquirySerializer, SessionSerializer
from utils.throttles import RequestOTPDayRateThrottle, RequestOTPMinRateThrottle
from utils.throttles import RequestOTPDayRateThrottle, RequestOTPMinRateThrottle, NumberedRequestOTPDayRateThrottle, NumberedRequestOTPMinRateThrottle
UserModel = get_user_model()
@ -90,7 +90,10 @@ class RequestOTPView(generics.CreateAPIView):
permission_classes = []
serializer_class = RequestOTPSerializer
required_scopes = []
throttle_classes = [RequestOTPMinRateThrottle, RequestOTPDayRateThrottle]
throttle_classes = [RequestOTPMinRateThrottle,
RequestOTPDayRateThrottle,
NumberedRequestOTPDayRateThrottle,
NumberedRequestOTPMinRateThrottle]
class RequestOTTView(generics.CreateAPIView):
permission_classes = [IsAuthenticatedOrTokenHasScope]

View file

@ -3,10 +3,10 @@ import time
import requests
OAUTH_CLIENT_ID = 'xrFXKf53jrxVOygbLEoqrtOlUwBP00jIQ4zVpzc6'
OAUTH_CLIENT_SECRET = 'qelUdRCdEEalVdko5aHRojxsC3CaL29yjwxmc6FeWs39SeVSb6aM9mNrYQixMJNTYQK7s2wffwPW94JPPbP6jTdd9dSf1mlqYcr6hW2COuayFUk4jP33OWu4taUYP2F5'
OAUTH_CLIENT_ID = '4INGOCMoulE0fNY1SQlTbPtsWqqxGj2DdqjADq6u'
OAUTH_CLIENT_SECRET = 'KPc4dMSztNwAIB3vii3geXrzC1mKUIsAztz3t2ylC3HlrgJudJWhdrtoY6XeRJIuadTAREYYsXk9XtFHUDfPVcJvyfHMpNkz2VvghwrijhVprok0VYV7XrOirJ5nFUxD'
API_URI = 'https://accounts.gooyal.com'
API_URI = 'https://accounts.gooyal.ir'
# API_URI = 'http://127.0.0.1:8000'
@ -27,7 +27,7 @@ class ApiClient():
"grant_type": "password",
"username": phone_number,
"password": password,
"scope": 'accounts.account:request_ott accounts.account:change_password accounts.profile:inquiry accounts.account:update accounts.account:retrieve accounts.profile:retrieve accounts.profile:list introspection wallet.wallet:get_balance',
"scope": 'introspection',
"auth_fields": 'phone_number:otp'
}
auth = (OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET)
@ -51,7 +51,8 @@ class ApiClient():
"grant_type": "password",
"username": phone_number,
"password": token,
"scope": 'introspection education.course:retrieve education.course:submit superapp.applications:list accounts.account:request_ott accounts.profile:list accounts.profile:retrieve accounts.account:retrieve accounts.account:update accounts.profile:inquiry accounts.account:change_password wallet.transaction:list wallet.invoice:create wallet.transaction:retrieve wallet.invoice:pay wallet.invoice:receipt wallet.deposit:submit wallet.deposit:verify wallet.withdraw:submit wallet.withdraw:verify ',
# "scope": 'introspection education.course:retrieve education.course:submit superapp.applications:list accounts.account:request_ott accounts.profile:list accounts.profile:retrieve accounts.account:retrieve accounts.account:update accounts.profile:inquiry accounts.account:change_password wallet.transaction:list wallet.invoice:create wallet.transaction:retrieve wallet.invoice:pay wallet.invoice:receipt wallet.deposit:submit wallet.deposit:verify wallet.withdraw:submit wallet.withdraw:verify ',
"scope": 'introspection',
"auth_fields": 'phone_number:ott'
}
auth = (OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET)
@ -156,6 +157,7 @@ class ApiClient():
}
url = f'{API_URI}/{path}'
response = self._request(url, method='PUT', data=data)
print(response)
return response and 'code' in response, response
def introspect_account(self, token):
@ -185,19 +187,29 @@ class ApiClient():
return self._request(url=url)
def get_wallet_balance(self):
url = 'http://127.0.0.1:8000/wallet/api/wallet/default/balance'
def get_application_preferences(self):
url = 'https://preferences.gooyal.com/data/application/'
return self._request(url=url)
auth_data = {'access_token': 'DJ1mycH9r5FCwaNgDA9nB9uU3KWt9m', 'expires_in': 36000, 'token_type': 'Bearer', 'scope': 'accounts.account:change_password accounts.account:update accounts.account:retrieve wallet.wallet:get_balance billboard_merchant.billboard:retrieve billboard_merchant.billboard:update billboard_merchant.billboard:create wallet.user:transaction_list data_crud.data:retrieve data_crud.data:update data_crud.data:delete', 'refresh_token': 'VF4P11tfcnGv9tc2u0qH6035OW5qU4'}
client = ApiClient('+989106853582')
# client.auth_data = auth_data
# print(client.login_as_client_credentials())
print(client.request_otp())
print(client.otp_login('12345'))
print(client.introspect_account('V3LUQ9OryHOy6q5iWwLBRAtRBm80ex'))
print(client.get_wallet_balance())
import time
start = time.time()
print(client.otp_login('77502'))
# end = time.time()
# print(end - start)
# print(client.get_application_preferences())
# exit()
# print(client.introspect_account('V3LUQ9OryHOy6q5iWwLBRAtRBm80ex'))
# print(client.get_wallet_balance())
# ott = client.get_application_token()[1]['ott']
# print(client.ott_login(ott))
# print(ott)
client.update_account('test')

View file

@ -6,7 +6,7 @@
# from django.conf import settings
#
# # set the default Django settings module for the 'celery' program.
# # os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'accounts.settings')
# # os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'main.settings')
#
# app = Celery('notification_service')
#

View file

@ -126,7 +126,9 @@ REST_FRAMEWORK = {
],
'DEFAULT_THROTTLE_RATES': {
'otp_min': '2/min',
'otp_day': '200/day',
'otp_day': '50/day',
'numbered_otp_min': '1/min',
'numbered_otp_day': '10/day',
},
'EXCEPTION_HANDLER': 'utils.exceptions.exception_handler',
}
@ -293,7 +295,7 @@ CACHES = {
}
}
LOKI_BASE_PUBLIC_URL = config('LOKI_BASE_PUBLIC_URL', default=None, cast=str)
from main.other_settings.logging import LOGGING
@ -315,7 +317,7 @@ STORAGES = {
"MINIO_ACCESS_KEY": config('MINIO_ACCESS_KEY'),
"MINIO_SECRET_KEY": config('MINIO_SECRET_KEY'),
"MINIO_URL_EXPIRY_HOURS": timedelta(days=1), # Default is 7 days (longest) if not defined
"MINIO_CONSISTENCY_CHECK_ON_START": False,
"MINIO_CONSISTENCY_CHECK_ON_START": True,
"MINIO_DEFAULT_BUCKET": config('MINIO_MEDIA_FILES_BUCKET'), # replacement for MEDIA_ROOT
# MINIO_STATIC_FILES_BUCKET = 'my-static-files-bucket' # replacement for STATIC_ROOT

4
run.sh
View file

@ -4,6 +4,6 @@
# sleep 3
#done
#python3 manage.py collectstatic --noinput
#python3 manage.py migrate
python3 manage.py migrate
gunicorn main.wsgi:application --bind 0.0.0.0:8000 -w 4
#daphne -b 0.0.0.0 -p 8000 accounts.asgi:application
#daphne -b 0.0.0.0 -p 8000 main.asgi:application

View file

@ -23,14 +23,9 @@ def exception_handler(exc, context):
if isinstance(exc, APIException):
try:
if isinstance(exc.detail, dict):
if 'code' in exc.detail:
error = exc.detail['code']
else:
attr = next(iter(exc.detail))
error = exc.detail[attr].code
else:
error = exc.detail.code or exc.code
error = getattr(getattr(exc, 'detail', None), 'code', None) or getattr(exc, 'code', None)
if not error:
error = getattr(exc, 'default_code')
except:
error = ''
@ -46,9 +41,6 @@ def exception_handler(exc, context):
# message = error
#
# response_data['message'] = message
if isinstance(exc.detail, dict):
response_data['details'] = exc.detail
else:
response_data['details'] = {"message": exc.detail}
response_data['details']['error'] = error
response_data['details']['timestamp'] = timezone.now().isoformat()
@ -89,7 +81,7 @@ from django.utils.translation import gettext_lazy as _
class UnprocessableEntity(APIException):
status_code = 422
status_code = status.HTTP_422_UNPROCESSABLE_ENTITY
default_detail = 'The request was well-formed but cannot be processed due to semantic errors.'
default_code = 'unprocessable_entity'

View file

@ -16,9 +16,33 @@ class RequestOTPDayRateThrottle(SimpleRateThrottle):
}
class RequestOTPMinRateThrottle(RequestOTPDayRateThrottle):
scope = 'otp_min'
class NumberedRequestOTPDayRateThrottle(SimpleRateThrottle):
scope = 'numbered_otp_day'
def get_ident(self, request):
return request.data.get('phone_number')
def get_cache_key(self, request, view):
if request.user and request.user.is_authenticated:
ident = request.user.pk
else:
ident = self.get_ident(request)
return self.cache_format % {
'scope': self.scope,
'ident': ident
}
class NumberedRequestOTPMinRateThrottle(NumberedRequestOTPDayRateThrottle):
scope = 'numbered_otp_min'