Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ jobs:
docker stop null_jobs_backend || true
docker rm null_jobs_backend || true
docker run -d --network null_jobs --env-file /home/dev@null/projects/nulljobs/backend/.env null_jobs_backend:latest python manage.py migrate
docker run -d --network null_jobs --env-file /home/dev@null/projects/nulljobs/backend/.env null_jobs_backend:latest python manage.py create_superuser
docker run -d --name null_jobs_backend --network null_jobs --restart always --env-file /home/dev@null/projects/nulljobs/backend/.env null_jobs_backend:latest python manage.py runserver 0.0.0.0:8000
rm -r /tmp/null_job_backend_latest.tar
Empty file.
18 changes: 18 additions & 0 deletions apps/accounts/management/commands/create_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model


class Command(BaseCommand):
help = 'Create an initial admin User'

def handle(self, *args, **kwargs):
User = get_user_model()
if not User.objects.filter(email='', user_type="Moderator").exists():
User.objects.create_superuser(
email='',
name='',
password=''
)
self.stdout.write(self.style.SUCCESS('Successfully created the admin user'))
else:
self.stdout.write(self.style.WARNING('Admin user already exists'))
60 changes: 59 additions & 1 deletion apps/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# from Jobapp.models import User as JobUser
# Create your models here.

USER_TYPE = (("Job Seeker", "User/Employee"), ("Employer", "HR/Employer"))
USER_TYPE = (("Job Seeker", "User/Employee"), ("Employer", "HR/Employer"), ("Moderator", "Admin/Moderator"))


class UserManager(BaseUserManager):
Expand All @@ -33,12 +33,35 @@ def create_superuser(self, email, name, password=None):
email,
password=password,
name=name,
user_type="Moderator" # keep it as it is
)
user.is_admin = True
user.is_staff = True
user.is_moderator = True
user.is_verified = True
user.save(using=self._db)
return user

# todo: to have it when we have moderator dashboard
def create_moderator(self, email, name, password=None):
"""
Creates and saves a superuser with the given email, name, tc and password.
"""
user = self.create_user(
email,
password=password,
name=name,
user_type="Moderator" # as it moderator
)
#
user.is_admin = False # false
user.is_staff = True
user.is_moderator = True
user.save(using=self._db)
return user



class User(AbstractBaseUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

Expand All @@ -51,6 +74,8 @@ class User(AbstractBaseUser):
is_admin = models.BooleanField(default=False, editable=False)
is_moderator = models.BooleanField(default=False, null=True, editable=False)

is_staff = models.BooleanField(default=False)

created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

Expand All @@ -72,3 +97,36 @@ class User(AbstractBaseUser):

class Meta:
db_table = "tbl_user_auth"


def get_full_name(self):
# The user is identified by their email address
return self.email

def get_short_name(self):
# The user is identified by their email address
return self.email

def __str__(self):
return self.email

def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True

def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True

@property
def is_staff_member(self):
"Is the user a member of staff?"
return self.is_staff

@property
def is_admin_member(self):
"Is the user a admin member?"
return self.is_admin

24 changes: 24 additions & 0 deletions apps/accounts/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,27 @@ def validate(self, attrs):

def create(self, validate_data):
return User.objects.create_user(**validate_data)

from django.contrib.auth import get_user_model

User = get_user_model()

class AdminUserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)

class Meta:
model = User
fields = ['email', 'name', 'password']

def create(self, validated_data):
user = User(
email=validated_data['email'],
name=validated_data['name'],
)
user.set_password(validated_data['password'])
user.is_staff = True
user.is_superuser = True # for time being lets keep it this only
user.user_type = "Moderator"
user.is_verified = True
user.save()
return user
3 changes: 2 additions & 1 deletion apps/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
UserLogOutView,
UserPasswordResetView,
UserProfileView,
UserRegistrationView,
UserRegistrationView, CreateAdminUserView,
)

app_name = "apps.accounts"
Expand Down Expand Up @@ -52,4 +52,5 @@
# google oauth endpoints
path("google/login/", GoogleHandle.as_view(), name="google"),
path("google/login/callback/", CallbackHandleView.as_view(), name="callback"),
path('create-admin', CreateAdminUserView.as_view(), name='create-admin'),
]
34 changes: 32 additions & 2 deletions apps/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.conf import settings
from django.contrib.auth import authenticate
from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework import status
from rest_framework import status, generics
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
Expand All @@ -28,10 +28,11 @@
UserPasswordResetSerializer,
UserRegistrationResponseSerializer,
UserRegistrationSerializer,
UserSerializer,
UserSerializer, AdminUserSerializer,
)
from apps.accounts.utils import *
from apps.userprofile.models import UserProfile
import logging

# from django.shortcuts import render

Expand Down Expand Up @@ -473,3 +474,32 @@ def get(self, request):
{"msg": "There was an error authenticating the user"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)




class IsSuperuserOrStaff(IsAuthenticated):
def has_permission(self, request, view):
return super().has_permission(request, view) and (request.user.is_admin or request.user.is_staff)


class CreateAdminUserView(generics.CreateAPIView):
serializer_class = AdminUserSerializer
permission_classes = [IsSuperuserOrStaff]

def create(self, request, *args, **kwargs):
# Check if the current user email matches the one in the environment variable
admin_email_env = os.getenv('DJANGO_ADMIN_EMAIL')
admin_password_env = os.getenv('DJANGO_ADMIN_PASSWORD')
if not (admin_email_env or admin_password_env):
return Response({'error': 'Admin email is not set in environment variables'},
status=status.HTTP_400_BAD_REQUEST)

if request.user.email != admin_email_env and request.user.password != admin_password_env:
return Response({'error': 'You are not authorized to create a new superuser'},
status=status.HTTP_403_FORBIDDEN)

response = super().create(request, *args, **kwargs)
if response.status_code == status.HTTP_201_CREATED:
logger.info(f"Admin user created: {response.data['email']} by {request.user.email}")
return response
2 changes: 2 additions & 0 deletions apps/applicants/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.contrib import admin
from .models import Applicants

admin.site.register(Applicants)
# Register your models here.
6 changes: 5 additions & 1 deletion apps/jobs/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from django.contrib import admin

from .models import Job, ContactMessage, Company
# Register your models here.

admin.site.register(Job)
admin.site.register(ContactMessage)
admin.site.register(Company)
2 changes: 1 addition & 1 deletion apps/jobs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Meta:
updated_at = models.DateTimeField(auto_now=True) # update timestamp on every save()

# flags are un explained here
is_active = models.BooleanField(default=False, null=False, editable=False)
is_active = models.BooleanField(default=False, null=False)
is_created = models.BooleanField(default=False, null=True, editable=False)
is_deleted = models.BooleanField(default=False, null=True, editable=False)
is_featured = models.BooleanField(default=False, null=True)
Expand Down
5 changes: 4 additions & 1 deletion apps/userprofile/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from django.contrib import admin

from .models import UserProfile, FavoriteProfiles
# Register your models here.

admin.site.register(UserProfile)
admin.site.register(FavoriteProfiles)
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ services:
condition: service_healthy
volumes:
- .:/workspace
command: bash -c "python manage.py loaddata utils/seed/accounts/userauth.json && python manage.py loaddata utils/seed/jobs/company.json && python manage.py loaddata utils/seed/jobs/userprofile.json && python manage.py loaddata utils/seed/jobs/job.json"
# command: bash -c "python manage.py loaddata utils/seed/accounts/userauth.json && python manage.py loaddata utils/seed/jobs/company.json && python manage.py loaddata utils/seed/jobs/job.json && python manage.py loaddata utils/seed/jobs/drf-spectacular.json"
env_file:
- .env

Expand Down
5 changes: 5 additions & 0 deletions null_jobs_backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@
"PASSWORD": os.getenv("DB_PWD"),
"HOST": os.getenv("DB_HOST"),
"PORT": os.getenv("DB_PORT"),
},
'local': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'mydatabase', # This is where you put the name of the db file.
# If one doesn't exist, it will be created at migration time.
}
}

Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ jsonschema-specifications==2023.12.1
lazy-object-proxy==1.9.0
MarkupSafe==2.1.3
mccabe==0.7.0
mysqlclient==2.2.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without this the db connection code might break.

nodeenv==1.8.0
packaging==23.1
pkgutil_resolve_name==1.3.10
Expand Down