* refactor: folder structure for urls * chore: deleted the urls file * chore: proper naming for urls * chore: reset password url * dev: create refresh token endpoint and endpoint to get settings for user * dev: workspace member me serializer * dev: remove extra fields from project list and retrieve endpoints * dev: update the project list endpoint with member details and deploy boolean * dev: enable user favorite project endpoint and remove is_favorite from project list * dev: analytics refactoring * dev: revert is_favorite settings * dev: create new serializer for project list and add pagination from projects * dev: fix analytics api * dev: module and cycle * dev: update error message, fix module analytics and add null check for labels * dev: member serializer * dev: dynamic base serializer * dev: remove view issues endpoint * dev: url pattern updates * dev: add comments to delete this file * dev: last workspace id * dev: analytics export * dev: export analytics validation * dev: update python runtime * dev: update notification endpoints * dev: cycle and validation fix * dev: issue activity validation when creating updating and deleting issue and comments * dev: update issue activity logging for link and reactions * dev: update module issue activity logging * dev: update module issue activity --------- Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
158 lines
5.5 KiB
Python
158 lines
5.5 KiB
Python
## Python imports
|
|
import jwt
|
|
|
|
## Django imports
|
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
|
from django.utils.encoding import (
|
|
smart_str,
|
|
smart_bytes,
|
|
DjangoUnicodeDecodeError,
|
|
)
|
|
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
|
|
from django.conf import settings
|
|
|
|
## Third Party Imports
|
|
from rest_framework import status
|
|
from rest_framework.response import Response
|
|
from rest_framework import permissions
|
|
from rest_framework_simplejwt.tokens import RefreshToken
|
|
|
|
from sentry_sdk import capture_exception
|
|
|
|
## Module imports
|
|
from . import BaseAPIView
|
|
from plane.api.serializers import (
|
|
ChangePasswordSerializer,
|
|
ResetPasswordSerializer,
|
|
)
|
|
from plane.db.models import User
|
|
from plane.bgtasks.email_verification_task import email_verification
|
|
from plane.bgtasks.forgot_password_task import forgot_password
|
|
|
|
|
|
class RequestEmailVerificationEndpoint(BaseAPIView):
|
|
def get(self, request):
|
|
token = RefreshToken.for_user(request.user).access_token
|
|
current_site = settings.WEB_URL
|
|
email_verification.delay(
|
|
request.user.first_name, request.user.email, token, current_site
|
|
)
|
|
return Response(
|
|
{"message": "Email sent successfully"}, status=status.HTTP_200_OK
|
|
)
|
|
|
|
|
|
class VerifyEmailEndpoint(BaseAPIView):
|
|
def get(self, request):
|
|
token = request.GET.get("token")
|
|
try:
|
|
payload = jwt.decode(token, settings.SECRET_KEY, algorithms="HS256")
|
|
user = User.objects.get(id=payload["user_id"])
|
|
|
|
if not user.is_email_verified:
|
|
user.is_email_verified = True
|
|
user.save()
|
|
return Response(
|
|
{"email": "Successfully activated"}, status=status.HTTP_200_OK
|
|
)
|
|
except jwt.ExpiredSignatureError as indentifier:
|
|
return Response(
|
|
{"email": "Activation expired"}, status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
except jwt.exceptions.DecodeError as indentifier:
|
|
return Response(
|
|
{"email": "Invalid token"}, status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
|
|
class ForgotPasswordEndpoint(BaseAPIView):
|
|
permission_classes = [permissions.AllowAny]
|
|
|
|
def post(self, request):
|
|
email = request.data.get("email")
|
|
|
|
if User.objects.filter(email=email).exists():
|
|
user = User.objects.get(email=email)
|
|
uidb64 = urlsafe_base64_encode(smart_bytes(user.id))
|
|
token = PasswordResetTokenGenerator().make_token(user)
|
|
|
|
current_site = settings.WEB_URL
|
|
|
|
forgot_password.delay(
|
|
user.first_name, user.email, uidb64, token, current_site
|
|
)
|
|
|
|
return Response(
|
|
{"message": "Check your email to reset your password"},
|
|
status=status.HTTP_200_OK,
|
|
)
|
|
return Response(
|
|
{"error": "Please check the email"}, status=status.HTTP_400_BAD_REQUEST
|
|
)
|
|
|
|
|
|
class ResetPasswordEndpoint(BaseAPIView):
|
|
permission_classes = [permissions.AllowAny]
|
|
|
|
def post(self, request, uidb64, token):
|
|
try:
|
|
id = smart_str(urlsafe_base64_decode(uidb64))
|
|
user = User.objects.get(id=id)
|
|
if not PasswordResetTokenGenerator().check_token(user, token):
|
|
return Response(
|
|
{"error": "token is not valid, please check the new one"},
|
|
status=status.HTTP_401_UNAUTHORIZED,
|
|
)
|
|
serializer = ResetPasswordSerializer(data=request.data)
|
|
|
|
if serializer.is_valid():
|
|
# set_password also hashes the password that the user will get
|
|
user.set_password(serializer.data.get("new_password"))
|
|
user.save()
|
|
response = {
|
|
"status": "success",
|
|
"code": status.HTTP_200_OK,
|
|
"message": "Password updated successfully",
|
|
}
|
|
|
|
return Response(response)
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
except DjangoUnicodeDecodeError as indentifier:
|
|
return Response(
|
|
{"error": "token is not valid, please check the new one"},
|
|
status=status.HTTP_401_UNAUTHORIZED,
|
|
)
|
|
|
|
|
|
class ChangePasswordEndpoint(BaseAPIView):
|
|
def post(self, request):
|
|
try:
|
|
serializer = ChangePasswordSerializer(data=request.data)
|
|
|
|
user = User.objects.get(pk=request.user.id)
|
|
if serializer.is_valid():
|
|
# Check old password
|
|
if not user.object.check_password(serializer.data.get("old_password")):
|
|
return Response(
|
|
{"old_password": ["Wrong password."]},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
# set_password also hashes the password that the user will get
|
|
self.object.set_password(serializer.data.get("new_password"))
|
|
self.object.save()
|
|
response = {
|
|
"status": "success",
|
|
"code": status.HTTP_200_OK,
|
|
"message": "Password updated successfully",
|
|
}
|
|
|
|
return Response(response)
|
|
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
except Exception as e:
|
|
capture_exception(e)
|
|
return Response(
|
|
{"error": "Something went wrong please try again later"},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|