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

refactor 11th sep 2023 #30

Merged
merged 1 commit into from
Sep 11, 2023
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
DJANGO_ENV=DEVELOPMENT
PORT=5000
SECRET_KEY='SECRET_KEY'
REST_KEY=123456789
RDS_BACKEND_SECRET_KEY=123456789
AUTH_TOKEN_INVALIDATION_TIME_IN_SECONDS=2592000

# ALLOWED_HOSTS accepts string as value with space as delimiter
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ GitHub.sublime-settings


# Ignoring .env file
django_jsonapi/.env
config/.env

# Ignore local setting file
django_jsonapi/settings/local.py
config/settings/local.py
19 changes: 19 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Django",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/manage.py",
"args": [
"runserver"
],
"django": true,
"justMyCode": true
}
]
}
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion base/apps.py → apps/base/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

class BaseConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'base'
name = 'apps.base'
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions apps/base/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from rest_framework import permissions


class IsSuperUserPermission(permissions.BasePermission):
def has_permission(self, request, view):
return False
4 changes: 4 additions & 0 deletions apps/base/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from rest_framework_simplejwt.tokens import RefreshToken

def get_user_token(user):
return f'Bearer {str(RefreshToken.for_user(user).access_token)}'
File renamed without changes.
File renamed without changes.
31 changes: 31 additions & 0 deletions apps/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest

from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework.test import APITestCase, APIClient
from django.contrib.auth import get_user_model

User = get_user_model()


def get_user_token(user):
return f'Bearer {str(RefreshToken.for_user(user).access_token)}'


@pytest.fixture
def new_user_factory(db):
def create_app_user(rds_id):
user = User.objects.create_user(rds_id=rds_id)
return user

yield create_app_user


@pytest.fixture
def user_t1(db, new_user_factory):
user = new_user_factory("hello_1")
return user


@pytest.fixture
def user_t2(db, new_user_factory):
return new_user_factory("hello_2")
File renamed without changes.
2 changes: 1 addition & 1 deletion goals/admin.py → apps/goals/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.contrib import admin
from safedelete.admin import SafeDeleteAdmin, highlight_deleted

from goals.models import Goal
from apps.goals.models import Goal
# Register your models here.


Expand Down
2 changes: 1 addition & 1 deletion goals/apps.py → apps/goals/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

class GoalsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'goals'
name = 'apps.goals'
32 changes: 32 additions & 0 deletions apps/goals/fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
goals = [
{
"model": "goals.goal",
"fields": {
"title": "Goal 1",
"description": "This is the description for Goal 1",
"created_at": "2023-08-04T12:00:00Z",
"created_by": "User 1",
"assigned_to": "User A",
"starts_on": "2023-08-05T00:00:00Z",
"ends_on": "2023-08-10T00:00:00Z",
"percentage_completed": 20,
"assigned_by": "Admin",
"status": "In Progress"
}
},
{
"model": "goals.goal",
"fields": {
"title": "Goal 2",
"description": "This is the description for Goal 2",
"created_at": "2023-08-04T13:00:00Z",
"created_by": "User 2",
"assigned_to": "User B",
"starts_on": "2023-08-06T00:00:00Z",
"ends_on": "2023-08-12T00:00:00Z",
"percentage_completed": 50,
"assigned_by": "Admin",
"status": "In Progress"
}
}
]
File renamed without changes.
File renamed without changes.
File renamed without changes.
5 changes: 4 additions & 1 deletion goals/models.py → apps/goals/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db import models

from base.models import BaseModel
from apps.base.models import BaseModel


class GoalStatusChoices(models.TextChoices):
Expand All @@ -18,3 +18,6 @@ class Goal(BaseModel):
percentage_completed = models.IntegerField(default=0)
assigned_by = models.CharField(max_length=200, blank=True)
status = models.CharField(max_length=70, choices=GoalStatusChoices.choices, default=GoalStatusChoices.ONGOING)

def __str__(self) -> str:
return self.title
2 changes: 1 addition & 1 deletion goals/serializers.py → apps/goals/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from rest_framework_json_api import serializers
from goals.models import Goal
from apps.goals.models import Goal

class GoalSerializer(serializers.ModelSerializer):
class Meta:
Expand Down
File renamed without changes.
51 changes: 51 additions & 0 deletions apps/goals/tests/test_drf_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest
from rest_framework import status
from rest_framework.test import APIClient
from django.conf import LazySettings

from apps.conftest import get_user_token
from apps.goals.fixtures import goals
from apps.goals.models import Goal

settings = LazySettings()


@pytest.mark.django_db
class TestGoalsViewSet:
@pytest.fixture(autouse=True)
def setup(self):
self.client = APIClient()
for goal in goals:
Goal.objects.create(**goal["fields"])

def test_get_goals(self, user_t1):
self.client.credentials(HTTP_AUTHORIZATION=get_user_token(user_t1))
_response = self.client.get('/api/v1/goal/', format="vnd.api+json")
_response_data = _response.json()

_response_goals_data = _response_data["data"]
_response_goal_data = _response_goals_data[0]["attributes"]

assert _response.status_code == status.HTTP_200_OK
assert len(_response_goals_data) > 0
assert "title" in _response_goal_data
assert "description" in _response_goal_data
assert "assigned_by" in _response_goal_data
assert "status" in _response_goal_data

def test_get_goals_filtered(self, user_t1):
goal_title = goals[1]["fields"]["title"]
self.client.credentials(HTTP_AUTHORIZATION=get_user_token(user_t1))
_response = self.client.get(f'/api/v1/goal/?title={goal_title}', format="vnd.api+json")
_response_data = _response.json()

_response_goals_data = _response_data["data"]
_response_goal_data = _response_goals_data[0]["attributes"]

assert _response.status_code == status.HTTP_200_OK
assert len(_response_goals_data) > 0
assert "title" in _response_goal_data
assert goal_title == _response_goal_data["title"]
assert "description" in _response_goal_data
assert "assigned_by" in _response_goal_data
assert "status" in _response_goal_data
11 changes: 11 additions & 0 deletions apps/goals/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.urls import include, path
from rest_framework import routers
from django.urls import path
from apps.goals.views import GoalViewSet

router = routers.DefaultRouter()
router.register(r'goal', GoalViewSet)

urlpatterns = [
path("", include(router.urls)),
]
11 changes: 11 additions & 0 deletions apps/goals/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from apps.base.base_views import ModelBaseViewSet
from apps.goals.models import Goal
from apps.goals.serializers import GoalSerializer
from rest_framework.permissions import IsAuthenticated


class GoalViewSet(ModelBaseViewSet):
queryset = Goal.objects.all().order_by('-created_at')
serializer_class = GoalSerializer
filterset_fields = ['status', 'title', 'assigned_to']
permission_classes = [IsAuthenticated]
File renamed without changes.
11 changes: 11 additions & 0 deletions apps/user/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

from django.contrib import admin
from apps.user.models import User
from safedelete.admin import SafeDeleteAdmin, highlight_deleted


@admin.register(User)
class UserAdmin(SafeDeleteAdmin):
list_display = ["id", "rds_id", "created_at", "modified_at"]
search_fields = ('rds_id', 'id')
ordering = ('created_at', )
2 changes: 1 addition & 1 deletion user/apps.py → apps/user/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

class UserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'user'
name = 'apps.user'
32 changes: 32 additions & 0 deletions apps/user/authentications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# from .models import User
# from rest_framework import authentication
# from rest_framework import exceptions


# class UserAuthenticationExtender():
# def __init__(self, auth_token, userId, created):
# self.auth_token = auth_token
# self.user_id = userId
# self.token_created = created
# self.is_authenticated = True


# class UserAuthentication(authentication.BaseAuthentication):
# def authenticate(self, request):
# try:
# goal_token = request.COOKIES['goal-site-session']
# except Exception:
# return None

# try:
# token = User.objects.get(auth_token=goal_token)
# if token.is_invalid():
# raise exceptions.AuthenticationFailed(
# "Token is expired or invalid")
# except User.DoesNotExist:
# raise exceptions.AuthenticationFailed(
# 'Token is expired or invalid')

# user = UserAuthenticationExtender(
# token.auth_token, token.user_id, token.token_created)
# return (user, None)
27 changes: 27 additions & 0 deletions apps/user/managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django.contrib.auth.models import BaseUserManager
import string
from django.utils.crypto import get_random_string


class UserManager(BaseUserManager):
def create_user(self, rds_id, password=None, **extra_fields):
if not rds_id:
raise ValueError('The rds_id field must be set')
user = self.model(rds_id=rds_id, **extra_fields)
if password is None:
password = self._generate_random_password()
user.set_password(password)
user.save(using=self._db)
return user

def create_superuser(self, rds_id, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)

return self.create_user(rds_id, password, **extra_fields)

@staticmethod
def _generate_random_password():
length = 50 # You can adjust the password length as needed
chars = string.ascii_letters + string.digits + string.punctuation
return get_random_string(length, chars)
37 changes: 37 additions & 0 deletions apps/user/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Generated by Django 4.0.9 on 2023-09-10 10:24

from django.db import migrations, models
import uuid


class Migration(migrations.Migration):

initial = True

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

operations = [
migrations.CreateModel(
name='User',
fields=[
('deleted', models.DateTimeField(db_index=True, editable=False, null=True)),
('deleted_by_cascade', models.BooleanField(default=False, editable=False)),
('created_at', models.DateTimeField(auto_now_add=True)),
('modified_at', models.DateTimeField(auto_now=True)),
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('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')),
('rds_id', models.CharField(blank=True, max_length=80, unique=True)),
('is_active', models.BooleanField(default=True)),
('is_staff', 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')),
],
options={
'abstract': False,
},
),
]
File renamed without changes.
21 changes: 21 additions & 0 deletions apps/user/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.db import models
# from django.contrib.postgres.fields import JSONField
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin

from apps.base.models import BaseModel
from apps.user.managers import UserManager


class User(AbstractBaseUser, PermissionsMixin, BaseModel):
rds_id = models.CharField(max_length=80, unique=True, blank=True)

is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)

objects = UserManager()

USERNAME_FIELD = 'rds_id'

def __str__(self):
return self.rds_id
7 changes: 5 additions & 2 deletions user/permission.py → apps/user/permission.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from rest_framework import permissions
from .utils import env
from django.conf import LazySettings

settings = LazySettings()


class RestKeyPermission(permissions.BasePermission):
def has_permission(self, request, view):
key = request.headers.get('Rest-Key')
return key == env('REST_KEY')
return key == settings.RDS_BACKEND_SECRET_KEY
File renamed without changes.
Loading
Loading