Skip to content

Commit

Permalink
Add db connections and migrations. Add a script for populating user a…
Browse files Browse the repository at this point in the history
…lbum/playlist data.
  • Loading branch information
CalPinSW committed Sep 1, 2024
1 parent ddc4b71 commit 6bca25c
Show file tree
Hide file tree
Showing 18 changed files with 410 additions and 2 deletions.
1 change: 1 addition & 0 deletions ansible/.ansible-secrets.template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ spotify_client_id: spotify_client_id
spotify_secret: spotify_secret
debug_mode: false
flask_secret_key: flask_secret_key
db_connection_string: postgresql://username:password@hostname:port/database
3 changes: 3 additions & 0 deletions backend/.env.j2
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ SECRET_KEY={{flask_secret_key}}
SPOTIFY_CLIENT_ID={{spotify_client_id}}
SPOTIFY_SECRET={{spotify_secret}}
SPOTIFY_REDIRECT_URI="{{backend_url}}/auth/get-user-code"

# Database Connection String
DB_CONNECTION_STRING=postgresql://username:password@hostname:port/database
3 changes: 3 additions & 0 deletions backend/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ SECRET_KEY="secret-key"
SPOTIFY_CLIENT_ID="https://developer.spotify.com/dashboard"
SPOTIFY_SECRET="https://developer.spotify.com/dashboard"
SPOTIFY_REDIRECT_URI="http://localhost:8080/spotify-redirect"

# Database Connection String
DB_CONNECTION_STRING=postgresql://username:password@hostname:port/database
3 changes: 3 additions & 0 deletions backend/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ SECRET_KEY="secret-key"
SPOTIFY_CLIENT_ID="https://developer.spotify.com/dashboard"
SPOTIFY_SECRET="https://developer.spotify.com/dashboard"
SPOTIFY_REDIRECT_URI="http://localhost:8080/spotify-redirect"

# Database Connection String
DB_CONNECTION_STRING=postgresql://username:password@hostname:port/database
81 changes: 80 additions & 1 deletion backend/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ flask-cors = "^4.0.1"
pydantic = "^2.6.4"
requests = "^2.32.3"
gunicorn = "^22.0.0"
peewee = "^3.17.6"
psycopg = "^3.2.1"
asyncio = "^3.4.3"
psycopg2 = "^2.9.9"

[tool.poetry.group.dev.dependencies]
pytest = "^8.1.1"
Expand Down
3 changes: 3 additions & 0 deletions backend/src/app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from flask import Flask, make_response
from flask_cors import CORS
from src.controllers.database import database_controller
from src.controllers.spotify import spotify_controller
from src.exceptions.Unauthorized import UnauthorizedException
from src.flask_config import Config
Expand Down Expand Up @@ -44,4 +45,6 @@ def handle_unauthorized_exception(_):

app.register_blueprint(auth_controller(spotify=spotify))
app.register_blueprint(spotify_controller(spotify=spotify))
app.register_blueprint(database_controller(spotify=spotify))

return app
55 changes: 55 additions & 0 deletions backend/src/controllers/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from logging import Logger
from flask import Blueprint, make_response, request

from src.database.crud.playlist import (
create_playlist,
get_playlist_by_id_or_none,
update_playlist,
)
from src.database.crud.user import get_or_create_user
from src.spotify import SpotifyClient


def database_controller(spotify: SpotifyClient):
database_controller = Blueprint(
name="database_controller", import_name=__name__, url_prefix="/database"
)

@database_controller.route("populate_user", methods=["GET"])
def populate_user():
access_token = request.cookies.get("spotify_access_token")
user = spotify.get_current_user(access_token)
simplified_playlists = spotify.get_all_playlists(
user_id=user.id, access_token=access_token
)
get_or_create_user(user)

for simplified_playlist in simplified_playlists:
if "Albums" in simplified_playlist.name:
db_playlist = get_playlist_by_id_or_none(simplified_playlist.id)

if db_playlist is None:
[playlist, albums] = [
spotify.get_playlist(
access_token=access_token, id=simplified_playlist.id
),
spotify.get_playlist_album_info(
access_token=access_token, id=simplified_playlist.id
),
]
create_playlist(playlist, albums)
else:
if db_playlist.snapshot_id != simplified_playlist.snapshot_id:
[playlist, albums] = [
spotify.get_playlist(
access_token=access_token, id=simplified_playlist.id
),
spotify.get_playlist_album_info(
access_token=access_token, id=simplified_playlist.id
),
]
update_playlist(playlist, albums)

return make_response("Playlist data populated", 201)

return database_controller
2 changes: 2 additions & 0 deletions backend/src/controllers/spotify.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from logging import Logger
from flask import Blueprint, make_response, request
from src.dataclasses.playback_info import PlaybackInfo
from src.dataclasses.playback_request import StartPlaybackRequest
from src.dataclasses.playlist import Playlist
from src.spotify import SpotifyClient
import sys


def spotify_controller(spotify: SpotifyClient):
Expand Down
37 changes: 37 additions & 0 deletions backend/src/database/crud/album.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from src.dataclasses.album import Album
from src.database.models import (
AlbumArtistRelationship,
AlbumGenreRelationship,
DbGenre,
DbAlbum,
DbArtist,
)


def create_album_or_none(album: Album):
if DbAlbum.get_or_none(DbAlbum.id == album.id):
return
album = DbAlbum.create(
id=album.id,
album_type=album.album_type,
total_tracks=album.total_tracks,
image_url=album.images[0].url if album.images else None,
name=album.name,
release_date=album.release_date,
release_date_precision=album.release_date_precision,
label=album.label,
uri=album.uri,
)
for artist in album.artists:
DbArtist.get_or_create(
id=artist.id,
image_url=album.images[0].url if album.images else None,
name=artist.name,
uri=artist.uri,
)
AlbumArtistRelationship.create(album=album.id, artist=artist.id)
for genre in album.genres or []:
db_genre = DbGenre.get_or_create(name=genre)
AlbumGenreRelationship.create(album=album.id, genre=db_genre.id)

return album
46 changes: 46 additions & 0 deletions backend/src/database/crud/playlist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from typing import List
from src.database.crud.album import create_album_or_none
from src.database.models import DbPlaylist, PlaylistAlbumRelationship
from src.dataclasses.album import Album
from src.dataclasses.playlist import Playlist


def get_playlist_by_id_or_none(id: str):
return DbPlaylist.get_or_none(DbPlaylist.id == id)


def create_playlist(playlist: Playlist, albums: List[Album]):
playlist = DbPlaylist.create(
id=playlist.id,
description=playlist.description,
image_url=playlist.images[0].url if playlist.images else None,
name=playlist.name,
owner=playlist.owner.id,
snapshot_id=playlist.snapshot_id,
uri=playlist.uri,
)

for album in albums:
create_album_or_none(album)
PlaylistAlbumRelationship.create(playlist=playlist.id, album=album.id)

return playlist


def update_playlist(playlist: Playlist, albums: List[Album]):
playlist = DbPlaylist.update(
id=playlist.id,
description=playlist.description,
image_url=playlist.images[0].url if playlist.images else None,
name=playlist.name,
owner=playlist.owner.id,
snapshot_id=playlist.snapshot_id,
uri=playlist.uri,
)
PlaylistAlbumRelationship.delete().where(playlist=playlist.id)

for album in albums:
create_album_or_none(album)
PlaylistAlbumRelationship.create(playlist=playlist.id, album=album.id)

return playlist
28 changes: 28 additions & 0 deletions backend/src/database/crud/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from src.database.models import DbUser
from src.dataclasses.user import User


def get_user_by_id(id: str):
return DbUser.get(
DbUser.id == id,
)


def create_user(user: User):
return DbUser.create(
id=user.id,
display_name=user.display_name,
image_url=user.images[-1].url,
uri=user.uri,
)


def get_or_create_user(user: User):
return DbUser.get_or_create(
id=user.id,
defaults={
"display_name": user.display_name,
"image_url": user.images[-1].url,
"uri": user.uri,
},
)
43 changes: 43 additions & 0 deletions backend/src/database/migrations/init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from src.database.models import (
DbAlbum,
AlbumArtistRelationship,
AlbumGenreRelationship,
DbArtist,
DbGenre,
DbPlaylist,
PlaylistAlbumRelationship,
DbUser,
database,
)


def up():
with database:
database.create_tables(
[
DbUser,
DbPlaylist,
DbAlbum,
DbArtist,
DbGenre,
PlaylistAlbumRelationship,
AlbumArtistRelationship,
AlbumGenreRelationship,
]
)


def down():
with database:
database.drop_tables(
[
DbUser,
DbPlaylist,
DbAlbum,
DbArtist,
DbGenre,
PlaylistAlbumRelationship,
AlbumArtistRelationship,
AlbumGenreRelationship,
]
)
Loading

0 comments on commit 6bca25c

Please sign in to comment.