diff --git a/README.md b/README.md index c33ae12..0d03275 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,4 @@ To run tests: `pip3 install -r requirements.txt` -`python3 app.py` \ No newline at end of file +`python3 app.py` diff --git a/rest-app/db.sqlite3 b/rest-app/db.sqlite3 index d864fe3..2f940d6 100644 Binary files a/rest-app/db.sqlite3 and b/rest-app/db.sqlite3 differ diff --git a/rest-app/smartpicasso/__pycache__/settings.cpython-38.pyc b/rest-app/smartpicasso/__pycache__/settings.cpython-38.pyc index 8f74e30..68dbbda 100644 Binary files a/rest-app/smartpicasso/__pycache__/settings.cpython-38.pyc and b/rest-app/smartpicasso/__pycache__/settings.cpython-38.pyc differ diff --git a/rest-app/smartpicasso/__pycache__/urls.cpython-38.pyc b/rest-app/smartpicasso/__pycache__/urls.cpython-38.pyc index 74531e5..d832aea 100644 Binary files a/rest-app/smartpicasso/__pycache__/urls.cpython-38.pyc and b/rest-app/smartpicasso/__pycache__/urls.cpython-38.pyc differ diff --git a/rest-app/smartpicasso/__pycache__/wsgi.cpython-38.pyc b/rest-app/smartpicasso/__pycache__/wsgi.cpython-38.pyc index 624cd2c..532843f 100644 Binary files a/rest-app/smartpicasso/__pycache__/wsgi.cpython-38.pyc and b/rest-app/smartpicasso/__pycache__/wsgi.cpython-38.pyc differ diff --git a/rest-app/smartpicasso/app/project/__init__.py b/rest-app/smartpicasso/app/project/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rest-app/smartpicasso/app/project/admin.py b/rest-app/smartpicasso/app/project/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/rest-app/smartpicasso/app/project/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/rest-app/smartpicasso/app/project/apps.py b/rest-app/smartpicasso/app/project/apps.py new file mode 100644 index 0000000..e50f77b --- /dev/null +++ b/rest-app/smartpicasso/app/project/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ProjectConfig(AppConfig): + name = 'smartpicasso.app.project' diff --git a/rest-app/smartpicasso/app/project/migrations/0001_initial.py b/rest-app/smartpicasso/app/project/migrations/0001_initial.py new file mode 100644 index 0000000..3822f16 --- /dev/null +++ b/rest-app/smartpicasso/app/project/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 3.1.3 on 2020-12-14 19:08 + +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='Project', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=100)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'project', + }, + ), + ] diff --git a/rest-app/smartpicasso/app/project/migrations/__init__.py b/rest-app/smartpicasso/app/project/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rest-app/smartpicasso/app/project/models.py b/rest-app/smartpicasso/app/project/models.py new file mode 100644 index 0000000..e4f5eb3 --- /dev/null +++ b/rest-app/smartpicasso/app/project/models.py @@ -0,0 +1,29 @@ +""" +@author p.dolata +""" + +import uuid + +from django.db import models + +from smartpicasso.app.user.models import User + + +class Project(models.Model): + """ + Model representing user's project + """ + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + user = models.ForeignKey(User, on_delete=models.CASCADE) + name = models.CharField(max_length=100) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.name + + class Meta: + """ + Meta to set table name in database + """ + db_table = 'project' diff --git a/rest-app/smartpicasso/app/project/serializers.py b/rest-app/smartpicasso/app/project/serializers.py new file mode 100644 index 0000000..0eb99b2 --- /dev/null +++ b/rest-app/smartpicasso/app/project/serializers.py @@ -0,0 +1,17 @@ +""" +@author p.dolata +""" + +from rest_framework import serializers + +from smartpicasso.app.project.models import Project + + +class ProjectSerializer(serializers.ModelSerializer): + """ + Class to manage serializing Project + """ + + class Meta: + model = Project + fields = ('id', 'name', 'created_at', 'updated_at') diff --git a/rest-app/smartpicasso/app/project/tests.py b/rest-app/smartpicasso/app/project/tests.py new file mode 100644 index 0000000..376f3fb --- /dev/null +++ b/rest-app/smartpicasso/app/project/tests.py @@ -0,0 +1,70 @@ +""" +@author: p.dolata +""" + +from datetime import datetime + +from django.test import TestCase +from django.urls import reverse +from rest_framework import status +from rest_framework.test import APITestCase, APIClient + +from smartpicasso.app.project.models import Project +from smartpicasso.app.user.models import User + + +class ProjectsApiTest(APITestCase): + client = APIClient() + projects_url = reverse('projects-list') + new_project = {'name': 'test_project'} + + def test_create_project_without_auth(self): + response = self.client.post(self.projects_url, self.new_project, format='json') + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_create_project_with_invalid_token(self): + self.client.force_authenticate(user=None) + response = self.client.post(self.projects_url, self.new_project, format='json') + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_create_project(self): + user = User.objects.create_user(email='test@test.com', password='test') + self.client.force_authenticate(user=user) + response = self.client.post(self.projects_url, self.new_project, format='json') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + project = Project.objects.get(id=response.data['id']) + self.assertEqual(project.user.id, user.id) + self.assertEqual(project.name, self.new_project['name']) + self.assertAlmostEqual(datetime.timestamp(project.created_at), datetime.timestamp(datetime.now()), + delta=600) + self.assertAlmostEqual(datetime.timestamp(project.updated_at), datetime.timestamp(datetime.now()), + delta=600) + + def test_get_user_projects_without_auth(self): + response = self.client.get(self.projects_url, format='json') + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_get_user_projects_with_invalid_token(self): + self.client.force_authenticate(user=None) + response = self.client.get(self.projects_url, format='json') + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + def test_get_user_projects(self): + user = User.objects.create_user(email='test@test.com', password='test') + self.client.force_authenticate(user=user) + Project.objects.create(user=user, name='project_1') + Project.objects.create(user=user, name='project_2') + response = self.client.get(self.projects_url, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + projects = response.data + self.assertEqual(len(projects), 2) + self.assertEqual(projects[0]['name'], 'project_1') + self.assertEqual(projects[1]['name'], 'project_2') + + +class ProjectTest(TestCase): + + def test_project_str(self): + user = User.objects.create_user(email='test@test.com', password='test') + project = Project.objects.create(user=user, name='test_project') + self.assertEqual(str(project), 'test_project') diff --git a/rest-app/smartpicasso/app/project/urls.py b/rest-app/smartpicasso/app/project/urls.py new file mode 100644 index 0000000..f966670 --- /dev/null +++ b/rest-app/smartpicasso/app/project/urls.py @@ -0,0 +1,11 @@ +""" +@author: p.dolata +""" + +from rest_framework.routers import SimpleRouter + +from smartpicasso.app.project.views import ProjectsView + +router = SimpleRouter(trailing_slash=False) +router.register('projects', ProjectsView, basename="projects") +urlpatterns = router.urls diff --git a/rest-app/smartpicasso/app/project/views.py b/rest-app/smartpicasso/app/project/views.py new file mode 100644 index 0000000..611f9c8 --- /dev/null +++ b/rest-app/smartpicasso/app/project/views.py @@ -0,0 +1,24 @@ +""" +@author p.dolata +""" + +from rest_framework.permissions import IsAuthenticated +from rest_framework.viewsets import ModelViewSet + +from smartpicasso.app.project.serializers import ProjectSerializer +from smartpicasso.app.project.models import Project + + +class ProjectsView(ModelViewSet): + """ + View for project endpoints + """ + permission_classes = (IsAuthenticated,) + serializer_class = ProjectSerializer + + def perform_create(self, serializer): + serializer.save(user=self.request.user) + + def get_queryset(self): + user = self.request.user + return Project.objects.filter(user=user) diff --git a/rest-app/smartpicasso/app/user_profile/__pycache__/models.cpython-38.pyc b/rest-app/smartpicasso/app/user_profile/__pycache__/models.cpython-38.pyc index 615a595..80f08c3 100644 Binary files a/rest-app/smartpicasso/app/user_profile/__pycache__/models.cpython-38.pyc and b/rest-app/smartpicasso/app/user_profile/__pycache__/models.cpython-38.pyc differ diff --git a/rest-app/smartpicasso/app/user_profile/models.py b/rest-app/smartpicasso/app/user_profile/models.py index 8f25c64..e14ef4a 100644 --- a/rest-app/smartpicasso/app/user_profile/models.py +++ b/rest-app/smartpicasso/app/user_profile/models.py @@ -22,6 +22,6 @@ class UserProfile(models.Model): class Meta: """ - Meta to se table name in database + Meta to set table name in database """ db_table = 'user_profile' diff --git a/rest-app/smartpicasso/settings.py b/rest-app/smartpicasso/settings.py index ee23a99..fee38e9 100644 --- a/rest-app/smartpicasso/settings.py +++ b/rest-app/smartpicasso/settings.py @@ -38,7 +38,8 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'smartpicasso.app.user', - 'smartpicasso.app.user_profile' + 'smartpicasso.app.user_profile', + 'smartpicasso.app.project' ] MIDDLEWARE = [ diff --git a/rest-app/smartpicasso/urls.py b/rest-app/smartpicasso/urls.py index bd27833..146dbd0 100644 --- a/rest-app/smartpicasso/urls.py +++ b/rest-app/smartpicasso/urls.py @@ -19,5 +19,6 @@ from django.urls import path, include urlpatterns = [ path('api/', include('smartpicasso.app.user.urls')), path('api/', include('smartpicasso.app.user_profile.urls')), + path('api/', include('smartpicasso.app.project.urls')), path('admin/', admin.site.urls), ]