forked from CatimaLoyalty/Sync
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
API: base implementation of /cards, /card/<uuid>
Implements CatimaLoyalty#1 Implements CatimaLoyalty#2
- Loading branch information
Showing
5 changed files
with
113 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters