mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-06-28 05:26:07 +00:00
Add wallet balance to User model and implement Atoll/Island management
- Added `wallet_balance` field to the User model. - Updated UserAdmin to include `wallet_balance` in the admin interface. - Created serializers and views for Atoll and Island management. - Implemented endpoints for listing, creating, and updating Atolls and Islands. - Enhanced payment processing with UUIDs for Payment and Topup models. - Added migration files for new fields and constraints. - Improved error handling and validation in various views. - Updated email templates for better responsiveness and SEO.
This commit is contained in:
@ -1,5 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Your login token">
|
||||
<meta name="keywords" content="login, token, SARLink Portal">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Your Login Token</title>
|
||||
@ -62,6 +66,7 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
@ -85,4 +90,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
@ -1,10 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Your verification token">
|
||||
<meta name="keywords" content="verification, token, sarlink">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Your Verification Token</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Use this verification code: {{ callback_token }}</h2>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
|
||||
# import os
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import PermissionDenied
|
||||
@ -7,10 +8,12 @@ from django.template import loader
|
||||
from django.utils import timezone
|
||||
from djangopasswordlessknox.models import CallbackToken
|
||||
from djangopasswordlessknox.settings import api_settings
|
||||
|
||||
# from twilio.rest import Client
|
||||
from decouple import config
|
||||
import requests
|
||||
import json
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
User = get_user_model()
|
||||
|
||||
@ -27,9 +30,13 @@ def authenticate_by_token(callback_token):
|
||||
return token.user
|
||||
|
||||
except CallbackToken.DoesNotExist:
|
||||
logger.debug("djangopasswordlessknox: Challenged with a callback token that doesn't exist.")
|
||||
logger.debug(
|
||||
"djangopasswordlessknox: Challenged with a callback token that doesn't exist."
|
||||
)
|
||||
except User.DoesNotExist:
|
||||
logger.debug("djangopasswordlessknox: Authenticated user somehow doesn't exist.")
|
||||
logger.debug(
|
||||
"djangopasswordlessknox: Authenticated user somehow doesn't exist."
|
||||
)
|
||||
except PermissionDenied:
|
||||
logger.debug("djangopasswordlessknox: Permission denied while authenticating.")
|
||||
|
||||
@ -41,15 +48,19 @@ def create_callback_token_for_user(user, token_type):
|
||||
token = None
|
||||
token_type = token_type.upper()
|
||||
|
||||
if token_type == 'EMAIL':
|
||||
token = CallbackToken.objects.create(user=user,
|
||||
to_alias_type=token_type,
|
||||
to_alias=getattr(user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME))
|
||||
if token_type == "EMAIL":
|
||||
token = CallbackToken.objects.create(
|
||||
user=user,
|
||||
to_alias_type=token_type,
|
||||
to_alias=getattr(user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME),
|
||||
)
|
||||
|
||||
elif token_type == 'MOBILE':
|
||||
token = CallbackToken.objects.create(user=user,
|
||||
to_alias_type=token_type,
|
||||
to_alias=getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME))
|
||||
elif token_type == "MOBILE":
|
||||
token = CallbackToken.objects.create(
|
||||
user=user,
|
||||
to_alias_type=token_type,
|
||||
to_alias=getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME),
|
||||
)
|
||||
|
||||
if token is not None:
|
||||
return token
|
||||
@ -83,12 +94,20 @@ def verify_user_alias(user, token):
|
||||
"""
|
||||
Marks a user's contact point as verified depending on accepted token type.
|
||||
"""
|
||||
if token.to_alias_type == 'EMAIL':
|
||||
if token.to_alias == getattr(user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME):
|
||||
setattr(user, api_settings.PASSWORDLESS_USER_EMAIL_VERIFIED_FIELD_NAME, True)
|
||||
elif token.to_alias_type == 'MOBILE':
|
||||
if token.to_alias == getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME):
|
||||
setattr(user, api_settings.PASSWORDLESS_USER_MOBILE_VERIFIED_FIELD_NAME, True)
|
||||
if token.to_alias_type == "EMAIL":
|
||||
if token.to_alias == getattr(
|
||||
user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME
|
||||
):
|
||||
setattr(
|
||||
user, api_settings.PASSWORDLESS_USER_EMAIL_VERIFIED_FIELD_NAME, True
|
||||
)
|
||||
elif token.to_alias_type == "MOBILE":
|
||||
if token.to_alias == getattr(
|
||||
user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME
|
||||
):
|
||||
setattr(
|
||||
user, api_settings.PASSWORDLESS_USER_MOBILE_VERIFIED_FIELD_NAME, True
|
||||
)
|
||||
else:
|
||||
return False
|
||||
user.save()
|
||||
@ -116,32 +135,47 @@ def send_email_with_callback_token(user, email_token, **kwargs):
|
||||
# Make sure we have a sending address before sending.
|
||||
|
||||
# Get email subject and message
|
||||
email_subject = kwargs.get('email_subject',
|
||||
api_settings.PASSWORDLESS_EMAIL_SUBJECT)
|
||||
email_plaintext = kwargs.get('email_plaintext',
|
||||
api_settings.PASSWORDLESS_EMAIL_PLAINTEXT_MESSAGE)
|
||||
email_html = kwargs.get('email_html',
|
||||
api_settings.PASSWORDLESS_EMAIL_TOKEN_HTML_TEMPLATE_NAME)
|
||||
email_subject = kwargs.get(
|
||||
"email_subject", api_settings.PASSWORDLESS_EMAIL_SUBJECT
|
||||
)
|
||||
email_plaintext = kwargs.get(
|
||||
"email_plaintext", api_settings.PASSWORDLESS_EMAIL_PLAINTEXT_MESSAGE
|
||||
)
|
||||
email_html = kwargs.get(
|
||||
"email_html", api_settings.PASSWORDLESS_EMAIL_TOKEN_HTML_TEMPLATE_NAME
|
||||
)
|
||||
# Inject context if user specifies.
|
||||
context = inject_template_context({'callback_token': email_token.key, })
|
||||
html_message = loader.render_to_string(email_html, context,)
|
||||
context = inject_template_context(
|
||||
{
|
||||
"callback_token": email_token.key,
|
||||
}
|
||||
)
|
||||
html_message = loader.render_to_string(
|
||||
email_html,
|
||||
context,
|
||||
)
|
||||
send_mail(
|
||||
email_subject,
|
||||
email_plaintext % email_token.key,
|
||||
api_settings.PASSWORDLESS_EMAIL_NOREPLY_ADDRESS,
|
||||
[getattr(user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME)],
|
||||
fail_silently=False,
|
||||
html_message=html_message,)
|
||||
html_message=html_message,
|
||||
)
|
||||
|
||||
else:
|
||||
logger.debug("Failed to send token email. Missing PASSWORDLESS_EMAIL_NOREPLY_ADDRESS.")
|
||||
logger.debug(
|
||||
"Failed to send token email. Missing PASSWORDLESS_EMAIL_NOREPLY_ADDRESS."
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.debug("Failed to send token email to user: %d."
|
||||
"Possibly no email on user object. Email entered was %s" %
|
||||
(user.id, getattr(user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME)))
|
||||
logger.debug(
|
||||
"Failed to send token email to user: %d."
|
||||
"Possibly no email on user object. Email entered was %s"
|
||||
% (user.id, getattr(user, api_settings.PASSWORDLESS_USER_EMAIL_FIELD_NAME))
|
||||
)
|
||||
logger.debug(e)
|
||||
return False
|
||||
|
||||
@ -152,60 +186,62 @@ def send_sms_with_callback_token(user, mobile_token, **kwargs):
|
||||
|
||||
Passes silently without sending in test environment.
|
||||
"""
|
||||
base_string = kwargs.get('mobile_message', api_settings.PASSWORDLESS_MOBILE_MESSAGE)
|
||||
base_string = kwargs.get("mobile_message", api_settings.PASSWORDLESS_MOBILE_MESSAGE)
|
||||
|
||||
try:
|
||||
if api_settings.PASSWORDLESS_MOBILE_NOREPLY_NUMBER:
|
||||
print("Sending SMS")
|
||||
# We need a sending number to send properly
|
||||
if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True:
|
||||
# we assume success to prevent spamming SMS during testing.
|
||||
return True
|
||||
to_number = getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME)
|
||||
if to_number.__class__.__name__ == 'PhoneNumber':
|
||||
to_number = to_number.__str__()
|
||||
print("Sending SMS")
|
||||
# We need a sending number to send properly
|
||||
if api_settings.PASSWORDLESS_TEST_SUPPRESSION is True:
|
||||
# we assume success to prevent spamming SMS during testing.
|
||||
return True
|
||||
to_number = getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME)
|
||||
if to_number.__class__.__name__ == "PhoneNumber":
|
||||
to_number = to_number.__str__()
|
||||
|
||||
# user_withh_mobile_exists = User.objects.filter(mobile=to_number).exists()
|
||||
# if not user_withh_mobile_exists:
|
||||
# print("User with mobile number does not exist.")
|
||||
# logger.debug("User with mobile number does not exist.")
|
||||
# return False
|
||||
# user_withh_mobile_exists = User.objects.filter(mobile=to_number).exists()
|
||||
# if not user_withh_mobile_exists:
|
||||
# print("User with mobile number does not exist.")
|
||||
# logger.debug("User with mobile number does not exist.")
|
||||
# return False
|
||||
|
||||
|
||||
api_url = config("SMS_API_URL")
|
||||
api_key = config("SMS_API_KEY")
|
||||
if not api_url or not api_key:
|
||||
logger.debug("Failed to send SMS. Missing SMS_API_URL or SMS_API_KEY.")
|
||||
return False
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}"
|
||||
}
|
||||
data = {
|
||||
"number": to_number,
|
||||
"message": base_string % mobile_token.key,
|
||||
"check_delivery": False
|
||||
}
|
||||
|
||||
response = requests.post(api_url, headers=headers, data=json.dumps(data))
|
||||
if response.status_code == 200:
|
||||
return True
|
||||
else:
|
||||
logger.debug(f"Failed to send SMS. Status code: {response.status_code}")
|
||||
return False
|
||||
else:
|
||||
logger.debug("Failed to send token sms. Missing PASSWORDLESS_MOBILE_NOREPLY_NUMBER.")
|
||||
api_url = config("SMS_API_URL")
|
||||
api_key = config("SMS_API_KEY")
|
||||
if not api_url or not api_key:
|
||||
logger.debug("Failed to send SMS. Missing SMS_API_URL or SMS_API_KEY.")
|
||||
return False
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
}
|
||||
data = {
|
||||
"number": to_number,
|
||||
"message": base_string % mobile_token.key,
|
||||
"check_delivery": False,
|
||||
}
|
||||
|
||||
response = requests.post(api_url, headers=headers, data=json.dumps(data))
|
||||
if response.status_code == 200:
|
||||
return True
|
||||
else:
|
||||
logger.debug(f"Failed to send SMS. Status code: {response.status_code}")
|
||||
return False
|
||||
|
||||
except ImportError:
|
||||
logger.debug("Couldn't import Twilio client. Is twilio installed?")
|
||||
return False
|
||||
except KeyError:
|
||||
logger.debug("Couldn't send SMS."
|
||||
"Did you set your Twilio account tokens and specify a PASSWORDLESS_MOBILE_NOREPLY_NUMBER?")
|
||||
logger.debug(
|
||||
"Couldn't send SMS."
|
||||
"Did you set your Twilio account tokens and specify a PASSWORDLESS_MOBILE_NOREPLY_NUMBER?"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("Failed to send token SMS to user: {}. "
|
||||
"Possibly no mobile number on user object or the twilio package isn't set up yet. "
|
||||
"Number entered was {}".format(user.id, getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME)))
|
||||
logger.debug(
|
||||
"Failed to send token SMS to user: {}. "
|
||||
"Possibly no mobile number on user object or the twilio package isn't set up yet. "
|
||||
"Number entered was {}".format(
|
||||
user.id, getattr(user, api_settings.PASSWORDLESS_USER_MOBILE_FIELD_NAME)
|
||||
)
|
||||
)
|
||||
logger.debug(e)
|
||||
return False
|
||||
|
Reference in New Issue
Block a user