Compare commits

..

10 Commits

Author SHA1 Message Date
Lucas Jensen
4ddda1ca7c Merge pull request 'Add systemd service file' (#8) from server-service into main
Some checks failed
build app / build (21.x) (push) Has been cancelled
Portfolio Backend CI / build (push) Has been cancelled
Reviewed-on: #8
2024-07-07 17:04:11 +00:00
Lucas Jensen
972e8637ce Add systemd service file 2024-07-07 09:39:58 -07:00
Lucas Jensen
758a40f6b5 Merge pull request 'more moving of files' (#7) from another-refactor into main
Reviewed-on: #7
2024-07-06 17:57:32 +00:00
Lucas Jensen
68dedbf1ec more moving of files 2024-07-06 10:57:10 -07:00
Lucas Jensen
50d0e8cdd6 Merge pull request 'reorganized' (#6) from refactor into main
Reviewed-on: #6
2024-07-06 17:38:20 +00:00
Lucas Jensen
a8b6807b79 reorganized 2024-07-06 10:36:37 -07:00
Lucas Jensen
734f20ce0e Merge pull request 'poetry-migration' (#2) from poetry-migration into main
Reviewed-on: #2
2024-06-29 21:40:08 +00:00
Lucas Jensen
62f2e5c244 run black using poetry 2024-06-29 11:53:42 -07:00
Lucas Jensen
8df865b5b4 changed black path 2024-06-29 11:52:44 -07:00
Lucas Jensen
0a86242ef4 fixed typo 2024-06-29 11:48:24 -07:00
19 changed files with 92 additions and 173 deletions

View File

@@ -23,9 +23,10 @@ jobs:
- name: Install dependencies - name: Install dependencies
working-directory: server working-directory: server
run: | run: |
poetry Install poetry install
- name: Lint with black - name: Lint with black
working-directory: server working-directory: server
run: | run: |
black --check . ls -al
poetry run black --check .

View File

@@ -1,12 +1,8 @@
[mysql]
DB_USER=username DB_USER=username
DB_PASS=password DB_PASS=password
DB_NAME=portfolio DB_NAME=portfolio
DB_HOST=localhost DB_HOST=localhost
AUTH0_DOMAIN=domain.auth0.com [application]
AUTH0_API_AUDIENCE=https://audience.auth0.com/api/v2/ PORT=8080
AUTH0_ISSUER=https://issuer.auth0.com/
AUTH0_ALGORITHMS=RS256
CLIENT_SECRET=secret
CLIENT_ID=id

13
server/.service Normal file
View 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

View File

@@ -18,7 +18,7 @@ mysql -u [username] -p [database] < create_tables.sql
### Run ### Run
```bash ```bash
uvicorn main:app --reload --port 8001 ./run.py
``` ```
### Test ### Test

1
server/app/__init__.py Normal file
View File

@@ -0,0 +1 @@
from .main import app # noqa: F401

View File

@@ -1,17 +1,25 @@
import os
from dotenv import load_dotenv 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.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
import queries from app.model import queries
from helpers import origins from app.types import About, Project, Lucas
from models import About, Project, Lucas
load_dotenv() load_dotenv()
app = FastAPI() 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( app.add_middleware(
CORSMiddleware, CORSMiddleware,

View File

View 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)

View File

@@ -0,0 +1,3 @@
from .about import About # noqa: F401
from .project import Project # noqa: F401
from .lucas import Lucas # noqa: F401

View File

@@ -0,0 +1,9 @@
from pydantic import BaseModel
class About(BaseModel):
name: str
email: str
bio: str
github: str
gitea: str

View 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

View File

@@ -2,14 +2,6 @@ from pydantic import BaseModel
from typing import Optional from typing import Optional
class About(BaseModel):
name: str
email: str
bio: str
github: str
gitea: str
class Project(BaseModel): class Project(BaseModel):
id: Optional[int] = None id: Optional[int] = None
name: str name: str
@@ -17,8 +9,3 @@ class Project(BaseModel):
source: Optional[str] = None source: Optional[str] = None
live: Optional[str] = None live: Optional[str] = None
is_self_hosted: Optional[bool] = False is_self_hosted: Optional[bool] = False
class Lucas(BaseModel):
projects: list[Project]
about: About

View File

View 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
)

View File

@@ -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"]

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "lucasjensen-fastapi" name = "lucasjensen-fastapi"
version = "0.1.0" version = "1.0.0"
description = "A RESTful API for lucasjensen.me" description = "A RESTful API for lucasjensen.me"
authors = ["Lucas Jensen <lucas@lucasjensen.me>"] authors = ["Lucas Jensen <lucas@lucasjensen.me>"]
readme = "README.md" readme = "README.md"

View File

@@ -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
View File

@@ -1,10 +1,13 @@
#!.venv/bin/python
import os import os
import uvicorn import uvicorn
from main import app from app import app
from dotenv import load_dotenv from dotenv import load_dotenv
if __name__ == "__main__": if __name__ == "__main__":
load_dotenv() load_dotenv()
print("Starting development environment.\nDO NOT USE THIS IN PRODUCTION.")
port = int(os.getenv("PORT", 5050)) port = int(os.getenv("PORT", 5050))
uvicorn.run(app, port=port) uvicorn.run(app, port=port)