Skip to content

Commit

Permalink
Merge pull request #17 from iurwpoietknckvjndfsm-gndvkd/authentication
Browse files Browse the repository at this point in the history
Activation email endpoint & Login with email
  • Loading branch information
shroukhegazi committed Feb 4, 2023
2 parents 284bc3e + 819d082 commit d6ee4a6
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 29 deletions.
8 changes: 8 additions & 0 deletions agriwise/users/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.contrib import admin

from .models import User


@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ["id", "username", "email", "is_active"]
5 changes: 5 additions & 0 deletions agriwise/users/api/helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import re


def check_password_strength(password):
return re.match(r"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])", password)
37 changes: 37 additions & 0 deletions agriwise/users/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from djoser.serializers import UserCreateSerializer as BaseUserCreateSerializer
from rest_framework import serializers

from .helper import check_password_strength

User = get_user_model()


Expand All @@ -20,3 +22,38 @@ class UserCreateSerializer(BaseUserCreateSerializer):

class Meta(BaseUserCreateSerializer.Meta):
fields = ["id", "username", "password", "email"]

def validate(self, attrs):
if not attrs.get("email"):
raise serializers.ValidationError(
{"email_error", "User should have a email"}
)

if not attrs.get("username"):
raise serializers.ValidationError(
{"username_error": "User should have a username"}
)

if User.objects.filter(email=attrs["email"]):
raise serializers.ValidationError(
{"email_duplication": "This email already exists"}
)

if User.objects.filter(username=attrs["username"]):
raise serializers.ValidationError(
{"username_duplication": "This username already exists"}
)
if not check_password_strength(attrs.get("password")):
raise serializers.ValidationError(
{
"password_strength_error": "Password should contain at lowercase/uppercase characters and numbers"
}
)
return attrs

def create(self, validation_data):
return User.objects.create_user(
username=validation_data["username"],
email=validation_data["email"],
password=validation_data["password"],
)
2 changes: 2 additions & 0 deletions agriwise/users/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from django.urls import include, path
from djoser.views import UserViewSet

app_name = "users"
urlpatterns = [
path("auth/api/", include("djoser.urls")),
path("auth/api/", include("djoser.urls.jwt")),
path("auth/api/users/activation/<str:uid>/<str:token>", UserViewSet().activation),
]
6 changes: 3 additions & 3 deletions agriwise/users/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.0.8 on 2023-02-02 02:00
# Generated by Django 4.0.8 on 2023-02-04 22:26

import django.contrib.auth.validators
from django.db import migrations, models
Expand All @@ -23,10 +23,10 @@ class Migration(migrations.Migration):
('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')),
('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')),
('name', models.CharField(blank=True, max_length=255, verbose_name='Name of User')),
('email', models.EmailField(error_messages={'unique': 'A user with that email already exists.'}, max_length=254, unique=True, verbose_name='email address')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')),
('is_active', models.BooleanField(default=False)),
('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')),
],
Expand Down
10 changes: 5 additions & 5 deletions agriwise/users/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db.models import CharField, EmailField
from django.db.models import BooleanField, CharField, EmailField
from django.utils.translation import gettext_lazy as _


Expand All @@ -23,13 +23,13 @@ class User(AbstractUser):
first_name = None
last_name = None
email = EmailField(
error_messages={"unique": "A user with that email already exists."},
max_length=254,
verbose_name="email address",
unique=True,
)

USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["email"]
is_active = BooleanField(default=False)
USERNAME_FIELD = "email"
EMAIL_FIELD = "email"
REQUIRED_FIELDS = ["username"]

objects = UserManager()
20 changes: 20 additions & 0 deletions agriwise/users/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pytest
from rest_framework.test import APIClient

from agriwise.users.models import User


@pytest.fixture
def user(db) -> User:
return User.objects.create_user(
username="username1",
email="username1@email.com",
password="sh0123456789123456",
)


@pytest.fixture
def auth_client(user):
client = APIClient()
client.force_authenticate(user)
return client
21 changes: 0 additions & 21 deletions agriwise/users/tests/test_swagger.py

This file was deleted.

9 changes: 9 additions & 0 deletions config/settings/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Base settings to build other settings files upon.
"""
from datetime import timedelta
from pathlib import Path

import environ
Expand Down Expand Up @@ -109,6 +110,14 @@
"SERIALIZERS": {
"user_create": "agriwise.users.api.serializers.UserCreateSerializer"
},
"ACTIVATION_URL": "users/auth/api/users/activation/{uid}/{token}",
"SEND_ACTIVATION_EMAIL": True,
"LOGIN_FIELD": "email",
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(days=5),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"AUTH_HEADER_TYPES": ("JWT",),
}
# https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url
LOGIN_REDIRECT_URL = "users:redirect"
Expand Down
1 change: 1 addition & 0 deletions config/settings/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
EMAIL_HOST = env("EMAIL_HOST", default="mailhog")
# https://docs.djangoproject.com/en/dev/ref/settings/#email-port
EMAIL_PORT = 1025
DOMAIN = "0.0.0.0:8000"

# django-debug-toolbar
# ------------------------------------------------------------------------------
Expand Down

0 comments on commit d6ee4a6

Please sign in to comment.