Skip to content

Commit

Permalink
Merge pull request #1 from smdirr/dev
Browse files Browse the repository at this point in the history
Dev to main
  • Loading branch information
smdirr authored Jun 14, 2024
2 parents 29a9796 + ab2d72f commit e0ea885
Show file tree
Hide file tree
Showing 27 changed files with 724 additions and 0 deletions.
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 Debugger: Django",
"type": "debugpy",
"request": "launch",
"args": [
"runserver"
],
"django": true,
"autoStartBrowser": false,
"program": "${workspaceFolder}/src/manage.py"
}
]
}
3 changes: 3 additions & 0 deletions src/.coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[run]
omit =
manage.py
14 changes: 14 additions & 0 deletions src/.flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[flake8]
max-line-length = 120
max-complexity = 7
exclude =
.git,
__pycache__,
old,
.tox,
build,
dist,
venv,
.venv,
env,
.env
22 changes: 22 additions & 0 deletions src/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'time_tracker.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)


if __name__ == '__main__':
main()
Empty file added src/person/__init__.py
Empty file.
41 changes: 41 additions & 0 deletions src/person/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import List
from ninja import Router
from django.shortcuts import get_object_or_404
from person.models import Person
from person.schema import PersonIn, PersonOut

router = Router()


@router.post("/", url_name="person_create")
def create_person(request, payload: PersonIn):
person = Person.objects.create(**payload.dict())
return {"id": person.id}


@router.get("/{person_id}", response=PersonOut, url_name="person_get")
def get_person(request, person_id: int):
person = get_object_or_404(Person, id=person_id)
return person


@router.get("/", response=List[PersonOut], url_name="person_list")
def list_persons(request):
qs = Person.objects.all()
return qs


@router.put("/{person_id}", url_name="person_edit")
def update_person(request, person_id: int, payload: PersonIn):
person = get_object_or_404(Person, id=person_id)
for attr, value in payload.dict().items():
setattr(person, attr, value)
person.save()
return {"success": True}


@router.delete("/{person_id}", url_name="person_delete")
def delete_person(request, person_id: int):
person = get_object_or_404(Person, id=person_id)
person.delete()
return {"success": True}
6 changes: 6 additions & 0 deletions src/person/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class PersonConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'person'
43 changes: 43 additions & 0 deletions src/person/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 5.0.6 on 2024-06-13 11:23

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


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Person",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("first_name", models.CharField(max_length=100)),
("last_name", models.CharField(max_length=100)),
("birth_date", models.DateField(null=True)),
("email", models.EmailField(max_length=254, unique=True)),
(
"user",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
Empty file.
14 changes: 14 additions & 0 deletions src/person/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.db import models
from django.contrib.auth import models as models_auth


class Person(models.Model):
first_name = models.CharField(max_length=100, null=False)
last_name = models.CharField(max_length=100, null=False)
birth_date = models.DateField(null=True)
email = models.EmailField(max_length=254, null=False, unique=True)

user = models.ForeignKey(to=models_auth.User, on_delete=models.CASCADE, null=True)

def __str__(self):
return f"{self.last_name}, {self.first_name}"
17 changes: 17 additions & 0 deletions src/person/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from datetime import date
from ninja import Schema


class PersonIn(Schema):
first_name: str
last_name: str
email: str
birth_date: date = None


class PersonOut(Schema):
id: int
first_name: str
last_name: str
email: str
# birth_date: date = None
Empty file added src/person/tests/__init__.py
Empty file.
200 changes: 200 additions & 0 deletions src/person/tests/test_person.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
from django.test import TestCase, Client
from django.urls import reverse
from person.models import Person


class TestPerson(TestCase):

def setUp(self) -> None:
super().setUp()
self.client = Client()
my_pass = "devtestlocal"
data = {
"first_name": "Thomas",
"last_name": "Anderson",
"email": "tand@mail.me",
"password": f"{my_pass}",
"confirm_password": f"{my_pass}",
}
self.client.post(
reverse("register"), data=data, content_type="application/json"
)
token = self.client.post(
reverse("token_obtain_pair"),
{"username": data.get("email"), "password": f"{my_pass}"},
content_type="application/json",
)
self.access_token = token.json().get("access")

def test_get_person(self):

Person.objects.create(first_name="John", last_name="Doe", email="john@test.com")
Person.objects.create(
first_name="Alice", last_name="Silver", email="asilver@test.com"
)

response = self.client.get(
reverse("api:person_list"),
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 2)
self.assertEqual(response.json()[0]["first_name"], "John")
self.assertEqual(response.json()[0]["email"], "john@test.com")

def test_create_person(self):

data = {
"first_name": "Jenifer",
"last_name": "Lopez",
"email": "jlo@mail.com",
"birth_date": "1970-03-21",
}
response = self.client.post(
reverse("api:person_create"),
data=data,
content_type="application/json",
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(response.status_code, 200)
self.assertGreater(response.json().get("id"), 0)

def test_update_person(self):
data = {
"first_name": "Jenifer",
"last_name": "Lopez",
"email": "jlo@mail.com",
"birth_date": "1970-03-21",
}
response = self.client.post(
reverse("api:person_create"),
data=data,
content_type="application/json",
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(response.status_code, 200)
id = response.json().get("id")
url = reverse("api:person_edit", kwargs={"person_id": id})
data["last_name"] = "López"
response = self.client.put(
url,
data=data,
content_type="application/json",
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json().get("success"), True)
person = self.client.get(
reverse("api:person_get", args=[id]),
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(person.status_code, 200)
self.assertEqual(person.json()["last_name"], "López")

def test_person_delete(self):
data = {
"first_name": "Jenifer",
"last_name": "Lopez",
"email": "jlo@mail.com",
"birth_date": "1970-03-21",
}
response = self.client.post(
reverse("api:person_create"),
data=data,
content_type="application/json",
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(response.status_code, 200)
id = response.json().get("id")
url = reverse("api:person_delete", kwargs={"person_id": id})
response = self.client.delete(
url,
headers={"Authorization": f"Bearer {self.access_token}"},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json().get("success"), True)

def test_get_person_401(self):
response = self.client.get(reverse("api:person_list"))
self.assertEqual(response.status_code, 401)

def test_get_persons(self):

Person.objects.create(first_name="John", last_name="Doe", email="john@test.com")

response = self.client.get(
reverse("api:person_list"),
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.json()), 1)
self.assertEqual(response.json()[0]["email"], "john@test.com")

def test_retrieve_person(self):

my_person = Person.objects.create(
first_name="Juan", last_name="Fangio", email="jf@test.com"
)
response = self.client.get(
reverse("api:person_get", args=[my_person.id]),
headers={"Authorization": f"Bearer {self.access_token}"},
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["email"], "jf@test.com")

def test_str_person(self):

person = Person.objects.create(
first_name="John", last_name="Doe", email="john@test.com"
)
self.assertEqual(str(person), "Doe, John")

def test_register_pass_no_match(self):
data = {
"first_name": "Mick",
"last_name": "Jaegger",
"email": "mj@mail.me",
"password": "match",
"confirm_password": "no match",
}
response = self.client.post(
reverse("register"), data=data, content_type="application/json"
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json().get("error"), "Passwords do not match")

def test_register_username_already_exist(self):
data = {
"first_name": "Mick",
"last_name": "Jaegger",
"email": "tand@mail.me",
"password": "test@1234",
"confirm_password": "test@1234",
}
response = self.client.post(
reverse("register"), data=data, content_type="application/json"
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json().get("error"), "Username already taken")

def test_register_invalid_body(self):
invalid_json = "{email: 'test@example.com', password: 'pass123', confirm_password: 'pass123'"
response = self.client.post(
reverse("register"), data=invalid_json, content_type="application/json"
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json().get("error"), "Invalid JSON")

def test_register_invalid_request_method(self):

response = self.client.get(reverse("register"), content_type="application/json")
self.assertEqual(response.status_code, 405)
self.assertEqual(response.json().get("error"), "Invalid request method")
Loading

0 comments on commit e0ea885

Please sign in to comment.