Selah/backend/users_app/views.py

349 lines
13 KiB
Python
Raw Normal View History

2023-06-14 10:34:24 +00:00
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.'})