Add interface package. Start adding auth stuff for refreshing tokens.

This commit is contained in:
jude
2023-09-12 19:35:49 +01:00
parent 5ff56d8396
commit 08cc752932
20 changed files with 4934 additions and 67 deletions

View File

@ -35,4 +35,4 @@ pub async fn update_playlists_daemon() -> Result<(), Box<dyn std::error::Error>>
}
}
async fn update_playlist(playlist: TrackedPlaylist) {}
async fn update_playlist(_playlist: TrackedPlaylist) {}

View File

@ -2,17 +2,16 @@ mod daemon;
mod listenbrainz;
mod models;
use navidrome::{
client::{builder::NavidromeBuilder, library::Library},
models::navidrome::NavidromeTrack,
};
use navidrome::{client::builder::NavidromeBuilder, models::navidrome::NavidromeTrack};
use crate::daemon::{update_playlists_daemon, update_tracks_daemon};
use crate::listenbrainz::StatsRange;
use crate::models::{PartialTrackedPlaylist, TrackedPlaylist};
use axum::extract::State;
use axum::routing::get;
use axum::Router;
use axum::routing::{get, put};
use axum::{extract, Json, Router};
use serde::Serialize;
use sqlx::postgres::PgPool;
use sqlx::Error;
use std::collections::HashMap;
use std::env;
use std::net::SocketAddr;
@ -50,7 +49,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.unwrap();
});
let app = Router::new().route("/", get(index)).with_state(database);
let app = Router::new()
.route("/playlists", get(all_playlists))
.route("/playlists", put(create_playlist))
.with_state(database)
.with_state(state);
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
@ -60,15 +63,38 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
async fn index(State(pool): State<PgPool>) -> String {
let response = listenbrainz::recordings(env::var("LISTENBRAINZ_USER")?, StatsRange::Week)
.await
.unwrap();
response
.recordings
.iter()
.map(|a| a.track_name.clone())
.collect::<Vec<String>>()
.join(", ")
#[derive(Serialize)]
struct JsonError {
error: String,
}
impl From<Error> for JsonError {
fn from(value: Error) -> Self {
Self {
error: value.to_string(),
}
}
}
#[derive(Serialize)]
enum Response<T> {
Success(T),
Error(JsonError),
}
async fn create_playlist(
State(pool): State<PgPool>,
extract::Json(partial): extract::Json<PartialTrackedPlaylist>,
) -> Json<Response<TrackedPlaylist>> {
match partial.record(&pool).await {
Ok(playlist) => Json(Response::Success(playlist)),
Err(e) => Json(Response::Error(e.into())),
}
}
async fn all_playlists(State(pool): State<PgPool>) -> Json<Vec<TrackedPlaylist>> {
match TrackedPlaylist::all(&pool).await {
Ok(playlists) => Json(playlists),
Err(_) => Json(vec![]),
}
}

View File

@ -1,11 +1,71 @@
use sqlx::types::Uuid;
use serde::{Deserialize, Serialize};
use sqlx::error::Error;
use sqlx::types::Uuid as UuidType;
use sqlx::{Executor, Postgres};
use uuid::Uuid;
pub struct TrackedPlaylist {
pub rule_id: i64,
pub playlist_id: Option<Uuid>,
#[derive(Deserialize)]
pub struct PartialTrackedPlaylist {
pub playlist_name: Option<String>,
pub playlist_size: i32,
pub tracking_user: Option<String>,
pub tracking_type: Option<String>,
pub reduce_duplication_on: Option<String>,
}
impl PartialTrackedPlaylist {
pub async fn record(
&self,
pool: impl Executor<'_, Database = Postgres> + Copy,
) -> Result<TrackedPlaylist, Error> {
let uuid = Uuid::new_v4();
sqlx::query!(
r#"INSERT INTO "tracked_playlist"
(rule_id, playlist_name, playlist_size, tracking_user, tracking_type, reduce_duplication_on)
VALUES ($1, $2, $3, $4, $5, $6)"#,
uuid,
self.playlist_name,
self.playlist_size,
self.tracking_user,
self.tracking_type,
self.reduce_duplication_on,
)
.execute(pool)
.await?;
TrackedPlaylist::rule(pool, uuid).await
}
}
#[derive(Serialize)]
pub struct TrackedPlaylist {
pub rule_id: Uuid,
pub playlist_id: Option<UuidType>,
pub playlist_name: Option<String>,
pub playlist_size: i32,
pub tracking_user: Option<String>,
pub tracking_type: Option<String>,
pub reduce_duplication_on: Option<String>,
}
impl TrackedPlaylist {
pub async fn all(pool: impl Executor<'_, Database = Postgres>) -> Result<Vec<Self>, Error> {
sqlx::query_as!(Self, r#"SELECT * FROM "tracked_playlist""#)
.fetch_all(pool)
.await
}
pub async fn rule(
pool: impl Executor<'_, Database = Postgres>,
uuid: Uuid,
) -> Result<Self, Error> {
sqlx::query_as!(
Self,
r#"SELECT * FROM "tracked_playlist" WHERE rule_id = $1"#,
uuid
)
.fetch_one(pool)
.await
}
}