Skip to content

Commit

Permalink
refactor: [#157] extract service: settings
Browse files Browse the repository at this point in the history
Decoupling services from actix-web framework.
  • Loading branch information
josecelano committed May 18, 2023
1 parent c9fb249 commit 0387b97
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 50 deletions.
4 changes: 3 additions & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crate::common::AppData;
use crate::config::Configuration;
use crate::databases::database;
use crate::services::category::{self, DbCategoryRepository};
use crate::services::proxy;
use crate::services::user::DbUserRepository;
use crate::services::{proxy, settings};
use crate::tracker::statistics_importer::StatisticsImporter;
use crate::{mailer, routes, tracker};

Expand Down Expand Up @@ -55,6 +55,7 @@ pub async fn run(configuration: Configuration) -> Running {
let user_repository = Arc::new(DbUserRepository::new(database.clone()));
let category_service = Arc::new(category::Service::new(category_repository.clone(), user_repository.clone()));
let proxy_service = Arc::new(proxy::Service::new(image_cache_service.clone(), user_repository.clone()));
let settings_service = Arc::new(settings::Service::new(cfg.clone(), user_repository.clone()));

// Build app container

Expand All @@ -70,6 +71,7 @@ pub async fn run(configuration: Configuration) -> Running {
user_repository,
category_service,
proxy_service,
settings_service,
));

// Start repeating task to import tracker torrent data and updating
Expand Down
5 changes: 4 additions & 1 deletion src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::cache::image::manager::ImageCacheService;
use crate::config::Configuration;
use crate::databases::database::Database;
use crate::services::category::{self, DbCategoryRepository};
use crate::services::proxy;
use crate::services::user::DbUserRepository;
use crate::services::{proxy, settings};
use crate::tracker::statistics_importer::StatisticsImporter;
use crate::{mailer, tracker};
pub type Username = String;
Expand All @@ -25,6 +25,7 @@ pub struct AppData {
pub user_repository: Arc<DbUserRepository>,
pub category_service: Arc<category::Service>,
pub proxy_service: Arc<proxy::Service>,
pub settings_service: Arc<settings::Service>,
}

impl AppData {
Expand All @@ -41,6 +42,7 @@ impl AppData {
user_repository: Arc<DbUserRepository>,
category_service: Arc<category::Service>,
proxy_service: Arc<proxy::Service>,
settings_service: Arc<settings::Service>,
) -> AppData {
AppData {
cfg,
Expand All @@ -54,6 +56,7 @@ impl AppData {
user_repository,
category_service,
proxy_service,
settings_service,
}
}
}
12 changes: 12 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,12 @@ impl Configuration {
}
}

pub async fn get_all(&self) -> TorrustBackend {
let settings_lock = self.settings.read().await;

settings_lock.clone()
}

pub async fn get_public(&self) -> ConfigurationPublic {
let settings_lock = self.settings.read().await;

Expand All @@ -331,6 +337,12 @@ impl Configuration {
email_on_signup: settings_lock.auth.email_on_signup.clone(),
}
}

pub async fn get_site_name(&self) -> String {
let settings_lock = self.settings.read().await;

settings_lock.website.name.clone()
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down
84 changes: 36 additions & 48 deletions src/routes/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ use actix_web::{web, HttpRequest, HttpResponse, Responder};

use crate::common::WebAppData;
use crate::config;
use crate::errors::{ServiceError, ServiceResult};
use crate::errors::ServiceResult;
use crate::models::response::OkResponse;
use crate::routes::API_VERSION;

pub fn init(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope(&format!("/{API_VERSION}/settings"))
.service(web::resource("").route(web::get().to(get)).route(web::post().to(update)))
.service(web::resource("/name").route(web::get().to(site_name)))
.service(web::resource("/public").route(web::get().to(get_public))),
.service(
web::resource("")
.route(web::get().to(get_all_handler))
.route(web::post().to(update_handler)),
)
.service(web::resource("/name").route(web::get().to(get_site_name_handler)))
.service(web::resource("/public").route(web::get().to(get_public_handler))),
);
}

Expand All @@ -20,42 +24,12 @@ pub fn init(cfg: &mut web::ServiceConfig) {
/// # Errors
///
/// This function will return an error if unable to get user from database.
pub async fn get(req: HttpRequest, app_data: WebAppData) -> ServiceResult<impl Responder> {
// check for user
let user = app_data.auth.get_user_compact_from_request(&req).await?;
pub async fn get_all_handler(req: HttpRequest, app_data: WebAppData) -> ServiceResult<impl Responder> {
let user_id = app_data.auth.get_user_id_from_request(&req).await?;

// check if user is administrator
if !user.administrator {
return Err(ServiceError::Unauthorized);
}
let all_settings = app_data.settings_service.get_all(&user_id).await?;

let settings: tokio::sync::RwLockReadGuard<config::TorrustBackend> = app_data.cfg.settings.read().await;

Ok(HttpResponse::Ok().json(OkResponse { data: &*settings }))
}

/// Get Public Settings
///
/// # Errors
///
/// This function should not return an error.
pub async fn get_public(app_data: WebAppData) -> ServiceResult<impl Responder> {
let public_settings = app_data.cfg.get_public().await;

Ok(HttpResponse::Ok().json(OkResponse { data: public_settings }))
}

/// Get Name of Website
///
/// # Errors
///
/// This function should not return an error.
pub async fn site_name(app_data: WebAppData) -> ServiceResult<impl Responder> {
let settings = app_data.cfg.settings.read().await;

Ok(HttpResponse::Ok().json(OkResponse {
data: &settings.website.name,
}))
Ok(HttpResponse::Ok().json(OkResponse { data: all_settings }))
}

/// Update the settings
Expand All @@ -67,22 +41,36 @@ pub async fn site_name(app_data: WebAppData) -> ServiceResult<impl Responder> {
/// - There is no logged-in user.
/// - The user is not an administrator.
/// - The settings could not be updated because they were loaded from env vars.
pub async fn update(
pub async fn update_handler(
req: HttpRequest,
payload: web::Json<config::TorrustBackend>,
app_data: WebAppData,
) -> ServiceResult<impl Responder> {
// check for user
let user = app_data.auth.get_user_compact_from_request(&req).await?;
let user_id = app_data.auth.get_user_id_from_request(&req).await?;

let new_settings = app_data.settings_service.update_all(payload.into_inner(), &user_id).await?;

Ok(HttpResponse::Ok().json(OkResponse { data: new_settings }))
}

// check if user is administrator
if !user.administrator {
return Err(ServiceError::Unauthorized);
}
/// Get Public Settings
///
/// # Errors
///
/// This function should not return an error.
pub async fn get_public_handler(app_data: WebAppData) -> ServiceResult<impl Responder> {
let public_settings = app_data.settings_service.get_public().await;

let _ = app_data.cfg.update_settings(payload.into_inner()).await;
Ok(HttpResponse::Ok().json(OkResponse { data: public_settings }))
}

let settings = app_data.cfg.settings.read().await;
/// Get Name of Website
///
/// # Errors
///
/// This function should not return an error.
pub async fn get_site_name_handler(app_data: WebAppData) -> ServiceResult<impl Responder> {
let site_name = app_data.settings_service.get_site_name().await;

Ok(HttpResponse::Ok().json(OkResponse { data: &*settings }))
Ok(HttpResponse::Ok().json(OkResponse { data: site_name }))
}
1 change: 1 addition & 0 deletions src/services/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod about;
pub mod category;
pub mod proxy;
pub mod settings;
pub mod user;
75 changes: 75 additions & 0 deletions src/services/settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::sync::Arc;

use super::user::DbUserRepository;
use crate::config::{Configuration, ConfigurationPublic, TorrustBackend};
use crate::errors::ServiceError;
use crate::models::user::UserId;

pub struct Service {
configuration: Arc<Configuration>,
user_repository: Arc<DbUserRepository>,
}

impl Service {
#[must_use]
pub fn new(configuration: Arc<Configuration>, user_repository: Arc<DbUserRepository>) -> Service {
Service {
configuration,
user_repository,
}
}

/// It gets all the settings.
///
/// # Errors
///
/// It returns an error if the user does not have the required permissions.
pub async fn get_all(&self, user_id: &UserId) -> Result<TorrustBackend, ServiceError> {
let user = self.user_repository.get_compact_user(user_id).await?;

// Check if user is administrator
// todo: extract authorization service
if !user.administrator {
return Err(ServiceError::Unauthorized);
}

Ok(self.configuration.get_all().await)
}

/// It updates all the settings.
///
/// # Errors
///
/// It returns an error if the user does not have the required permissions.
pub async fn update_all(&self, torrust_backend: TorrustBackend, user_id: &UserId) -> Result<TorrustBackend, ServiceError> {
let user = self.user_repository.get_compact_user(user_id).await?;

// Check if user is administrator
// todo: extract authorization service
if !user.administrator {
return Err(ServiceError::Unauthorized);
}

let _ = self.configuration.update_settings(torrust_backend).await;

Ok(self.configuration.get_all().await)
}

/// It gets only the public settings.
///
/// # Errors
///
/// It returns an error if the user does not have the required permissions.
pub async fn get_public(&self) -> ConfigurationPublic {
self.configuration.get_public().await
}

/// It gets the site name from the settings.
///
/// # Errors
///
/// It returns an error if the user does not have the required permissions.
pub async fn get_site_name(&self) -> String {
self.configuration.get_site_name().await
}
}

0 comments on commit 0387b97

Please sign in to comment.