initial commit for GitHub

This commit is contained in:
Lucas Jensen
2024-12-01 19:15:25 -08:00
commit 925b334e4c
91 changed files with 8031 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
from .albums import Album, Artist
from .artwork import Artwork, Medium
from .bio import Bio, ProfessionalService, SocialUrl
from .quotes import Quote
from .video import Video

View File

@@ -0,0 +1,94 @@
from typing import Optional, Type
from icecream import ic
from pydantic import HttpUrl
from app.constants import ALBUMS_TABLE, ARTISTS_TABLE
from app.model.model_object import ModelObject
from app.model.response_object import ResponseObject
class Artist(ModelObject, ResponseObject):
artist_name: str
artist_url: Optional[HttpUrl] = None
class Album(ModelObject, ResponseObject):
album_name: str
release_year: int
artist: Artist
front_artwork_url: HttpUrl
spotify_url: Optional[HttpUrl] = None
itunes_url: Optional[HttpUrl] = None
bandcamp_url: Optional[HttpUrl] = None
apple_music_url: Optional[HttpUrl] = None
rear_artwork_url: Optional[HttpUrl] = None
bandcamp_player: Optional[str] = None
@classmethod
def select_one(
cls, album_id: int, table_name: str = ALBUMS_TABLE
) -> "Album | None":
cursor, conn = cls._get_cursor_and_conn()
cursor.execute(
f"""-- sql
SELECT
al.id,
al.album_name ,
al.release_year,
al.artist_id ,
al.spotify_url ,
al.itunes_url ,
al.bandcamp_url ,
al.apple_music_url ,
al.front_artwork_url ,
al.rear_artwork_url ,
al.bandcamp_player ,
ar.artist_name ,
ar.artist_url
FROM {table_name} al
LEFT JOIN {ARTISTS_TABLE} ar
ON al.artist_id = ar.id
WHERE al.id = {album_id};
"""
)
data: dict = cursor.fetchone() # type: ignore
cls._close_cursor_and_conn(cursor, conn)
return cls._construct(cls, data) if data else None
@classmethod
def select_all(cls, table_name: str = ALBUMS_TABLE) -> list["Album"]:
cursor, conn = cls._get_cursor_and_conn()
cursor.execute(
f"""-- sql
SELECT
al.id,
al.album_name ,
al.release_year,
al.artist_id ,
al.spotify_url ,
al.itunes_url ,
al.bandcamp_url ,
al.apple_music_url ,
al.front_artwork_url ,
al.rear_artwork_url ,
al.bandcamp_player ,
ar.artist_name ,
ar.artist_url
FROM {table_name} al
LEFT JOIN {ARTISTS_TABLE} ar
ON al.artist_id = ar.id;
"""
)
data: dict = cursor.fetchall() # type: ignore
cls._close_cursor_and_conn(cursor, conn)
return sorted(
[cls._construct(cls, row) for row in data],
key=lambda album: album.release_year,
reverse=True,
)
@classmethod
def _construct(cls, Obj: Type, data: dict) -> "Album":
data["artist"] = Artist(**data)
return Obj(**data)

View File

@@ -0,0 +1,11 @@
from typing import Optional
from pydantic import BaseModel, HttpUrl
class Article(BaseModel):
id: int
article_title: str
body: str
is_featured: Optional[bool] = False
video_url: Optional[HttpUrl] = None

View File

@@ -0,0 +1,85 @@
from typing import Optional, Type
from pydantic import HttpUrl
from app.constants import ART_MEDIUM_TABLE, ARTWORK_TABLE
from app.model.model_object import ModelObject
from app.model.response_object import ResponseObject
class Medium(ModelObject, ResponseObject):
medium_name: str
class Artwork(ModelObject, ResponseObject):
artwork_name: str
source: HttpUrl
thumbnail: HttpUrl
is_featured: bool = False
medium: Optional[Medium] = None
release_year: Optional[int] = None
size: Optional[str] = None
@classmethod
def select_one(
cls, artwork_id: int, table_name: str = ARTWORK_TABLE
) -> "Artwork | None":
cursor, conn = cls._get_cursor_and_conn()
cursor.execute(
f"""-- sql
SELECT
a.id,
a.medium_id ,
a.artwork_name ,
a.source ,
a.thumbnail ,
a.is_featured ,
a.release_year ,
a.`size` ,
m.id as medium_id,
m.medium_name
FROM {table_name} a
LEFT JOIN {ART_MEDIUM_TABLE} m ON a.medium_id = m.id
WHERE a.id = {artwork_id}
"""
)
row: dict = cursor.fetchone() # type: ignore
cls._close_cursor_and_conn(cursor, conn)
return cls._construct(cls, row) if row else None
@classmethod
def select_all(cls, table_name: str = ARTWORK_TABLE) -> list["Artwork"]:
cursor, conn = cls._get_cursor_and_conn()
cursor.execute(
f"""-- sql
SELECT
a.id,
a.medium_id ,
a.artwork_name ,
a.source ,
a.thumbnail ,
a.is_featured ,
a.release_year ,
a.`size` ,
m.id as medium_id,
m.medium_name
FROM {table_name} a
LEFT JOIN {ART_MEDIUM_TABLE} m ON a.medium_id = m.id
"""
)
rows: list[dict] = cursor.fetchall() # type: ignore
cls._close_cursor_and_conn(cursor, conn)
return sorted(
[cls._construct(cls, row) for row in rows],
key=lambda a: (a.is_featured, a.release_year if a.release_year else 0),
reverse=True,
)
@classmethod
def _construct(cls, Obj: Type, row: dict) -> "Artwork":
row["medium"] = (
Medium(id=row["medium_id"], medium_name=row["medium_name"])
if row.get("medium_id")
else None
)
return Obj(**row)

62
server/app/model/bio.py Normal file
View File

@@ -0,0 +1,62 @@
from pydantic import HttpUrl
from app.constants import BIO_CONTENT_TABLE, SERVICES_TABLE, SOCIAL_TABLE
from app.model.model_object import ModelObject
from app.model.response_object import ResponseObject
class ProfessionalService(ModelObject, ResponseObject):
service_name: str
@classmethod
def select_all(
cls, table_name: str = SERVICES_TABLE
) -> list["ProfessionalService"]:
return [
cls._construct(ProfessionalService, row)
for row in super().select_all(table_name)
]
@classmethod
def select_one(
cls, obj_id: int, table_name: str = SERVICES_TABLE
) -> "ProfessionalService | None":
return cls._construct(
ProfessionalService, super().select_one(obj_id, table_name)
)
class SocialUrl(ModelObject, ResponseObject):
social_name: str
social_url: HttpUrl
@classmethod
def select_one(
cls, obj_id: int, table_name: str = SOCIAL_TABLE
) -> "SocialUrl | None":
return cls._construct(SocialUrl, super().select_one(obj_id, table_name))
@classmethod
def select_all(cls, table_name: str = SOCIAL_TABLE) -> list["SocialUrl"]:
return [
cls._construct(SocialUrl, row) for row in super().select_all(table_name)
]
class Bio(ModelObject, ResponseObject):
name: str
bio: str
social_urls: list[SocialUrl]
@classmethod
def select_one(cls, table_name: str = BIO_CONTENT_TABLE) -> "Bio":
bio_data = super().select_one(1, table_name)
bio_content = bio_data.get("content", "") if bio_data else ""
socials = SocialUrl.select_all()
bio = Bio(bio=bio_content, social_urls=socials, name="Megan Johns")
del bio.id
return bio
@classmethod
def select_all(cls, **args) -> None:
raise NotImplemented

View File

@@ -0,0 +1,59 @@
from typing import Any, Optional, Type
from icecream import ic
from mysql.connector.connection import MySQLConnection
from mysql.connector.cursor import MySQLCursor
from pydantic import BaseModel
from app.db.conn import connect_db
class ModelObject:
@classmethod
def select_one(cls, obj_id: int, table_name: str = "") -> dict | None:
if not table_name:
raise Exception(
"table_name cannot be an empty string. Check default arguments."
)
cursor, conn = cls._get_cursor_and_conn()
cursor.execute(
f"""-- sql
SELECT *
FROM {table_name}
WHERE id = {obj_id};
"""
)
data: dict[Any, Any] | None = cursor.fetchone() # type: ignore
cls._close_cursor_and_conn(cursor, conn)
return data
@classmethod
def select_all(cls, table_name: str = "") -> list[dict]:
if not table_name:
raise Exception(
"table_name cannot be an empty string. Check default arguments."
)
cursor, conn = cls._get_cursor_and_conn()
cursor.execute(
f"""-- sql
SELECT *
FROM {table_name};
"""
)
data: list[dict] = cursor.fetchall() # type: ignore
cls._close_cursor_and_conn(cursor, conn)
return data
@classmethod
def _get_cursor_and_conn(cls) -> tuple[MySQLCursor, MySQLConnection]:
conn = connect_db()
return conn.cursor(dictionary=True), conn
@classmethod
def _close_cursor_and_conn(cls, cursor: MySQLCursor, conn: MySQLConnection) -> None:
cursor.close()
conn.close()
@classmethod
def _construct(cls, Obj: Type, data: dict | None) -> Any:
return Obj(**data) if data is not None else None

View File

@@ -0,0 +1,22 @@
from typing import Optional, Type
from icecream import ic
from pydantic import HttpUrl
from app.constants import QUOTES_TABLE
from app.model.model_object import ModelObject
from app.model.response_object import ResponseObject
class Quote(ModelObject, ResponseObject):
body: str
author: str
source: Optional[HttpUrl] = None
@classmethod
def select_one(cls, obj_id: int, table_name: str = QUOTES_TABLE) -> "Quote | None":
return cls._construct(cls, super().select_one(obj_id, table_name))
@classmethod
def select_all(cls, table_name: str = QUOTES_TABLE) -> list["Quote"]:
return [cls._construct(cls, row) for row in super().select_all(table_name)]

View File

@@ -0,0 +1,7 @@
from typing import Optional
from pydantic import BaseModel
class ResponseObject(BaseModel):
id: Optional[int] = None

25
server/app/model/video.py Normal file
View File

@@ -0,0 +1,25 @@
from typing import Optional, Type
from pydantic import HttpUrl
from app.constants import VIDEOS_TABLE
from app.model.model_object import ModelObject
from app.model.response_object import ResponseObject
class Video(ModelObject, ResponseObject):
title: str
subtitle: str
description: str # html
source: HttpUrl
embedded_player_iframe: str # an iframe from YouTube/Vimeo
website: Optional[HttpUrl] = None
@classmethod
def select_one(cls, obj_id: int, table_name: str = VIDEOS_TABLE) -> "Video | None":
data = super().select_one(obj_id, table_name)
return cls._construct(cls, data)
@classmethod
def select_all(cls, table_name: str = VIDEOS_TABLE) -> list["Video"]:
return [cls._construct(cls, row) for row in super().select_all(table_name)]