Skip to content
This repository has been archived by the owner on Nov 20, 2023. It is now read-only.

Commit

Permalink
Merge pull request #91 from factryflow/feature/user-can-be-resource
Browse files Browse the repository at this point in the history
Feature/user can be resource
  • Loading branch information
Yacobolo authored Nov 9, 2023
2 parents 87d9294 + 4a251e5 commit 65714ef
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 76 deletions.
25 changes: 25 additions & 0 deletions backend/api/migrations/0002_user_resources_alter_user_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.2.5 on 2023-11-09 07:35

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


class Migration(migrations.Migration):
dependencies = [
("api", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="user",
name="resources",
field=models.ManyToManyField(related_name="users", to="api.resource"),
),
migrations.AlterField(
model_name="user",
name="role",
field=models.ForeignKey(
default=3, on_delete=django.db.models.deletion.DO_NOTHING, to="api.role"
),
),
]
7 changes: 5 additions & 2 deletions backend/api/models/user.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
from .role import Role

from api.models.resource import Resource
from api.models.role import Role


class User(AbstractUser):
email = models.EmailField(unique=True)
otp = models.CharField(max_length=6, blank=True, null=True)
otp_send_time = models.DateTimeField(blank=True, null=True)
role = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True, blank=True)
role = models.ForeignKey(Role, on_delete=models.DO_NOTHING, default=3)
resources = models.ManyToManyField(Resource, related_name="users")
57 changes: 32 additions & 25 deletions backend/api/schemas/user.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,62 @@
from ninja import Schema
from pydantic import BaseModel
from ninja import ModelSchema, Schema
from pydantic import EmailStr

from api.models.resource import Resource
from api.models.role import Role
from api.models.user import User


class UserIn(Schema):
"""
This schema is using for getting the input data for the User model.
"""
username: str
email: str
email: EmailStr
password: str
role_id:int
role_id: int = 3
resource_ids: list[int] = None


class UserTestIn(Schema):
"""
This schema is using for getting the input data for the User model.
"""
id : int
username: str
email: str
password: str

class UserRoleOut(ModelSchema):
class Config:
model = Role
model_fields = ["id", "name"]


class UserOut(Schema):
"""
This schema is using for returning the output of the User
"""
id: int
username: str
email: str
class UserResourceOut(ModelSchema):
class Config:
model = Resource
model_fields = ["id", "name"]


class UserOut(ModelSchema):
role: UserRoleOut
resources: list[UserResourceOut] = None

class Config:
model = User
model_exclude = ["password", "role", "resources"]


class UserForgotPassword(Schema):
"""
This schema is using for getting the input data for Forgot Password
"""
email: str

email: EmailStr


class VerifyOtpIn(Schema):
"""
This schema is using for getting the input data for Verify Otp
"""
email:str

email: EmailStr
otp: int


class UpdatePasswordIn(Schema):
"""
This schema is using for getting the input data for Update password, This is using when user forgot password.
"""

id: int
password: str

Expand All @@ -59,5 +65,6 @@ class ChangePasswordIn(Schema):
"""
This schema is using for getting the input data for change password, This is using when user is login and want to change password
"""

current_password: str
new_password: str
5 changes: 3 additions & 2 deletions backend/api/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from django.core.management import call_command
from django.test import Client
from ninja_jwt.tokens import RefreshToken
from api.tests.factories import UserFactory

client = Client()


# @pytest.fixture(scope="session")
@pytest.fixture()
def user():
def user(load_specific_fixtures):
load_specific_fixtures(["roles"])
return get_user_model().objects.create_user(
username="testuser", password="testpass", email="[email protected]"
)
Expand Down Expand Up @@ -49,6 +49,7 @@ def test_change_password_data():
"new_password": "updatedtestpass",
}


@pytest.fixture
def test_update_password_data():
return {
Expand Down
45 changes: 19 additions & 26 deletions backend/api/tests/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@

import pytest

from api.tests.factories import UserFactory,UserCreateFactory

from django.urls import reverse



from api.tests.factories import UserCreateFactory, UserFactory


@pytest.mark.django_db
def test_create_user(api_client, load_specific_fixtures):
load_specific_fixtures(["role"])
data = UserFactory.build(role_id=1).dict()
load_specific_fixtures(["roles"])
data = UserFactory.build(role_id=1, resource_ids=[]).dict()
response = api_client.post(
"/api/users/", json.dumps(data, default=str), content_type="application/json"
)
Expand All @@ -32,21 +27,20 @@ def test_get_user(api_client):
instance = UserCreateFactory.create()
print(vars(instance))
# data = instance.dict()
response = api_client.get(
f'/api/users/{instance.id}'
)
response = api_client.get(f"/api/users/{instance.id}")
print(response.content)
assert response.status_code == 200



@pytest.mark.django_db
def test_update_user(api_client):
instance = UserCreateFactory.create()
print(vars(instance))
data = instance.__dict__
response = api_client.put(
f'/api/users/{instance.id}', json.dumps(data, default=str), content_type="application/json"
f"/api/users/{instance.id}",
json.dumps(data, default=str),
content_type="application/json",
)
print(response.content)
assert response.status_code == 200
Expand All @@ -57,37 +51,36 @@ def test_delete_user(api_client):
instance = UserCreateFactory.create()
print(vars(instance))
data = instance.__dict__
response = api_client.delete(
f'/api/users/{instance.id}'
)
response = api_client.delete(f"/api/users/{instance.id}")
print(response.content)
assert response.status_code == 204


@pytest.mark.django_db
def test_change_user_password(api_client,test_change_password_data):
def test_change_user_password(api_client, test_change_password_data):
response = api_client.put(
'/api/users/change-password/', json.dumps(test_change_password_data, default=str), content_type="application/json"
"/api/users/change-password/",
json.dumps(test_change_password_data, default=str),
content_type="application/json",
)
data = response.json()
assert response.status_code == 200
assert data["message"] == "Password changed successfully"


@pytest.mark.django_db
def test_update_user_password(api_client,test_update_password_data):
def test_update_user_password(api_client, test_update_password_data):
response = api_client.post(
'/api/users/update-password', json.dumps(test_update_password_data, default=str), content_type="application/json"
"/api/users/update-password",
json.dumps(test_update_password_data, default=str),
content_type="application/json",
)

assert response.status_code == 200


@pytest.mark.django_db
def test_get_current_user(api_client):
response = api_client.get(
'/api/users/me/'
)

assert response.status_code == 200
response = api_client.get("/api/users/me/")

assert response.status_code == 200
11 changes: 9 additions & 2 deletions backend/api/views/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,16 @@ def register_user(request, user_in: UserIn):
password=user_in.password,
role_id=user_in.role_id,
)
if user_in.resource_ids:
user.resources.set(user_in.resource_ids)
return user


@user_no_auth_router.get("/check-first-user", response=dict[str, bool])
def check_first_user(request):
return {"is_first_user": User.objects.count() == 0}


@user_no_auth_router.post("/forgot-password")
def forgot_password(request, user_in: UserForgotPassword):
email = user_in.email
Expand Down Expand Up @@ -85,7 +92,7 @@ def change_password(request, change_password: ChangePasswordIn):
return {"message": "Current password is incorrect"}


class UserViewSet(ModelViewSet):
class UserViewSetAuth(ModelViewSet):
model_class = User

# AbstractModelView subclasses can be used as-is
Expand All @@ -96,4 +103,4 @@ class UserViewSet(ModelViewSet):


# The register_routes method must be called to register the routes with the router
UserViewSet.register_routes(user_auth_router)
UserViewSetAuth.register_routes(user_auth_router)
18 changes: 0 additions & 18 deletions backend/fixtures/role.json

This file was deleted.

39 changes: 39 additions & 0 deletions backend/fixtures/roles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[
{
"model": "api.role",
"pk": 1,
"fields": {
"name": "Administrator",
"created_at": "2023-08-19T21:46:44.097Z",
"updated_at": "2023-08-19T21:46:44.097Z",
"can_delete": true
}
},
{
"model": "api.role",
"pk": 2,
"fields": {
"name": "Planner",
"created_at": "2023-08-19T21:46:51.501Z",
"updated_at": "2023-08-19T21:46:51.501Z"
}
},
{
"model": "api.role",
"pk": 3,
"fields": {
"name": "Operator",
"created_at": "2023-08-19T21:46:51.501Z",
"updated_at": "2023-08-19T21:46:51.501Z"
}
},
{
"model": "api.role",
"pk": 4,
"fields": {
"name": "Read-Only",
"created_at": "2023-08-19T21:46:51.501Z",
"updated_at": "2023-08-19T21:46:51.501Z"
}
}
]
3 changes: 2 additions & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ pytest-django==4.5.2
polyfactory==2.9.0
django-ordered-model==3.7.4
psycopg2==2.9.9
factory-boy==3.3.0
factory-boy==3.3.0
email-validator==2.0.0.post2

0 comments on commit 65714ef

Please sign in to comment.