Initial seeding logic
This commit is contained in:
parent
c36c4bd3b8
commit
cc6c4818ad
@ -1,6 +1,6 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from . import decks, games, players
|
||||
from . import base, decks, games, players, seed
|
||||
|
||||
api_router = APIRouter(prefix="/api")
|
||||
html_router = APIRouter()
|
||||
@ -8,7 +8,11 @@ html_router = APIRouter()
|
||||
api_router.include_router(decks.api_router)
|
||||
api_router.include_router(players.api_router)
|
||||
api_router.include_router(games.api_router)
|
||||
api_router.include_router(seed.api_router)
|
||||
|
||||
html_router.include_router(decks.html_router)
|
||||
html_router.include_router(players.html_router)
|
||||
html_router.include_router(games.html_router)
|
||||
html_router.include_router(seed.html_router)
|
||||
|
||||
html_router.include_router(base.html_router)
|
||||
|
16
app/routers/base.py
Normal file
16
app/routers/base.py
Normal file
@ -0,0 +1,16 @@
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
from ..sql import crud
|
||||
from ..templates import jinja_templates, _jsonify
|
||||
from ..sql.database import get_db
|
||||
|
||||
html_router = APIRouter(include_in_schema=False, default_response_class=HTMLResponse)
|
||||
|
||||
|
||||
@html_router.get("/")
|
||||
def main(request: Request, db=Depends(get_db)):
|
||||
games = crud.get_games(db=db)
|
||||
return jinja_templates.TemplateResponse(
|
||||
request, "/main.html", {"games": _jsonify(games)}
|
||||
)
|
53
app/routers/seed.py
Normal file
53
app/routers/seed.py
Normal file
@ -0,0 +1,53 @@
|
||||
import csv
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, Request, UploadFile
|
||||
from fastapi.responses import HTMLResponse
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..templates import jinja_templates
|
||||
from ..sql import crud, schemas
|
||||
from ..sql.database import get_db
|
||||
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
api_router = APIRouter(prefix="/seed", tags=["seed"])
|
||||
html_router = APIRouter(
|
||||
prefix="/seed", include_in_schema=False, default_response_class=HTMLResponse
|
||||
)
|
||||
|
||||
|
||||
@api_router.post("/players")
|
||||
def seed_players(file: UploadFile, db: Session = Depends(get_db)):
|
||||
file_contents = file.file.read().decode("utf-8").split("\n")
|
||||
reader = csv.reader(file_contents, delimiter=",")
|
||||
for row in reader:
|
||||
if not row:
|
||||
continue
|
||||
player_name = row[1]
|
||||
crud.create_player(db=db, player=schemas.PlayerCreate(name=player_name))
|
||||
return "OK!"
|
||||
|
||||
|
||||
@api_router.post("/decks")
|
||||
def seed_decks(file: UploadFile, db: Session = Depends(get_db)):
|
||||
file_contents = file.file.read().decode("utf-8").split("\n")
|
||||
reader = csv.DictReader(file_contents, delimiter=",")
|
||||
for row in reader:
|
||||
if not row:
|
||||
continue
|
||||
crud.create_deck(
|
||||
db=db,
|
||||
deck=schemas.DeckCreate(
|
||||
**{key: row[key] for key in ["name", "description", "owner_id"]}
|
||||
),
|
||||
)
|
||||
return "OK!"
|
||||
|
||||
|
||||
@html_router.get("/")
|
||||
def main(request: Request, db=Depends(get_db)):
|
||||
return jinja_templates.TemplateResponse(
|
||||
request,
|
||||
"/seed.html",
|
||||
)
|
@ -1,3 +1,4 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
@ -47,7 +48,7 @@ class WinType(WinTypeBase):
|
||||
|
||||
|
||||
class GameBase(BaseModel):
|
||||
date: int
|
||||
date: datetime
|
||||
deck_id_1: int
|
||||
deck_id_2: int
|
||||
deck_id_3: int
|
||||
|
@ -13,5 +13,10 @@ jinja_templates = Jinja2Templates(directory="app/templates")
|
||||
# TODO - would this be better as a method on a class extending `db.Model` that the classes in `models.py` could then
|
||||
# extend?
|
||||
# (Probably not, as we'd still need to explicitly call it - it wouldn't be implicitly called _by_ Flask)
|
||||
#
|
||||
# (Assumes that this will only be passed lists or objects, not primitives)
|
||||
def _jsonify(o):
|
||||
if hasattr(o, "__dict__"):
|
||||
return {k: v for (k, v) in o.__dict__.items() if k != "_sa_instance_state"}
|
||||
else:
|
||||
return [_jsonify(e) for e in o]
|
||||
|
@ -9,11 +9,12 @@
|
||||
<table>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Deck ID 1</th>
|
||||
<th>Decks</th>
|
||||
<th>Winning Deck</th>
|
||||
</tr>
|
||||
{% for game in games %}
|
||||
<tr>
|
||||
<td>{{ game.date }}</td>
|
||||
<td><a href="/game/{{ game.id }}">{{ game.date }}</a></td>
|
||||
<td>
|
||||
{{ game.deck_id_1 }}
|
||||
</td>
|
||||
|
10
app/templates/main.html
Normal file
10
app/templates/main.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}EDH ELO{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>Welcome to EDH ELO!</p>
|
||||
{% endblock %}
|
27
app/templates/seed.html
Normal file
27
app/templates/seed.html
Normal file
@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Seeding from files{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Seed from files</h2>
|
||||
|
||||
<div>
|
||||
<form action="/api/seed/players" method="post" enctype="multipart/form-data">
|
||||
<label for="file">Upload Players</label>
|
||||
<input type="file" id="file" name="file" accept=".csv"/>
|
||||
<input type="submit">Upload</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form action="/api/seed/decks" method="post" enctype="multipart/form-data">
|
||||
<label for="file">Upload Decks</label>
|
||||
<input type="file" id="file" name="file" accept=".csv"/>
|
||||
<input type="submit">Upload</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
@ -2,4 +2,4 @@
|
||||
|
||||
# Idempotent
|
||||
source .venv/bin/activate
|
||||
uvicorn app:app --reload
|
||||
uvicorn app:app --reload --log-config ./local-run-log-config.yaml
|
||||
|
37
local-run-log-config.yaml
Normal file
37
local-run-log-config.yaml
Normal file
@ -0,0 +1,37 @@
|
||||
# See https://github.com/encode/uvicorn/discussions/2254 -
|
||||
# Ideally, would not have to re-implement uvicorn's loggers.
|
||||
version: 1
|
||||
disable_existing_loggers: False
|
||||
formatters:
|
||||
default:
|
||||
(): 'uvicorn.logging.DefaultFormatter'
|
||||
fmt: '%(asctime)s %(levelprefix)-9s %(name)s -: %(message)s'
|
||||
access:
|
||||
(): 'uvicorn.logging.AccessFormatter'
|
||||
fmt: '%(asctime)s %(levelprefix)-9s %(name)s -: %(client_addr)s - "%(request_line)s" %(status_code)s'
|
||||
handlers:
|
||||
default:
|
||||
class: logging.StreamHandler
|
||||
formatter: default
|
||||
stream: ext://sys.stderr
|
||||
access:
|
||||
class: logging.StreamHandler
|
||||
formatter: access
|
||||
stream: ext://sys.stdout
|
||||
loggers:
|
||||
uvicorn:
|
||||
level: INFO
|
||||
propagate: False
|
||||
handlers:
|
||||
- default
|
||||
uvicorn.error:
|
||||
level: INFO
|
||||
uvicorn.access:
|
||||
level: INFO
|
||||
propagate: False
|
||||
handlers:
|
||||
- access
|
||||
root:
|
||||
level: INFO
|
||||
handlers:
|
||||
- default
|
@ -1,4 +1,6 @@
|
||||
fastapi
|
||||
uvicorn
|
||||
python-multipart
|
||||
sqlalchemy
|
||||
uvicorn
|
||||
Jinja2
|
||||
pyyaml
|
||||
|
1
seed-data/README.md
Normal file
1
seed-data/README.md
Normal file
@ -0,0 +1 @@
|
||||
Data I use for initialization during testing.
|
57
seed-data/decks.csv
Normal file
57
seed-data/decks.csv
Normal file
@ -0,0 +1,57 @@
|
||||
id,name,description,owner_id
|
||||
1,Kelsien the Plague,,1
|
||||
2,Ravos/Rebbec,,2
|
||||
3,Duke Ulder Ravengard,,3
|
||||
4,Mondrak,,4
|
||||
5,Wernog/Cecily,,2
|
||||
6,Jasmine Boreal of the Seven,,1
|
||||
7,Go-Shintai of Life's Origin,,4
|
||||
8,Kethis the Hidden Hand,,1
|
||||
9,Rograkh/Silas ninjas,,2
|
||||
10,Tekuthal,,3
|
||||
11,Gitrog,,5
|
||||
12,Illuna,,4
|
||||
13,Atraxa,,1
|
||||
14,Muldrotha,,2
|
||||
15,Grist,,5
|
||||
16,Goose Mother,,5
|
||||
17,Maarika,,3
|
||||
18,Wilson/Cultist,,2
|
||||
19,Abdel Adrian/Far Traveler,,2
|
||||
20,Obeka,,5
|
||||
21,Laelia,,3
|
||||
22,Jan Jansen,,2
|
||||
23,Don Andres,,5
|
||||
24,Urza,,3
|
||||
25,"Me,the Immortal",,2
|
||||
26,Kiora,,3
|
||||
27,Raffine,,2
|
||||
28,Kozilek,,5
|
||||
29,Jhoira of the Ghitu,,6
|
||||
30,Anikthea,,7
|
||||
31,Oops all Kayas,,3
|
||||
32,Silvar/Trynn,,7
|
||||
33,"Purphoros, God of the Forge",,5
|
||||
34,Jhoira of the Ghitu,,6
|
||||
35,Brago,,6
|
||||
36,Marneus Calgar,,7
|
||||
37,Slimefoot and Squee,,2
|
||||
38,Ayara,,3
|
||||
39,Omnath,,5
|
||||
40,Wilson/Cultist,,2
|
||||
41,Myrel,,5
|
||||
42,Elmar storm,,3
|
||||
43,Gale/Scion of Halaster,,8
|
||||
44,Kefnet the Mindful,,2
|
||||
45,Rograkh/Silas ninjas,,2
|
||||
46,Emiel,,5
|
||||
47,Myrkul planeswalkers,,3
|
||||
48,Syr Ginger,,8
|
||||
49,Rafiq,,3
|
||||
50,Yoshimaru/Reyhan,,2
|
||||
51,Go-Shintai of Life's Origin,,4
|
||||
52,Dargo/Nadier,,2
|
||||
53,Pantlaza,,5
|
||||
54,Niv-Mizzet,,3
|
||||
55,"Liesa, Shroud of Dusk",,5
|
||||
56,Malcolm/Ich-Tekik,,2
|
|
8
seed-data/players.csv
Normal file
8
seed-data/players.csv
Normal file
@ -0,0 +1,8 @@
|
||||
1,Evan
|
||||
2,Terence
|
||||
3,Patrick
|
||||
4,Jeff
|
||||
5,Ryan
|
||||
6,Ajit
|
||||
7,Brandon
|
||||
8,Jack
|
|
Loading…
x
Reference in New Issue
Block a user