Skip to content

Commit

Permalink
First Version Tested and Complete
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomilola-ng committed Oct 20, 2024
1 parent 1464ccc commit 505ef92
Show file tree
Hide file tree
Showing 31 changed files with 889 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
DEBUG=True
SECRET_KEY="add-your-secret-key-here"
ALLOWED_HOSTS=*,127.0.0.1,localhost

DATABASE_ENGINE="django.db.backends.sqlite3"
DATABASE_NAME="db.sqlite3"

CORS_ORIGIN_ALLOW_ALL=True
EMAIL_SENDER="add-your-email-here"
35 changes: 35 additions & 0 deletions .github/workflows/build-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Build and Push Docker Image

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build Docker image
run: |
docker-compose -f docker-compose.yml build
- name: Push Docker image
run: |
docker tag image-name:latest yourusername/image-name:latest
docker push yourusername/image-name:latest
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.11.6-slim-bullseye

ENV PYTHONUNBUFFERED=1

WORKDIR /django

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD python3 manage.py runserver 0.0.0.0:8000
Empty file added accounts/__init__.py
Empty file.
79 changes: 79 additions & 0 deletions accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
""" User Account Admin """

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.utils.translation import gettext_lazy as _

from .forms import CustomUserChangeForm, CustomUserCreationForm
from .models import UserAccount


class UserAdmin(BaseUserAdmin):
"""Define a model for UserAccount."""
ordering = ["email"]
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = UserAccount
list_display = [
"pkid",
"id",
"email",
"first_name",
"last_name",
"is_staff",
"is_active",
]
list_display_links = ["id", "email"]
list_filter = [
"email",
"first_name",
"last_name",
"is_staff",
"is_active",
]
fieldsets = (
(
_("Login Credentials"),
{
"fields": (
"email",
"password",
)
},
),
(
_("Personal Information"),
{
"fields": (
"first_name",
"last_name",
)
},
),
(
_("Permissions and Groups"),
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
"groups",
"user_permissions",
)
},
),
(_("Important Dates"), {"fields": ("last_login", "date_joined")}),
)
add_fieldsets = (
(
None,
{
"classes": ("wide",),
"fields": ("email", "password1", "password2", "is_staff", "is_active"),
},
),
)
search_fields = ["email", "first_name", "last_name"]


admin.site.register(UserAccount, UserAdmin)
6 changes: 6 additions & 0 deletions accounts/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AccountsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'accounts'
24 changes: 24 additions & 0 deletions accounts/authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
""" Custom Authentication """

from rest_framework_simplejwt.authentication import JWTAuthentication
from django.conf import settings


class CustomJWTAuthentication(JWTAuthentication):
"""Define a custom JWT Authentication."""

def authenticate(self, request):
"""Authenticate the request."""
try:
header = self.get_header(request)
if header is None:
raw_token = request.COOKIES.get(settings.AUTH_COOKIE)
else:
raw_token = self.get_raw_token(header)

if raw_token is None:
return None
validated_token = self.get_validated_token(raw_token)
return self.get_user(validated_token), validated_token
except Exception as e: # pylint: disable=broad-except disable=unused-variable
return None
23 changes: 23 additions & 0 deletions accounts/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
""" User Account Forms """

from django.contrib.auth.forms import UserChangeForm, UserCreationForm

from .models import UserAccount


class CustomUserCreationForm(UserCreationForm):
"""Define a form for creating UserAccount."""
class Meta(UserCreationForm):
"""Define Meta options for CustomUserCreationForm."""
model = UserAccount
fields = ["email", "first_name", "last_name"]
error_class = "error"


class CustomUserChangeForm(UserChangeForm):
"""Define a form for updating UserAccount."""
class Meta:
"""Define Meta options for CustomUserChangeForm."""
model = UserAccount
fields = ["email", "first_name", "last_name"]
error_class = "error"
33 changes: 33 additions & 0 deletions accounts/managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
""" User Account Manager """

from django.contrib.auth.models import BaseUserManager


class UserAccountManager(BaseUserManager):
"""Define a model manager for UserAccount."""

def create_user(self, email, password=None, **extra_fields):
"""Create and save a User with the given email and password."""
if not email:
raise ValueError('Users must have an email address')

email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user

def create_superuser(self, email, password=None, **kwargs):
"""Create and save a SuperUser with the given email and password."""
kwargs.setdefault('is_active', True)
kwargs.setdefault('is_staff', True)
kwargs.setdefault('is_superuser', True)

if kwargs.get('is_active') is not True:
raise ValueError('Super User must be active')
if kwargs.get('is_staff') is not True:
raise ValueError('Super User must be staff')
if kwargs.get('is_superuser') is not True:
raise ValueError('Super User must have is superuser is True')

return self.create_user(email, password, **kwargs)
52 changes: 52 additions & 0 deletions accounts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
""" Django Migrations """
# pylint: disable=line-too-long disable=invalid-name

import uuid
import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):
""" Migration """
initial = True

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]

operations = [
migrations.CreateModel(
name='UserAccount',
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')),
('pkid', models.BigAutoField(
editable=False, primary_key=True, serialize=False)),
('id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
('email', models.EmailField(db_index=True, max_length=255,
unique=True, verbose_name='Email Address')),
('role', models.CharField(choices=[
('default', 'Default'), ('admin', 'Admin')], db_index=True, default='default', max_length=20)),
('first_name', models.CharField(
max_length=255, verbose_name='First Name')),
('last_name', models.CharField(
max_length=255, verbose_name='Last Name')),
('is_active', models.BooleanField(default=True)),
('is_staff', models.BooleanField(default=False)),
('date_joined', models.DateTimeField(
default=django.utils.timezone.now)),
('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={
'verbose_name': 'User',
'verbose_name_plural': 'Users',
},
),
]
Empty file added accounts/migrations/__init__.py
Empty file.
48 changes: 48 additions & 0 deletions accounts/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
""" User Account Model """

import uuid

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from accounts.managers import UserAccountManager


class UserAccount(AbstractBaseUser, PermissionsMixin):
"""Define a model for UserAccount."""

ROLE_CHOICES = (
('default', 'Default'),
('admin', 'Admin'),
)

pkid = models.BigAutoField(primary_key=True, editable=False)
id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
email = models.EmailField(verbose_name=_(
"Email Address"), max_length=255, unique=True, db_index=True)
role = models.CharField(max_length=20, choices=ROLE_CHOICES,
default='default', db_index=True)
first_name = models.CharField(verbose_name=_("First Name"), max_length=255)
last_name = models.CharField(verbose_name=_("Last Name"), max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)

objects = UserAccountManager()

USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']

class Meta:
"""Define Meta options for UserAccount."""
verbose_name = _("User")
verbose_name_plural = _("Users")

def get_short_name(self):
""" Return the short name for the user. """
return self.first_name

def __str__(self):
return f"{self.email}"
Loading

0 comments on commit 505ef92

Please sign in to comment.