Skip to content
This repository has been archived by the owner on May 13, 2024. It is now read-only.

chore(deps): switch to djangorestframework-simplejwt #502

Merged
merged 3 commits into from
Feb 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.6
FROM python:3.8

WORKDIR /app

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ You can now access the API at http://localhost:8000/api/v1 and the admin interfa

For end user interface have a look at our [Timed Frontend](https://github.com/adfinis-sygroup/timed-frontend) project.

## Development

To get the application working locally for development, make sure to create a file `.env` with the following content:

```
ENV=dev
```

## Configuration

Following options can be set as environment variables to configure Timed backend in documented [format](https://github.com/joke2k/django-environ#supported-types)
Expand Down
31 changes: 16 additions & 15 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
-r requirements.txt
black==19.3b0
coverage==4.5.3
black==19.10b0
coverage==5.0.3
factory-boy==2.12.0
flake8==3.7.7
flake8==3.7.9
flake8-blind-except==0.1.1
flake8-debugger==3.1.0
flake8-debugger==3.2.1
flake8-deprecated==1.3
flake8-docstrings==1.3.0
flake8-isort==2.7.0
flake8-docstrings==1.5.0
flake8-isort==2.8.0
flake8-string-format==0.2.3
ipdb==0.12
isort==4.3.20
mockldap==0.3.0
pytest==4.5.0
pytest-cov==2.7.1
pytest-django==3.4.8
ipdb==0.12.3
isort==4.3.21
mockldap==0.3.0.post1
pdbpp==0.10.2
pytest==5.3.5
pytest-cov==2.8.1
pytest-django==3.8.0
pytest-env==0.6.2
pytest-freezegun==0.3.0.post1
pytest-mock==1.10.4
pytest-randomly==3.0.0
pytest-freezegun==0.4.1
pytest-mock==2.0.0
pytest-randomly==3.2.1
26 changes: 13 additions & 13 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
python-dateutil==2.8.0
django==1.11.22 # pyup: >=1.11,<1.12
django-auth-ldap==1.7.0
django-filter==2.1.0
django-multiselectfield==0.1.8
djangorestframework==3.9.4
djangorestframework-jwt==1.11.0
djangorestframework-jsonapi==2.7.0
psycopg2-binary==2.8.2
pytz==2019.1
python-dateutil==2.8.1
django==2.2.10 # pyup: <3.0
django-auth-ldap==2.1.0
django-filter==2.2.0
django-multiselectfield==0.1.11
djangorestframework==3.11.0
djangorestframework-simplejwt==4.4.0
djangorestframework-jsonapi==3.0.0
psycopg2-binary==2.8.4
pytz==2019.3
pyexcel-webio==0.1.4
pyexcel-io==0.5.17
pyexcel-io==0.5.20
django-excel==0.0.10
pyexcel-ods3==0.5.3
pyexcel-xlsx==0.5.7
pyexcel-xlsx==0.5.8
pyexcel-ezodf==0.3.4
django-environ==0.4.5
django-money==0.14.4
django-money==1.0
python-redmine==2.2.1
uwsgi==2.0.18
4 changes: 2 additions & 2 deletions timed/projects/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Viewsets for the projects app."""

from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework_json_api.views import PrefetchForIncludesHelperMixin
from rest_framework_json_api.views import PreloadIncludesMixin

from timed.projects import filters, models, serializers

Expand Down Expand Up @@ -38,7 +38,7 @@ def get_queryset(self):
return models.CostCenter.objects.all()


class ProjectViewSet(PrefetchForIncludesHelperMixin, ReadOnlyModelViewSet):
class ProjectViewSet(PreloadIncludesMixin, ReadOnlyModelViewSet):
"""Project view set."""

serializer_class = serializers.ProjectSerializer
Expand Down
10 changes: 7 additions & 3 deletions timed/redmine/management/commands/redmine_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,17 @@ def handle(self, *args, **options):
.values("id")
)
# calculate total hours
projects = Project.objects.filter(id__in=affected_projects).annotate(
total_hours=Sum("tasks__reports__duration")
projects = (
Project.objects.filter(id__in=affected_projects)
.order_by("name")
.annotate(total_hours=Sum("tasks__reports__duration"))
)

for project in projects:
estimated_hours = (
project.estimated_time and project.estimated_time.total_seconds() / 3600
project.estimated_time.total_seconds() / 3600
if project.estimated_time
else 0.0
)
total_hours = project.total_hours.total_seconds() / 3600
try:
Expand Down
4 changes: 2 additions & 2 deletions timed/reports/tests/test_month_statistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ def test_month_statistic_list(auth_client):
expected_json = [
{
"type": "month-statistics",
"id": "2015-12",
"id": "201512",
"attributes": {"year": 2015, "month": 12, "duration": "03:00:00"},
},
{
"type": "month-statistics",
"id": "2016-1",
"id": "201601",
"attributes": {"year": 2016, "month": 1, "duration": "01:00:00"},
},
]
Expand Down
2 changes: 1 addition & 1 deletion timed/reports/tests/test_notify_supervisors_shorttime.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def test_notify_supervisors(db, mailoutbox):
mail = mailoutbox[0]
assert mail.to == [supervisor.email]
body = mail.body
assert "Time range: 17.07.2017 - 23.07.2017\nRatio: 0.9" in body
assert "Time range: July 17, 2017 - July 23, 2017\nRatio: 0.9" in body
expected = ("{0} 35.0/42.5 (Ratio 0.82 Delta -7.5 Balance -9.0)").format(
supervisee.get_full_name()
)
Expand Down
6 changes: 3 additions & 3 deletions timed/reports/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from zipfile import ZipFile

from django.conf import settings
from django.db.models import F, Sum, Value
from django.db.models.functions import Concat, ExtractMonth, ExtractYear
from django.db.models import F, Sum
from django.db.models.functions import ExtractMonth, ExtractYear
from django.http import HttpResponse, HttpResponseBadRequest
from ezodf import Cell, opendoc
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet
Expand Down Expand Up @@ -49,7 +49,7 @@ def get_queryset(self):
)
queryset = queryset.values("year", "month")
queryset = queryset.annotate(duration=Sum("duration"))
queryset = queryset.annotate(pk=Concat("year", Value("-"), "month"))
queryset = queryset.annotate(pk=F("year") * 100 + F("month"))
return queryset


Expand Down
13 changes: 6 additions & 7 deletions timed/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,7 @@ def default(default_dev=env.NOTSET, default_prod=env.NOTSET):
"DEFAULT_PARSER_CLASSES": ("rest_framework_json_api.parsers.JSONParser",),
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_jwt.authentication.JSONWebTokenAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"DEFAULT_METADATA_CLASS": "rest_framework_json_api.metadata.JSONAPIMetadata",
"EXCEPTION_HANDLER": "rest_framework_json_api.exceptions.exception_handler",
Expand Down Expand Up @@ -187,11 +186,11 @@ def default(default_dev=env.NOTSET, default_prod=env.NOTSET):

AUTH_USER_MODEL = "employment.User"

JWT_AUTH = {
"JWT_EXPIRATION_DELTA": datetime.timedelta(days=2),
"JWT_ALLOW_REFRESH": True,
"JWT_REFRESH_EXPIRATION_DELTA": datetime.timedelta(days=7),
"JWT_AUTH_HEADER_PREFIX": "Bearer",
SIMPLE_AUTH = {
"ACCESS_TOKEN_LIFETIME": datetime.timedelta(days=2),
"REFRESH_TOKEN_LIFETIME": datetime.timedelta(days=7),
# TODO check if this is ROTATE_REFRESH_TOKENS
# "JWT_ALLOW_REFRESH": True,
}

AUTH_PASSWORD_VALIDATORS = [
Expand Down
15 changes: 5 additions & 10 deletions timed/tests/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from django.urls import reverse
from rest_framework import exceptions, status
from rest_framework.test import APIClient
from rest_framework_jwt.settings import api_settings


class JSONAPIClient(APIClient):
Expand Down Expand Up @@ -40,7 +39,7 @@ def post(self, path, data=None, **kwargs):
path=path,
data=self._parse_data(data),
content_type=self._content_type,
**kwargs
**kwargs,
)

def delete(self, path, data=None, **kwargs):
Expand All @@ -53,7 +52,7 @@ def delete(self, path, data=None, **kwargs):
path=path,
data=self._parse_data(data),
content_type=self._content_type,
**kwargs
**kwargs,
)

def patch(self, path, data=None, **kwargs):
Expand All @@ -66,7 +65,7 @@ def patch(self, path, data=None, **kwargs):
path=path,
data=self._parse_data(data),
content_type=self._content_type,
**kwargs
**kwargs,
)

def login(self, username, password):
Expand All @@ -79,7 +78,7 @@ def login(self, username, password):
data = {
"data": {
"attributes": {"username": username, "password": password},
"type": "obtain-json-web-tokens",
"type": "token-obtain-pair-views",
}
}

Expand All @@ -88,8 +87,4 @@ def login(self, username, password):
if response.status_code != status.HTTP_200_OK:
raise exceptions.AuthenticationFailed()

self.credentials(
HTTP_AUTHORIZATION="{0} {1}".format(
api_settings.JWT_AUTH_HEADER_PREFIX, response.data["token"]
)
)
self.credentials(HTTP_AUTHORIZATION=f"Bearer {response.data['access']}")
6 changes: 3 additions & 3 deletions timed/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

from django.conf.urls import include, url
from django.contrib import admin
from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns = [
url(r"^admin/", admin.site.urls),
url(r"^api/v1/auth/login", obtain_jwt_token, name="login"),
url(r"^api/v1/auth/refresh", refresh_jwt_token, name="refresh"),
url(r"^api/v1/auth/login", TokenObtainPairView.as_view(), name="login"),
url(r"^api/v1/auth/refresh", TokenRefreshView.as_view(), name="refresh"),
url(r"^api/v1/", include("timed.employment.urls")),
url(r"^api/v1/", include("timed.projects.urls")),
url(r"^api/v1/", include("timed.tracking.urls")),
Expand Down