rework-drf #4
@@ -5,6 +5,7 @@ ESI_USER_AGENT=
|
||||
|
||||
REDIS_URL=
|
||||
REDIS_PORT=
|
||||
REDIS_DB=
|
||||
REDIS_PASSWORD=
|
||||
|
||||
SQLITE_DB_PATH=
|
||||
@@ -12,3 +13,7 @@ POSTGRES_HOST=
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_USER=
|
||||
POSTGRES_DB=
|
||||
|
||||
DRF_SECRET_KEY=
|
||||
DRF_DEBUG=
|
||||
ALLOWED_HOSTS=
|
||||
|
||||
@@ -6,9 +6,12 @@ ENV PYTHONDONTWRITEBYTECODE=1
|
||||
RUN adduser -u 5678 --disabled-password --gecos "" appuser
|
||||
|
||||
WORKDIR /app
|
||||
COPY --chown=appuser:appuser manage.py /app/manage.py
|
||||
COPY requirements.txt .
|
||||
RUN python -m pip install --no-cache-dir --upgrade -r requirements.txt
|
||||
COPY --chown=appuser:appuser eveal /app/eveal
|
||||
COPY --chown=appuser:appuser marbas /app/marbas
|
||||
COPY --chown=appuser:appuser sde /app/sde
|
||||
COPY --chown=appuser:appuser api /app/api
|
||||
|
||||
USER appuser
|
||||
CMD ["uvicorn", "eveal.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
CMD ["uvicorn", "marbas.asgi:application", "--host", "0.0.0.0", "--port", "8000"]
|
||||
3
api/admin.py
Normal file
3
api/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
api/apps.py
Normal file
6
api/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApiConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'api'
|
||||
31
api/migrations/0001_initial.py
Normal file
31
api/migrations/0001_initial.py
Normal file
@@ -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)),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
api/migrations/__init__.py
Normal file
0
api/migrations/__init__.py
Normal file
15
api/models.py
Normal file
15
api/models.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django.db import models
|
||||
from sde.models import SDEType
|
||||
|
||||
|
||||
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)
|
||||
22
api/serializers.py
Normal file
22
api/serializers.py
Normal file
@@ -0,0 +1,22 @@
|
||||
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 = auth_models.User
|
||||
fields = ['id', 'username', 'email', 'groups']
|
||||
|
||||
|
||||
class GroupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = auth_models.Group
|
||||
fields = ['id', 'name']
|
||||
|
||||
|
||||
class AcquisitionSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = models.Acquisition
|
||||
fields = '__all__'
|
||||
3
api/tests.py
Normal file
3
api/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
14
api/urls.py
Normal file
14
api/urls.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from . import views
|
||||
from django.urls import include, path
|
||||
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)),
|
||||
path('types/search', views.custom_types_search, name='custom_types_search'),
|
||||
path('reprocess/eval', views.reprocess_eval, name='custom_types_search'),
|
||||
]
|
||||
96
api/views.py
Normal file
96
api/views.py
Normal file
@@ -0,0 +1,96 @@
|
||||
from django.shortcuts import render
|
||||
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, 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 = auth_models.User.objects.all().order_by('-date_joined')
|
||||
serializer_class = serializers.UserSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class GroupViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
API endpoint that allows groups to be viewed or edited.
|
||||
"""
|
||||
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 = []
|
||||
|
||||
for q in request.data:
|
||||
conditions = Q()
|
||||
for k in q.keys():
|
||||
value = q[k]
|
||||
|
||||
token = k.split('___')
|
||||
key, mods = token[0], token[1:]
|
||||
|
||||
cond = Q(**{key: value})
|
||||
|
||||
if "not" in mods:
|
||||
cond = ~cond
|
||||
|
||||
conditions = conditions & cond
|
||||
|
||||
items.extend(sde_models.SDEType.objects.filter(conditions))
|
||||
|
||||
paginator = settings.api_settings.DEFAULT_PAGINATION_CLASS()
|
||||
result_page = paginator.paginate_queryset(items, request)
|
||||
serializer = sde_serializers.SDETypeSerializer(result_page, many=True)
|
||||
return paginator.get_paginated_response(serializer.data)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
def reprocess_eval(request):
|
||||
ep_mat = request.data.get("ep_mat")
|
||||
ep_items = request.data.get("ep_items")
|
||||
efficiency = request.data.get("efficiency", 0.55)
|
||||
|
||||
matprices = {item["typeID"]: {'sell': item["prices"]["sell"]["min"], 'buy': item["prices"]["buy"]["max"]} for item in ep_mat['items']}
|
||||
|
||||
item_reprocess = []
|
||||
for rawitem in ep_items["items"]:
|
||||
item = sde_models.SDEType.objects.get(id=rawitem["typeID"])
|
||||
buy_reprocess = sell_reprocess = 0.0
|
||||
for mat in item.typematerials.all():
|
||||
try:
|
||||
buy_reprocess += matprices[mat.material_type_id]['buy'] * mat.quantity/item.portionSize * efficiency
|
||||
sell_reprocess += matprices[mat.material_type_id]['sell'] * mat.quantity/item.portionSize * efficiency
|
||||
except KeyError as e:
|
||||
JsonResponse({"error": f"No price for material {e}"})
|
||||
item_reprocess.append({
|
||||
"typeID": item.id,
|
||||
"name": item.name,
|
||||
"buy": rawitem["prices"]['buy']["max"],
|
||||
"sell": rawitem["prices"]['sell']["min"],
|
||||
"buy_reprocess": buy_reprocess,
|
||||
"sell_reprocess": sell_reprocess,
|
||||
})
|
||||
|
||||
paginator = settings.api_settings.DEFAULT_PAGINATION_CLASS()
|
||||
result_page = paginator.paginate_queryset(item_reprocess, request)
|
||||
return paginator.get_paginated_response(result_page)
|
||||
@@ -1,22 +1,44 @@
|
||||
version: '3'
|
||||
services:
|
||||
eveal:
|
||||
image: mabras:local
|
||||
migrations:
|
||||
image: marbas:local
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- .env
|
||||
user: "1000:1000"
|
||||
volumes:
|
||||
- ./marbas:/app/marbas
|
||||
- ./api:/app/api
|
||||
- ./sde:/app/sde
|
||||
- ./manage.py:/app/manage.py
|
||||
command: sh -c "python manage.py makemigrations && python manage.py migrate"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
eveal:
|
||||
image: marbas:local
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 8000:8000
|
||||
user: "1000:1000"
|
||||
volumes:
|
||||
- ./eveal:/app/eveal
|
||||
command: ["uvicorn", "eveal.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||
- ./marbas:/app/marbas
|
||||
- ./api:/app/api
|
||||
- ./sde:/app/sde
|
||||
- ./manage.py:/app/manage.py
|
||||
# - ./static_eve:/app/static_eve
|
||||
command: ["uvicorn", "marbas.asgi:application", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
db:
|
||||
condition: service_healthy
|
||||
migrations:
|
||||
condition: service_completed_successfully
|
||||
# elasticsearch:
|
||||
# condition: service_healthy
|
||||
|
||||
@@ -33,14 +55,14 @@ services:
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- mabras_dbdata:/var/lib/postgresql/data
|
||||
- marbas_dbdata:/var/lib/postgresql/data
|
||||
env_file:
|
||||
- .env
|
||||
healthcheck:
|
||||
test: pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}
|
||||
interval: 10s
|
||||
interval: 1s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
retries: 10
|
||||
|
||||
# elasticsearch:
|
||||
# image: elasticsearch:latest
|
||||
@@ -58,4 +80,4 @@ services:
|
||||
# retries: 3
|
||||
|
||||
volumes:
|
||||
mabras_dbdata:
|
||||
marbas_dbdata:
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import os
|
||||
from sqlmodel import create_engine, Session
|
||||
|
||||
|
||||
if os.getenv("POSTGRES_HOST"):
|
||||
engine = create_engine(f"postgresql://{os.getenv('POSTGRES_USER')}:{os.getenv('POSTGRES_PASSWORD')}@{os.getenv('POSTGRES_HOST')}/{os.getenv('POSTGRES_DB')}",
|
||||
echo=False, future=True)
|
||||
else:
|
||||
sqlite_file_name = os.getenv("SQLITE_DB_PATH", "eveal.db")
|
||||
engine = create_engine(f"sqlite:///{sqlite_file_name}", echo=True, future=True, connect_args={"check_same_thread": False})
|
||||
|
||||
def get_session():
|
||||
db = Session(engine)
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
33
eveal/esi.py
33
eveal/esi.py
@@ -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()
|
||||
@@ -1,97 +0,0 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from fastapi import FastAPI, Depends, Path, Query
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from typing import List, Annotated, Tuple, Literal, Dict, TypedDict
|
||||
from sqlmodel import SQLModel, Session, select
|
||||
|
||||
from eveal.schemas import Evepraisal, PriceReprocess
|
||||
from eveal.database import engine, get_session
|
||||
from eveal import models_sde, esi
|
||||
|
||||
SQLModel.metadata.create_all(engine) # use alembic?
|
||||
|
||||
app = FastAPI()
|
||||
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return {"message": "Hello World"}
|
||||
|
||||
|
||||
@app.post("/reprocess/")
|
||||
async def reprocess(ep_items: Evepraisal, ep_mat: Evepraisal, efficiency: float = .55, db: Session = Depends(get_session)) -> List[PriceReprocess]:
|
||||
matprices = {item.typeID: {'sell': item.prices.sell.min, 'buy': item.prices.buy.max} for item in ep_mat.items}
|
||||
|
||||
item_reprocess: List[PriceReprocess] = []
|
||||
for rawitem in ep_items.items:
|
||||
item = db.get(models_sde.SDEType, rawitem.typeID)
|
||||
buy_reprocess = sell_reprocess = 0.0
|
||||
for mat in item.materials.all():
|
||||
buy_reprocess += matprices[mat.material_type_id]['buy'] * mat.quantity/mat.type.portionSize * efficiency
|
||||
sell_reprocess += matprices[mat.material_type_id]['sell'] * mat.quantity/mat.type.portionSize * efficiency
|
||||
item_reprocess.append(PriceReprocess(typeID=rawitem.typeID,
|
||||
buy=rawitem.prices.buy.max,
|
||||
sell=rawitem.prices.sell.min,
|
||||
buy_reprocess=buy_reprocess,
|
||||
sell_reprocess=sell_reprocess,
|
||||
name=rawitem.name
|
||||
))
|
||||
return item_reprocess
|
||||
|
||||
|
||||
@app.get("/sde/types/{sde_type}/")
|
||||
async def sde_types(sde_type: int | str, db: Session = Depends(get_session)) -> models_sde.SDEType:
|
||||
try:
|
||||
item = db.get(models_sde.SDEType, int(sde_type))
|
||||
except ValueError:
|
||||
item = db.query(models_sde.SDEType).filter(models_sde.SDEType.name == sde_type).one()
|
||||
return item
|
||||
|
||||
|
||||
@app.post("/sde/types/search")
|
||||
async def sde_types_search(query: List[Dict[str, int | str | None | List]], db: Session = Depends(get_session)) -> List[models_sde.SDEType]:
|
||||
items = []
|
||||
for q in query:
|
||||
qitems = db.query(models_sde.SDEType)
|
||||
for k in q.keys():
|
||||
value = q[k]
|
||||
|
||||
tokens = k.split("__")
|
||||
key, mods = tokens[0], tokens[1:]
|
||||
|
||||
if "i" in mods:
|
||||
condition = getattr(models_sde.SDEType, key).ilike(f"%{value}%") # change to icontains when sqlmodel start using sqlalchemy > 2.0
|
||||
elif "in" in mods:
|
||||
condition = getattr(models_sde.SDEType, key).in_(value)
|
||||
else:
|
||||
condition = getattr(models_sde.SDEType, key) == value
|
||||
|
||||
if "not" in mods:
|
||||
condition = ~condition
|
||||
|
||||
qitems = qitems.filter(condition)
|
||||
items.extend(qitems.all())
|
||||
return items
|
||||
|
||||
|
||||
@app.get("/esi/types/{sde_type}/market/{region_id}/")
|
||||
async def sde_types_market(sde_type: int | str, region_id: int | str, db: Session = Depends(get_session)):
|
||||
"""Get market orders for a type in a region. example: /esi/types/22291/market/10000002/"""
|
||||
"""TODO: use ESIMarketOrder"""
|
||||
return list(esi.esi_client.Market.get_markets_region_id_orders(order_type="all", type_id=sde_type, region_id=region_id))
|
||||
|
||||
|
||||
@app.get("/_tools/get_all_mat")
|
||||
async def _get_all_mat(db: Session = Depends(get_session)):
|
||||
materials = db.query(models_sde.SDETypeMaterial).filter(models_sde.SDETypeMaterial.type.has(models_sde.SDEType.published == True)).all()
|
||||
allmat = set()
|
||||
for mat in materials:
|
||||
allmat.add(mat.material_type.name)
|
||||
return allmat
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run("eveal.main:app", host="0.0.0.0", port=8000, reload=True)
|
||||
@@ -1,24 +0,0 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from sqlmodel import SQLModel, Field, Relationship
|
||||
|
||||
|
||||
class ESIMarketOrder(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
||||
|
||||
region_id: int
|
||||
type_id: int # TODO: link to SDE
|
||||
location_id: int # TODO: link to SDE
|
||||
volume_total: int
|
||||
volume_remain: int
|
||||
min_volume: int
|
||||
order_id: int # TODO: use this as PK ? (will lose volume_remain history)
|
||||
price: float
|
||||
is_buy_order: bool
|
||||
duration: int
|
||||
issued: datetime
|
||||
range: str # TODO: enum?
|
||||
system_id: int # TODO: link to SDE
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
from typing import Optional, List
|
||||
from sqlmodel import SQLModel, Field, Relationship
|
||||
from functools import partial
|
||||
|
||||
DynamicRelationship = partial(Relationship, sa_relationship_kwargs={"lazy": "dynamic"}) # change default lazy loading to dynamic
|
||||
|
||||
|
||||
class SDEIcon(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
|
||||
description: Optional[str] = None
|
||||
iconFile: str
|
||||
|
||||
categories: List['SDECategory'] = DynamicRelationship(back_populates="icon")
|
||||
groups: List['SDEGroup'] = DynamicRelationship(back_populates="icon")
|
||||
marketgroups: List['SDEMarketGroup'] = DynamicRelationship(back_populates="icon")
|
||||
types: List['SDEType'] = DynamicRelationship(back_populates="icon")
|
||||
metagroups: List['SDEMetaGroup'] = DynamicRelationship(back_populates="icon")
|
||||
|
||||
|
||||
class SDECategory(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
|
||||
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
|
||||
icon: Optional[SDEIcon] = Relationship(back_populates="categories")
|
||||
|
||||
name: str
|
||||
published: bool
|
||||
|
||||
groups: List['SDEGroup'] = DynamicRelationship(back_populates="category")
|
||||
|
||||
|
||||
class SDEGroup(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
|
||||
anchorable: bool
|
||||
anchored: bool
|
||||
|
||||
category_id: Optional[int] = Field(default=None, foreign_key="sdecategory.id")
|
||||
category: Optional[SDECategory] = Relationship(back_populates="groups")
|
||||
|
||||
fittableNonSingletion: bool
|
||||
|
||||
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
|
||||
icon: Optional[SDEIcon] = Relationship(back_populates="groups")
|
||||
|
||||
name: str
|
||||
published: bool
|
||||
useBasePrice: bool
|
||||
|
||||
types: List['SDEType'] = DynamicRelationship(back_populates="group")
|
||||
|
||||
|
||||
class SDEMarketGroup(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
|
||||
description: Optional[str] = None
|
||||
hasTypes: bool
|
||||
|
||||
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
|
||||
icon: Optional[SDEIcon] = Relationship(back_populates="marketgroups")
|
||||
|
||||
name: str
|
||||
|
||||
parent_marketgroup_id: Optional[int] = Field(default=None, foreign_key="sdemarketgroup.id")
|
||||
parent_marketgroup: Optional['SDEMarketGroup'] = Relationship(back_populates="children_marketgroups",
|
||||
sa_relationship_kwargs={"remote_side": 'SDEMarketGroup.id'}) # workaround for self reference: https://github.com/tiangolo/sqlmodel/issues/127#issuecomment-1224135123
|
||||
children_marketgroups: List['SDEMarketGroup'] = DynamicRelationship(back_populates="parent_marketgroup")
|
||||
|
||||
types: List['SDEType'] = DynamicRelationship(back_populates="marketgroup")
|
||||
|
||||
|
||||
class SDEMetaGroup(SQLModel, table=True):
|
||||
id: int = Field(primary_key=True)
|
||||
|
||||
name: str
|
||||
iconSuffix: Optional[str] = None
|
||||
|
||||
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
|
||||
icon: Optional[SDEIcon] = Relationship(back_populates="metagroups")
|
||||
|
||||
types: List['SDEType'] = DynamicRelationship(back_populates="metagroup")
|
||||
|
||||
|
||||
class SDEType(SQLModel, table=True):
|
||||
id: int = Field(primary_key=True)
|
||||
|
||||
group_id: Optional[int] = Field(default=None, foreign_key="sdegroup.id")
|
||||
group: Optional[SDEGroup] = Relationship(back_populates="types")
|
||||
|
||||
marketgroup_id: Optional[int] = Field(default=None, foreign_key="sdemarketgroup.id")
|
||||
marketgroup: Optional[SDEMarketGroup] = Relationship(back_populates="types")
|
||||
|
||||
metagroup_id: Optional[int] = Field(default=None, foreign_key="sdemetagroup.id")
|
||||
metagroup: Optional[SDEMetaGroup] = Relationship(back_populates="types")
|
||||
|
||||
name: str
|
||||
published: bool = False
|
||||
description: Optional[str] = None
|
||||
basePrice: Optional[float] = None
|
||||
|
||||
icon_id: Optional[int] = Field(default=None, foreign_key="sdeicon.id")
|
||||
icon: Optional[SDEIcon] = Relationship(back_populates="types")
|
||||
|
||||
volume: Optional[float] = None
|
||||
portionSize: int
|
||||
|
||||
materials: List['SDETypeMaterial'] = DynamicRelationship(back_populates="type",
|
||||
sa_relationship_kwargs={"lazy": "dynamic", "foreign_keys": '[SDETypeMaterial.type_id]'}) # https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1537445078
|
||||
material_of: List['SDETypeMaterial'] = DynamicRelationship(back_populates="material_type",
|
||||
sa_relationship_kwargs={"lazy": "dynamic", "foreign_keys": '[SDETypeMaterial.material_type_id]'}) # https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1537445078
|
||||
|
||||
|
||||
class SDETypeMaterial(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
|
||||
type_id: Optional[int] = Field(default=None, foreign_key="sdetype.id")
|
||||
type: Optional[SDEType] = Relationship(back_populates="materials",
|
||||
sa_relationship_kwargs={"primaryjoin": 'SDETypeMaterial.type_id==SDEType.id',
|
||||
'lazy': 'joined'}) # workaround: https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1002835506
|
||||
|
||||
material_type_id: Optional[int] = Field(default=None, foreign_key="sdetype.id")
|
||||
material_type: Optional[SDEType] = Relationship(back_populates="material_of",
|
||||
sa_relationship_kwargs={"primaryjoin": 'SDETypeMaterial.material_type_id==SDEType.id',
|
||||
'lazy': 'joined'}) # workaround: https://github.com/tiangolo/sqlmodel/issues/10#issuecomment-1002835506
|
||||
|
||||
quantity: int
|
||||
@@ -1,52 +0,0 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Price(BaseModel):
|
||||
avg: float
|
||||
max: float
|
||||
median: float
|
||||
min: float
|
||||
percentile: float
|
||||
stddev: float
|
||||
volume: int
|
||||
order_count: int
|
||||
|
||||
class Prices(BaseModel):
|
||||
all: Price
|
||||
buy: Price
|
||||
sell: Price
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
typeID: int
|
||||
typeName: str
|
||||
typeVolume: float
|
||||
quantity: int
|
||||
prices: Prices
|
||||
|
||||
class Total_price(BaseModel):
|
||||
buy: float
|
||||
sell: float
|
||||
volume: float
|
||||
|
||||
class Evepraisal(BaseModel):
|
||||
id: str
|
||||
created: int
|
||||
kind: str
|
||||
market_name: str
|
||||
items: list[Item]
|
||||
totals: Total_price
|
||||
price_percentage: float
|
||||
raw: str
|
||||
|
||||
|
||||
class PriceReprocess(BaseModel):
|
||||
typeID: int
|
||||
buy: float
|
||||
sell: float
|
||||
buy_reprocess: float
|
||||
sell_reprocess: float
|
||||
name: str
|
||||
|
||||
|
||||
173
import_sde.py
173
import_sde.py
@@ -1,173 +0,0 @@
|
||||
import yaml
|
||||
from eveal.database import engine
|
||||
from sqlmodel import Session, SQLModel, select
|
||||
from eveal import models_sde
|
||||
|
||||
SQLModel.metadata.drop_all(engine) # use alembic!
|
||||
SQLModel.metadata.create_all(engine)
|
||||
|
||||
|
||||
print("Importing SDE data...")
|
||||
print("Importing icons...")
|
||||
with open("static_eve/sde/fsd/iconIDs.yaml", "r", encoding="utf-8") as f:
|
||||
icons = yaml.safe_load(f)
|
||||
new_icons = total_icons = 0
|
||||
with Session(engine) as db:
|
||||
for id, icon in icons.items():
|
||||
db_icon = db.get(models_sde.SDEIcon, id)
|
||||
if not db_icon:
|
||||
db_icon = models_sde.SDEIcon(id=id)
|
||||
db.add(db_icon)
|
||||
new_icons += 1
|
||||
db_icon.iconFile = icon['iconFile']
|
||||
db_icon.description = icon['description'] if 'description' in icon else None
|
||||
total_icons += 1
|
||||
db.commit()
|
||||
print(f"Imported {new_icons} new icons / {total_icons} total icons.")
|
||||
|
||||
|
||||
print("Importing categories...")
|
||||
with open("static_eve/sde/fsd/categoryIDs.yaml", "r", encoding="utf-8") as f:
|
||||
categories = yaml.safe_load(f)
|
||||
new_categories = total_categories = 0
|
||||
with Session(engine) as db:
|
||||
for id, category in categories.items():
|
||||
# if category["published"] == False:
|
||||
# continue
|
||||
db_category = db.get(models_sde.SDECategory, id)
|
||||
if not db_category:
|
||||
db_category = models_sde.SDECategory(id=id)
|
||||
db.add(db_category)
|
||||
new_categories += 1
|
||||
db_category.name = category['name']['en']
|
||||
db_category.published = category['published']
|
||||
db_category.icon_id = category['iconID'] if 'iconID' in category else None
|
||||
total_categories += 1
|
||||
db.commit()
|
||||
print(f"Imported {new_categories} new categories / {total_categories} total categories.")
|
||||
|
||||
|
||||
print("Importing groups...")
|
||||
with open("static_eve/sde/fsd/groupIDs.yaml", "r", encoding="utf-8") as f:
|
||||
groups = yaml.safe_load(f)
|
||||
new_groups = total_groups = 0
|
||||
with Session(engine) as db:
|
||||
for id, group in groups.items():
|
||||
# if group["published"] == False:
|
||||
# continue
|
||||
db_group = db.get(models_sde.SDEGroup, id)
|
||||
if not db_group:
|
||||
db_group = models_sde.SDEGroup(id=id)
|
||||
db.add(db_group)
|
||||
new_groups += 1
|
||||
db_group.anchorable = group['anchorable']
|
||||
db_group.anchored = group['anchored']
|
||||
db_group.category_id = group['categoryID']
|
||||
db_group.fittableNonSingletion = group['fittableNonSingleton']
|
||||
db_group.icon_id = group['iconID'] if 'iconID' in group else None
|
||||
db_group.name = group['name']['en']
|
||||
db_group.published = group['published']
|
||||
db_group.useBasePrice = group['useBasePrice']
|
||||
total_groups += 1
|
||||
db.commit()
|
||||
print(f"Imported {new_groups} new groups / {total_groups} total groups.")
|
||||
|
||||
|
||||
print("Importing marketgroups...")
|
||||
with open("static_eve/sde/fsd/marketGroups.yaml", "r", encoding="utf-8") as f:
|
||||
marketgroups = yaml.safe_load(f)
|
||||
new_marketgroups = total_marketgroups = 0
|
||||
with Session(engine) as db:
|
||||
for id, marketgroup in marketgroups.items():
|
||||
db_marketgroups = db.get(models_sde.SDEMarketGroup, id)
|
||||
if not db_marketgroups:
|
||||
db_marketgroups = models_sde.SDEMarketGroup(id=id)
|
||||
db.add(db_marketgroups)
|
||||
new_marketgroups += 1
|
||||
db_marketgroups.description = marketgroup['descriptionID']['en'] if 'descriptionID' in marketgroup else None
|
||||
db_marketgroups.hasTypes = marketgroup['hasTypes']
|
||||
db_marketgroups.icon_id = marketgroup['iconID'] if 'iconID' in marketgroup else None
|
||||
db_marketgroups.name = marketgroup['nameID']['en']
|
||||
# db_marketgroups.parent_marketgroup_id = marketgroup['parentGroupID'] if 'parentGroupID' in marketgroup else None
|
||||
total_marketgroups += 1
|
||||
db.commit()
|
||||
print(f"Imported {new_marketgroups} marketgroups / {total_marketgroups} total marketgroups.")
|
||||
print("Setting up marketgroup Parents...")
|
||||
total_marketgroup_links = 0
|
||||
with Session(engine) as db:
|
||||
for id, marketgroup in marketgroups.items():
|
||||
db_marketgroups = db.get(models_sde.SDEMarketGroup, id)
|
||||
db_marketgroups.parent_marketgroup_id = marketgroup['parentGroupID'] if 'parentGroupID' in marketgroup else None
|
||||
total_marketgroup_links += 1
|
||||
db.commit()
|
||||
print(f"Updated {total_marketgroup_links} marketgroup Parents")
|
||||
|
||||
|
||||
print("Importing metagroups...")
|
||||
with open("static_eve/sde/fsd/metaGroups.yaml", "r", encoding="utf-8") as f:
|
||||
metagroups = yaml.safe_load(f)
|
||||
new_metagroups = total_metagroups = 0
|
||||
with Session(engine) as db:
|
||||
for id, metagroup in metagroups.items():
|
||||
db_metagroups = db.get(models_sde.SDEMetaGroup, id)
|
||||
if not db_metagroups:
|
||||
db_metagroups = models_sde.SDEMetaGroup(id=id)
|
||||
db.add(db_metagroups)
|
||||
new_metagroups += 1
|
||||
db_metagroups.name = metagroup['nameID']['en']
|
||||
db_metagroups.iconSuffix = metagroup['iconSuffix'] if 'iconSuffix' in metagroup else None
|
||||
db_metagroups.icon_id = metagroup['iconID'] if 'iconID' in metagroup else None
|
||||
total_metagroups += 1
|
||||
db.commit()
|
||||
print(f"Imported {new_metagroups} metagroups / {total_metagroups} total metagroups.")
|
||||
|
||||
|
||||
print("Importing types...")
|
||||
with open("static_eve/sde/fsd/typeIDs.yaml", "r", encoding="utf-8") as f:
|
||||
types = yaml.safe_load(f)
|
||||
new_types = total_types = 0
|
||||
with Session(engine) as db:
|
||||
for id, type in types.items():
|
||||
# if type["published"] == False:
|
||||
# continue
|
||||
db_type = db.get(models_sde.SDEType, id)
|
||||
if not db_type:
|
||||
db_type = models_sde.SDEType(id=id)
|
||||
db.add(db_type)
|
||||
new_types += 1
|
||||
db_type.group_id = type['groupID']
|
||||
db_type.marketgroup_id = type['marketGroupID'] if 'marketGroupID' in type else None
|
||||
db_type.name = type['name']['en']
|
||||
db_type.published = type['published']
|
||||
db_type.basePrice = type['basePrice'] if 'basePrice' in type else None
|
||||
db_type.description = type['description']['en'] if 'description' in type else None
|
||||
db_type.icon_id = type['iconID'] if 'iconID' in type else None
|
||||
db_type.portionSize = type['portionSize']
|
||||
db_type.volume = type['volume'] if 'volume' in type else None
|
||||
db_type.metagroup_id = type['metaGroupID'] if 'metaGroupID' in type else None
|
||||
total_types += 1
|
||||
db.commit()
|
||||
print(f"Imported {new_types} types / {total_types} total types.")
|
||||
|
||||
|
||||
print("Importing materials...")
|
||||
with open("static_eve/sde/fsd/typeMaterials.yaml", "r", encoding="utf-8") as f:
|
||||
materials = yaml.safe_load(f)
|
||||
new_typemat = total_typemat = 0
|
||||
with Session(engine) as db:
|
||||
for id, material in materials.items():
|
||||
for mat in material['materials']:
|
||||
db_typemat = db.query(models_sde.SDETypeMaterial).filter(models_sde.SDETypeMaterial.type_id == id, models_sde.SDETypeMaterial.material_type_id == mat['materialTypeID']).one_or_none()
|
||||
if not db_typemat:
|
||||
db_typemat = models_sde.SDETypeMaterial()
|
||||
db.add(db_typemat)
|
||||
new_typemat += 1
|
||||
db_typemat.type_id = id
|
||||
db_typemat.material_type_id = mat['materialTypeID']
|
||||
db_typemat.quantity = mat['quantity']
|
||||
total_typemat += 1
|
||||
db.commit()
|
||||
print(f"Imported {new_typemat} materials / {total_typemat} total materials.")
|
||||
|
||||
|
||||
print("DONE!")
|
||||
22
manage.py
Executable file
22
manage.py
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'marbas.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
0
marbas/__init__.py
Normal file
0
marbas/__init__.py
Normal file
16
marbas/asgi.py
Normal file
16
marbas/asgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for marbas project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'marbas.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
8
marbas/pagination.py
Normal file
8
marbas/pagination.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from rest_framework import pagination
|
||||
|
||||
|
||||
class CustomPagination(pagination.PageNumberPagination):
|
||||
page_size = 10
|
||||
page_size_query_param = 'page_size'
|
||||
max_page_size = 250
|
||||
|
||||
157
marbas/settings.py
Normal file
157
marbas/settings.py
Normal file
@@ -0,0 +1,157 @@
|
||||
"""
|
||||
Django settings for marbas project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.2.6.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.2/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = os.getenv("DRF_SECRET_KEY")
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = os.getenv("DRF_DEBUG", False) == "True"
|
||||
|
||||
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
|
||||
ALLOWED_HOSTS = [] if not any(ALLOWED_HOSTS) else ALLOWED_HOSTS
|
||||
|
||||
# Application definition
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PAGINATION_CLASS': 'marbas.pagination.CustomPagination',
|
||||
'DEFAULT_RENDERER_CLASSES': [
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
],
|
||||
'DEFAULT_PARSER_CLASSES': [
|
||||
'rest_framework.parsers.JSONParser',
|
||||
],
|
||||
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
|
||||
}
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'api',
|
||||
'sde',
|
||||
'esi',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django_filters',
|
||||
'rest_framework'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'marbas.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': ["marbas/templates"],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'marbas.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
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
"HOST": os.getenv("POSTGRES_HOST"),
|
||||
"PORT": os.getenv("POSTGRES_PORT", 5432),
|
||||
"USER": os.getenv("POSTGRES_USER"),
|
||||
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
|
||||
"NAME": os.getenv("POSTGRES_DB"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
|
||||
# Default primary key field type
|
||||
# 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")
|
||||
21
marbas/templates/redoc.html
Normal file
21
marbas/templates/redoc.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>ReDoc</title>
|
||||
<!-- needed for adaptive design -->
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
||||
<!-- ReDoc doesn't change outer page styles -->
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<redoc spec-url='{% url schema_url %}'></redoc>
|
||||
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
28
marbas/templates/swagger-ui.html
Normal file
28
marbas/templates/swagger-ui.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Swagger</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="//unpkg.com/swagger-ui-dist@3/swagger-ui.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
|
||||
<script>
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "{% url schema_url %}",
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIBundle.SwaggerUIStandalonePreset
|
||||
],
|
||||
layout: "BaseLayout",
|
||||
requestInterceptor: (request) => {
|
||||
request.headers['X-CSRFToken'] = "{{ csrf_token }}"
|
||||
return request;
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
40
marbas/urls.py
Normal file
40
marbas/urls.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""
|
||||
URL configuration for marbas project.
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.urls import include, path
|
||||
from rest_framework.schemas import get_schema_view
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
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="marbas",
|
||||
description="API for EvEal",
|
||||
version="0.0.9"
|
||||
), name='openapi-schema'),
|
||||
path('swagger-ui/', TemplateView.as_view(
|
||||
template_name='swagger-ui.html',
|
||||
extra_context={'schema_url': 'openapi-schema'}
|
||||
), name='swagger-ui'),
|
||||
path('redoc/', TemplateView.as_view(
|
||||
template_name='redoc.html',
|
||||
extra_context={'schema_url': 'openapi-schema'}
|
||||
), name='redoc'),
|
||||
]
|
||||
16
marbas/wsgi.py
Normal file
16
marbas/wsgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for marbas project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'marbas.settings')
|
||||
|
||||
application = get_wsgi_application()
|
||||
@@ -1,7 +1,10 @@
|
||||
fastapi
|
||||
httpx
|
||||
django
|
||||
djangorestframework
|
||||
django-filter
|
||||
markdown
|
||||
uvicorn[standard]
|
||||
sqlmodel
|
||||
esy
|
||||
psycopg[binary]
|
||||
redis
|
||||
psycopg2-binary
|
||||
pyyaml
|
||||
uritemplate
|
||||
django-esi
|
||||
|
||||
0
sde/__init__.py
Normal file
0
sde/__init__.py
Normal file
6
sde/apps.py
Normal file
6
sde/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SdeConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'sde'
|
||||
0
sde/management/__init__.py
Normal file
0
sde/management/__init__.py
Normal file
0
sde/management/commands/__init__.py
Normal file
0
sde/management/commands/__init__.py
Normal file
141
sde/management/commands/import_sde.py
Normal file
141
sde/management/commands/import_sde.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from sde.models import *
|
||||
import yaml
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Import SDE data from YAML files'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('path', type=str, help='Path to the SDE YAML files')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Import the SDE data
|
||||
self.stdout.write(self.style.SUCCESS('Importing SDE data'))
|
||||
self.import_sde_data(path=options['path'])
|
||||
self.stdout.write(self.style.SUCCESS('Successfully imported SDE data'))
|
||||
|
||||
def import_sde_data(self, path):
|
||||
self.import_icons(path + "/iconIDs.yaml")
|
||||
self.import_categories(path + "/categoryIDs.yaml")
|
||||
self.import_groups(path + "/groupIDs.yaml")
|
||||
self.import_marketgroups(path + "/marketGroups.yaml")
|
||||
self.import_metagroups(path + "/metaGroups.yaml")
|
||||
self.import_types(path + "/typeIDs.yaml")
|
||||
self.import_type_materials(path + "/typeMaterials.yaml")
|
||||
|
||||
def import_icons(self, path):
|
||||
with open(path) as file:
|
||||
icons = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for id, icon in icons.items():
|
||||
SDEIcon.objects.update_or_create(
|
||||
id=id,
|
||||
defaults={
|
||||
'iconFile': icon['iconFile'],
|
||||
'description': icon['description'] if "description" in icon else ""
|
||||
}
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS('Icons imported'))
|
||||
|
||||
def import_categories(self, path):
|
||||
with open(path) as file:
|
||||
categories = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for id, category in categories.items():
|
||||
SDECategory.objects.update_or_create(
|
||||
id=id,
|
||||
defaults={
|
||||
'icon': SDEIcon.objects.get(id=category['iconID']) if "iconID" in category else None,
|
||||
'name': category['name']['en'],
|
||||
'published': category['published']
|
||||
}
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS('Categories imported'))
|
||||
|
||||
def import_groups(self, path):
|
||||
with open(path) as file:
|
||||
groups = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for id, group in groups.items():
|
||||
SDEGroup.objects.update_or_create(
|
||||
id=id,
|
||||
defaults={
|
||||
'category': SDECategory.objects.get(id=group['categoryID']),
|
||||
'name': group['name'],
|
||||
'published': group['published'],
|
||||
'useBasePrice': group['useBasePrice'],
|
||||
'fittableNonSingleton': group['fittableNonSingleton'],
|
||||
'anchored': group['anchored'],
|
||||
'anchorable': group['anchorable'],
|
||||
'icon': SDEIcon.objects.get(id=group['iconID']) if "iconID" in group else None
|
||||
}
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS('Groups imported'))
|
||||
|
||||
def import_marketgroups(self, path):
|
||||
with open(path) as file:
|
||||
marketgroups = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for id, marketgroup in marketgroups.items():
|
||||
SDEMarektGroup.objects.update_or_create(
|
||||
id=id,
|
||||
defaults={
|
||||
'icon': SDEIcon.objects.get(id=marketgroup['iconID']) if "iconID" in marketgroup else None,
|
||||
'name': marketgroup['nameID']['en'],
|
||||
'description': marketgroup['descriptionID']['en'] if "descriptionID" in marketgroup else "",
|
||||
'hasTypes': marketgroup['hasTypes'],
|
||||
}
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS('Marketgroups imported'))
|
||||
for id, marketgroup in marketgroups.items():
|
||||
if "parentGroupID" in marketgroup:
|
||||
sde_mg = SDEMarektGroup.objects.get(id=id)
|
||||
sde_mg.parent_marketgroup = SDEMarektGroup.objects.get(id=marketgroup['parentGroupID'])
|
||||
sde_mg.save()
|
||||
self.stdout.write(self.style.SUCCESS('Marketgroups linked'))
|
||||
|
||||
def import_metagroups(self, path):
|
||||
with open(path) as file:
|
||||
metagroups = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for id, metagroup in metagroups.items():
|
||||
SDEMetaGroup.objects.update_or_create(
|
||||
id=id,
|
||||
defaults={
|
||||
'icon': SDEIcon.objects.get(id=metagroup['iconID']) if "iconID" in metagroup else None,
|
||||
'name': metagroup['nameID']['en'],
|
||||
'iconSuffix': metagroup['iconSuffix'] if "iconSuffix" in metagroup else "",
|
||||
}
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS('Metagroups imported'))
|
||||
|
||||
def import_types(self, path):
|
||||
with open(path) as file:
|
||||
types = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for id, type in types.items():
|
||||
SDEType.objects.update_or_create(
|
||||
id=id,
|
||||
defaults={
|
||||
'group': SDEGroup.objects.get(id=type['groupID']),
|
||||
'marketgroup': SDEMarektGroup.objects.get(id=type['marketGroupID']) if "marketGroupID" in type else None,
|
||||
'metagroup': SDEMetaGroup.objects.get(id=type['metaGroupID']) if "metaGroupID" in type else None,
|
||||
'name': type['name']['en'],
|
||||
'description': type['description']['en'] if "description" in type else "",
|
||||
'published': type['published'],
|
||||
'basePrice': type['basePrice'] if "basePrice" in type else 0,
|
||||
'icon': SDEIcon.objects.get(id=type['iconID']) if "iconID" in type else None,
|
||||
'volume': type['volume'] if "volume" in type else 0,
|
||||
'portionSize': type['portionSize'],
|
||||
}
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS('Types imported'))
|
||||
|
||||
def import_type_materials(self, path):
|
||||
with open(path) as file:
|
||||
type_materials = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for id, type_material in type_materials.items():
|
||||
for material in type_material['materials']:
|
||||
SDETypeMaterial.objects.update_or_create(
|
||||
type=SDEType.objects.get(id=id),
|
||||
material_type=SDEType.objects.get(id=material['materialTypeID']),
|
||||
defaults={
|
||||
'quantity': material['quantity'],
|
||||
}
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS('Materials imported'))
|
||||
108
sde/migrations/0001_initial.py
Normal file
108
sde/migrations/0001_initial.py
Normal file
@@ -0,0 +1,108 @@
|
||||
# Generated by Django 4.2.6 on 2023-10-28 11:26
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SDECategory',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField()),
|
||||
('published', models.BooleanField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SDEGroup',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField()),
|
||||
('published', models.BooleanField()),
|
||||
('useBasePrice', models.BooleanField()),
|
||||
('fittableNonSingleton', models.BooleanField()),
|
||||
('anchored', models.BooleanField()),
|
||||
('anchorable', models.BooleanField()),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='sde.sdecategory')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SDEIcon',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('iconFile', models.CharField()),
|
||||
('description', models.CharField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SDEMarektGroup',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField()),
|
||||
('description', models.CharField(default='')),
|
||||
('hasTypes', models.BooleanField()),
|
||||
('icon', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='sde.sdeicon')),
|
||||
('parent_marketgroup', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child_marketgroups', to='sde.sdemarektgroup')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SDEMetaGroup',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField()),
|
||||
('iconSuffix', models.CharField()),
|
||||
('icon', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='metagroups', to='sde.sdeicon')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SDEType',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField()),
|
||||
('description', models.CharField()),
|
||||
('published', models.BooleanField()),
|
||||
('basePrice', models.FloatField()),
|
||||
('volume', models.FloatField()),
|
||||
('portionSize', models.IntegerField()),
|
||||
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='types', to='sde.sdegroup')),
|
||||
('icon', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='types', to='sde.sdeicon')),
|
||||
('marketgroup', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='types', to='sde.sdemarektgroup')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SDETypeMaterial',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quantity', models.IntegerField()),
|
||||
('material_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='typematerials_of', to='sde.sdetype')),
|
||||
('type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='typematerials', to='sde.sdetype')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sdetype',
|
||||
name='materials',
|
||||
field=models.ManyToManyField(related_name='material_of', through='sde.SDETypeMaterial', to='sde.sdetype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sdetype',
|
||||
name='metagroup',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='types', to='sde.sdemetagroup'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sdegroup',
|
||||
name='icon',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='groups', to='sde.sdeicon'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sdecategory',
|
||||
name='icon',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='categories', to='sde.sdeicon'),
|
||||
),
|
||||
]
|
||||
0
sde/migrations/__init__.py
Normal file
0
sde/migrations/__init__.py
Normal file
67
sde/models.py
Normal file
67
sde/models.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class SDEIcon(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
iconFile = models.CharField()
|
||||
description = models.CharField()
|
||||
|
||||
|
||||
class SDECategory(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
icon = models.ForeignKey(SDEIcon, related_name="categories", null=True, on_delete=models.SET_NULL)
|
||||
name = models.CharField()
|
||||
published = models.BooleanField()
|
||||
|
||||
|
||||
class SDEGroup(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
category = models.ForeignKey(SDECategory, related_name="groups", on_delete=models.CASCADE)
|
||||
name = models.CharField()
|
||||
published = models.BooleanField()
|
||||
useBasePrice = models.BooleanField()
|
||||
fittableNonSingleton = models.BooleanField()
|
||||
anchored = models.BooleanField()
|
||||
anchorable = models.BooleanField()
|
||||
icon = models.ForeignKey(SDEIcon, related_name="groups", null=True, on_delete=models.SET_NULL)
|
||||
|
||||
|
||||
class SDEMarektGroup(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
icon = models.ForeignKey(SDEIcon, null=True, on_delete=models.SET_NULL)
|
||||
name = models.CharField()
|
||||
description = models.CharField(default="")
|
||||
hasTypes = models.BooleanField()
|
||||
parent_marketgroup = models.ForeignKey("self", null=True, related_name="child_marketgroups", on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class SDEMetaGroup(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
icon = models.ForeignKey(SDEIcon, related_name="metagroups", null=True, on_delete=models.SET_NULL)
|
||||
name = models.CharField()
|
||||
iconSuffix = models.CharField()
|
||||
|
||||
|
||||
class SDEType(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
group = models.ForeignKey(SDEGroup, related_name="types", on_delete=models.CASCADE)
|
||||
marketgroup = models.ForeignKey(SDEMarektGroup, related_name="types", on_delete=models.SET_NULL, null=True)
|
||||
metagroup = models.ForeignKey(SDEMetaGroup, related_name="types", on_delete=models.SET_NULL, null=True)
|
||||
name = models.CharField()
|
||||
description = models.CharField()
|
||||
published = models.BooleanField()
|
||||
basePrice = models.FloatField()
|
||||
icon = models.ForeignKey(SDEIcon, related_name="types", null=True, on_delete=models.SET_NULL)
|
||||
volume = models.FloatField()
|
||||
portionSize = models.IntegerField()
|
||||
materials = models.ManyToManyField("self", through="SDETypeMaterial", symmetrical=False, related_name="material_of")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class SDETypeMaterial(models.Model):
|
||||
type = models.ForeignKey(SDEType, on_delete=models.CASCADE, related_name="typematerials")
|
||||
material_type = models.ForeignKey(SDEType, on_delete=models.CASCADE, related_name="typematerials_of")
|
||||
|
||||
quantity = models.IntegerField()
|
||||
54
sde/serializers.py
Normal file
54
sde/serializers.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from sde.models import *
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class SDEIconSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SDEIcon
|
||||
# fields = ['id', 'iconFile', 'description']
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class SDECategorySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SDECategory
|
||||
# fields = ['id', 'icon', 'name', 'published']
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class SDEGroupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SDEGroup
|
||||
# fields = ['id', 'category', 'name', 'published', 'useBasePrice', 'fittableNonSingleton', 'anchored', 'anchorable', 'icon']
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class SDEMarektGroupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SDEMarektGroup
|
||||
# fields = ['id', 'icon', 'name', 'description', 'hasTypes', 'parent_marketgroup']
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class SDEMetaGroupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SDEMetaGroup
|
||||
# fields = ['id', 'icon', 'name', 'iconSuffix']
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class SDETypeMaterialSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SDETypeMaterial
|
||||
# fields = ['type', 'material', 'quantity']
|
||||
# fields = "__all__"
|
||||
exclude = ['id', 'type']
|
||||
|
||||
|
||||
class SDETypeSerializer(serializers.ModelSerializer):
|
||||
# typematerials = SDETypeMaterialSerializer(many=True, read_only=True)
|
||||
class Meta:
|
||||
model = SDEType
|
||||
# fields = ['id', 'group', 'marketgroup', 'metagroup', 'name', 'description', 'published', 'basePrice', 'icon', 'volume', 'portionSize', 'materials']
|
||||
fields = "__all__"
|
||||
|
||||
16
sde/urls.py
Normal file
16
sde/urls.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from . import views
|
||||
from django.urls import include, path
|
||||
from rest_framework import routers
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'icons', views.SDEIconViewSet)
|
||||
router.register(r'categories', views.SDECategoryViewSet)
|
||||
router.register(r'groups', views.SDEGroupViewSet)
|
||||
router.register(r'marketgroups', views.SDEMarketGroupViewSet)
|
||||
router.register(r'metagroups', views.SDEMetaGroupViewSet)
|
||||
router.register(r'types', views.SDETypeViewSet)
|
||||
router.register(r'typematerials', views.SDETypeMaterialViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
46
sde/views.py
Normal file
46
sde/views.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from sde.serializers import *
|
||||
from rest_framework import viewsets
|
||||
|
||||
|
||||
class SDEIconViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SDEIcon.objects.all()
|
||||
serializer_class = SDEIconSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class SDECategoryViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SDECategory.objects.all()
|
||||
serializer_class = SDECategorySerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class SDEGroupViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SDEGroup.objects.all()
|
||||
serializer_class = SDEGroupSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class SDEMarketGroupViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SDEMarektGroup.objects.all()
|
||||
serializer_class = SDEMarektGroupSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class SDEMetaGroupViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SDEMetaGroup.objects.all()
|
||||
serializer_class = SDEMetaGroupSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class SDETypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SDEType.objects.all()
|
||||
serializer_class = SDETypeSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class SDETypeMaterialViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = SDETypeMaterial.objects.all()
|
||||
serializer_class = SDETypeMaterialSerializer
|
||||
# permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user