Skip to content

Commit

Permalink
Merge pull request #32 from Build-Squad/GEn-71-Refactor-User-Auth
Browse files Browse the repository at this point in the history
Add token field in User Model and check for token expiration
  • Loading branch information
varsha1305nav authored Dec 11, 2023
2 parents 7936a45 + 4eab492 commit 9ac3544
Show file tree
Hide file tree
Showing 16 changed files with 495 additions and 338 deletions.
18 changes: 18 additions & 0 deletions src/api/marketplace/accounts/migrations/0002_user_jwt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.7 on 2023-12-11 05:54

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('accounts', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='user',
name='jwt',
field=models.CharField(blank=True, max_length=255, null=True),
),
]
1 change: 1 addition & 0 deletions src/api/marketplace/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class User(AbstractUser):
otp_expiration = models.DateTimeField(blank=True, null=True)
twitter_account = models.ForeignKey(TwitterAccount, related_name='user_twitter_account_id', on_delete=SET_NULL,
null=True, blank=True)
jwt = models.CharField(max_length=255, blank=True, null=True)

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
Expand Down
25 changes: 9 additions & 16 deletions src/api/marketplace/accounts/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,20 @@ class Meta:
fields = "__all__"


class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = Role
fields = "__all__"


class UserSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(read_only=True)
username = serializers.CharField(read_only=True)
email = serializers.EmailField(read_only=True)
first_name = serializers.CharField(read_only=True)
last_name = serializers.CharField(read_only=True)
status = serializers.CharField(read_only=True)
joined_at = serializers.DateTimeField(read_only=True)
last_login = serializers.DateTimeField(read_only=True)
role = serializers.CharField(read_only=True)
twitter_account = TwitterAccountSerializer(read_only=True)
role = RoleSerializer(read_only=True)

class Meta:
model = User
fields = "__all__"
exclude = ("password", "otp", "otp_expiration", "is_superuser",
"is_staff", "is_active", "groups", "user_permissions")


class UserCreateSerializer(serializers.ModelSerializer):
Expand All @@ -51,9 +50,3 @@ class Meta:

class TwitterAuthSerializer(serializers.Serializer):
role = serializers.CharField(max_length=100)


class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = Role
fields = "__all__"
3 changes: 0 additions & 3 deletions src/api/marketplace/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,12 +630,10 @@ def get_object(self, twitter_id):
return None

def get(self, request):
print("-------------------------Reached GET call-------------------------")
try:
twitter_auth_service = TwitterAuthenticationService()
user_data = twitter_auth_service.get_twitter_client_data(request)
twitter_account = self.get_object(user_data.id)
print("-------------------------Reached Twitter Account-------------------------")
if twitter_account:
twitter_account.access_token = twitter_auth_service.get_twitter_access_token(
request.build_absolute_uri())
Expand Down Expand Up @@ -731,5 +729,4 @@ def get(self, request):
status=status.HTTP_404_NOT_FOUND,
)
except Exception as e:
print(e)
return handleServerException(e)
38 changes: 24 additions & 14 deletions src/api/marketplace/marketplace/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@

class JWTAuthentication(BaseAuthentication):
def authenticate(self, request):
payload, token = JWTOperations.getPayload(req=request, cookie_name="jwt")
try:
payload, token = JWTOperations.getPayload(
req=request, cookie_name="jwt")

# Extract user ID from the payload
user_id = payload.get("id")
if not user_id:
raise exceptions.AuthenticationFailed("Invalid JWT payload")
# Check for the expiration of the token
if JWTOperations.isTokenExpired(payload):
raise exceptions.AuthenticationFailed("Token has expired")

# Retrieve the corresponding user object
try:
userAccount = User.objects.filter(
id=payload["id"]
).first()
except userAccount.DoesNotExist:
raise exceptions.AuthenticationFailed("User does not exist")
request.user_account = userAccount
request.token = token
# Extract user ID from the payload
user_id = payload.get("id")
if not user_id:
raise exceptions.AuthenticationFailed(
"No user ID found in the token")

# Retrieve the corresponding user object
try:
userAccount = User.objects.get(id=user_id)
except userAccount.DoesNotExist:
raise exceptions.AuthenticationFailed(
"No user found for the given token")

request.user_account = userAccount
request.token = token
except Exception as e:
print("Error", e)
raise exceptions.AuthenticationFailed(e)
13 changes: 8 additions & 5 deletions src/api/marketplace/marketplace/services.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
import jwt
from decouple import config
from rest_framework import exceptions
Expand All @@ -12,11 +13,11 @@ class JWTOperations:
def getPayload(req, cookie_name):
token = req.COOKIES.get(cookie_name)
if not token:
raise exceptions.AuthenticationFailed("JWT Token not present in the request!")
raise exceptions.AuthenticationFailed("User is not logged in")
try:
payload = jwt.decode(token, config("JWT_SECRET"), algorithms=["HS256"])
except jwt.DecodeError:
raise exceptions.AuthenticationFailed("Invalid JWT token")
raise exceptions("Invalid JWT token")
return payload, token

def setJwtToken(res, payload, cookie_name):
Expand All @@ -43,6 +44,9 @@ def deleteJwtToken(res, cookie_name):
)
return res

def isTokenExpired(payload):
return payload.get("exp") < int(time.time())

class Pagination:
def __init__(self, qs, request):
self.qs = qs
Expand All @@ -55,7 +59,6 @@ def __init__(self, qs, request):
self.page_data = self.qs[i:j]

def setValidPagination(self):
# print(self.page_size, self.page_number)
page_size = PageSizeSerializer(data={'page_size': self.page_size})
page_number = PageNumberSerializer(data={'page_number': self.page_number})
if not page_size.is_valid():
Expand Down Expand Up @@ -96,17 +99,17 @@ def getPageInfo(self):
'current_page_size': self.getCurrentPageSize()
}


def handleServerException(e):
# print(e)
return Response({
'isSuccess': False,
'data': None,
'message': 'Internal Server Error',
'errors': e,
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


def handleBadRequest(e):
# print(e)
return Response({
'isSuccess': False,
'data': None,
Expand Down
1 change: 0 additions & 1 deletion src/api/marketplace/marketplace/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,5 @@
views.twitterLoginCallback,
name="twitter-login-callback",
),
path("is-authenticated/", views.isAuthenticated, name="is-authenticated"),
path("logout/", views.logoutUser, name="logout"),
]
40 changes: 0 additions & 40 deletions src/api/marketplace/marketplace/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,46 +37,6 @@


# Apply these authentication class wherever JWT authentication is necessary.
@api_view(["GET"])
@authentication_classes([JWTAuthentication])
def isAuthenticated(request):
# Get the user id from the decoded token.
user = request.user_account

# If user is not found, return 401.
if user is None:
HttpResponse({
"message": "Unauthorized",
"error": "User not found"
}, status=401)
else:
return JsonResponse({
"message": "User is authenticated",
"data": {
"user": {
"id": user.id,
"username": user.username,
"first_name": user.first_name,
"last_name": user.last_name,
"email": user.email,
},
"twitter_account": {
"id": user.twitter_account.id,
"twitter_id": user.twitter_account.twitter_id,
"name": user.twitter_account.name,
"user_name": user.twitter_account.user_name,
"description": user.twitter_account.description,
"profile_image_url": user.twitter_account.profile_image_url,
"followers_count": user.twitter_account.followers_count,
"following_count": user.twitter_account.following_count,
"tweet_count": user.twitter_account.tweet_count,
"listed_count": user.twitter_account.listed_count,
"verified": user.twitter_account.verified,
}
},
"isSuccess": True,
})


def logoutUser(request):
response = HttpResponse("Token Deleted")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 4.2.7 on 2023-12-11 06:59

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('packages', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='service',
name='end_date',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='service',
name='start_date',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='servicemaster',
name='is_duration_based',
field=models.BooleanField(default=False),
),
]
3 changes: 3 additions & 0 deletions src/api/marketplace/packages/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ServiceMaster(models.Model):
type = models.CharField(choices=TYPE_CHOICES, max_length=50, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
deleted_at = models.DateTimeField(blank=True, null=True)
is_duration_based = models.BooleanField(default=False)

class Meta:
db_table = "service_master"
Expand All @@ -68,6 +69,8 @@ class Service(models.Model):
status = models.CharField(max_length=100, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
deleted_at = models.DateTimeField(blank=True, null=True)
start_date = models.DateTimeField(blank=True, null=True)
end_date = models.DateTimeField(blank=True, null=True)
class Meta:
db_table = "service"

Expand Down
22 changes: 21 additions & 1 deletion src/api/marketplace/packages/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,24 @@ class CreateServicesSerializer(serializers.ModelSerializer):
class Meta:
model = Service
fields = '__all__'
# fields = ('id', 'service_master', 'package', 'quantity', 'price', 'currency', 'status'
# fields = ('id', 'service_master', 'package', 'quantity', 'price', 'currency', 'status'

def validate(self, data):
service_master = data.get('service_master')
start_date = data.get('start_date')
end_date = data.get('end_date')

# If service_master is just the ID, retrieve the ServiceMaster instance
if isinstance(service_master, int):
service_master = ServiceMaster.objects.get(id=service_master)

if service_master.is_duration_based:
if start_date is None or end_date is None:
raise serializers.ValidationError(
"Start date and end date cannot be empty")
else:
if start_date is not None or end_date is not None:
raise serializers.ValidationError(
"Service Master is not duration based. Start date and end date should be empty")

return data
47 changes: 14 additions & 33 deletions src/ui/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
"use client";

import { useEffect, useState } from "react";
import Banner from "@/src/components/homePage/banner";
import InfluencersContainer from "@/src/components/homePage/influencersContainer";
import Navbar from "@/src/components/homePage/navbar";
import { getServicewithCredentials } from "@/src/services/httpServices";
import { Box, Typography } from "@mui/material";
import axios from "axios";
import Navbar from "@/src/components/homePage/navbar";
import Image from "next/image";
import { Menu } from "@mui/icons-material/";
import {
getServicewithCredentials,
postService,
} from "@/src/services/httpServices";
import { notification } from "@/src/components/shared/notification";
import Banner from "@/src/components/homePage/banner";
import InfluencersContainer from "@/src/components/homePage/influencersContainer";
import { useEffect, useState } from "react";

export default function Home() {
const [isUserAuthenticated, setIsUserAuthenticated] = useState(false);
Expand All @@ -25,15 +20,16 @@ export default function Home() {
// Authenticate user based on cookie present on the browser
const isAuthenticated = async () => {
try {
const res = await axios.get(
process.env.NEXT_PUBLIC_BACKEND_URL + "is-authenticated/",
{
withCredentials: true,
}
const { isSuccess, data, message } = await getServicewithCredentials(
"account/"
);
console.log("User is authenticated:", res);
localStorage.setItem("user", JSON.stringify(res?.data?.data));
setIsUserAuthenticated(true);
if (isSuccess) {
setIsUserAuthenticated(true);
localStorage.setItem("user", JSON.stringify(data));
} else {
setIsUserAuthenticated(false);
localStorage.clear();
}
} catch (e) {
setIsUserAuthenticated(false);
}
Expand Down Expand Up @@ -63,21 +59,6 @@ export default function Home() {
}
};

// const authTwitterUser = async () => {
// const { isSuccess, data, message } = await postService(
// "account/twitter-auth/",
// {
// role: "influecer",
// }
// );
// if (isSuccess) {
// console.log(data);
// window.location.href = data;
// } else {
// notification(message ? message : "Something went wrong", "error");
// }
// };

return (
<Box>
<Navbar
Expand Down
Loading

0 comments on commit 9ac3544

Please sign in to comment.