-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
11 changed files
with
199 additions
and
155 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
FROM python:3.9 | ||
FROM python:3.8.14 | ||
|
||
ENV PYTHONUNBUFFERED 1 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from rest_framework import status | ||
from rest_framework.response import Response | ||
|
||
|
||
class BaseResponse: | ||
def __init__(self, status_code=status.HTTP_200_OK, message="", data=None): | ||
self.status_code = status_code | ||
self.message = message | ||
self.data = data | ||
|
||
def success(self): | ||
return Response({ | ||
"success": status.HTTP_201_CREATED, | ||
"message": self.message | ||
}, self.status_code) | ||
|
||
def error(self): | ||
return Response({ | ||
"success": False, | ||
"message": self.message, | ||
}, self.status_code) | ||
|
||
def success_with_data(self): | ||
return Response({ | ||
"success": self.success, | ||
"data": self.data | ||
}, self.status_code) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from rest_framework.pagination import PageNumberPagination | ||
|
||
|
||
class StandardResultsSetPagination(PageNumberPagination): | ||
page_size = 25 | ||
page_size_query_param = 'page_size' | ||
max_page_size = 1000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from django.db import models | ||
|
||
import datetime | ||
|
||
|
||
class SkillForgeBaseQuerySet(models.QuerySet): | ||
def update(self, *args, **kwargs): | ||
if 'last_updated' not in kwargs: | ||
kwargs['last_updated'] = datetime.datetime.now() | ||
return super().update(**kwargs) | ||
|
||
class BaseModel(models.Model): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Generated by Django 4.2.7 on 2023-12-03 22:17 | ||
|
||
import django.contrib.auth.models | ||
import django.contrib.auth.validators | ||
from django.db import migrations, models | ||
import django.utils.timezone | ||
import uuid | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
('auth', '0012_alter_user_first_name_max_length'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='User', | ||
fields=[ | ||
('password', models.CharField(max_length=128, verbose_name='password')), | ||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), | ||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), | ||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), | ||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), | ||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), | ||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), | ||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), | ||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), | ||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), | ||
('email', models.EmailField(max_length=200, unique=True)), | ||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), | ||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), | ||
], | ||
options={ | ||
'db_table': 'user', | ||
}, | ||
managers=[ | ||
('objects', django.contrib.auth.models.UserManager()), | ||
], | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,142 +1,82 @@ | ||
import datetime | ||
|
||
from django.contrib import auth | ||
from django.contrib.auth.password_validation import validate_password | ||
from django.db.models import Q | ||
from rest_framework import serializers | ||
from rest_framework.exceptions import AuthenticationFailed | ||
from rest_framework.generics import get_object_or_404 | ||
from rest_framework.validators import UniqueValidator | ||
from rest_framework_simplejwt.exceptions import TokenError | ||
from rest_framework_simplejwt.tokens import RefreshToken | ||
|
||
# Bugra Ahmet Caglar | ||
from drf_yasg.utils import swagger_auto_schema | ||
|
||
from skillforge.generics import StandardResultsSetPagination | ||
from rest_framework import status | ||
from rest_framework.permissions import (AllowAny, IsAuthenticated) | ||
from rest_framework.generics import ( | ||
CreateAPIView, RetrieveAPIView, ListAPIView | ||
) | ||
from rest_framework_jwt.settings import api_settings | ||
|
||
from skillforge.constants import BaseResponse | ||
from user.models import User | ||
|
||
|
||
class UserLoginSerializer(serializers.ModelSerializer): | ||
email = serializers.CharField(max_length=255, min_length=3, read_only=True) | ||
username = serializers.CharField(max_length=255, min_length=3) | ||
password = serializers.CharField(max_length=128, write_only=True) | ||
|
||
class Meta: | ||
model = User | ||
fields = ['email', 'password', 'username', 'data'] | ||
|
||
def validate(self, attrs): | ||
username = attrs.get('username', '') | ||
password = attrs.get('password', '') | ||
try: | ||
instance = User.objects.get(Q(email=username) | Q(username=username)) | ||
except: | ||
raise AuthenticationFailed('Invalid credential, try again') | ||
user = auth.authenticate(username=instance.username, password=password) | ||
if not user: | ||
raise AuthenticationFailed('Invalid credential, try again') | ||
user.last_login = datetime.datetime.now() | ||
user.save() | ||
return { | ||
'email': user.email, | ||
'username': user.username, | ||
'data': user.data | ||
} | ||
|
||
|
||
class UserDetailSerializer(serializers.ModelSerializer): | ||
|
||
class Meta: | ||
model = User | ||
fields = ( | ||
'id', | ||
'username', | ||
'email', | ||
'first_name', | ||
'last_name', | ||
'date_joined', | ||
'last_login', | ||
) | ||
|
||
|
||
class UserListSerializer(serializers.ModelSerializer): | ||
email = serializers.EmailField(read_only=True) | ||
username = serializers.CharField(read_only=True) | ||
first_name = serializers.CharField(read_only=True) | ||
last_name = serializers.CharField(read_only=True) | ||
date_joined = serializers.DateTimeField(read_only=True) | ||
last_login = serializers.DateTimeField(read_only=True) | ||
|
||
class Meta: | ||
model = User | ||
fields = ['email', 'username', 'first_name', 'last_name', 'date_joined', 'last_login'] | ||
|
||
|
||
class UserLogoutSerializer(serializers.Serializer): | ||
refresh = serializers.CharField() | ||
|
||
default_error_messages = { | ||
'bad_token': 'Token is expired or invalid' | ||
} | ||
|
||
def validate(self, attrs): | ||
self.token = attrs['refresh'] | ||
return attrs | ||
|
||
def save(self, **kwargs): | ||
try: | ||
RefreshToken(self.token).blacklist() | ||
except TokenError: | ||
self.fail('bad_token') | ||
|
||
|
||
class UserRegisterSerializer(serializers.ModelSerializer): | ||
email = serializers.EmailField( | ||
required=True, | ||
validators=[UniqueValidator(queryset=User.objects.all())] | ||
) | ||
password = serializers.CharField(write_only=True, required=True, validators=[validate_password]) | ||
password2 = serializers.CharField(write_only=True, required=True) | ||
|
||
class Meta: | ||
model = User | ||
fields = ('username', 'password', 'password2', 'email', 'first_name', 'last_name') | ||
extra_kwargs = { | ||
'first_name': {'required': False}, | ||
'last_name': {'required': False} | ||
} | ||
|
||
def validate(self, attrs): | ||
if attrs['password'] != attrs['password2']: | ||
raise serializers.ValidationError({"password": "Password fields didn't match."}) | ||
return attrs | ||
|
||
def create(self, validated_data): | ||
user = User.objects.create( | ||
username=validated_data['username'], | ||
email=validated_data['email'], | ||
first_name=validated_data['first_name'], | ||
last_name=validated_data['last_name'] | ||
) | ||
user.set_password(validated_data['password']) | ||
user.save() | ||
return user | ||
|
||
|
||
class UserForgetPasswordSerializer(serializers.Serializer): | ||
email = serializers.EmailField(required=True) | ||
|
||
def validate(self, attrs): | ||
get_object_or_404(User, email=attrs['email']) | ||
return attrs | ||
|
||
|
||
class UserResetPasswordSerializer(serializers.ModelSerializer): | ||
password = serializers.CharField(required=True, validators=[validate_password]) | ||
password2 = serializers.CharField(write_only=True, required=True) | ||
|
||
class Meta: | ||
model = User | ||
fields = ('password', 'password2') | ||
|
||
def validate(self, attrs): | ||
if attrs['password'] != attrs['password2']: | ||
raise serializers.ValidationError({"password": "Password fields didn't match."}) | ||
return attrs | ||
from user.v1.serializers import ( | ||
UserLoginSerializer, UserRegisterSerializer, | ||
UserLogoutSerializer, UserListSerializer | ||
) | ||
|
||
JWT_PAYLOAD_HANDLER = api_settings.JWT_PAYLOAD_HANDLER | ||
JWT_ENCODE_HANDLER = api_settings.JWT_ENCODE_HANDLER | ||
|
||
|
||
class UserLoginAPIView(CreateAPIView): | ||
permission_classes = [AllowAny] | ||
serializer_class = UserLoginSerializer | ||
|
||
@swagger_auto_schema(operation_summary="User login API") | ||
def post(self, request, *args, **kwargs): | ||
serializer = self.serializer_class(data=request.data) | ||
serializer.is_valid(raise_exception=True) | ||
return BaseResponse(data=serializer.data, status_code=status.HTTP_200_OK).success_with_data() | ||
|
||
|
||
class UserRegistrationAPIView(CreateAPIView): | ||
serializer_class = UserRegisterSerializer | ||
permission_classes = [AllowAny] | ||
|
||
@swagger_auto_schema(operation_summary="Create a new user API") | ||
def post(self, request, *args, **kwargs): | ||
serializer = self.serializer_class(data=request.data) | ||
serializer.is_valid(raise_exception=True) | ||
serializer.save() | ||
return BaseResponse( | ||
message="User created successfully.", | ||
status_code=status.HTTP_201_CREATED | ||
).success() | ||
|
||
|
||
class UserDetailAPIView(RetrieveAPIView): | ||
permission_classes = [AllowAny] | ||
serializer_class = UserListSerializer | ||
queryset = User.objects.all() | ||
lookup_field = 'id' | ||
|
||
|
||
class UserLogoutAPIView(CreateAPIView): | ||
permission_classes = [IsAuthenticated] | ||
serializer_class = UserLogoutSerializer | ||
|
||
@swagger_auto_schema(operation_summary="Logout api") | ||
def post(self, request, *args, **kwargs): | ||
serializer = self.serializer_class(data=request.data) | ||
serializer.is_valid(raise_exception=True) | ||
serializer.save() | ||
return BaseResponse( | ||
message="Successfully logged out.", status_code=status.HTTP_200_OK | ||
).success() | ||
|
||
|
||
class UserListAPIView(ListAPIView): | ||
permission_classes = [AllowAny] | ||
serializer_class = UserListSerializer | ||
pagination_class = StandardResultsSetPagination | ||
queryset = User.objects.filter(is_active=True) | ||
lookup_field = 'id' | ||
|
||
def list(self, request, *args, **kwargs): | ||
serializer_data = self.serializer_class(self.queryset, many=True).data | ||
return BaseResponse( | ||
data=serializer_data, | ||
status_code=status.HTTP_200_OK | ||
).success_with_data() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.