Fakultas Ilmu Komputer UI

Commit 411b3928 authored by Jonathan Christopher Jakub's avatar Jonathan Christopher Jakub
Browse files

Merge branch 'jojo/PBI-8-User' into 'PBI-8-User'

Implemented Account Model and Endpoint

See merge request !6
parents 945f547b 693f139a
Pipeline #31585 passed with stage
in 16 minutes and 55 seconds
......@@ -39,7 +39,7 @@ test:
script:
- echo "Starting tests"
- coverage erase
- coverage run --include="./*/*" --omit="./env/*","./manage.py" manage.py test
- coverage run --include="./*/*" --omit="./env/*","./project/*","./manage.py" manage.py test apps
- coverage xml -i
- coverage report -m
artifacts:
......
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = "accounts"
# Generated by Django 3.0.1 on 2020-02-24 09:13
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Account",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("name", models.CharField(max_length=128)),
("email", models.EmailField(max_length=128)),
("phone_number", models.CharField(max_length=64)),
("area", models.CharField(max_length=128)),
("is_admin", models.BooleanField(default=False)),
("is_verified", models.BooleanField(default=False)),
("is_active", models.BooleanField(default=False)),
(
"user",
models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
import uuid
from django.contrib.auth.models import User
from django.db import models
class Account(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=128)
email = models.EmailField(max_length=128)
phone_number = models.CharField(max_length=64)
area = models.CharField(max_length=128)
is_admin = models.BooleanField(default=False)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
from rest_framework import serializers
from apps.accounts.models import Account
class AccountSummarySerializer(serializers.ModelSerializer):
username = serializers.CharField(source="user.username", required=False)
class Meta:
model = Account
fields = [
"id",
"username",
"name",
"email",
"phone_number",
"area",
"is_admin",
"is_verified",
"is_active",
]
read_only_fields = [
"id",
"username",
]
class AccountRegisterSerializer(serializers.ModelSerializer):
username = serializers.CharField(max_length=128)
password = serializers.CharField(max_length=128)
class Meta:
model = Account
fields = [
"id",
"username",
"password",
"name",
"email",
"phone_number",
"area",
"is_admin",
"is_verified",
"is_active",
]
from apps.accounts.models import Account
from django.contrib.auth.models import User
from faker import Faker
import factory
faker = Faker()
class UserFactory(factory.DjangoModelFactory):
class Meta:
model = User
username = "username"
password = "justpass"
class AccountFactory(factory.DjangoModelFactory):
class Meta:
model = Account
class Params:
admin = factory.Trait(is_admin=True,)
user = factory.SubFactory(UserFactory)
name = faker.name()
email = faker.email()
phone_number = faker.phone_number()
area = faker.city()
import json
from django.test import TestCase
from django.urls import reverse
from faker import Faker
from rest_framework import status
from apps.accounts.models import Account
from apps.accounts.tests.factories.accounts import AccountFactory, UserFactory
class AccountViewTest(TestCase):
def setUp(self):
self.user_1 = UserFactory(username="user_1")
self.user_2 = UserFactory(username="user_2")
self.admin = AccountFactory(admin=True, user=self.user_1)
self.officer = AccountFactory(admin=False, user=self.user_2)
self.accounts = [self.admin, self.officer]
self.faker = Faker()
def test_list_all_accounts(self):
url = "/accounts/"
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_retrieve_account(self):
url = "/accounts/" + str(self.officer.id) + "/"
response = self.client.get(url)
data = {
"id": str(self.officer.id),
"name": self.officer.name,
"username": self.officer.user.username,
"email": self.officer.email,
"phone_number": self.officer.phone_number,
"area": self.officer.area,
"is_admin": False,
"is_verified": False,
"is_active": False,
}
self.assertJSONEqual(json.dumps(response.data), data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_create_new_admin(self):
url = "/accounts/"
_account_id = self.faker.email()
admin_prev_count = Account.objects.filter(is_admin=True).count()
data = {
"name": self.faker.name(),
"username": _account_id,
"password": "justpass",
"email": _account_id,
"phone_number": self.faker.phone_number(),
"area": self.faker.city(),
"is_admin": True,
}
response = self.client.post(
path=url, data=data, content_type="application/json", format="json",
)
admin_current_count = Account.objects.filter(is_admin=True).count()
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(admin_current_count, admin_prev_count + 1)
def test_create_new_officer(self):
url = "/accounts/"
_account_id = self.faker.email()
officer_prev_count = Account.objects.filter(is_admin=False).count()
data = {
"name": self.faker.name(),
"username": _account_id,
"password": "justpass",
"email": _account_id,
"phone_number": self.faker.phone_number(),
"area": self.faker.city(),
"is_admin": False,
}
response = self.client.post(
path=url, data=data, content_type="application/json", format="json",
)
officer_current_count = Account.objects.filter(is_admin=False).count()
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(officer_current_count, officer_prev_count + 1)
def test_edit_account(self):
url = "/accounts/" + str(self.officer.id) + "/"
data = {
"id": str(self.officer.id),
"name": self.faker.name(),
"email": self.faker.email(),
"phone_number": self.faker.phone_number(),
"area": self.faker.city(),
"is_admin": False,
"is_verified": True,
"is_active": True,
}
response = self.client.put(
path=url, data=data, content_type="application/json", format="json",
)
expected_returned_data = data
expected_returned_data["username"] = self.officer.user.username
self.assertJSONEqual(
str(response.content, encoding="utf8"), expected_returned_data
)
"""app URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.accounts.views import AccountViewSet
router = DefaultRouter()
router.register(r"", AccountViewSet, basename="account")
urlpatterns = [
path("auth/", include("django.contrib.auth.urls")),
]
urlpatterns += router.urls
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework import status, viewsets
from rest_framework.response import Response
from apps.accounts.models import Account
from apps.accounts.serializers import (
AccountSummarySerializer,
AccountRegisterSerializer,
)
class AccountViewSet(viewsets.ViewSet):
queryset = Account.objects.all().select_related("user")
def list(self, request):
queryset = self.queryset
serializer = AccountSummarySerializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def retrieve(self, request, pk=None):
instance = get_object_or_404(self.queryset, pk=pk)
serializer = AccountSummarySerializer(instance)
return Response(serializer.data, status=status.HTTP_200_OK)
def create(self, request):
serializer = AccountRegisterSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
username = serializer.validated_data.pop("username")
password = serializer.validated_data.pop("password")
user = User.objects.create_user(username=username, password=password)
account = Account.objects.create(user=user, **serializer.validated_data)
return Response(
AccountSummarySerializer(account).data, status=status.HTTP_201_CREATED,
)
def update(self, request, pk=None):
instance = get_object_or_404(self.queryset, pk=pk)
serializer = AccountSummarySerializer(instance, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
......@@ -5,7 +5,7 @@ import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
......@@ -17,5 +17,5 @@ def main():
execute_from_command_line(sys.argv)
if __name__ == '__main__':
if __name__ == "__main__":
main()
......@@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
application = get_asgi_application()
......@@ -14,6 +14,7 @@ import os
# Get all local env variables
from dotenv import load_dotenv
load_dotenv()
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
......@@ -42,6 +43,7 @@ INSTALLED_APPS = [
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"apps.accounts",
]
MIDDLEWARE = [
......@@ -78,26 +80,26 @@ WSGI_APPLICATION = "project.wsgi.application"
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
USE_POSTGRE = "DATABASE_IS_PSQL" in os.environ
USE_POSTGRE = os.environ.get("DATABASE_IS_PSQL", False)
if USE_POSTGRE:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ.get('DATABASE_NAME'),
'USER': os.environ.get('DATABASE_USER'),
'PASSWORD': os.environ.get('DATABASE_PASSWORD'),
'HOST': os.environ.get('DATABASE_HOST'),
'PORT': os.environ.get('DATABASE_PORT'),
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": os.environ.get("DATABASE_NAME"),
"USER": os.environ.get("DATABASE_USER"),
"PASSWORD": os.environ.get("DATABASE_PASSWORD"),
"HOST": os.environ.get("DATABASE_HOST"),
"PORT": os.environ.get("DATABASE_PORT"),
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
......@@ -129,6 +131,6 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATIC_URL = '/static/'
STATIC_URL = "/static/"
......@@ -18,4 +18,5 @@ from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("accounts/", include("apps.accounts.urls")),
]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment