nightly - 2025-09-20
This commit is contained in:
2
api/.gitignore
vendored
Normal file
2
api/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
*/__pycache__
|
||||
7
api/data/config.ini
Normal file
7
api/data/config.ini
Normal file
@@ -0,0 +1,7 @@
|
||||
[db]
|
||||
host = localhost
|
||||
port = 3306
|
||||
user = tam3
|
||||
password = tam3
|
||||
database = tam3
|
||||
|
||||
10
api/db.py
Normal file
10
api/db.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from settings import read_config
|
||||
from mysql.connector import connect
|
||||
|
||||
|
||||
def session():
|
||||
config = read_config()
|
||||
conn = connect(**config["db"])
|
||||
cur = conn.cursor()
|
||||
return conn, cur
|
||||
|
||||
9
api/exceptions.py
Normal file
9
api/exceptions.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
bad_key = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="API Key is bad, very bad."
|
||||
)
|
||||
|
||||
not_found = HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND, detail="Resource not found."
|
||||
)
|
||||
48
api/key.py
Executable file
48
api/key.py
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import string
|
||||
from sys import argv
|
||||
|
||||
from repos import ApiKeyRepo
|
||||
|
||||
rdm_str = string.ascii_lowercase + string.digits
|
||||
|
||||
|
||||
def generate():
|
||||
if len(argv) < 3:
|
||||
print("Please put name after the generate verb.")
|
||||
quit()
|
||||
new_key = ApiKeyRepo().create_api(argv[2])
|
||||
print(new_key)
|
||||
|
||||
|
||||
def list_keys():
|
||||
result_keys = ApiKeyRepo().get_all()
|
||||
for key in result_keys:
|
||||
print(f"pc_name: {key.pc_name}")
|
||||
print(key.api_key)
|
||||
print("\n")
|
||||
|
||||
|
||||
def delete_key():
|
||||
if len(argv) < 3:
|
||||
print("Please put api key to delete after the delete verb.")
|
||||
quit()
|
||||
del_status = ApiKeyRepo().delete(argv[2])
|
||||
print(del_status)
|
||||
|
||||
|
||||
if len(argv) < 2:
|
||||
print("Please put action after api.py such as generate, list, or remove.")
|
||||
quit()
|
||||
else:
|
||||
action = argv[1]
|
||||
|
||||
match action:
|
||||
case "generate":
|
||||
generate()
|
||||
case "list":
|
||||
list_keys()
|
||||
case "delete":
|
||||
delete_key()
|
||||
|
||||
13
api/main.py
13
api/main.py
@@ -0,0 +1,13 @@
|
||||
#!/bin/env python3
|
||||
|
||||
from fastapi import FastAPI
|
||||
from sys import argv
|
||||
|
||||
from routers.prefixes import prefix_router
|
||||
|
||||
if argv[1] == "run":
|
||||
app = FastAPI(title="TAM3 API Server", docs_url=None, redoc_url=None)
|
||||
else:
|
||||
app = FastAPI(title="TAM3 API Server")
|
||||
|
||||
app.include_router(prefix_router)
|
||||
|
||||
1
api/repos/__init__.py
Normal file
1
api/repos/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .api_keys import ApiKey, ApiKeyRepo
|
||||
43
api/repos/api_keys.py
Normal file
43
api/repos/api_keys.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import random as r
|
||||
import string
|
||||
from dataclasses import dataclass
|
||||
from .template import Repo
|
||||
|
||||
rdm_set = string.ascii_lowercase + string.digits
|
||||
|
||||
|
||||
@dataclass
|
||||
class ApiKey:
|
||||
api_key: str
|
||||
pc_name: str = ""
|
||||
|
||||
|
||||
class ApiKeyRepo(Repo):
|
||||
def check_api(self, api_key: str) -> bool:
|
||||
self.cur.execute("SELECT * FROM api_keys WHERE api_key = %s", (api_key,))
|
||||
result = self.cur.fetchone()
|
||||
if result:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def create_api(self, name: str) -> str:
|
||||
while True:
|
||||
new_key = "".join(r.choice(rdm_set) for i in range(16))
|
||||
if not self.check_api(new_key):
|
||||
break
|
||||
self.cur.execute("INSERT INTO api_keys VALUES (%s, %s)", (new_key, name))
|
||||
self.conn.commit()
|
||||
return new_key
|
||||
|
||||
def get_all(self) -> list[ApiKey]:
|
||||
self.cur.execute("SELECT * FROM api_keys")
|
||||
results = self.cur.fetchall()
|
||||
if not results:
|
||||
return []
|
||||
return [ApiKey(*r) for r in results]
|
||||
|
||||
def delete(self, api_key: str) -> str:
|
||||
self.cur.execute("DELETE FROM api_keys WHERE api_key = %s", (api_key,))
|
||||
self.conn.commit()
|
||||
return "Key deleted successfully."
|
||||
39
api/repos/prefixes.py
Normal file
39
api/repos/prefixes.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from .template import Repo
|
||||
from dataclasses import dataclass
|
||||
from exceptions import not_found
|
||||
|
||||
|
||||
@dataclass
|
||||
class Prefix:
|
||||
name: str
|
||||
color: str = ""
|
||||
weight: int = 0
|
||||
|
||||
|
||||
class PrefixRepo(Repo):
|
||||
def get_all(self) -> list[Prefix]:
|
||||
self.cur.execute("SELECT * FROM prefixes ORDER BY weight, name")
|
||||
results = self.cur.fetchall()
|
||||
if not results:
|
||||
return []
|
||||
return [Prefix(*r) for r in results]
|
||||
|
||||
def get_one(self, prefix_name: str):
|
||||
self.cur.execute("SELECT * FROM prefixes WHERE name = %s", (prefix_name,))
|
||||
result = self.cur.fetchone()
|
||||
if not result:
|
||||
raise not_found
|
||||
return Prefix(*result)
|
||||
|
||||
def add_one(self, prefix: Prefix) -> str:
|
||||
self.cur.execute(
|
||||
"REPLACE INTO prefixes VALUES (%s, %s, %s)",
|
||||
(prefix.name, prefix.color, prefix.weight),
|
||||
)
|
||||
self.conn.commit()
|
||||
return "Prefix inserted successfully."
|
||||
|
||||
def del_one(self, prefix_name: str) -> str:
|
||||
self.cur.execute("DELETE FROM prefixes WHERE name = %s", (prefix_name,))
|
||||
self.conn.commit()
|
||||
return "Prefix deleted successfully."
|
||||
6
api/repos/template.py
Normal file
6
api/repos/template.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from db import session
|
||||
|
||||
|
||||
class Repo:
|
||||
def __init__(self):
|
||||
self.conn, self.cur = session()
|
||||
0
api/routers/__init__.py
Normal file
0
api/routers/__init__.py
Normal file
26
api/routers/prefixes.py
Normal file
26
api/routers/prefixes.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from fastapi import APIRouter
|
||||
from repos.prefixes import Prefix, PrefixRepo
|
||||
|
||||
prefix_router = APIRouter(prefix="/api/prefixes")
|
||||
|
||||
|
||||
@prefix_router.get("/")
|
||||
def get_all_prefixes():
|
||||
return PrefixRepo().get_all()
|
||||
|
||||
|
||||
@prefix_router.get("/{prefix_name}/")
|
||||
def get_one_prefix(prefix_name: str):
|
||||
return PrefixRepo().get_one(prefix_name)
|
||||
|
||||
|
||||
@prefix_router.post("/")
|
||||
def post_one_prefix(p: Prefix):
|
||||
rep_detail = PrefixRepo().add_one(p)
|
||||
return {"detail": rep_detail}
|
||||
|
||||
|
||||
@prefix_router.delete("/")
|
||||
def del_one_prefix(prefix_name: str):
|
||||
rep_detail = PrefixRepo().del_one(prefix_name)
|
||||
return {"detail": rep_detail}
|
||||
25
api/settings.py
Normal file
25
api/settings.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from configparser import ConfigParser
|
||||
|
||||
data_path = Path(os.getenv("TAM3_DATA_PATH", "data"))
|
||||
data_path.mkdir(exist_ok=True)
|
||||
|
||||
|
||||
def read_config():
|
||||
config = ConfigParser()
|
||||
config_path = data_path / "config.ini"
|
||||
if config_path.is_file():
|
||||
config.read(config_path)
|
||||
return config
|
||||
else:
|
||||
config["db"] = {
|
||||
"host": os.getenv("TAM3_DB_HOST", "localhost"),
|
||||
"port": os.getenv("TAM3_DB_PORT", "3306"),
|
||||
"user": os.getenv("TAM3_DB_USER", "tam3"),
|
||||
"password": os.getenv("TAM3_DB_PASSWD", "tam3"),
|
||||
"database": os.getenv("TAM3_DB_DATABASE", "tam3"),
|
||||
}
|
||||
with open(config_path, "w") as f:
|
||||
config.write(f)
|
||||
return config
|
||||
Reference in New Issue
Block a user