349 lines
13 KiB
Python
349 lines
13 KiB
Python
|
from django.shortcuts import render
|
||
|
|
||
|
# Create your views here.
|
||
|
from rest_framework.views import APIView
|
||
|
from rest_framework.decorators import api_view
|
||
|
from rest_framework.response import Response
|
||
|
from rest_framework import authentication, permissions
|
||
|
from rest_framework.decorators import api_view, authentication_classes, permission_classes
|
||
|
from rest_framework.authtoken.models import Token
|
||
|
from rest_framework.permissions import IsAuthenticated
|
||
|
from django.contrib.auth import get_user_model
|
||
|
from users_app.serializers import *
|
||
|
from django.core.mail import EmailMessage
|
||
|
# converts html template to a string message for emails
|
||
|
from django.template.loader import render_to_string
|
||
|
from django.http import HttpResponse
|
||
|
from django.conf import settings
|
||
|
from main_project import settings
|
||
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||
|
from django.utils.encoding import force_bytes
|
||
|
from django.utils.http import urlsafe_base64_encode
|
||
|
from django.utils.encoding import force_str
|
||
|
from django.utils.http import urlsafe_base64_decode
|
||
|
from django.contrib.auth.tokens import default_token_generator
|
||
|
from rest_framework import permissions, status
|
||
|
|
||
|
# for saving profilepic
|
||
|
from PIL import Image
|
||
|
from django.core.files import File
|
||
|
from io import BytesIO
|
||
|
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||
|
from rest_framework.permissions import AllowAny
|
||
|
|
||
|
# set up logger
|
||
|
import logging
|
||
|
import os
|
||
|
logger = logging.getLogger(__name__)
|
||
|
logger.setLevel(logging.DEBUG)
|
||
|
|
||
|
# create file handler and set level to INFO
|
||
|
log_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'user_logs.txt')
|
||
|
fh = logging.FileHandler(log_file)
|
||
|
fh.setLevel(logging.INFO)
|
||
|
|
||
|
# create formatter
|
||
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||
|
fh.setFormatter(formatter)
|
||
|
logger.addHandler(fh)
|
||
|
|
||
|
|
||
|
user_obj = get_user_model()
|
||
|
|
||
|
# email stuff for sending email notifications
|
||
|
EMAIL_ON = False
|
||
|
URL = settings.env('DEV_DOMAIN') if settings.env('DEV_MODE') == 'True' else None
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
# save user pfp on signup
|
||
|
# SaveUserProfilePicture API view
|
||
|
class SaveCustomBasicUser(APIView):
|
||
|
permission_classes = [AllowAny]
|
||
|
|
||
|
def post(self, request, *args, **kwargs):
|
||
|
serializer = CustomUserCreateSerializer(data=request.data)
|
||
|
if serializer.is_valid():
|
||
|
profile_pic = request.FILES.get('user_profile_pic', None)
|
||
|
if profile_pic:
|
||
|
profile_pic.file.seek(0)
|
||
|
image = Image.open(BytesIO(profile_pic.read()))
|
||
|
if image.mode == 'RGBA':
|
||
|
image = image.convert('RGB')
|
||
|
pfp_name = serializer.validated_data['username'] + '_pfp'
|
||
|
buffer = BytesIO()
|
||
|
image.save(buffer, format='JPEG')
|
||
|
image_file = InMemoryUploadedFile(
|
||
|
buffer, None, pfp_name + '.jpg', 'image/jpeg',
|
||
|
buffer.getbuffer().nbytes, None
|
||
|
)
|
||
|
# Call create_user method of custom user manager to create user instance
|
||
|
user = Users_CustomUserManager().create_user(
|
||
|
email=serializer.validated_data['email'],
|
||
|
username=serializer.validated_data['username'],
|
||
|
password=serializer.validated_data['password'],
|
||
|
user_profile_pic=image_file,
|
||
|
user_first_name=serializer.validated_data['user_first_name'],
|
||
|
user_last_name=serializer.validated_data['user_last_name'],
|
||
|
user_favorite_bible_verse=serializer.validated_data['user_favorite_bible_verse']
|
||
|
)
|
||
|
return Response(status=status.HTTP_200_OK)
|
||
|
else:
|
||
|
|
||
|
# save user without profile pic
|
||
|
user = Users_CustomUserManager().create_user(
|
||
|
email=serializer.validated_data['email'],
|
||
|
username=serializer.validated_data['username'],
|
||
|
password=serializer.validated_data['password'],
|
||
|
user_profile_pic=image_file,
|
||
|
user_first_name=serializer.validated_data['user_first_name'],
|
||
|
user_last_name=serializer.validated_data['user_last_name'],
|
||
|
user_favorite_bible_verse=serializer.validated_data['user_favorite_bible_verse']
|
||
|
)
|
||
|
return Response(status=status.HTTP_200_OK)
|
||
|
else:
|
||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||
|
|
||
|
|
||
|
# get user pfp on login
|
||
|
@api_view(['GET'])
|
||
|
@authentication_classes([authentication.TokenAuthentication])
|
||
|
@permission_classes([permissions.IsAuthenticated])
|
||
|
def get_user_pfp(request):
|
||
|
current_user = user_obj.objects.get(pk=request.user.pk)
|
||
|
user_pfp_serializer = GetUserPfpSerializer(current_user)
|
||
|
|
||
|
response = Response(user_pfp_serializer.data, status=status.HTTP_200_OK)
|
||
|
# added this to prevent vuejs from caching cart data
|
||
|
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||
|
response['Expires'] = '0'
|
||
|
|
||
|
|
||
|
return response
|
||
|
|
||
|
|
||
|
# delete user account
|
||
|
@api_view(['POST'])
|
||
|
@authentication_classes([authentication.TokenAuthentication])
|
||
|
@permission_classes([permissions.IsAuthenticated])
|
||
|
def delete_user_account_data(request):
|
||
|
|
||
|
# use first to prevent exception from being raised
|
||
|
try:
|
||
|
|
||
|
user_to_be_deleted = user_obj.objects.get(pk=request.user.pk)
|
||
|
user_to_be_deleted.delete()
|
||
|
# return no content, everything worked
|
||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||
|
|
||
|
except:
|
||
|
return Response({'error': 'Invalid token or user'}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
|
||
|
|
||
|
# update user account info
|
||
|
@api_view(['POST'])
|
||
|
@authentication_classes([authentication.TokenAuthentication])
|
||
|
@permission_classes([permissions.IsAuthenticated])
|
||
|
def update_user_account_data(request):
|
||
|
|
||
|
# get the user
|
||
|
current_user = user_obj.objects.get(pk=request.user.pk)
|
||
|
# Deserialize incoming data
|
||
|
# serializer = UpdateUserAccountDataSerializer(data=request.data)
|
||
|
serializer = UpdateUserAccountDataSerializer(data=request.data, context={'request': request})
|
||
|
|
||
|
if serializer.is_valid():
|
||
|
|
||
|
# get the img file
|
||
|
profile_pic = request.FILES.get('user_profile_pic', None)
|
||
|
|
||
|
if profile_pic:
|
||
|
|
||
|
profile_pic.file.seek(0)
|
||
|
# Open the uploaded image file
|
||
|
image = Image.open(BytesIO(profile_pic.read()))
|
||
|
|
||
|
# Convert RGBA to RGB mode if it exists
|
||
|
if image.mode == 'RGBA':
|
||
|
image = image.convert('RGB')
|
||
|
|
||
|
pfp_name = current_user.username + '_pfp'
|
||
|
|
||
|
buffer = BytesIO()
|
||
|
image.save(buffer, format='JPEG')
|
||
|
image_file = InMemoryUploadedFile(
|
||
|
buffer, None, pfp_name + '.jpg', 'image/jpeg',
|
||
|
buffer.getbuffer().nbytes, None
|
||
|
)
|
||
|
current_user.user_profile_pic.save(pfp_name + '.jpg', image_file)
|
||
|
|
||
|
else:
|
||
|
print('\n\n Image does not exist')
|
||
|
# save the rest of the text fields
|
||
|
# Update user fields
|
||
|
# validated_data is a dictionary that holds validated data ready to be saved to db
|
||
|
current_user.username = serializer.validated_data.get('username', current_user.username)
|
||
|
current_user.email = serializer.validated_data.get('email', current_user.email)
|
||
|
current_user.user_first_name = serializer.validated_data.get('user_first_name', current_user.first_name)
|
||
|
current_user.user_last_name = serializer.validated_data.get('user_last_name', current_user.last_name)
|
||
|
current_user.user_favorite_bible_verse = serializer.validated_data.get('user_favorite_bible_verse', current_user.favorite_color)
|
||
|
|
||
|
current_user.save()
|
||
|
return Response(status=status.HTTP_200_OK)
|
||
|
else:
|
||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||
|
|
||
|
|
||
|
# get user account data
|
||
|
@api_view(['GET'])
|
||
|
@authentication_classes([authentication.TokenAuthentication])
|
||
|
@permission_classes([permissions.IsAuthenticated])
|
||
|
def get_user_account_data(request):
|
||
|
|
||
|
current_user = user.objects.get(pk=request.user.pk)
|
||
|
user_serializer = GetUserSerializer(current_user)
|
||
|
|
||
|
response = Response(user_serializer.data, status=status.HTTP_200_OK)
|
||
|
# added this to prevent frontend from caching cart data
|
||
|
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||
|
response['Expires'] = '0'
|
||
|
|
||
|
|
||
|
return response
|
||
|
|
||
|
|
||
|
'''
|
||
|
|
||
|
# reset password
|
||
|
@api_view(['POST'])
|
||
|
@permission_classes([permissions.AllowAny])
|
||
|
def reset_password(request):
|
||
|
|
||
|
try:
|
||
|
|
||
|
uid = force_str(urlsafe_base64_decode(request.data.get('uidb64')))
|
||
|
|
||
|
current_user = user.objects.get(pk=uid)
|
||
|
|
||
|
except (TypeError, ValueError, OverflowError, user.DoesNotExist):
|
||
|
current_user = None
|
||
|
|
||
|
# Check if the token is valid
|
||
|
if current_user is not None and default_token_generator.check_token(current_user, request.data.get('token')):
|
||
|
# Set the new password for the user
|
||
|
password = request.data.get('password')
|
||
|
current_user.set_password(password)
|
||
|
current_user.save()
|
||
|
|
||
|
template = render_to_string('../templates/changed_account_notice_email.html', {'name':current_user.first_name})
|
||
|
email = EmailMessage(
|
||
|
# email subject title default is 'subject'
|
||
|
'There was a change to your account -- アカウント情報変更のお知らせ',
|
||
|
# email template default is 'body'
|
||
|
template,
|
||
|
|
||
|
settings.EMAIL_HOST_USER,
|
||
|
# recipient list
|
||
|
[current_user.email],
|
||
|
)
|
||
|
email.fail_silently=False
|
||
|
# eonly send email if this flag is true
|
||
|
if EMAIL_ON:
|
||
|
email.send()
|
||
|
|
||
|
return Response({'success': 'Password reset successful'}, status=status.HTTP_200_OK)
|
||
|
else:
|
||
|
return Response({'error': 'Invalid token or user'}, status=status.HTTP_400_BAD_REQUEST)
|
||
|
|
||
|
|
||
|
# send password reset link
|
||
|
@api_view(['POST'])
|
||
|
@permission_classes([permissions.AllowAny])
|
||
|
def send_password_reset_link(request):
|
||
|
|
||
|
# get the email address from the POST request
|
||
|
email = request.data.get('potential_email_address')
|
||
|
|
||
|
# check if the email address is valid
|
||
|
try:
|
||
|
get_user = user.objects.get(email=email)
|
||
|
|
||
|
# creating a password reset url unique for each user
|
||
|
token_generator = PasswordResetTokenGenerator()
|
||
|
uidb64 = urlsafe_base64_encode(force_bytes(get_user.pk))
|
||
|
token = token_generator.make_token(get_user)
|
||
|
# create the password reset URL using the generated token
|
||
|
password_reset_url = f'{URL}{request.data.get("password_reset_url")}/{uidb64}/{token}/'
|
||
|
|
||
|
|
||
|
|
||
|
EMAIL_ON = True
|
||
|
template = render_to_string('../templates/password-reset-email.html', {'name':get_user.first_name, 'password_reset_url': password_reset_url})
|
||
|
email = EmailMessage(
|
||
|
# email subject title default is 'subject'
|
||
|
'Password reset -- パスワードのリセット',
|
||
|
# email template default is 'body'
|
||
|
template,
|
||
|
settings.EMAIL_HOST_USER,
|
||
|
# recipient list
|
||
|
[get_user.email],
|
||
|
)
|
||
|
email.fail_silently=False
|
||
|
# only send email if this flag is true
|
||
|
if EMAIL_ON:
|
||
|
email.send()
|
||
|
# just return a 200 response
|
||
|
return HttpResponse(status=200)
|
||
|
except user.DoesNotExist:
|
||
|
# handle the case where the user does not exist
|
||
|
return Response({'error': 'User does not exist'}, status=200)
|
||
|
|
||
|
except Exception as e:
|
||
|
return Response({'error': 'Unknown error occurred'}, status=500)
|
||
|
'''
|
||
|
|
||
|
# get user data
|
||
|
@api_view(['GET'])
|
||
|
def get_user_device(request):
|
||
|
user_agent = request.META.get('HTTP_USER_AGENT', None)
|
||
|
# do something with usr's device
|
||
|
return Response({'message': 'success'})
|
||
|
|
||
|
|
||
|
|
||
|
# checking username in form validation
|
||
|
# need to include the request or else there will be an error
|
||
|
@api_view(['GET'])
|
||
|
def check_username(request, username):
|
||
|
username_available = not user.objects.filter(username=username).exists()
|
||
|
|
||
|
response = Response({'available': username_available})
|
||
|
# added this to prevent vuejs from caching cart data
|
||
|
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||
|
response['Expires'] = '0'
|
||
|
|
||
|
return response
|
||
|
|
||
|
# checking username in form validation
|
||
|
@api_view(['GET'])
|
||
|
def check_email(request, email):
|
||
|
email_available = not user.objects.filter(email=email).exists()
|
||
|
|
||
|
response = Response({'available': email_available})
|
||
|
# added this to prevent vuejs from caching cart data
|
||
|
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||
|
response['Expires'] = '0'
|
||
|
|
||
|
return response
|
||
|
|
||
|
# de-authenticate user by deleting auth token, and storing/updating and then saving the user's cart data
|
||
|
class LogoutView(APIView):
|
||
|
permission_classes = (IsAuthenticated,)
|
||
|
|
||
|
def post(self, request, format=None):
|
||
|
|
||
|
|
||
|
Token.objects.filter(user=user).delete()
|
||
|
return Response({'success': 'Logged out successfully.'})
|