Compare commits
10 Commits
f328cab00d
...
4ddda1ca7c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ddda1ca7c | ||
|
|
972e8637ce | ||
|
|
758a40f6b5 | ||
|
|
68dedbf1ec | ||
|
|
50d0e8cdd6 | ||
|
|
a8b6807b79 | ||
|
|
734f20ce0e | ||
|
|
62f2e5c244 | ||
|
|
8df865b5b4 | ||
|
|
0a86242ef4 |
@@ -23,9 +23,10 @@ jobs:
|
||||
- name: Install dependencies
|
||||
working-directory: server
|
||||
run: |
|
||||
poetry Install
|
||||
poetry install
|
||||
|
||||
- name: Lint with black
|
||||
working-directory: server
|
||||
run: |
|
||||
black --check .
|
||||
ls -al
|
||||
poetry run black --check .
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
[mysql]
|
||||
DB_USER=username
|
||||
DB_PASS=password
|
||||
DB_NAME=portfolio
|
||||
DB_HOST=localhost
|
||||
|
||||
AUTH0_DOMAIN=domain.auth0.com
|
||||
AUTH0_API_AUDIENCE=https://audience.auth0.com/api/v2/
|
||||
AUTH0_ISSUER=https://issuer.auth0.com/
|
||||
AUTH0_ALGORITHMS=RS256
|
||||
|
||||
CLIENT_SECRET=secret
|
||||
CLIENT_ID=id
|
||||
[application]
|
||||
PORT=8080
|
||||
|
||||
13
server/.service
Normal file
13
server/.service
Normal file
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=uvicorn service for api.lucasjensen.me
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=lucas
|
||||
Group=www-data
|
||||
WorkingDirectory=/home/lucas/LucasJensen/server
|
||||
ExecStart=/home/lucas/LucasJensen/server/.venv/bin/uvicorn app:app --host 0.0.0.0 --port 8080 --workers 2
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -18,7 +18,7 @@ mysql -u [username] -p [database] < create_tables.sql
|
||||
### Run
|
||||
|
||||
```bash
|
||||
uvicorn main:app --reload --port 8001
|
||||
./run.py
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
1
server/app/__init__.py
Normal file
1
server/app/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .main import app # noqa: F401
|
||||
@@ -1,17 +1,25 @@
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from fastapi import FastAPI, HTTPException, Security, status
|
||||
from fastapi import FastAPI, HTTPException, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
import queries
|
||||
from helpers import origins
|
||||
from models import About, Project, Lucas
|
||||
from app.model import queries
|
||||
from app.types import About, Project, Lucas
|
||||
|
||||
load_dotenv()
|
||||
app = FastAPI()
|
||||
|
||||
origins = [
|
||||
"http://localhost",
|
||||
"http://localhost:3000",
|
||||
"https://localhost:3000",
|
||||
"http://127.0.0.1:3000",
|
||||
"https://lucasjensen.me/",
|
||||
"https://lucasjensen.me",
|
||||
"https://www.lucasjensen.me/",
|
||||
"https://www.lucasjensen.me",
|
||||
]
|
||||
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
0
server/app/model/__init__.py
Normal file
0
server/app/model/__init__.py
Normal file
31
server/app/model/queries.py
Normal file
31
server/app/model/queries.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from app.utils.db import connect_db
|
||||
from app.types import About, Project
|
||||
|
||||
|
||||
def get_projects() -> list[Project]:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM projects")
|
||||
data = cursor.fetchall()
|
||||
projects = [Project(**p) for p in data] # type: ignore
|
||||
db.close()
|
||||
return projects
|
||||
|
||||
|
||||
def get_project(project_id: int) -> Project | None:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM projects WHERE id=%s", (project_id,))
|
||||
data = cursor.fetchone()
|
||||
db.close()
|
||||
|
||||
return None if data is None else Project(**data) # type: ignore
|
||||
|
||||
|
||||
def get_about() -> About:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("SELECT name, email, bio, github, gitea FROM self")
|
||||
data = {key: val for key, val in cursor.fetchone().items()} # type: ignore
|
||||
db.close()
|
||||
return About(**data)
|
||||
3
server/app/types/__init__.py
Normal file
3
server/app/types/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .about import About # noqa: F401
|
||||
from .project import Project # noqa: F401
|
||||
from .lucas import Lucas # noqa: F401
|
||||
9
server/app/types/about.py
Normal file
9
server/app/types/about.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class About(BaseModel):
|
||||
name: str
|
||||
email: str
|
||||
bio: str
|
||||
github: str
|
||||
gitea: str
|
||||
8
server/app/types/lucas.py
Normal file
8
server/app/types/lucas.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from pydantic import BaseModel
|
||||
from .about import About
|
||||
from .project import Project
|
||||
|
||||
|
||||
class Lucas(BaseModel):
|
||||
projects: list[Project]
|
||||
about: About
|
||||
@@ -2,14 +2,6 @@ from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class About(BaseModel):
|
||||
name: str
|
||||
email: str
|
||||
bio: str
|
||||
github: str
|
||||
gitea: str
|
||||
|
||||
|
||||
class Project(BaseModel):
|
||||
id: Optional[int] = None
|
||||
name: str
|
||||
@@ -17,8 +9,3 @@ class Project(BaseModel):
|
||||
source: Optional[str] = None
|
||||
live: Optional[str] = None
|
||||
is_self_hosted: Optional[bool] = False
|
||||
|
||||
|
||||
class Lucas(BaseModel):
|
||||
projects: list[Project]
|
||||
about: About
|
||||
0
server/app/utils/__init__.py
Normal file
0
server/app/utils/__init__.py
Normal file
@@ -1,27 +0,0 @@
|
||||
import os
|
||||
from functools import lru_cache
|
||||
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
auth0_domain: str
|
||||
auth0_api_audience: str
|
||||
auth0_issuer: str
|
||||
auth0_algorithms: str
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def get_settings():
|
||||
domain = os.getenv("AUTH0_DOMAIN")
|
||||
audience = os.getenv("AUTH0_API_AUDIENCE")
|
||||
issuer = os.getenv("AUTH0_ISSUER")
|
||||
algorithms = os.getenv("AUTH0_ALGORITHMS")
|
||||
if None in [domain, audience, issuer, algorithms]:
|
||||
raise ValueError("Missing environment variables")
|
||||
return Settings(
|
||||
auth0_domain=domain, # type: ignore
|
||||
auth0_api_audience=audience, # type: ignore
|
||||
auth0_issuer=issuer, # type: ignore
|
||||
auth0_algorithms=algorithms, # type: ignore
|
||||
)
|
||||
@@ -1,47 +0,0 @@
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
origins = [
|
||||
"http://localhost",
|
||||
"http://localhost:3000",
|
||||
"https://localhost:3000",
|
||||
"http://127.0.0.1:3000",
|
||||
"https://lucasjensen.me/",
|
||||
"https://lucasjensen.me",
|
||||
"https://www.lucasjensen.me/",
|
||||
"https://www.lucasjensen.me",
|
||||
]
|
||||
|
||||
|
||||
def get_token() -> str:
|
||||
import http.client
|
||||
import json
|
||||
|
||||
load_dotenv()
|
||||
|
||||
client_id = os.getenv("CLIENT_ID")
|
||||
client_secret = os.getenv("CLIENT_SECRET")
|
||||
|
||||
conn = http.client.HTTPSConnection("lucasjensen.us.auth0.com")
|
||||
|
||||
payload = (
|
||||
'{"client_id":"'
|
||||
+ f"{client_id}"
|
||||
+ '","client_secret":"'
|
||||
+ f"{client_secret}"
|
||||
+ '","audience":"'
|
||||
+ f"https://api.lucasjensen.me/"
|
||||
+ '","grant_type":"client_credentials"}'
|
||||
)
|
||||
|
||||
headers = {"content-type": "application/json"}
|
||||
|
||||
conn.request("POST", "/oauth/token", payload, headers)
|
||||
|
||||
res = conn.getresponse()
|
||||
|
||||
data = res.read()
|
||||
body = json.loads(data.decode("utf-8"))
|
||||
|
||||
return body["access_token"]
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "lucasjensen-fastapi"
|
||||
version = "0.1.0"
|
||||
version = "1.0.0"
|
||||
description = "A RESTful API for lucasjensen.me"
|
||||
authors = ["Lucas Jensen <lucas@lucasjensen.me>"]
|
||||
readme = "README.md"
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
from db import connect_db
|
||||
from models import About, Project
|
||||
|
||||
|
||||
def get_projects() -> list[Project]:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM projects")
|
||||
data = cursor.fetchall()
|
||||
projects = [Project(**p) for p in data] # type: ignore
|
||||
db.close()
|
||||
return projects
|
||||
|
||||
|
||||
def get_project(project_id: int) -> Project | None:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("SELECT * FROM projects WHERE id=%s", (project_id,))
|
||||
data = cursor.fetchone()
|
||||
db.close()
|
||||
|
||||
return None if data is None else Project(**data) # type: ignore
|
||||
|
||||
|
||||
def create_project(project: Project) -> Project:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute(
|
||||
"INSERT INTO projects (name, description, source, live, is_self_hosted) VALUES (%s, %s, %s, %s, %s)",
|
||||
(
|
||||
project.name,
|
||||
project.description,
|
||||
project.source,
|
||||
project.live,
|
||||
project.is_self_hosted,
|
||||
),
|
||||
)
|
||||
db.commit()
|
||||
project.id = cursor.lastrowid
|
||||
db.close()
|
||||
return project
|
||||
|
||||
|
||||
def delete_project(project_id: int) -> None:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("DELETE FROM projects WHERE id=%s", (project_id,))
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
|
||||
def get_about() -> About:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("SELECT name, email, bio, github, gitea FROM self")
|
||||
data = {key: val for key, val in cursor.fetchone().items()} # type: ignore
|
||||
db.close()
|
||||
return About(**data)
|
||||
|
||||
|
||||
def get_subs() -> dict[str, str]:
|
||||
db = connect_db()
|
||||
cursor = db.cursor(dictionary=True)
|
||||
cursor.execute("SELECT auth0_sub, test_sub FROM self")
|
||||
data = {key: val for key, val in cursor.fetchone().items()} # type: ignore
|
||||
db.close()
|
||||
return data
|
||||
5
server/run.py
Normal file → Executable file
5
server/run.py
Normal file → Executable file
@@ -1,10 +1,13 @@
|
||||
#!.venv/bin/python
|
||||
|
||||
import os
|
||||
import uvicorn
|
||||
from main import app
|
||||
from app import app
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
load_dotenv()
|
||||
print("Starting development environment.\nDO NOT USE THIS IN PRODUCTION.")
|
||||
port = int(os.getenv("PORT", 5050))
|
||||
uvicorn.run(app, port=port)
|
||||
|
||||
Reference in New Issue
Block a user