Implements more endpoints
This commit is contained in:
parent
5c4631c673
commit
03d5568765
5 changed files with 193 additions and 13 deletions
|
@ -34,6 +34,18 @@ impl FromRef<App> for app::config::Manager {
|
|||
}
|
||||
}
|
||||
|
||||
impl FromRef<App> for app::ddns::Manager {
|
||||
fn from_ref(app: &App) -> Self {
|
||||
app.ddns_manager.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRef<App> for app::index::Index {
|
||||
fn from_ref(app: &App) -> Self {
|
||||
app.index.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRef<App> for app::user::Manager {
|
||||
fn from_ref(app: &App) -> Self {
|
||||
app.user_manager.clone()
|
||||
|
@ -45,3 +57,9 @@ impl FromRef<App> for app::settings::Manager {
|
|||
app.settings_manager.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRef<App> for app::vfs::Manager {
|
||||
fn from_ref(app: &App) -> Self {
|
||||
app.vfs_manager.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use axum::{
|
||||
extract::State,
|
||||
routing::{get, put},
|
||||
extract::{Path, State},
|
||||
routing::{delete, get, post, put},
|
||||
Json, Router,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{config, settings, user, App},
|
||||
app::{config, ddns, index, settings, user, vfs, App},
|
||||
server::{dto, error::APIError},
|
||||
};
|
||||
|
||||
use super::auth::AdminRights;
|
||||
use super::auth::{AdminRights, Auth};
|
||||
|
||||
pub fn router() -> Router<App> {
|
||||
Router::new()
|
||||
|
@ -18,6 +18,18 @@ pub fn router() -> Router<App> {
|
|||
.route("/config", put(put_config))
|
||||
.route("/settings", get(get_settings))
|
||||
.route("/settings", put(put_settings))
|
||||
.route("/mount_dirs", get(get_mount_dirs))
|
||||
.route("/mount_dirs", put(put_mount_dirs))
|
||||
.route("/ddns", get(get_ddns))
|
||||
.route("/ddns", put(put_ddns))
|
||||
.route("/auth", post(post_auth))
|
||||
.route("/user", post(post_user))
|
||||
.route("/user/:name", delete(delete_user))
|
||||
.route("/user/:name", put(put_user))
|
||||
.route("/users", get(get_users))
|
||||
.route("/preferences", get(get_preferences))
|
||||
.route("/preferences", put(put_preferences))
|
||||
.route("/trigger_index", post(post_trigger_index))
|
||||
}
|
||||
|
||||
async fn get_version() -> Json<dto::Version> {
|
||||
|
@ -68,3 +80,142 @@ async fn put_settings(
|
|||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_mount_dirs(
|
||||
_admin_rights: AdminRights,
|
||||
State(vfs_manager): State<vfs::Manager>,
|
||||
) -> Result<Json<Vec<dto::MountDir>>, APIError> {
|
||||
let mount_dirs = vfs_manager.mount_dirs().await?;
|
||||
let mount_dirs = mount_dirs.into_iter().map(|m| m.into()).collect();
|
||||
Ok(Json(mount_dirs))
|
||||
}
|
||||
|
||||
async fn put_mount_dirs(
|
||||
_admin_rights: AdminRights,
|
||||
State(vfs_manager): State<vfs::Manager>,
|
||||
new_mount_dirs: Json<Vec<dto::MountDir>>,
|
||||
) -> Result<(), APIError> {
|
||||
let new_mount_dirs: Vec<vfs::MountDir> =
|
||||
new_mount_dirs.iter().cloned().map(|m| m.into()).collect();
|
||||
vfs_manager.set_mount_dirs(&new_mount_dirs).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_ddns(
|
||||
_admin_rights: AdminRights,
|
||||
State(ddns_manager): State<ddns::Manager>,
|
||||
) -> Result<Json<dto::DDNSConfig>, APIError> {
|
||||
let ddns_config = ddns_manager.config().await?;
|
||||
Ok(Json(ddns_config.into()))
|
||||
}
|
||||
|
||||
async fn put_ddns(
|
||||
_admin_rights: AdminRights,
|
||||
State(ddns_manager): State<ddns::Manager>,
|
||||
Json(new_ddns_config): Json<dto::DDNSConfig>,
|
||||
) -> Result<(), APIError> {
|
||||
ddns_manager.set_config(&new_ddns_config.into()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn post_auth(
|
||||
State(user_manager): State<user::Manager>,
|
||||
credentials: Json<dto::Credentials>,
|
||||
) -> Result<Json<dto::Authorization>, APIError> {
|
||||
let username = credentials.username.clone();
|
||||
|
||||
let user::AuthToken(token) = user_manager
|
||||
.login(&credentials.username, &credentials.password)
|
||||
.await?;
|
||||
let is_admin = user_manager.is_admin(&credentials.username).await?;
|
||||
|
||||
let authorization = dto::Authorization {
|
||||
username: username.clone(),
|
||||
token,
|
||||
is_admin,
|
||||
};
|
||||
|
||||
Ok(Json(authorization))
|
||||
}
|
||||
|
||||
async fn get_users(
|
||||
_admin_rights: AdminRights,
|
||||
State(user_manager): State<user::Manager>,
|
||||
) -> Result<Json<Vec<dto::User>>, APIError> {
|
||||
let users = user_manager.list().await?;
|
||||
let users = users.into_iter().map(|u| u.into()).collect();
|
||||
Ok(Json(users))
|
||||
}
|
||||
|
||||
async fn post_user(
|
||||
_admin_rights: AdminRights,
|
||||
State(user_manager): State<user::Manager>,
|
||||
Json(new_user): Json<dto::NewUser>,
|
||||
) -> Result<(), APIError> {
|
||||
user_manager.create(&new_user.into()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn put_user(
|
||||
admin_rights: AdminRights,
|
||||
State(user_manager): State<user::Manager>,
|
||||
Path(name): Path<String>,
|
||||
user_update: Json<dto::UserUpdate>,
|
||||
) -> Result<(), APIError> {
|
||||
if let Some(auth) = &admin_rights.get_auth() {
|
||||
if auth.get_username() == name.as_str() && user_update.new_is_admin == Some(false) {
|
||||
return Err(APIError::OwnAdminPrivilegeRemoval);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(password) = &user_update.new_password {
|
||||
user_manager.set_password(&name, password).await?;
|
||||
}
|
||||
|
||||
if let Some(is_admin) = &user_update.new_is_admin {
|
||||
user_manager.set_is_admin(&name, *is_admin).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn delete_user(
|
||||
admin_rights: AdminRights,
|
||||
State(user_manager): State<user::Manager>,
|
||||
Path(name): Path<String>,
|
||||
) -> Result<(), APIError> {
|
||||
if let Some(auth) = &admin_rights.get_auth() {
|
||||
if auth.get_username() == name.as_str() {
|
||||
return Err(APIError::DeletingOwnAccount);
|
||||
}
|
||||
}
|
||||
user_manager.delete(&name).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_preferences(
|
||||
auth: Auth,
|
||||
State(user_manager): State<user::Manager>,
|
||||
) -> Result<Json<user::Preferences>, APIError> {
|
||||
let preferences = user_manager.read_preferences(auth.get_username()).await?;
|
||||
Ok(Json(preferences))
|
||||
}
|
||||
|
||||
async fn put_preferences(
|
||||
auth: Auth,
|
||||
State(user_manager): State<user::Manager>,
|
||||
Json(preferences): Json<user::Preferences>,
|
||||
) -> Result<(), APIError> {
|
||||
user_manager
|
||||
.write_preferences(auth.get_username(), &preferences)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn post_trigger_index(
|
||||
_admin_rights: AdminRights,
|
||||
State(index): State<index::Index>,
|
||||
) -> Result<(), APIError> {
|
||||
index.trigger_reindex();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -15,6 +15,12 @@ pub struct Auth {
|
|||
username: String,
|
||||
}
|
||||
|
||||
impl Auth {
|
||||
pub fn get_username(&self) -> &String {
|
||||
return &self.username;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for Auth
|
||||
where
|
||||
|
@ -58,6 +64,12 @@ pub struct AdminRights {
|
|||
auth: Option<Auth>,
|
||||
}
|
||||
|
||||
impl AdminRights {
|
||||
pub fn get_auth(&self) -> &Option<Auth> {
|
||||
return &self.auth;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for AdminRights
|
||||
where
|
||||
|
@ -69,14 +81,12 @@ where
|
|||
async fn from_request_parts(parts: &mut Parts, app: &S) -> Result<Self, Self::Rejection> {
|
||||
let user_manager = user::Manager::from_ref(app);
|
||||
|
||||
let auth_future = Auth::from_request_parts(parts, app);
|
||||
|
||||
let user_count = user_manager.count().await?;
|
||||
if user_count == 0 {
|
||||
return Ok(AdminRights { auth: None });
|
||||
}
|
||||
|
||||
let auth = auth_future.await?;
|
||||
let auth = Auth::from_request_parts(parts, app).await?;
|
||||
if user_manager.is_admin(&auth.username).await? {
|
||||
Ok(AdminRights { auth: Some(auth) })
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ impl IntoResponse for APIError {
|
|||
let message = self.to_string();
|
||||
let status_code = match self {
|
||||
APIError::AuthorizationTokenEncoding => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::AdminPermissionRequired => StatusCode::UNAUTHORIZED,
|
||||
APIError::AdminPermissionRequired => StatusCode::FORBIDDEN,
|
||||
APIError::AudioFileIOError => StatusCode::NOT_FOUND,
|
||||
APIError::AuthenticationRequired => StatusCode::UNAUTHORIZED,
|
||||
APIError::BrancaTokenEncoding => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
|
|
|
@ -32,13 +32,14 @@ async fn get_ddns_config_golden_path() {
|
|||
#[tokio::test]
|
||||
async fn put_ddns_config_requires_admin() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
let request = protocol::put_ddns_config(dto::DDNSConfig {
|
||||
host: "test".to_owned(),
|
||||
username: "test".to_owned(),
|
||||
password: "test".to_owned(),
|
||||
});
|
||||
service.complete_initial_setup().await;
|
||||
|
||||
let request = protocol::put_ddns_config(dto::DDNSConfig {
|
||||
host: "host".to_owned(),
|
||||
username: "ddns_user".to_owned(),
|
||||
password: "ddns_password".to_owned(),
|
||||
});
|
||||
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue