Rework versions models

- Added ListView and DetailView
- Move to pytest style tests
- Fix migrations to be clean to rebuild and throw away existing data
- Add model_bakery
This commit is contained in:
Frank Wiles
2022-05-28 16:00:24 -05:00
parent fd62c10356
commit 29878c3f90
27 changed files with 947 additions and 722 deletions

View File

@@ -1,4 +1,4 @@
from django.conf.urls import include, url
from django.conf.urls import include
from django.contrib import admin
from django.urls import path
from rest_framework import routers
@@ -13,7 +13,8 @@ from ak.views import (
NotFoundView,
OKView,
)
from versions.views import *
from versions.api import VersionViewSet, VersionFileViewSet
from versions.views import VersionList, VersionDetail
router = routers.SimpleRouter()
@@ -26,11 +27,13 @@ urlpatterns = [
path("", HomepageView.as_view(), name="home"),
path("admin/", admin.site.urls),
path("users/me/", CurrentUserView.as_view(), name="current-user"),
url(r"^api/v1/", include(router.urls)),
path("api/v1/", include(router.urls)),
path("200", OKView.as_view(), name="ok"),
path("403", ForbiddenView.as_view(), name="forbidden"),
path("404", NotFoundView.as_view(), name="not_found"),
path("500", InternalServerErrorView.as_view(), name="internal_server_error"),
path("health/", include("health_check.urls")),
path("forum/", include(machina_urls)),
path("versions/", VersionList.as_view(), name="version-list"),
path("version/<int:pk>/", VersionDetail.as_view(), name="version-detail"),
]

6
conftest.py Normal file
View File

@@ -0,0 +1,6 @@
import pytest
pytest_plugins = [
"users.tests.fixtures",
"versions.tests.fixtures",
]

View File

@@ -30,10 +30,11 @@ pytest-cov
pytest-django
pytest-xdist
Faker
factory_boy
model_bakery
ipython
# Packaging
pip-tools
pip-tools>=6.6.2
# Markdown and Frontmatter
mistletoe

View File

@@ -2,7 +2,7 @@
# This file is autogenerated by pip-compile with python 3.9
# To update, run:
#
# pip-compile
# pip-compile --output-file=./requirements.txt ./requirements.in
#
amqp==5.0.6
# via kombu
@@ -14,12 +14,16 @@ appdirs==1.4.4
# fs
asgiref==3.3.4
# via django
asttokens==2.0.5
# via stack-data
attrs==21.1.0
# via pytest
backcall==0.2.0
# via ipython
billiard==3.6.4.0
# via celery
black==21.5b0
# via -r requirements.in
# via -r ./requirements.in
boto3==1.17.68
# via django-bakery
botocore==1.20.68
@@ -29,9 +33,9 @@ botocore==1.20.68
bump2version==1.0.1
# via bumpversion
bumpversion==0.6.0
# via -r requirements.in
# via -r ./requirements.in
celery==5.0.5
# via -r requirements.in
# via -r ./requirements.in
click==7.1.2
# via
# black
@@ -48,13 +52,15 @@ click-repl==0.1.6
# via celery
coverage==5.5
# via pytest-cov
decorator==5.1.1
# via ipython
dj-database-url==0.5.0
# via environs
dj-email-url==1.0.2
# via environs
django==3.2.2
# via
# -r requirements.in
# -r ./requirements.in
# django-db-geventpool
# django-extensions
# django-haystack
@@ -63,58 +69,61 @@ django==3.2.2
# django-redis
# django-rest-auth
# djangorestframework
# model-bakery
django-bakery==0.12.7
# via -r requirements.in
# via -r ./requirements.in
django-cache-url==3.2.3
# via environs
django-db-geventpool==4.0.0
# via -r requirements.in
# via -r ./requirements.in
django-extensions==3.1.3
# via -r requirements.in
# via -r ./requirements.in
django-haystack==3.1.1
# via django-machina
django-health-check==3.16.4
# via -r requirements.in
# via -r ./requirements.in
django-js-asset==1.2.2
# via django-mptt
django-machina==1.1.5
# via -r requirements.in
# via -r ./requirements.in
django-mptt==0.13.4
# via django-machina
django-redis==5.0.0
# via -r requirements.in
# via -r ./requirements.in
django-rest-auth==0.9.5
# via -r requirements.in
# via -r ./requirements.in
django-test-plus==1.4.0
# via -r requirements.in
# via -r ./requirements.in
django-tracer==0.9.3
# via -r requirements.in
# via -r ./requirements.in
django-widget-tweaks==1.4.9
# via django-machina
djangorestframework==3.12.4
# via
# -r requirements.in
# -r ./requirements.in
# django-rest-auth
environs[django]==9.3.2
# via -r requirements.in
# via -r ./requirements.in
execnet==1.8.0
# via pytest-xdist
factory-boy==3.2.1
# via -r requirements.in
executing==0.8.3
# via stack-data
faker==9.8.2
# via
# -r requirements.in
# factory-boy
# via -r ./requirements.in
fs==2.4.13
# via django-bakery
gevent==21.1.2
# via -r requirements.in
# via -r ./requirements.in
greenlet==1.1.0
# via gevent
gunicorn==20.1.0
# via -r requirements.in
# via -r ./requirements.in
iniconfig==1.1.1
# via pytest
ipython==8.4.0
# via -r ./requirements.in
jedi==0.18.1
# via ipython
jmespath==0.10.0
# via
# boto3
@@ -125,49 +134,67 @@ markdown2==2.4.1
# via django-machina
marshmallow==3.11.1
# via environs
matplotlib-inline==0.1.3
# via ipython
mistletoe==0.8.2
# via -r requirements.in
# via -r ./requirements.in
model-bakery==1.5.0
# via -r ./requirements.in
mypy-extensions==0.4.3
# via black
packaging==20.9
# via pytest
parso==0.8.3
# via jedi
pathspec==0.8.1
# via black
pep517==0.10.0
# via pip-tools
pexpect==4.8.0
# via ipython
pickleshare==0.7.5
# via ipython
pillow==8.4.0
# via django-machina
pip-tools==6.1.0
# via -r requirements.in
pip-tools==6.6.2
# via -r ./requirements.in
pluggy==0.13.1
# via pytest
prompt-toolkit==3.0.18
# via click-repl
# via
# click-repl
# ipython
psycogreen==1.0.2
# via django-db-geventpool
psycopg2-binary==2.9.3
# via -r requirements.in
# via -r ./requirements.in
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.2
# via stack-data
py==1.10.0
# via
# pytest
# pytest-forked
pygments==2.12.0
# via ipython
pyparsing==2.4.7
# via packaging
pytest==6.2.4
# via
# -r requirements.in
# -r ./requirements.in
# pytest-cov
# pytest-django
# pytest-forked
# pytest-xdist
pytest-cov==2.11.1
# via -r requirements.in
# via -r ./requirements.in
pytest-django==4.2.0
# via -r requirements.in
# via -r ./requirements.in
pytest-forked==1.3.0
# via pytest-xdist
pytest-xdist==2.2.1
# via -r requirements.in
# via -r ./requirements.in
python-dateutil==2.8.1
# via
# botocore
@@ -175,9 +202,9 @@ python-dateutil==2.8.1
python-dotenv==0.17.1
# via environs
python-frontmatter==1.0.0
# via -r requirements.in
# via -r ./requirements.in
python-json-logger==2.0.1
# via -r requirements.in
# via -r ./requirements.in
pytz==2021.1
# via
# celery
@@ -187,7 +214,7 @@ pyyaml==6.0
# via python-frontmatter
redis==3.5.3
# via
# -r requirements.in
# -r ./requirements.in
# django-redis
regex==2021.4.4
# via black
@@ -195,6 +222,7 @@ s3transfer==0.4.2
# via boto3
six==1.16.0
# via
# asttokens
# click-repl
# django-bakery
# django-rest-auth
@@ -202,8 +230,10 @@ six==1.16.0
# python-dateutil
sqlparse==0.4.1
# via django
stack-data==0.2.0
# via ipython
structlog==21.1.0
# via -r requirements.in
# via -r ./requirements.in
text-unidecode==1.3
# via faker
toml==0.10.2
@@ -211,6 +241,10 @@ toml==0.10.2
# black
# pep517
# pytest
traitlets==5.2.1.post0
# via
# ipython
# matplotlib-inline
urllib3==1.26.4
# via botocore
vine==5.0.0
@@ -219,8 +253,10 @@ vine==5.0.0
# celery
wcwidth==0.2.5
# via prompt-toolkit
wheel==0.37.1
# via pip-tools
whitenoise==5.2.0
# via -r requirements.in
# via -r ./requirements.in
zope-event==4.5.0
# via gevent
zope-interface==5.4.0

View File

@@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block content %}
Version Detail
{% endblock %}

View File

@@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block content %}
Version List
{% endblock %}

View File

@@ -1,44 +0,0 @@
import factory
import django.contrib.auth.models as auth_models
from django.utils import timezone
from .models import User
class VersionGroupFactory(factory.django.DjangoModelFactory):
class Meta:
model = auth_models.Group
name = "version_manager"
class UserFactory(factory.django.DjangoModelFactory):
email = factory.Sequence(lambda n: "user%s@example.com" % n)
first_name = factory.Sequence(lambda n: "User%s Bob" % n)
last_name = factory.Sequence(lambda n: "User%s Smith" % n)
last_login = factory.LazyFunction(timezone.now)
password = factory.PostGenerationMethodCall("set_password", "password")
class Meta:
model = User
django_get_or_create = ("email",)
@factory.post_generation
def groups(self, create, extracted, **kwargs):
if not create:
return
if extracted:
for group in extracted:
self.groups.add(group)
class StaffUserFactory(UserFactory):
is_staff = True
class SuperUserFactory(StaffUserFactory):
is_superuser = True

View File

@@ -4,10 +4,11 @@ from django.db import migrations
from django.contrib.auth.models import Group, Permission
from django.core.management import BaseCommand
from django.contrib.contenttypes.models import ContentType
from versions.models import Version
def gen_version_manager_group(apps, schema_editor):
from versions.models import Version
new_group, created = Group.objects.get_or_create(name="version_manager")
# Code to add permission to group ???
ct = ContentType.objects.get_for_model(Version)

56
users/tests/fixtures.py Normal file
View File

@@ -0,0 +1,56 @@
import pytest
from django.utils import timezone
from model_bakery import baker
@pytest.fixture
def user(db):
"""Regular website user"""
user = baker.make(
"users.User",
email="user@example.com",
first_name="Regular",
last_name="User",
last_login=timezone.now(),
)
user.set_password("password")
user.save()
return user
@pytest.fixture
def staff_user(db):
"""Staff website user with access to the Django admin"""
user = baker.make(
"users.User",
email="staff@example.com",
first_name="Staff",
last_name="User",
last_login=timezone.now(),
is_staff=True,
)
user.set_password("password")
user.save()
return user
@pytest.fixture
def super_user(db):
"""Superuser with access to everything"""
user = baker.make(
"users.User",
email="super@example.com",
first_name="Super",
last_name="User",
last_login=timezone.now(),
is_staff=True,
is_superuser=True,
)
user.set_password("password")
user.save()
return user

View File

@@ -3,224 +3,225 @@ from faker import Faker
from rest_framework.test import APIClient
from test_plus.test import TestCase
from ..factories import UserFactory, StaffUserFactory
from .. import serializers
# from ..factories import UserFactory, StaffUserFactory
# from .. import serializers
class UserViewTests(TestCase):
client_class = APIClient
def setUp(self):
self.user = UserFactory()
self.staff = StaffUserFactory()
self.sample_user = UserFactory()
def test_list_user(self):
"""
Tests with a regular user
"""
# Does API work without auth?
response = self.get("users-list")
self.response_403(response)
# Does API work with auth?
with self.login(self.user):
response = self.get("users-list")
self.response_200(response)
self.assertEqual(len(response.data), 3)
# Are non-staff shown/hidden the right fields?
self.assertIn("first_name", response.data[0])
self.assertNotIn("date_joined", response.data[0])
def test_list_staff(self):
"""
Test with a staff user, who use a different serializer
"""
# Are staff shown the right fields?
with self.login(self.staff):
response = self.get("users-list")
self.response_200(response)
self.assertEqual(len(response.data), 3)
self.assertIn("first_name", response.data[0])
self.assertIn("date_joined", response.data[0])
def test_detail(self):
# Does this API work without auth?
response = self.get("users-detail", pk=self.sample_user.pk)
self.response_403(response)
# Does this API work with non-staff auth?
with self.login(self.user):
response = self.get("users-detail", pk=self.sample_user.pk)
self.response_200(response)
self.assertIn("first_name", response.data)
self.assertNotIn("date_joined", response.data)
# Does this API work with staff auth?
with self.login(self.staff):
response = self.get("users-detail", pk=self.sample_user.pk)
self.response_200(response)
self.assertIn("first_name", response.data)
self.assertIn("date_joined", response.data)
def test_create(self):
user = UserFactory.build()
payload = serializers.FullUserSerializer(user).data
# Does API work without auth?
response = self.client.post(reverse("users-list"), data=payload, format="json")
self.response_403(response)
# Does API work with non-staff user?
with self.login(self.user):
response = self.client.post(
reverse("users-list"), data=payload, format="json"
)
self.response_403(response)
# Does API work with staff user?
with self.login(self.staff):
response = self.client.post(
reverse("users-list"), data=payload, format="json"
)
self.response_201(response)
def test_delete(self):
url = reverse("users-detail", kwargs={"pk": self.sample_user.pk})
# Does this API work without auth?
response = self.client.delete(url, format="json")
self.response_403(response)
# Does this API wotk with non-staff user?
with self.login(self.user):
response = self.client.delete(url, format="json")
self.response_403(response)
# Does this API work with staff user?
with self.login(self.staff):
response = self.client.delete(url, format="json")
self.assertEqual(response.status_code, 204)
# Confirm object is gone
response = self.get(url)
self.response_404(response)
def test_update(self):
url = reverse("users-detail", kwargs={"pk": self.sample_user.pk})
old_name = self.sample_user.first_name
payload = serializers.FullUserSerializer(self.sample_user).data
# Does this API work without auth?
response = self.client.put(url, payload, format="json")
self.response_403(response)
# Does this API work with non-staff auth?
with self.login(self.user):
self.sample_user.first_name = Faker().name()
payload = serializers.FullUserSerializer(self.sample_user).data
response = self.client.put(url, payload, format="json")
self.response_403(response)
# Does this APO work with staff auth?
with self.login(self.staff):
self.sample_user.first_name = Faker().name()
payload = serializers.FullUserSerializer(self.sample_user).data
response = self.client.put(url, payload, format="json")
self.response_200(response)
self.assertFalse(response.data["first_name"] == old_name)
# Test updating reversions
self.sample_user.first_name = old_name
payload = serializers.FullUserSerializer(self.sample_user).data
response = self.client.put(url, payload, format="json")
self.assertTrue(response.data["first_name"] == old_name)
class CurrentUserViewTests(TestCase):
client_class = APIClient
def setUp(self):
self.user = UserFactory()
self.staff = StaffUserFactory()
def test_get_current_user(self):
# Does this API work without auth?
response = self.get("current-user")
self.response_403(response)
# Does this API work with auth?
with self.login(self.user):
response = self.get("current-user")
self.response_200(response)
self.assertIn("first_name", response.data)
self.assertIn("date_joined", response.data)
def test_create(self):
user = UserFactory.build()
payload = serializers.CurrentUserSerializer(user).data
# Does API work without auth?
response = self.client.post(
reverse("current-user"), data=payload, format="json"
)
self.response_403(response)
# Does API work with non-staff user?
with self.login(self.user):
response = self.client.post(
reverse("current-user"), data=payload, format="json"
)
self.response_405(response)
# Does API work with staff user?
with self.login(self.staff):
response = self.client.post(
reverse("current-user"), data=payload, format="json"
)
self.response_405(response)
def test_update(self):
old_name = self.user.first_name
payload = serializers.CurrentUserSerializer(self.user).data
# Does this API work without auth?
response = self.client.post(
reverse("current-user"), data=payload, format="json"
)
self.response_403(response)
# Does this API work with auth?
with self.login(self.user):
self.user.first_name = Faker().name()
payload = serializers.CurrentUserSerializer(self.user).data
response = self.client.put(reverse("current-user"), payload, format="json")
self.response_200(response)
self.assertFalse(response.data["first_name"] == old_name)
# Test updating reversions
self.user.first_name = old_name
payload = serializers.CurrentUserSerializer(self.user).data
response = self.client.put(reverse("current-user"), payload, format="json")
self.assertTrue(response.data["first_name"] == old_name)
# Can user update readonly fields?
old_email = self.user.email
with self.login(self.user):
self.user.email = Faker().email()
payload = serializers.CurrentUserSerializer(self.user).data
response = self.client.put(reverse("current-user"), payload, format="json")
self.response_200(response)
self.assertEqual(response.data["email"], old_email)
def test_delete(self):
# Does this API work without auth?
response = self.client.delete(reverse("current-user"), format="json")
self.response_403(response)
# Does this API wotk with auth? Should not.
with self.login(self.user):
response = self.client.delete(reverse("current-user"), format="json")
self.response_405(response)
# class UserViewTests(TestCase):
# client_class = APIClient
#
# def setUp(self):
# self.user = UserFactory()
# self.staff = StaffUserFactory()
# self.sample_user = UserFactory()
#
# def test_list_user(self):
# """
# Tests with a regular user
# """
# # Does API work without auth?
# response = self.get("users-list")
# self.response_403(response)
#
# # Does API work with auth?
# with self.login(self.user):
# response = self.get("users-list")
# self.response_200(response)
# self.assertEqual(len(response.data), 3)
# # Are non-staff shown/hidden the right fields?
# self.assertIn("first_name", response.data[0])
# self.assertNotIn("date_joined", response.data[0])
#
# def test_list_staff(self):
# """
# Test with a staff user, who use a different serializer
# """
# # Are staff shown the right fields?
# with self.login(self.staff):
# response = self.get("users-list")
# self.response_200(response)
# self.assertEqual(len(response.data), 3)
# self.assertIn("first_name", response.data[0])
# self.assertIn("date_joined", response.data[0])
#
# def test_detail(self):
# # Does this API work without auth?
# response = self.get("users-detail", pk=self.sample_user.pk)
# self.response_403(response)
#
# # Does this API work with non-staff auth?
# with self.login(self.user):
# response = self.get("users-detail", pk=self.sample_user.pk)
# self.response_200(response)
# self.assertIn("first_name", response.data)
# self.assertNotIn("date_joined", response.data)
#
# # Does this API work with staff auth?
# with self.login(self.staff):
# response = self.get("users-detail", pk=self.sample_user.pk)
# self.response_200(response)
# self.assertIn("first_name", response.data)
# self.assertIn("date_joined", response.data)
#
# def test_create(self):
# user = UserFactory.build()
# payload = serializers.FullUserSerializer(user).data
#
# # Does API work without auth?
# response = self.client.post(reverse("users-list"), data=payload, format="json")
# self.response_403(response)
#
# # Does API work with non-staff user?
# with self.login(self.user):
# response = self.client.post(
# reverse("users-list"), data=payload, format="json"
# )
# self.response_403(response)
#
# # Does API work with staff user?
# with self.login(self.staff):
# response = self.client.post(
# reverse("users-list"), data=payload, format="json"
# )
# self.response_201(response)
#
# def test_delete(self):
# url = reverse("users-detail", kwargs={"pk": self.sample_user.pk})
#
# # Does this API work without auth?
# response = self.client.delete(url, format="json")
# self.response_403(response)
#
# # Does this API wotk with non-staff user?
# with self.login(self.user):
# response = self.client.delete(url, format="json")
# self.response_403(response)
#
# # Does this API work with staff user?
# with self.login(self.staff):
# response = self.client.delete(url, format="json")
# self.assertEqual(response.status_code, 204)
#
# # Confirm object is gone
# response = self.get(url)
# self.response_404(response)
#
# def test_update(self):
# url = reverse("users-detail", kwargs={"pk": self.sample_user.pk})
#
# old_name = self.sample_user.first_name
# payload = serializers.FullUserSerializer(self.sample_user).data
#
# # Does this API work without auth?
# response = self.client.put(url, payload, format="json")
# self.response_403(response)
#
# # Does this API work with non-staff auth?
# with self.login(self.user):
# self.sample_user.first_name = Faker().name()
# payload = serializers.FullUserSerializer(self.sample_user).data
# response = self.client.put(url, payload, format="json")
# self.response_403(response)
#
# # Does this APO work with staff auth?
# with self.login(self.staff):
# self.sample_user.first_name = Faker().name()
# payload = serializers.FullUserSerializer(self.sample_user).data
# response = self.client.put(url, payload, format="json")
# self.response_200(response)
# self.assertFalse(response.data["first_name"] == old_name)
#
# # Test updating reversions
# self.sample_user.first_name = old_name
# payload = serializers.FullUserSerializer(self.sample_user).data
# response = self.client.put(url, payload, format="json")
# self.assertTrue(response.data["first_name"] == old_name)
#
#
# class CurrentUserViewTests(TestCase):
# client_class = APIClient
#
# def setUp(self):
# self.user = UserFactory()
# self.staff = StaffUserFactory()
#
# def test_get_current_user(self):
# # Does this API work without auth?
# response = self.get("current-user")
# self.response_403(response)
#
# # Does this API work with auth?
# with self.login(self.user):
# response = self.get("current-user")
# self.response_200(response)
# self.assertIn("first_name", response.data)
# self.assertIn("date_joined", response.data)
#
# def test_create(self):
# user = UserFactory.build()
# payload = serializers.CurrentUserSerializer(user).data
#
# # Does API work without auth?
# response = self.client.post(
# reverse("current-user"), data=payload, format="json"
# )
# self.response_403(response)
#
# # Does API work with non-staff user?
# with self.login(self.user):
# response = self.client.post(
# reverse("current-user"), data=payload, format="json"
# )
# self.response_405(response)
#
# # Does API work with staff user?
# with self.login(self.staff):
# response = self.client.post(
# reverse("current-user"), data=payload, format="json"
# )
# self.response_405(response)
#
# def test_update(self):
# old_name = self.user.first_name
# payload = serializers.CurrentUserSerializer(self.user).data
#
# # Does this API work without auth?
# response = self.client.post(
# reverse("current-user"), data=payload, format="json"
# )
# self.response_403(response)
#
# # Does this API work with auth?
# with self.login(self.user):
# self.user.first_name = Faker().name()
# payload = serializers.CurrentUserSerializer(self.user).data
# response = self.client.put(reverse("current-user"), payload, format="json")
# self.response_200(response)
# self.assertFalse(response.data["first_name"] == old_name)
#
# # Test updating reversions
# self.user.first_name = old_name
# payload = serializers.CurrentUserSerializer(self.user).data
# response = self.client.put(reverse("current-user"), payload, format="json")
# self.assertTrue(response.data["first_name"] == old_name)
#
# # Can user update readonly fields?
# old_email = self.user.email
#
# with self.login(self.user):
# self.user.email = Faker().email()
# payload = serializers.CurrentUserSerializer(self.user).data
# response = self.client.put(reverse("current-user"), payload, format="json")
# self.response_200(response)
# self.assertEqual(response.data["email"], old_email)
#
# def test_delete(self):
# # Does this API work without auth?
# response = self.client.delete(reverse("current-user"), format="json")
# self.response_403(response)
#
# # Does this API wotk with auth? Should not.
# with self.login(self.user):
# response = self.client.delete(reverse("current-user"), format="json")
# self.response_405(response)
####

View File

@@ -0,0 +1,40 @@
from django.utils import timezone
from users.models import User
def test_record_login_email(user):
now = timezone.now()
assert user.last_login < now
User.objects.record_login(email=user.email)
user.refresh_from_db()
assert user.last_login > now
def test_record_login_user(user):
now = timezone.now()
assert user.last_login < now
User.objects.record_login(user=user)
user.refresh_from_db()
assert user.last_login > now
def test_user_creation(db):
u = User.objects.create_user("t1@example.com", "t1pass")
assert u.is_active == True
assert u.is_staff == False
assert u.is_superuser == False
def test_staff_user_creation(db):
u = User.objects.create_staffuser("t2@example.com", "t2pass")
assert u.is_active == True
assert u.is_staff == True
assert u.is_superuser == False
def test_super_user_creation(db):
u = User.objects.create_superuser("t3@example.com", "t3pass")
assert u.is_active == True
assert u.is_staff == True
assert u.is_superuser == True

View File

@@ -2,66 +2,22 @@ from test_plus import TestCase
from django.contrib.auth import get_user_model
from django.utils import timezone
from ..factories import UserFactory, StaffUserFactory, SuperUserFactory
User = get_user_model()
class UserModelTests(TestCase):
def test_simple_user_creation(self):
now = timezone.now()
f = UserFactory()
self.assertTrue(f.is_active)
# Ensure LastSeen model is created
self.assertTrue(f.last_seen.at > now)
def test_staff_creation(self):
s = StaffUserFactory()
self.assertTrue(s.is_active)
self.assertTrue(s.is_staff)
self.assertFalse(s.is_superuser)
def test_superuser_creation(self):
s = SuperUserFactory()
self.assertTrue(s.is_active)
self.assertTrue(s.is_staff)
self.assertTrue(s.is_superuser)
def test_regular_user(user):
assert user.is_active == True
assert user.is_staff == False
assert user.is_superuser == False
class UserManagerTests(TestCase):
def test_record_login_email(self):
user = UserFactory()
now = timezone.now()
self.assertTrue(user.last_login < now)
User.objects.record_login(email=user.email)
def test_staff_user(staff_user):
assert staff_user.is_active == True
assert staff_user.is_staff == True
assert staff_user.is_superuser == False
user = User.objects.get(pk=user.pk)
self.assertTrue(user.last_login > now)
def test_record_login_user(self):
user = UserFactory()
now = timezone.now()
self.assertTrue(user.last_login < now)
User.objects.record_login(user=user)
user = User.objects.get(pk=user.pk)
self.assertTrue(user.last_login > now)
def test_create_user(self):
u = User.objects.create_user("t1@example.com", "t1pass")
self.assertTrue(u.is_active)
self.assertFalse(u.is_staff)
self.assertFalse(u.is_superuser)
def test_create_staffuser(self):
u = User.objects.create_staffuser("t2@example.com", "t2pass")
self.assertTrue(u.is_active)
self.assertTrue(u.is_staff)
self.assertFalse(u.is_superuser)
def test_create_superuser(self):
u = User.objects.create_superuser("t3@example.com", "t3pass")
self.assertTrue(u.is_active)
self.assertTrue(u.is_staff)
self.assertTrue(u.is_superuser)
def test_super_user(super_user):
assert super_user.is_active == True
assert super_user.is_staff == True
assert super_user.is_superuser == True

View File

@@ -3,9 +3,18 @@ from django.contrib import admin
from . import models
class VersionFileInline(admin.StackedInline):
model = models.VersionFile
autocomplete_fields = ("version",)
verbose_name = "VersionFile"
verbose_name_plural = "VersionFiles"
extra = 0
@admin.register(models.Version)
class VersionAdmin(admin.ModelAdmin):
list_display = ["name", "release_date"]
search_fields = [
"name",
]
list_display = ["name", "release_date", "active"]
list_filter = ["active"]
search_fields = ["name", "description"]
date_hierarchy = "release_date"
inlines = [VersionFileInline]

21
versions/api.py Executable file
View File

@@ -0,0 +1,21 @@
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import permissions
from versions.permissions import SuperUserOrVersionManager
from versions.models import Version, VersionFile
from versions.serializers import VersionSerializer, VersionFileSerializer
class VersionViewSet(viewsets.ModelViewSet):
model = Version
queryset = Version.objects.all()
serializer_class = VersionSerializer
permission_classes = [permissions.IsAuthenticated, SuperUserOrVersionManager]
class VersionFileViewSet(viewsets.ModelViewSet):
model = VersionFile
queryset = VersionFile.objects.all()
serializer_class = VersionFileSerializer
permission_classes = [permissions.IsAuthenticated, SuperUserOrVersionManager]

16
versions/managers.py Normal file
View File

@@ -0,0 +1,16 @@
from django.db import models
class VersionQuerySet(models.QuerySet):
def active(self):
"""Return active versions"""
return self.filter(active=True)
class VersionManager(models.Manager):
def get_queryset(self):
return VersionQuerySet(self.model, using=self._db)
def active(self):
"""Return active versions"""
return self.get_queryset().active()

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.2.2 on 2022-05-28 19:05
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('versions', '0002_auto_20211216_1051'),
]
operations = [
migrations.DeleteModel(
name='Version',
),
migrations.DeleteModel(
name='VersionFile',
),
]

View File

@@ -0,0 +1,35 @@
# Generated by Django 3.2.2 on 2022-05-28 19:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('versions', '0003_auto_20220528_1905'),
]
operations = [
migrations.CreateModel(
name='Version',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(help_text='Version name', max_length=256)),
('release_date', models.DateField()),
('description', models.TextField(blank=True)),
],
),
migrations.CreateModel(
name='VersionFile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('operating_system', models.CharField(choices=[('Unix', 'Unix'), ('Windows', 'Windows')], default='Unix', max_length=15)),
('checksum', models.CharField(default=None, max_length=64, unique=True)),
('file', models.FileField(upload_to='uploads/')),
('version', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='versions.version')),
],
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.2.2 on 2022-05-28 20:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('versions', '0004_version_versionfile'),
]
operations = [
migrations.AddField(
model_name='version',
name='active',
field=models.BooleanField(default=True, help_text='Control whether or not this version is available on the website'),
),
]

View File

@@ -1,7 +1,24 @@
import hashlib
from django.db import models
# Create your models here.
from .managers import VersionManager
class Version(models.Model):
name = models.CharField(
max_length=256, null=False, blank=False, help_text="Version name"
)
release_date = models.DateField(auto_now=False, auto_now_add=False)
description = models.TextField(blank=True)
active = models.BooleanField(
default=True,
help_text="Control whether or not this version is available on the website",
)
objects = VersionManager()
def __str__(self):
return self.name
class VersionFile(models.Model):
@@ -11,24 +28,18 @@ class VersionFile(models.Model):
(Unix, "Unix"),
(Windows, "Windows"),
)
version = models.ForeignKey(Version, related_name="files", on_delete=models.CASCADE)
operating_system = models.CharField(
choices=OPERATING_SYSTEM_CHOICES, max_length=15, default=Unix
)
checksum = models.CharField(max_length=64, unique=True, default=None)
file = models.FileField(upload_to="uploads/")
operating_system = models.CharField(
choices=OPERATING_SYSTEM_CHOICES, max_length=15, null=False, blank=False
)
def save(self, *args, **kwargs):
if self.file is not None:
if self.checksum is None:
self.checksum = hashlib.sha256(
self.file.name.encode("utf-8")
self.file.file.encode("utf-8")
).hexdigest()
super().save(*args, **kwargs)
class Version(models.Model):
name = models.CharField(
max_length=256, null=False, blank=False, help_text="Version name"
)
files = models.ManyToManyField(VersionFile)
release_date = models.DateField(auto_now=False, auto_now_add=False)

View File

@@ -1,5 +1,6 @@
from django.core import files
from rest_framework import serializers
from versions.models import Version, VersionFile
@@ -9,7 +10,7 @@ class VersionFileSerializer(serializers.ModelSerializer):
class Meta:
model = VersionFile
fields = ["id", "checksum", "operating_system", "filename", "url", "file"]
fields = ["id", "filename", "checksum", "operating_system", "url"]
def get_url(self, obj):
request = self.context.get("request")
@@ -25,12 +26,4 @@ class VersionSerializer(serializers.ModelSerializer):
class Meta:
model = Version
fields = ["id", "name", "files", "release_date"]
# def create(self, validated_data):
# files = validated_data.pop('files')
# version = Version.objects.create(**validated_data)
# for file in files:
# version_file = VersionFile.objects.create(file=file.get("file"), operating_system=file.get("operating_system"))
# version.files.add(version_file)
# return version
fields = ["id", "name", "release_date", "description", "files"]

View File

@@ -0,0 +1,14 @@
import pytest
import datetime
from model_bakery import baker
@pytest.fixture
def version(db):
yesterday = datetime.date.today() - datetime.timedelta(days=1)
return baker.make(
"versions.Version",
name="Version 1.79.0",
description="Some awesome description of the library",
release_date=yesterday,
)

View File

@@ -0,0 +1,10 @@
from model_bakery import baker
from versions.models import Version
def test_active_manager(version):
v2 = baker.make("versions.Version", active=False)
v3 = baker.make("versions.Version", active=False)
assert Version.objects.active().count() == 1

View File

@@ -0,0 +1,6 @@
import datetime
def test_version_creation(version):
today = datetime.date.today()
assert version.release_date < today

View File

@@ -1,171 +1,172 @@
from django.db import transaction
from django.db import IntegrityError
import tempfile
from django.urls import reverse
from django.core.files import File as DjangoFile
from rest_framework.test import APIClient
from test_plus.test import TestCase
from users.factories import UserFactory, SuperUserFactory, VersionGroupFactory
from versions.factories import VersionFactory, VersionFileFactory
from PIL import Image
from versions.models import VersionFile
class VersionViewTests(TestCase):
client_class = APIClient
def setUp(self):
self.user = UserFactory()
self.group_user = UserFactory.create(groups=(VersionGroupFactory.create(),))
self.super_user = SuperUserFactory()
self.version_manager = UserFactory()
self.version_file1 = VersionFileFactory()
self.version_file2 = VersionFileFactory()
self.version = VersionFactory.create(
files=(self.version_file1, self.version_file2)
)
def test_list_version(self):
"""
Tests with a regular user
"""
# Does API work without auth?
response = self.get("versions-list")
self.response_403(response)
# Does API work with auth?
with self.login(self.user):
response = self.get("versions-list")
self.response_200(response)
self.assertEqual(len(response.data), 1)
# Are non-staff shown/hidden the right fields?
self.assertIn("name", response.data[0])
files = response.data[0].get("files")
for file in files:
self.assertIn("checksum", file)
self.assertIn("operating_system", file)
def test_create(self):
image = Image.new("RGB", (100, 100))
tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
image.save(tmp_file)
tmp_file.seek(0)
file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
payload = {
"files": [{"file": file_obj, "operating_system": "Windows"}],
"name": "First Version",
"release_date": "2021-01-01",
}
# Does API work without auth?
response = self.client.post(
reverse("versions-list"), files=payload, format="multipart"
)
self.response_403(response)
file_obj.seek(0)
# Does API work with normal user?
with self.login(self.user):
response = self.client.post(
reverse("versions-list"), data=payload, format="multipart"
)
self.response_403(response)
file_obj.seek(0)
# # Does API work with super user?
with self.login(self.super_user):
try:
with transaction.atomic():
response = self.client.post(
reverse("versions-list"), data=payload, format="multipart"
)
self.response_201(response)
except IntegrityError:
pass
file_obj.seek(0)
# Does API work with version_manager user?
with self.login(self.group_user):
try:
with transaction.atomic():
response = self.client.post(
reverse("versions-list"), data=payload, format="multipart"
)
self.response_201(response)
except IntegrityError:
pass
def test_delete(self):
url = reverse("versions-detail", kwargs={"pk": self.version.pk})
# Does this API work without auth?
response = self.client.delete(url, format="json")
self.response_403(response)
# Does this API wotk with non-staff user?
with self.login(self.user):
response = self.client.delete(url, format="json")
self.response_403(response)
# Does this API work with super user?
with self.login(self.super_user):
response = self.client.delete(url, format="json")
self.assertEqual(response.status_code, 204)
# Confirm object is gone
response = self.get(url)
self.response_404(response)
def test_update(self):
old_name = self.version.name
url = reverse("versions-detail", kwargs={"pk": self.version.pk})
image = Image.new("RGB", (100, 100))
tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
file_obj.seek(0)
payload = {
"files": [{"file": file_obj, "operating_system": "Windows"}],
"name": "Second Version",
}
# Does API work without auth?
response = self.client.post(url, files=payload, format="multipart")
self.response_403(response)
file_obj.seek(0)
# Does API work with normal user?
with self.login(self.user):
response = self.client.patch(url, data=payload, format="multipart")
self.response_403(response)
file_obj.seek(0)
# Does API work with super user?
with self.login(self.super_user):
try:
with transaction.atomic():
response = self.client.patch(url, data=payload, format="multipart")
self.response_200(response)
self.assertNotEqual(old_name, response.data["name"])
except IntegrityError:
pass
file_obj.seek(0)
# Does API work with version_manager user?
with self.login(self.group_user):
try:
with transaction.atomic():
response = self.client.patch(url, data=payload, format="multipart")
self.response_200(response)
self.assertNotEqual(old_name, response.data["name"])
except IntegrityError:
pass
# from django.db import transaction
# from django.db import IntegrityError
# import tempfile
# from django.urls import reverse
# from django.core.files import File as DjangoFile
# from rest_framework.test import APIClient
# from test_plus.test import TestCase
#
# from users.factories import UserFactory, SuperUserFactory, VersionGroupFactory
# from versions.factories import VersionFactory, VersionFileFactory
#
# from PIL import Image
#
# from versions.models import VersionFile
#
#
# class VersionViewTests(TestCase):
# client_class = APIClient
#
# def setUp(self):
# self.user = UserFactory()
# self.group_user = UserFactory.create(groups=(VersionGroupFactory.create(),))
# self.super_user = SuperUserFactory()
# self.version_manager = UserFactory()
# self.version_file1 = VersionFileFactory()
# self.version_file2 = VersionFileFactory()
# self.version = VersionFactory.create(
# files=(self.version_file1, self.version_file2)
# )
#
# def test_list_version(self):
# """
# Tests with a regular user
# """
# # Does API work without auth?
# response = self.get("versions-list")
# self.response_403(response)
#
# # Does API work with auth?
# with self.login(self.user):
# response = self.get("versions-list")
# self.response_200(response)
# self.assertEqual(len(response.data), 1)
# # Are non-staff shown/hidden the right fields?
# self.assertIn("name", response.data[0])
# files = response.data[0].get("files")
# for file in files:
# self.assertIn("checksum", file)
# self.assertIn("operating_system", file)
#
# def test_create(self):
# image = Image.new("RGB", (100, 100))
#
# tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
# image.save(tmp_file)
#
# tmp_file.seek(0)
# file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
#
# payload = {
# "files": [{"file": file_obj, "operating_system": "Windows"}],
# "name": "First Version",
# "release_date": "2021-01-01",
# }
#
# # Does API work without auth?
# response = self.client.post(
# reverse("versions-list"), files=payload, format="multipart"
# )
# self.response_403(response)
#
# file_obj.seek(0)
# # Does API work with normal user?
# with self.login(self.user):
# response = self.client.post(
# reverse("versions-list"), data=payload, format="multipart"
# )
# self.response_403(response)
#
# file_obj.seek(0)
# # # Does API work with super user?
# with self.login(self.super_user):
# try:
# with transaction.atomic():
# response = self.client.post(
# reverse("versions-list"), data=payload, format="multipart"
# )
# self.response_201(response)
# except IntegrityError:
# pass
#
# file_obj.seek(0)
# # Does API work with version_manager user?
# with self.login(self.group_user):
# try:
# with transaction.atomic():
# response = self.client.post(
# reverse("versions-list"), data=payload, format="multipart"
# )
# self.response_201(response)
# except IntegrityError:
# pass
#
# def test_delete(self):
# url = reverse("versions-detail", kwargs={"pk": self.version.pk})
#
# # Does this API work without auth?
# response = self.client.delete(url, format="json")
# self.response_403(response)
#
# # Does this API wotk with non-staff user?
# with self.login(self.user):
# response = self.client.delete(url, format="json")
# self.response_403(response)
#
# # Does this API work with super user?
# with self.login(self.super_user):
# response = self.client.delete(url, format="json")
# self.assertEqual(response.status_code, 204)
#
# # Confirm object is gone
# response = self.get(url)
# self.response_404(response)
#
# def test_update(self):
# old_name = self.version.name
# url = reverse("versions-detail", kwargs={"pk": self.version.pk})
#
# image = Image.new("RGB", (100, 100))
#
# tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
# file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
#
# file_obj.seek(0)
#
# payload = {
# "files": [{"file": file_obj, "operating_system": "Windows"}],
# "name": "Second Version",
# }
#
# # Does API work without auth?
# response = self.client.post(url, files=payload, format="multipart")
# self.response_403(response)
#
# file_obj.seek(0)
# # Does API work with normal user?
# with self.login(self.user):
# response = self.client.patch(url, data=payload, format="multipart")
# self.response_403(response)
#
# file_obj.seek(0)
# # Does API work with super user?
# with self.login(self.super_user):
# try:
# with transaction.atomic():
# response = self.client.patch(url, data=payload, format="multipart")
# self.response_200(response)
# self.assertNotEqual(old_name, response.data["name"])
# except IntegrityError:
# pass
#
# file_obj.seek(0)
# # Does API work with version_manager user?
# with self.login(self.group_user):
# try:
# with transaction.atomic():
# response = self.client.patch(url, data=payload, format="multipart")
# self.response_200(response)
# self.assertNotEqual(old_name, response.data["name"])
# except IntegrityError:
# pass
#

View File

@@ -7,157 +7,158 @@ from django.urls import reverse
from rest_framework.test import APIClient
from test_plus.test import TestCase
from users.factories import UserFactory, SuperUserFactory, VersionGroupFactory
from versions.factories import VersionFactory, VersionFileFactory
# from users.factories import UserFactory, SuperUserFactory, VersionGroupFactory
# from versions.factories import VersionFactory, VersionFileFactory
from PIL import Image
from versions.models import VersionFile
class VersionViewTests(TestCase):
client_class = APIClient
def setUp(self):
self.user = UserFactory()
self.group_user = UserFactory.create(groups=(VersionGroupFactory.create(),))
self.super_user = SuperUserFactory()
self.version_manager = UserFactory()
self.version_file1 = VersionFileFactory()
self.version_file2 = VersionFileFactory()
self.version = VersionFactory.create(
files=(self.version_file1, self.version_file2)
)
def test_list_version(self):
"""
Tests with a regular user
"""
# Does API work without auth?
response = self.get("version-files-list")
self.response_403(response)
# Does API work with auth?
with self.login(self.user):
response = self.get("version-files-list")
self.response_200(response)
self.assertEqual(len(response.data), 2)
self.assertIn("checksum", response.data[0])
self.assertIn("operating_system", response.data[0])
def test_create(self):
image = Image.new("RGB", (100, 100))
tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
image.save(tmp_file)
tmp_file.seek(0)
file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
payload = {"file": file_obj, "operating_system": "Windows"}
# Does API work without auth?
response = self.client.post(
reverse("version-files-list"), files=payload, format="multipart"
)
self.response_403(response)
file_obj.seek(0)
# Does API work with normal user?
with self.login(self.user):
response = self.client.post(
reverse("version-files-list"), data=payload, format="multipart"
)
self.response_403(response)
file_obj.seek(0)
# # Does API work with super user?
with self.login(self.super_user):
try:
with transaction.atomic():
response = self.client.post(
reverse("version-files-list"), data=payload, format="multipart"
)
self.response_201(response)
except IntegrityError:
pass
file_obj.seek(0)
# Does API work with version_manager user?
with self.login(self.group_user):
try:
with transaction.atomic():
response = self.client.post(
reverse("version-files-list"), data=payload, format="multipart"
)
self.response_201(response)
except IntegrityError:
pass
def test_delete(self):
url = reverse("version-files-detail", kwargs={"pk": self.version_file1.pk})
# Does this API work without auth?
response = self.client.delete(url, format="json")
self.response_403(response)
# Does this API wotk with non-staff user?
with self.login(self.user):
response = self.client.delete(url, format="json")
self.response_403(response)
# Does this API work with super user?
with self.login(self.super_user):
response = self.client.delete(url, format="json")
self.assertEqual(response.status_code, 204)
# Confirm object is gone
response = self.get(url)
self.response_404(response)
def test_update(self):
url = reverse("version-files-detail", kwargs={"pk": self.version_file2.pk})
image = Image.new("RGB", (100, 100))
tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
image.save(tmp_file)
tmp_file.seek(0)
file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
file_obj.seek(0)
payload = {
"file": file_obj,
}
# Does API work without auth?
response = self.client.post(url, files=payload, format="multipart")
self.response_403(response)
file_obj.seek(0)
# Does API work with normal user?
with self.login(self.user):
response = self.client.patch(url, data=payload, format="multipart")
self.response_403(response)
file_obj.seek(0)
# Does API work with super user?
with self.login(self.super_user):
try:
with transaction.atomic():
response = self.client.patch(url, data=payload, format="multipart")
self.response_200(response)
except IntegrityError:
pass
file_obj.seek(0)
# Does API work with version_manager user?
with self.login(self.group_user):
try:
with transaction.atomic():
response = self.client.patch(url, data=payload, format="multipart")
self.response_200(response)
except IntegrityError:
pass
# class VersionViewTests(TestCase):
# client_class = APIClient
#
# def setUp(self):
# self.user = UserFactory()
# self.group_user = UserFactory.create(groups=(VersionGroupFactory.create(),))
# self.super_user = SuperUserFactory()
# self.version_manager = UserFactory()
# self.version_file1 = VersionFileFactory()
# self.version_file2 = VersionFileFactory()
# self.version = VersionFactory.create(
# files=(self.version_file1, self.version_file2)
# )
#
# def test_list_version(self):
# """
# Tests with a regular user
# """
# # Does API work without auth?
# response = self.get("version-files-list")
# self.response_403(response)
#
# # Does API work with auth?
# with self.login(self.user):
# response = self.get("version-files-list")
# self.response_200(response)
# self.assertEqual(len(response.data), 2)
# self.assertIn("checksum", response.data[0])
# self.assertIn("operating_system", response.data[0])
#
# def test_create(self):
# image = Image.new("RGB", (100, 100))
#
# tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
# image.save(tmp_file)
#
# tmp_file.seek(0)
# file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
#
# payload = {"file": file_obj, "operating_system": "Windows"}
#
# # Does API work without auth?
# response = self.client.post(
# reverse("version-files-list"), files=payload, format="multipart"
# )
# self.response_403(response)
#
# file_obj.seek(0)
# # Does API work with normal user?
# with self.login(self.user):
# response = self.client.post(
# reverse("version-files-list"), data=payload, format="multipart"
# )
# self.response_403(response)
#
# file_obj.seek(0)
# # # Does API work with super user?
# with self.login(self.super_user):
# try:
# with transaction.atomic():
# response = self.client.post(
# reverse("version-files-list"), data=payload, format="multipart"
# )
# self.response_201(response)
# except IntegrityError:
# pass
#
# file_obj.seek(0)
# # Does API work with version_manager user?
# with self.login(self.group_user):
# try:
# with transaction.atomic():
# response = self.client.post(
# reverse("version-files-list"), data=payload, format="multipart"
# )
# self.response_201(response)
# except IntegrityError:
# pass
#
# def test_delete(self):
# url = reverse("version-files-detail", kwargs={"pk": self.version_file1.pk})
#
# # Does this API work without auth?
# response = self.client.delete(url, format="json")
# self.response_403(response)
#
# # Does this API wotk with non-staff user?
# with self.login(self.user):
# response = self.client.delete(url, format="json")
# self.response_403(response)
#
# # Does this API work with super user?
# with self.login(self.super_user):
# response = self.client.delete(url, format="json")
# self.assertEqual(response.status_code, 204)
#
# # Confirm object is gone
# response = self.get(url)
# self.response_404(response)
#
# def test_update(self):
# url = reverse("version-files-detail", kwargs={"pk": self.version_file2.pk})
#
# image = Image.new("RGB", (100, 100))
#
# tmp_file = tempfile.NamedTemporaryFile(suffix=".jpg")
# image.save(tmp_file)
#
# tmp_file.seek(0)
# file_obj = DjangoFile(open(tmp_file.name, mode="rb"), name="tmp_file")
#
# file_obj.seek(0)
#
# payload = {
# "file": file_obj,
# }
#
# # Does API work without auth?
# response = self.client.post(url, files=payload, format="multipart")
# self.response_403(response)
#
# file_obj.seek(0)
# # Does API work with normal user?
# with self.login(self.user):
# response = self.client.patch(url, data=payload, format="multipart")
# self.response_403(response)
#
# file_obj.seek(0)
# # Does API work with super user?
# with self.login(self.super_user):
# try:
# with transaction.atomic():
# response = self.client.patch(url, data=payload, format="multipart")
# self.response_200(response)
# except IntegrityError:
# pass
#
# file_obj.seek(0)
# # Does API work with version_manager user?
# with self.login(self.group_user):
# try:
# with transaction.atomic():
# response = self.client.patch(url, data=payload, format="multipart")
# self.response_200(response)
# except IntegrityError:
# pass
##

View File

@@ -0,0 +1,7 @@
def test_version_list(version, tp):
res = tp.get("version-list")
tp.response_200(res)
print(res.context)
objs = res.context["version_list"]
assert len(objs) == 1
assert version in objs

View File

@@ -1,21 +1,19 @@
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import permissions
from versions.permissions import SuperUserOrVersionManager
from django.views.generic import ListView, DetailView
from versions.models import Version, VersionFile
from versions.serializers import VersionSerializer, VersionFileSerializer
class VersionViewSet(viewsets.ModelViewSet):
class VersionList(ListView):
"""Web display of list of Versions"""
model = Version
queryset = Version.objects.all()
serializer_class = VersionSerializer
permission_classes = [permissions.IsAuthenticated, SuperUserOrVersionManager]
queryset = Version.objects.active()
template_name = "versions/list.html"
class VersionFileViewSet(viewsets.ModelViewSet):
model = VersionFile
queryset = VersionFile.objects.all()
serializer_class = VersionFileSerializer
permission_classes = [permissions.IsAuthenticated, SuperUserOrVersionManager]
class VersionDetail(DetailView):
"""Web display of list of Versions"""
model = Version
queryset = Version.objects.active()
template_name = "versions/detail.html"