Commit e736424f authored by VAN ZUIJLEN Nils's avatar VAN ZUIJLEN Nils
Browse files

Merge branch 'seagull-api' into 'master'

Add enibar/api/history for Seagull usage

See merge request !72
parents dd16e9a0 1e4c54eb
......@@ -12,6 +12,7 @@ types-Markdown = "*"
types-freezegun = "*"
types-redis = "*"
types-requests = "*"
black = "*"
[packages]
Markdown = "*"
......@@ -26,7 +27,6 @@ psycopg2-binary = "*"
redis = "*"
requests = "*"
[scripts]
test = "./test.sh"
create_recurrent_events = "./manage.py create_recurrent_events"
This diff is collapsed.
......@@ -315,7 +315,7 @@ class ManageCategoryView(PermissionRequiredMixin, ListView, ModelFormMixin): #
object = None
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
self.object_list = self.get_queryset()
self.object_list = self.get_queryset() # type: ignore # A QuerySet is a Sequence
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
......
import json
from datetime import datetime
from decimal import Decimal
from django.contrib.auth import get_user_model
from django.http import JsonResponse
from django.test import Client
from django.test import TestCase
from django.utils import timezone
......@@ -16,25 +18,25 @@ class TestEnibarImport(TestCase):
super().setUp()
def test_note_import_404(self):
response = self.client.options("/enibar/note/", "{}")
response = self.client.options("/enibar/api/note/", "{}")
self.assertEqual(response.status_code, 404)
response = self.client.put("/enibar/note", "pouet")
response = self.client.put("/enibar/api/note", "pouet")
self.assertEqual(response.status_code, 404)
def test_note_put_403(self):
response = self.client.put(
"/enibar/note",
"/enibar/api/note",
'{"id": 1, "nickname": "coucou", "mail": "test@test.fr", "note": 52.2}',
)
self.assertEqual(response.status_code, 403)
def test_note_delete_403(self):
response = self.client.delete("/enibar/note", '{"id": 2}')
response = self.client.delete("/enibar/api/note", '{"id": 2}')
self.assertEqual(response.status_code, 403)
def test_import_note_put(self):
response = self.client.put(
"/enibar/note",
"/enibar/api/note",
'{"token": "changeme", "id": 1, "nickname": "coucou", "mail": "test@test.fr", "note": 52.2}',
)
self.assertEqual(response.status_code, 200)
......@@ -44,7 +46,7 @@ class TestEnibarImport(TestCase):
self.assertEqual(note.mail, "test@test.fr")
self.assertEqual(note.note, Decimal("52.2"))
response = self.client.put(
"/enibar/note",
"/enibar/api/note",
'{"token": "changeme", "id": 1, "nickname": "coucou", "mail": "test@test.fr", "note": 50.2}',
)
self.assertEqual(response.status_code, 200)
......@@ -58,7 +60,9 @@ class TestEnibarImport(TestCase):
Note.objects.create(
foreign_id=2, nickname="toto", mail="coucou@test.fr", note=Decimal("10")
)
response = self.client.delete("/enibar/note", '{"token": "changeme", "id": 2}')
response = self.client.delete(
"/enibar/api/note", '{"token": "changeme", "id": 2}'
)
self.assertEqual(response.status_code, 200)
with self.assertRaises(Note.DoesNotExist):
Note.objects.get(foreign_id=2)
......@@ -71,7 +75,7 @@ class TestEnibarImport(TestCase):
foreign_id=3, nickname="toto2", mail="cou@test.com", note=Decimal("11")
)
response = self.client.get("/enibar/note")
response = self.client.get("/enibar/api/note")
self.assertEqual(
response.json(),
[
......@@ -89,7 +93,7 @@ class TestEnibarImport(TestCase):
},
],
)
response = self.client.get("/enibar/note", {"foreign_id": 2})
response = self.client.get("/enibar/api/note", {"foreign_id": 2})
self.assertEqual(
response.json(),
[
......@@ -101,10 +105,101 @@ class TestEnibarImport(TestCase):
}
],
)
response = self.client.get("/enibar/note", {"pouet": 2})
response = self.client.get("/enibar/api/note", {"pouet": 2})
self.assertEqual(response.status_code, 404)
class TestHistoryByUser(TestCase):
user_model = get_user_model()
def setUp(self) -> None:
self.note1 = Note.objects.create(
foreign_id=1,
nickname="Note1",
mail="user@local.test",
note=Decimal("10.00"),
)
self.note2 = Note.objects.create(
foreign_id=2,
nickname="Note 2",
mail="user@local.test",
note=Decimal("10.00"),
)
self.note_autre = Note.objects.create(
foreign_id=3,
nickname="Autre",
mail="other@local.test",
note=Decimal("10.00"),
)
self.user = self.user_model.objects.create_user(
"user", "user@local.test", "password"
)
self.client.force_login(self.user)
for i in range(60):
HistoryLine.objects.create(
foreign_id=i * 3 + 1,
date=timezone.make_aware(datetime(2020, 9, 1, 0, i, 0)),
note=self.note1.nickname,
category="Softs",
product="Produit",
price_name="default",
quantity=1,
liquid_quantity=10,
percentage=Decimal("0.00"),
price=Decimal("1.00"),
note_id=self.note1.foreign_id,
)
HistoryLine.objects.create(
foreign_id=i * 3 + 2,
date=timezone.make_aware(datetime(2020, 9, 1, 0, i, 20)),
note=self.note2.nickname,
category="Softs",
product="Produit",
price_name="default",
quantity=1,
liquid_quantity=10,
percentage=Decimal("0.00"),
price=Decimal("1.00"),
note_id=self.note2.foreign_id,
)
HistoryLine.objects.create(
foreign_id=i * 3 + 3,
date=timezone.make_aware(datetime(2020, 9, 1, 0, i, 40)),
note=self.note_autre.nickname,
category="Softs",
product="Produit",
price_name="default",
quantity=1,
liquid_quantity=10,
percentage=Decimal("0.00"),
price=Decimal("1.00"),
note_id=self.note_autre.foreign_id,
)
def test_all(self) -> None:
"""Tests the request getting all history lines of all notes"""
url = "/enibar/api/history-by-user"
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertIsInstance(response, JsonResponse)
self.assertNotContains(response, self.note_autre.nickname)
self.assertIsInstance(json.loads(response.content), list)
self.assertEqual(len(json.loads(response.content)), 120)
assert all(
isinstance(value, dict)
and all(
field.name in value.keys() for field in HistoryLine._meta.get_fields()
)
for value in json.loads(response.content)
)
self.assertContains(response, self.note1.nickname)
self.assertContains(response, self.note2.nickname)
class TestHistoryView(TestCase):
user_model = get_user_model()
......@@ -282,6 +377,8 @@ class TestHistoryView(TestCase):
class TestGetPhotoPaths(TestCase):
def test_last_update_in_dst_change(self):
"""Regression test for #43"""
resp = self.client.get("/enibar/photos?last_updated=2020-10-25T02%3A00%3A01")
resp = self.client.get(
"/enibar/api/photos?last_updated=2020-10-25T02%3A00%3A01"
)
self.assertEqual(resp.status_code, 200)
from django.urls import path
from django.urls import path, include
from . import views
app_name = "enibar"
urlpatterns = [
path("note", views.request_note, name="request_note"),
path("photos", views.get_photo_paths, name="photo_paths"),
path("history", views.request_history, name="request_history"),
path("show_history/", views.show_history, {"page": 1}, name="show_history"),
path("show_history/<int:page>", views.show_history, name="show_history"),
path(
......@@ -14,4 +11,19 @@ urlpatterns = [
views.show_history,
name="show_history",
),
path(
"api/",
include(
[
path("note", views.request_note, name="request_note"),
path("photos", views.get_photo_paths, name="photo_paths"),
path("history", views.request_history, name="request_history"),
path(
"history-by-user",
views.get_history_by_user,
name="get_history_by_user",
),
]
),
),
]
......@@ -21,6 +21,7 @@ from django.http import JsonResponse
from django.shortcuts import render
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from .models import HistoryLine
from .models import Note
......@@ -98,7 +99,9 @@ request_history = _create_view(HistoryLine)
@login_required
def show_history(request: HttpRequest, page, nickname: Optional[str] = None) -> HttpResponse:
def show_history(
request: HttpRequest, page, nickname: Optional[str] = None
) -> HttpResponse:
page = page or 1
notes = Note.objects.filter(mail=request.user.email) # type: ignore[union-attr] # login is required
personal_notes = set(notes)
......@@ -132,7 +135,9 @@ def get_photo_paths(request: HttpRequest) -> JsonResponse:
last_updated_in = request.GET.get("last_updated")
if last_updated_in is not None:
last_updated = datetime.datetime.strptime(last_updated_in, "%Y-%m-%dT%H:%M:%S")
last_updated = timezone.make_aware(last_updated, timezone=None, is_dst=True) # Make TZ aware avoiding DST by fetching more
last_updated = timezone.make_aware(
last_updated, timezone=None, is_dst=True
) # Make TZ aware avoiding DST by fetching more
users = User.objects.filter(
profile__last_updated__gt=last_updated
).select_related("profile")
......@@ -145,3 +150,23 @@ def get_photo_paths(request: HttpRequest) -> JsonResponse:
}
return JsonResponse(photos, safe=False)
@login_required
@require_http_methods(["GET"])
def get_history_by_user(request: HttpRequest) -> JsonResponse:
"""API GET method for getting all user's history lines"""
try:
notes = Note.objects.filter(mail=request.user.email) # type: ignore[union-attr] # login is required
if not notes:
raise Http404
result: List[dict] = []
for note in notes:
result.extend(
HistoryLine.objects.filter(note_id=note.foreign_id)
.annotate(nick=Value(note.nickname, output_field=CharField()))
.values()
)
return JsonResponse(result, safe=False)
except Exception:
raise Http404 from None
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