Skip to content

Commit

Permalink
API: base implementation of /cards, /card/<uuid>
Browse files Browse the repository at this point in the history
Implements CatimaLoyalty#1
Implements CatimaLoyalty#2
  • Loading branch information
tobast committed Sep 6, 2022
1 parent 0dfb119 commit 6950cc2
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,4 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

_token
7 changes: 7 additions & 0 deletions api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.urls import path
from . import views

urlpatterns = [
path("cards/", views.CardsGet.as_view()),
path("card/<uuid:uuid>/", views.CardGet.as_view()),
]
52 changes: 52 additions & 0 deletions api/view_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
""" Utility classes for API views """

from .models import AuthToken
import typing as t
from django import http
from django.views.generic.base import View

if t.TYPE_CHECKING:
_base_view_mixin = View
else:
_base_view_mixin = object


class TokenAuthMixin(_base_view_mixin):
"""Checks that the user provides a correct token-based auth through headers"""

auth_token: AuthToken

def dispatch(self, request, *args, **kwargs) -> http.response.HttpResponseBase:
token_name = request.headers.get("x-token-username", None)
token_secret = request.headers.get("x-token-secret", None)
if not token_name or not token_secret:
return http.JsonResponse(
{
"reason": "No X-Token-Username or X-Token-Secret provided",
},
status=403,
)

token = AuthToken.check_auth(token_name, token_secret)
if token is None:
return http.JsonResponse(
{"reason": "Token authentication failed"},
status=403,
)

self.auth_token = token
return super().dispatch(request, *args, **kwargs)


class APIView(View):
"""A View part of the API."""

# Override to empty list by default -- prevent mistakes
http_method_names: list[str] = []

def http_method_not_allowed(self, request, *args, **kwargs) -> http.HttpResponse:
"""Called when a bad method is used"""
return http.JsonResponse(
{"reason": f"{request.method} method not allowed for this endpoint."},
status=405,
)
53 changes: 51 additions & 2 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
from django.shortcuts import render
from backend import models as backend_models
from .view_utils import TokenAuthMixin, APIView
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.list import MultipleObjectMixin
from django.db.models.query import QuerySet
from django.http import JsonResponse

# Create your views here.

class LoyaltyCardAuthenticatedMixin(TokenAuthMixin):
"""Restricts the queryset to the LoyaltyCards owned by the authenticated user"""

def get_queryset(self) -> QuerySet:
return backend_models.LoyaltyCard.objects.filter(owner=self.auth_token.user)


class CardsGet(LoyaltyCardAuthenticatedMixin, MultipleObjectMixin, APIView):
"""Get the list of cards of this user, mapped to their revision ID"""

http_method_names = ["get"]

def get(self, request, *args, **kwargs) -> JsonResponse:
cards = self.get_queryset()
data = {str(card.uuid): card.revision_id for card in cards}
return JsonResponse(data)


class CardGet(LoyaltyCardAuthenticatedMixin, SingleObjectMixin, APIView):
"""Get the details of a single card"""

pk_url_kwarg = "uuid"

http_method_names = ["get"]

def get(self, request, *args, **kwargs):
card = self.get_object()
data = {
"uuid": str(card.uuid),
"store": card.store,
"note": card.note,
"expiracy": card.expiracy,
"balance": card.balance,
"balance_currency": card.balance_currency,
"card_id": card.card_id,
"barcode_id": card.barcode_id_raw,
"header_color": card.header_color.as_hex(),
"star_status": card.star_status,
"archive_status": card.archive_status,
"last_used": card.last_used,
"zoom_level": card.zoom_level,
"revision_id": card.revision_id,
}
return JsonResponse(data)
3 changes: 2 additions & 1 deletion catima_sync/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import include, path

urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("api.urls")),
]

0 comments on commit 6950cc2

Please sign in to comment.