Skip to content

Commit ce23fe5

Browse files
committed
AAAAAAA DONE ok testing time
1 parent 47d83ea commit ce23fe5

1 file changed

Lines changed: 189 additions & 8 deletions

File tree

qwave-server/src/qwave/api/tracks.py

Lines changed: 189 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33
from typing import List, Optional
44
from pathlib import Path
55
from fastapi import APIRouter, HTTPException, status, UploadFile, File
6-
from pydantic import BaseModel, Field
6+
from pydantic import BaseModel,
7+
from datetime import datetime
78
from sqlalchemy.orm import Session
89

910
from qwave.models import User, Track, Artist, Album, Genre, Job, track_artists, track_genres
1011
from qwave.config import get_config
1112
from qwave.depends import DBDep, UserDep
13+
from qwave.services import import_service
14+
from qwave.utils.log_item import log_item
15+
from qwave.workers.worker import queue_job
1216

1317
router = APIRouter()
1418

@@ -95,6 +99,7 @@ class GenreRequest(BaseModel):
9599
class MessageResponse(BaseModel):
96100
message: str
97101

102+
98103
@router.get("", response_model = TrackListResponse)
99104
def list_tracks(
100105
user: UserDep,
@@ -108,20 +113,146 @@ def list_tracks(
108113
limit: int = 128,
109114
offset: int = 0,
110115
):
111-
pass
116+
query = db.query(Track)
117+
118+
if artist_id:
119+
query = query.join(track_artists).filter(track_artists.c.artist_id == artist_id)
120+
if album_id:
121+
query = query.filter(Track.album_id == album_id)
122+
if genre_id:
123+
query = query.join(track_genres).filter(track_genres.c.genre_id == genre_id)
124+
if added_by:
125+
query = query.filter(Track.added_by_user_id == added_by)
126+
if date_from:
127+
query = query.filter(Track.added_date >= datetime.fromisoformat(date_from))
128+
if date_to:
129+
query = query.filter(Track.added_date <= datetime.fromisoformat(date_to))
130+
131+
query = query.order_by()
132+
total = query.count()
133+
tracks = query.limit(limit).offset(offset).all()
134+
135+
return TrackListResponse(
136+
tracks = [
137+
TrackSummary(
138+
id = t.id,
139+
title = t.title,
140+
duration = int(t.duration),
141+
artists = [
142+
ArtistInfo(
143+
id = a.id,
144+
name = a.name,
145+
is_primary = is_primary_artist(db, t.id, a.id)
146+
) for a in t.artists
147+
],
148+
album = AlbumInfo(
149+
id = t.album.id,
150+
title = t.album.title,
151+
release_date = t.album.release_date.isoformat() if t.album.release_date else None
152+
) if t.album else None,
153+
added_date = t.added_date.isoformat()
154+
) for t in tracks
155+
], total = total
156+
)
157+
112158

113159
@router.get("/{track_id}", response_model = TrackDetail)
114160
def get_track(user: UserDep, db: DBDep, track_id: int):
115-
pass
161+
track = db.query(Track).filter(Track.id == track_id).first()
162+
if not track:
163+
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND, detail = "Track not found!")
116164

117-
# TODO: allow adding data to track on upload instead of after
165+
return TrackDetail(
166+
id = track.id,
167+
title = track.title,
168+
duration = int(track.duration),
169+
track_number = track.track_number,
170+
artists = [
171+
ArtistInfo(
172+
id = a.id, name = a.name, is_primary = is_primary_artist(db, track.id, a.id)
173+
) for a in track.artists
174+
],
175+
album = AlbumInfo(
176+
id = track.album.id,
177+
title = track.album.title,
178+
release_date = track.album.release_date.isoformat() if track.album.release_date else None
179+
) if track.album else None,
180+
genres = [GenreInfo(id = g.id, name = g.name) for g in track.genres],
181+
lyrics = track.lyrics,
182+
added_date = track.added_date.isoformat(),
183+
added_by = UserInfo(id = track.added_by.id, username = track.added_by.username)
184+
)
185+
186+
# TODO: MAYBE: allow adding data to track on upload instead of after
118187
@router.post("/upload", response_model = UploadResponse)
119188
async def upload_track(user: UserDep, db: DBDep, file: UploadFile = File(...)):
120-
pass
189+
config = get_config()
190+
max_size = config.max_upload_size_mb * (1024 ** 2)
191+
192+
if not file.filename:
193+
raise Exception("WHAT DID YOU DO") # just here to get pyright to shut up
194+
195+
with tempfile.NamedTemporaryFile(delete = False, suffix = Path(file.filename).suffix) as tmp:
196+
content = await file.read()
197+
if len(content) > max_size:
198+
Path(tmp.name).unlink()
199+
raise HTTPException(status_code = status.HTTP_413_CONTENT_TOO_LARGE, detail = "file too large!")
200+
tmp.write(content)
201+
tmp_path = Path(tmp.name)
202+
203+
try:
204+
result = import_service.handle_upload(db = db, file_path = tmp_path, filename = file.filename, user_id = user.id)
205+
job = db.query(Job).filter(Job.id == result["job_id"]).first()
206+
if job:
207+
queue_job(job)
208+
209+
return UploadResponse(
210+
job_id = result["job_id"],
211+
track_id = result["track_id"],
212+
status = result["status"]
213+
)
214+
215+
except ValueError as e:
216+
tmp_path.unlink()
217+
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST, detail = str(e))
218+
219+
finally:
220+
if tmp_path.exists():
221+
tmp_path.unlink()
121222

223+
# TODO: add the rest of the fields? gotta do it different
122224
@router.patch("/{track_id}", response_model = UpdateTrackResponse)
123225
def update_track(user: UserDep, db: DBDep, track_id: int, request: UpdateTrackRequest): # can i just tack this onto upload_track()?
124-
pass
226+
track = db.query(Track).filter(Track.id == track_id).first()
227+
if not track:
228+
raise HTTPException(status.HTTP_404_NOT_FOUND, detail = "Trakc not found!")
229+
# too lazy to add the legacy permission check
230+
231+
updated_fields = []
232+
233+
if request.title is not None:
234+
track.title = request.title
235+
updated_fields.append("title")
236+
if request.track_number is not None:
237+
track.track_number = request.track_number
238+
updated_fields.append("track_number")
239+
if request.lyrics is not None:
240+
track.lyrics = request.lyrics
241+
updated_fields.append("lyrics")
242+
243+
db.commit()
244+
db.refresh(track)
245+
246+
return UpdateTrackResponse(
247+
id = track.id,
248+
updated_fields = updated_fields,
249+
track = {
250+
"id": track.id,
251+
"title": track.title,
252+
"track_number": track.track_number,
253+
"lyrics": track.lyrics
254+
}
255+
)
125256

126257
# i will hack this club
127258
@router.delete("/{track_id}", response_model = DeleteTrackResponse)
@@ -142,6 +273,7 @@ def delete_track(user: UserDep, db: DBDep, track_id: int):
142273
db.commit()
143274
return DeleteTrackResponse(message = f"Deleted track {track_id}", id = track_id)
144275

276+
145277
@router.get("/{track_id}/artists", response_model = ArtistListResponse)
146278
def get_track_artists(user: UserDep, db: DBDep, track_id: int):
147279
track = db.query(Track).filter(Track.id == track_id).first()
@@ -153,9 +285,41 @@ def get_track_artists(user: UserDep, db: DBDep, track_id: int):
153285
) for a in track.artists ]
154286
)
155287

288+
156289
@router.post("/{track_id}/artists", response_model = AddArtistResponse)
157290
def add_track_artist(user: UserDep, db: DBDep, track_id: int, request: AddArtistRequest):
158-
pass
291+
track = db.query(Track).filter(Track.id == track_id).first()
292+
artist = db.query(Artist).filter(Artist.id == request.artist_id).first()
293+
294+
if not track:
295+
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND, detail = "Track not found...")
296+
if not artist:
297+
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND, detail = "Artist not found...")
298+
# if track.added_by_user_id != user.id:
299+
# raise HTTPException(status_code = status.HTTP_403_FORBIDDEN, detail = "You don't own this...")
300+
301+
existing = db.execute( track_artists.select().where(
302+
track_artists.c.track_id == track_id,
303+
track_artists.c.artist_id == request.artist_id
304+
)).first()
305+
306+
if existing:
307+
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST, detail = "Artist already selected!")
308+
309+
db.execute(
310+
track_artists.insert().values(
311+
track_id = track_id,
312+
artist_id = request.artist_id,
313+
is_primary = request.is_primary
314+
))
315+
db.commit()
316+
317+
return AddArtistResponse(
318+
message = "Artist added :)",
319+
track_id = track_id,
320+
artist = ArtistInfo(id = artist.id, name = artist.name, is_primary = request.is_primary)
321+
)
322+
159323

160324
@router.delete("/{track_id}/artists/{artist_id}", response_model = MessageResponse)
161325
def remove_track_artist(user: UserDep, db: DBDep, track_id: int, artist_id: int):
@@ -174,9 +338,25 @@ def remove_track_artist(user: UserDep, db: DBDep, track_id: int, artist_id: int)
174338

175339
return MessageResponse(message = f"Removed artist {artist_id} from track {track_id}")
176340

341+
177342
@router.post("/{track_id}/genres", response_model = MessageResponse)
178343
def add_track_genre(user: UserDep, db: DBDep, track_id: int, request: GenreRequest):
179-
pass
344+
track = db.query(Track).filter(Track.id == track_id).first()
345+
genre = db.query(Genre).filter(Genre.id == request.genre_id).first()
346+
347+
if not track:
348+
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND, detail = "Track not found!")
349+
if not genre:
350+
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND, detail = "Genre not found!")
351+
# auth here?
352+
353+
db.execute(
354+
track_genres.insert().values(
355+
track_id = track_id,
356+
genre_id = request.genre_id
357+
)
358+
)
359+
return MessageResponse(message = "Genre added!")
180360

181361
@router.delete("/{track_id}/genres/{genre_id}", response_model = MessageResponse)
182362
def remove_track_genre(user: UserDep, db: DBDep, track_id: int, genre_id: int):
@@ -195,6 +375,7 @@ def remove_track_genre(user: UserDep, db: DBDep, track_id: int, genre_id: int):
195375
db.commit()
196376
return MessageResponse(message = f"Removed genre {genre_id} from {track_id}")
197377

378+
198379
def is_primary_artist(db: Session, track_id: int, artist_id: int) -> bool:
199380
result = db.execute(
200381
track_artists.select().where(

0 commit comments

Comments
 (0)