From f860a5bf1d9024733a95e7de46f58b8e98e52f14 Mon Sep 17 00:00:00 2001 From: Kaladaran Date: Sun, 29 Oct 2023 12:12:25 +0100 Subject: [PATCH] add redis cache, Acquisition & django-esi --- .env.template | 1 + api/migrations/0001_initial.py | 31 +++++++++++++++++++++++++++++++ api/models.py | 15 ++++++++++++++- api/serializers.py | 17 ++++++++++++----- api/urls.py | 1 + api/views.py | 28 ++++++++++++++++++---------- mabras/esi.py | 33 --------------------------------- mabras/settings.py | 14 ++++++++++++++ mabras/urls.py | 7 +++---- requirements.txt | 2 +- 10 files changed, 95 insertions(+), 54 deletions(-) create mode 100644 api/migrations/0001_initial.py delete mode 100644 mabras/esi.py diff --git a/.env.template b/.env.template index fb45ed3..428212c 100644 --- a/.env.template +++ b/.env.template @@ -5,6 +5,7 @@ ESI_USER_AGENT= REDIS_URL= REDIS_PORT= +REDIS_DB= REDIS_PASSWORD= SQLITE_DB_PATH= diff --git a/api/migrations/0001_initial.py b/api/migrations/0001_initial.py new file mode 100644 index 0000000..976b1fb --- /dev/null +++ b/api/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.6 on 2023-10-29 11:10 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('sde', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Acquisition', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.IntegerField()), + ('remaining', models.IntegerField()), + ('price', models.FloatField()), + ('date', models.DateTimeField(auto_now_add=True)), + ('source', models.CharField(max_length=255)), + ('type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='acquisitions', to='sde.sdetype')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='acquisitions', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/api/models.py b/api/models.py index d60611a..3041322 100644 --- a/api/models.py +++ b/api/models.py @@ -1,2 +1,15 @@ +from django.db import models +from sde.models import SDEType -# models \ No newline at end of file + +class Acquisition(models.Model): + type = models.ForeignKey(SDEType, related_name="acquisitions", on_delete=models.CASCADE) + + quantity = models.IntegerField() + remaining = models.IntegerField() + + price = models.FloatField() + date = models.DateTimeField(auto_now_add=True) + source = models.CharField(max_length=255) + + user = models.ForeignKey("auth.User", related_name="acquisitions", on_delete=models.CASCADE) diff --git a/api/serializers.py b/api/serializers.py index b6bf275..beebeae 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -1,15 +1,22 @@ -from django.contrib.auth.models import User, Group +from django.contrib.auth import models as auth_models from rest_framework import serializers from sde.models import SDEType +from api import models class UserSerializer(serializers.ModelSerializer): class Meta: - model = User - fields = ['url', 'username', 'email', 'groups'] + model = auth_models.User + fields = ['id', 'username', 'email', 'groups'] class GroupSerializer(serializers.ModelSerializer): class Meta: - model = Group - fields = ['url', 'name'] + model = auth_models.Group + fields = ['id', 'name'] + + +class AcquisitionSerializer(serializers.ModelSerializer): + class Meta: + model = models.Acquisition + fields = '__all__' diff --git a/api/urls.py b/api/urls.py index cfcc4ef..0ad437f 100644 --- a/api/urls.py +++ b/api/urls.py @@ -5,6 +5,7 @@ from rest_framework import routers router = routers.DefaultRouter() router.register(r'users', views.UserViewSet) router.register(r'groups', views.GroupViewSet) +router.register(r'acquisitions', views.AcquisitionViewSet) urlpatterns = [ path('', include(router.urls)), diff --git a/api/views.py b/api/views.py index 74c0361..b59b7bb 100644 --- a/api/views.py +++ b/api/views.py @@ -1,21 +1,20 @@ from django.shortcuts import render -from django.contrib.auth.models import User, Group +from django.http import JsonResponse +from django.db.models import Q +from django.contrib.auth import models as auth_models from rest_framework import viewsets, permissions, settings from rest_framework.decorators import api_view from rest_framework.response import Response -from api import serializers -from sde import serializers as sde_serializers -from django.http import JsonResponse -from django.db.models import Q -from sde.models import SDEType +from api import serializers, models +from sde import serializers as sde_serializers, models as sde_models class UserViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited. """ - queryset = User.objects.all().order_by('-date_joined') + queryset = auth_models.User.objects.all().order_by('-date_joined') serializer_class = serializers.UserSerializer permission_classes = [permissions.IsAuthenticated] @@ -24,11 +23,20 @@ class GroupViewSet(viewsets.ModelViewSet): """ API endpoint that allows groups to be viewed or edited. """ - queryset = Group.objects.all() + queryset = auth_models.Group.objects.all() serializer_class = serializers.GroupSerializer permission_classes = [permissions.IsAuthenticated] +class AcquisitionViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows acquisitions to be viewed or edited. + """ + queryset = models.Acquisition.objects.all().order_by('-date') + serializer_class = serializers.AcquisitionSerializer + permission_classes = [permissions.IsAuthenticated] + + @api_view(['POST']) def custom_types_search(request): items = [] @@ -51,7 +59,7 @@ def custom_types_search(request): if "not" in mods: condition = ~condition - items.extend(SDEType.objects.filter(condition)) + items.extend(sde_models.SDEType.objects.filter(condition)) paginator = settings.api_settings.DEFAULT_PAGINATION_CLASS() result_page = paginator.paginate_queryset(items, request) @@ -69,7 +77,7 @@ def reprocess_eval(request): item_reprocess = [] for rawitem in ep_items["items"]: - item = SDEType.objects.get(id=rawitem["typeID"]) + item = sde_models.SDEType.objects.get(id=rawitem["typeID"]) buy_reprocess = sell_reprocess = 0.0 for mat in item.typematerials.all(): try: diff --git a/mabras/esi.py b/mabras/esi.py deleted file mode 100644 index d186d94..0000000 --- a/mabras/esi.py +++ /dev/null @@ -1,33 +0,0 @@ -import datetime -import os -import redis -import pickle -from esy.client import ESIClient -from esy.auth import ESIAuthenticator - - -class ESICache(object): - def __init__(self, **kwargs): - self._r = redis.Redis(**kwargs) - # self._r = redis.StrictRedis(host=redis_url, port=redis_port, db=db) - - def get(self, key): - # return pickle.loads(self._r[key]) - return pickle.loads(self._r.get(key)) - - def set(self, key, data, cached_until: datetime.datetime): - self._r.set(key, pickle.dumps(data), ex=cached_until - datetime.datetime.now(datetime.timezone.utc)) - - def __contains__(self, item): - # return item in self._r - return self._r.exists(item) - - -esi_client_id = os.getenv('ESI_CLIENT_ID') -esi_secret_key = os.getenv('ESI_SECRET_KEY') - -esi_cache = ESICache(host=os.getenv("REDIS_URL"), port=int(os.getenv("REDIS_PORT")), db="0", - password=os.getenv("REDIS_PASSWD")) - -esi_client = ESIClient.get_client(user_agent=os.getenv('ESI_USER_AGENT'), cache=esi_cache) -esi_auth = ESIAuthenticator() diff --git a/mabras/settings.py b/mabras/settings.py index f785ee9..a002c71 100644 --- a/mabras/settings.py +++ b/mabras/settings.py @@ -46,6 +46,7 @@ REST_FRAMEWORK = { INSTALLED_APPS = [ 'api', 'sde', + 'esi', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -87,6 +88,13 @@ TEMPLATES = [ WSGI_APPLICATION = 'mabras.wsgi.application' +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.redis.RedisCache", + "LOCATION": f"redis://{os.getenv('REDIS_URL')}:{os.getenv('REDIS_PORT')}/{os.getenv('REDIS_DB')}", + } +} + # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases @@ -142,3 +150,9 @@ STATIC_URL = 'static/' # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +ESI_SSO_CLIENT_ID = os.getenv("ESI_CLIENT_ID") +ESI_SSO_CLIENT_SECRET = os.getenv("ESI_SECRET_KEY") +ESI_SSO_CALLBACK_URL = os.getenv("ESI_CALLBACK_URL") +ESI_USER_AGENT = os.getenv("ESI_USER_AGENT") +ESI_USER_CONTACT_EMAIL = os.getenv("ESI_USER_AGENT") diff --git a/mabras/urls.py b/mabras/urls.py index 4fe342a..7e158b1 100644 --- a/mabras/urls.py +++ b/mabras/urls.py @@ -17,14 +17,13 @@ Including another URLconf from django.urls import include, path from rest_framework.schemas import get_schema_view from django.views.generic import TemplateView -from sde.urls import urlpatterns as sde_urls -from api.urls import urlpatterns as api_urls urlpatterns = [ - path('api/', include(api_urls)), - path('sde/', include(sde_urls)), + path('api/', include("api.urls")), + path('sde/', include("sde.urls")), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), + path('sso/', include('esi.urls', namespace='esi')), path('openapi/', get_schema_view( title="Mabras", description="API for EvEal", diff --git a/requirements.txt b/requirements.txt index 97a7883..b304495 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,6 @@ markdown uvicorn[standard] psycopg[binary] redis -esy pyyaml uritemplate +django-esi