Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend user endpoints #114

Merged
merged 12 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@

.DS_Store
.env
__pycache__/**
*.pyc
**/mydb/**
mydb2/**
*.sqlite3
.venv
venv

/backend/project/staticfiles
/backend/project/mydb

/keypair
**/.env
16 changes: 0 additions & 16 deletions backend/project/.env

This file was deleted.

7 changes: 0 additions & 7 deletions backend/project/.gitignore

This file was deleted.

26 changes: 26 additions & 0 deletions backend/project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## Semanticflix Django Backend Application

Welcome !

## Notes for developers

### Before run
Please first activate your virtual environment and then use

> pip install -r requirements.txt

to get the latest updates to your environment

### Before push

Ensure that you updated the requirements.txt with your feature's new dependencies

Don't push docker-compose's data folder possibly called "mydb", it is in gitignore but if you pushed it before it can be still in staging area so use

> git rm -rf < foldername >

before commiting your changes


### About docker

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 5.0.4 on 2024-04-28 13:14

from django.db import migrations, models


class Migration(migrations.Migration):

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

operations = [
migrations.DeleteModel(
name='Comment',
),
migrations.AlterField(
model_name='actor',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='director',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='film',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='genre',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
]
25 changes: 25 additions & 0 deletions backend/project/app/migrations/0003_blacklistedtoken.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 5.0.4 on 2024-04-28 18:52

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('app', '0002_delete_comment_alter_actor_id_alter_director_id_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='BlacklistedToken',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('token', models.CharField(max_length=500)),
('timestamp', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
Binary file not shown.
9 changes: 9 additions & 0 deletions backend/project/app/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings


class Actor(models.Model):
Expand Down Expand Up @@ -28,3 +29,11 @@ class Film(models.Model):
release_date = models.DateField()
rating = models.FloatField()


class BlacklistedToken(models.Model):
token = models.CharField(max_length=500)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)

def __str__(self):
return self.token
55 changes: 55 additions & 0 deletions backend/project/app/serializers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,69 @@
from django.contrib.auth.models import User
from app.models import Genre, Film, Director, Actor
from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework.validators import UniqueValidator
from django.contrib.auth.password_validation import validate_password
from rest_framework_simplejwt.tokens import RefreshToken, TokenError



class RegisterSerializer(serializers.ModelSerializer):
email = serializers.EmailField(
required=True,
validators=[UniqueValidator(queryset=User.objects.all())]
)

password = serializers.CharField(write_only=True, required=True, validators=[validate_password])

class Meta:
model = User
fields = ('username', 'password', 'email', 'is_active')

def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
is_active=False
)

user.set_password(validated_data['password'])
user.save()

return user


class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super(MyTokenObtainPairSerializer, cls).get_token(user)

# Add custom claims
token['username'] = user.username
return token


class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email']


class LogoutSerializer(serializers.Serializer):
refresh = serializers.CharField()

def validate(self, attrs):
self.token = attrs['refresh']

return attrs

def save(self):
try:
RefreshToken(self.token).blacklist()
except TokenError:
self.fail('bad token')


class GenreSerializer(serializers.ModelSerializer):
class Meta:
model = Genre
Expand Down
8 changes: 7 additions & 1 deletion backend/project/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
from app import views
from django.urls import path
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from .views import film_api, film_detail_api
from .views import film_api, film_detail_api, RegisterView, MyObtainTokenPairView, LogoutView, VerifyEmail
from rest_framework_simplejwt.views import TokenRefreshView

urlpatterns = [
path('film/schema/', SpectacularAPIView.as_view(), name='schema'),
path('film/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('film/', film_api, name='film-list'),
path('film/<int:id>/', film_detail_api, name='film-detail'),
path('login/', MyObtainTokenPairView.as_view(), name='token_obtain_pair'),
path('login/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('register/', RegisterView.as_view(), name='auth_register'),
path('logout/', LogoutView.as_view(), name='logout'),
path('email-verify/', VerifyEmail.as_view(), name='email-verify'),
]
9 changes: 9 additions & 0 deletions backend/project/app/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.core.mail import EmailMessage, EmailMultiAlternatives

class Util:
@staticmethod
def send_email( data):
email = EmailMultiAlternatives(subject=data['email_subject'], to=[data['to_email']])

email.attach_alternative(data['html_message'], "text/html")
email.send()
Loading