Compare commits
1 Commits
421ec3199b
...
f6b363c40f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6b363c40f |
@@ -48,8 +48,7 @@ pub fn get_session_user(session: &Session) -> Option<(i32, String, String)> {
|
|||||||
|
|
||||||
/// Require authentication. Returns (user_id, username, role) or 401.
|
/// Require authentication. Returns (user_id, username, role) or 401.
|
||||||
pub fn require_auth(session: &Session) -> Result<(i32, String, String), ApiError> {
|
pub fn require_auth(session: &Session) -> Result<(i32, String, String), ApiError> {
|
||||||
get_session_user(session)
|
get_session_user(session).ok_or_else(|| ApiError::Unauthorized("not logged in".into()))
|
||||||
.ok_or_else(|| ApiError::Unauthorized("not logged in".into()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Require admin role. Returns (user_id, username, role) or 403.
|
/// Require admin role. Returns (user_id, username, role) or 403.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Web interface backend for Shanty.
|
//! Web interface backend for Shanty.
|
||||||
//!
|
//!
|
||||||
//! An Actix-web server that ties all Shanty components together, exposing a REST
|
//! An Actix-web server that ties all Shanty components together, exposing a REST
|
||||||
//! API consumed by the Elm frontend. Handles background tasks, configuration,
|
//! API consumed by the Yew (WASM) frontend. Handles background tasks, configuration,
|
||||||
//! and orchestration of indexing, tagging, downloading, and more.
|
//! and orchestration of indexing, tagging, downloading, and more.
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
|
|||||||
@@ -98,10 +98,11 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(cors)
|
.wrap(cors)
|
||||||
.wrap(SessionMiddleware::builder(
|
.wrap(
|
||||||
CookieSessionStore::default(),
|
SessionMiddleware::builder(CookieSessionStore::default(), session_key.clone())
|
||||||
session_key.clone(),
|
.cookie_secure(false)
|
||||||
).cookie_secure(false).build())
|
.build(),
|
||||||
|
)
|
||||||
.wrap(TracingLogger::default())
|
.wrap(TracingLogger::default())
|
||||||
.app_data(state.clone())
|
.app_data(state.clone())
|
||||||
.configure(routes::configure)
|
.configure(routes::configure)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use actix_session::Session;
|
use actix_session::Session;
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{HttpResponse, web};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use shanty_db::entities::user::UserRole;
|
use shanty_db::entities::user::UserRole;
|
||||||
@@ -76,7 +76,11 @@ async fn setup(
|
|||||||
// Adopt any orphaned wanted items from before auth was added
|
// Adopt any orphaned wanted items from before auth was added
|
||||||
let adopted = queries::users::adopt_orphaned_wanted_items(state.db.conn(), user.id).await?;
|
let adopted = queries::users::adopt_orphaned_wanted_items(state.db.conn(), user.id).await?;
|
||||||
if adopted > 0 {
|
if adopted > 0 {
|
||||||
tracing::info!(count = adopted, user_id = user.id, "adopted orphaned wanted items");
|
tracing::info!(
|
||||||
|
count = adopted,
|
||||||
|
user_id = user.id,
|
||||||
|
"adopted orphaned wanted items"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth::set_session(&session, user.id, &user.username, "admin");
|
auth::set_session(&session, user.id, &user.username, "admin");
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ async fn enqueue_download(
|
|||||||
Ok(HttpResponse::Ok().json(item))
|
Ok(HttpResponse::Ok().json(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn sync_downloads(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn sync_downloads(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let stats = shanty_dl::sync_wanted_to_queue(state.db.conn(), false).await?;
|
let stats = shanty_dl::sync_wanted_to_queue(state.db.conn(), false).await?;
|
||||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||||
@@ -67,7 +70,10 @@ async fn sync_downloads(state: web::Data<AppState>, session: Session) -> Result<
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trigger_process(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn trigger_process(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let task_id = state.tasks.register("download");
|
let task_id = state.tasks.register("download");
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_status(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn get_status(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let summary = shanty_watch::library_summary(state.db.conn()).await?;
|
let summary = shanty_watch::library_summary(state.db.conn()).await?;
|
||||||
let pending_items =
|
let pending_items =
|
||||||
@@ -61,7 +64,10 @@ async fn get_status(state: web::Data<AppState>, session: Session) -> Result<Http
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trigger_index(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn trigger_index(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let task_id = state.tasks.register("index");
|
let task_id = state.tasks.register("index");
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
@@ -86,7 +92,10 @@ async fn trigger_index(state: web::Data<AppState>, session: Session) -> Result<H
|
|||||||
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trigger_tag(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn trigger_tag(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let task_id = state.tasks.register("tag");
|
let task_id = state.tasks.register("tag");
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
@@ -119,7 +128,10 @@ async fn trigger_tag(state: web::Data<AppState>, session: Session) -> Result<Htt
|
|||||||
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trigger_organize(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn trigger_organize(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let task_id = state.tasks.register("organize");
|
let task_id = state.tasks.register("organize");
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
@@ -156,7 +168,10 @@ async fn trigger_organize(state: web::Data<AppState>, session: Session) -> Resul
|
|||||||
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trigger_pipeline(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn trigger_pipeline(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let sync_id = state.tasks.register_pending("sync");
|
let sync_id = state.tasks.register_pending("sync");
|
||||||
let download_id = state.tasks.register_pending("download");
|
let download_id = state.tasks.register_pending("download");
|
||||||
@@ -326,7 +341,10 @@ async fn get_task(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_watchlist(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn list_watchlist(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let (user_id, _, _) = auth::require_auth(&session)?;
|
let (user_id, _, _) = auth::require_auth(&session)?;
|
||||||
let items = shanty_watch::list_items(state.db.conn(), None, None, Some(user_id)).await?;
|
let items = shanty_watch::list_items(state.db.conn(), None, None, Some(user_id)).await?;
|
||||||
Ok(HttpResponse::Ok().json(items))
|
Ok(HttpResponse::Ok().json(items))
|
||||||
@@ -343,7 +361,10 @@ async fn remove_watchlist(
|
|||||||
Ok(HttpResponse::NoContent().finish())
|
Ok(HttpResponse::NoContent().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_config(state: web::Data<AppState>, session: Session) -> Result<HttpResponse, ApiError> {
|
async fn get_config(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
session: Session,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
auth::require_auth(&session)?;
|
auth::require_auth(&session)?;
|
||||||
let config = state.config.read().await;
|
let config = state.config.read().await;
|
||||||
Ok(HttpResponse::Ok().json(&*config))
|
Ok(HttpResponse::Ok().json(&*config))
|
||||||
|
|||||||
Reference in New Issue
Block a user