Skip to content

Commit 0387b97

Browse files
committed
refactor: [#157] extract service: settings
Decoupling services from actix-web framework.
1 parent c9fb249 commit 0387b97

File tree

6 files changed

+131
-50
lines changed

6 files changed

+131
-50
lines changed

src/app.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use crate::common::AppData;
1313
use crate::config::Configuration;
1414
use crate::databases::database;
1515
use crate::services::category::{self, DbCategoryRepository};
16-
use crate::services::proxy;
1716
use crate::services::user::DbUserRepository;
17+
use crate::services::{proxy, settings};
1818
use crate::tracker::statistics_importer::StatisticsImporter;
1919
use crate::{mailer, routes, tracker};
2020

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

5960
// Build app container
6061

@@ -70,6 +71,7 @@ pub async fn run(configuration: Configuration) -> Running {
7071
user_repository,
7172
category_service,
7273
proxy_service,
74+
settings_service,
7375
));
7476

7577
// Start repeating task to import tracker torrent data and updating

src/common.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use crate::cache::image::manager::ImageCacheService;
55
use crate::config::Configuration;
66
use crate::databases::database::Database;
77
use crate::services::category::{self, DbCategoryRepository};
8-
use crate::services::proxy;
98
use crate::services::user::DbUserRepository;
9+
use crate::services::{proxy, settings};
1010
use crate::tracker::statistics_importer::StatisticsImporter;
1111
use crate::{mailer, tracker};
1212
pub type Username = String;
@@ -25,6 +25,7 @@ pub struct AppData {
2525
pub user_repository: Arc<DbUserRepository>,
2626
pub category_service: Arc<category::Service>,
2727
pub proxy_service: Arc<proxy::Service>,
28+
pub settings_service: Arc<settings::Service>,
2829
}
2930

3031
impl AppData {
@@ -41,6 +42,7 @@ impl AppData {
4142
user_repository: Arc<DbUserRepository>,
4243
category_service: Arc<category::Service>,
4344
proxy_service: Arc<proxy::Service>,
45+
settings_service: Arc<settings::Service>,
4446
) -> AppData {
4547
AppData {
4648
cfg,
@@ -54,6 +56,7 @@ impl AppData {
5456
user_repository,
5557
category_service,
5658
proxy_service,
59+
settings_service,
5760
}
5861
}
5962
}

src/config.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,12 @@ impl Configuration {
321321
}
322322
}
323323

324+
pub async fn get_all(&self) -> TorrustBackend {
325+
let settings_lock = self.settings.read().await;
326+
327+
settings_lock.clone()
328+
}
329+
324330
pub async fn get_public(&self) -> ConfigurationPublic {
325331
let settings_lock = self.settings.read().await;
326332

@@ -331,6 +337,12 @@ impl Configuration {
331337
email_on_signup: settings_lock.auth.email_on_signup.clone(),
332338
}
333339
}
340+
341+
pub async fn get_site_name(&self) -> String {
342+
let settings_lock = self.settings.read().await;
343+
344+
settings_lock.website.name.clone()
345+
}
334346
}
335347

336348
#[derive(Debug, Clone, Serialize, Deserialize)]

src/routes/settings.rs

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@ use actix_web::{web, HttpRequest, HttpResponse, Responder};
22

33
use crate::common::WebAppData;
44
use crate::config;
5-
use crate::errors::{ServiceError, ServiceResult};
5+
use crate::errors::ServiceResult;
66
use crate::models::response::OkResponse;
77
use crate::routes::API_VERSION;
88

99
pub fn init(cfg: &mut web::ServiceConfig) {
1010
cfg.service(
1111
web::scope(&format!("/{API_VERSION}/settings"))
12-
.service(web::resource("").route(web::get().to(get)).route(web::post().to(update)))
13-
.service(web::resource("/name").route(web::get().to(site_name)))
14-
.service(web::resource("/public").route(web::get().to(get_public))),
12+
.service(
13+
web::resource("")
14+
.route(web::get().to(get_all_handler))
15+
.route(web::post().to(update_handler)),
16+
)
17+
.service(web::resource("/name").route(web::get().to(get_site_name_handler)))
18+
.service(web::resource("/public").route(web::get().to(get_public_handler))),
1519
);
1620
}
1721

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

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

32-
let settings: tokio::sync::RwLockReadGuard<config::TorrustBackend> = app_data.cfg.settings.read().await;
33-
34-
Ok(HttpResponse::Ok().json(OkResponse { data: &*settings }))
35-
}
36-
37-
/// Get Public Settings
38-
///
39-
/// # Errors
40-
///
41-
/// This function should not return an error.
42-
pub async fn get_public(app_data: WebAppData) -> ServiceResult<impl Responder> {
43-
let public_settings = app_data.cfg.get_public().await;
44-
45-
Ok(HttpResponse::Ok().json(OkResponse { data: public_settings }))
46-
}
47-
48-
/// Get Name of Website
49-
///
50-
/// # Errors
51-
///
52-
/// This function should not return an error.
53-
pub async fn site_name(app_data: WebAppData) -> ServiceResult<impl Responder> {
54-
let settings = app_data.cfg.settings.read().await;
55-
56-
Ok(HttpResponse::Ok().json(OkResponse {
57-
data: &settings.website.name,
58-
}))
32+
Ok(HttpResponse::Ok().json(OkResponse { data: all_settings }))
5933
}
6034

6135
/// Update the settings
@@ -67,22 +41,36 @@ pub async fn site_name(app_data: WebAppData) -> ServiceResult<impl Responder> {
6741
/// - There is no logged-in user.
6842
/// - The user is not an administrator.
6943
/// - The settings could not be updated because they were loaded from env vars.
70-
pub async fn update(
44+
pub async fn update_handler(
7145
req: HttpRequest,
7246
payload: web::Json<config::TorrustBackend>,
7347
app_data: WebAppData,
7448
) -> ServiceResult<impl Responder> {
75-
// check for user
76-
let user = app_data.auth.get_user_compact_from_request(&req).await?;
49+
let user_id = app_data.auth.get_user_id_from_request(&req).await?;
50+
51+
let new_settings = app_data.settings_service.update_all(payload.into_inner(), &user_id).await?;
52+
53+
Ok(HttpResponse::Ok().json(OkResponse { data: new_settings }))
54+
}
7755

78-
// check if user is administrator
79-
if !user.administrator {
80-
return Err(ServiceError::Unauthorized);
81-
}
56+
/// Get Public Settings
57+
///
58+
/// # Errors
59+
///
60+
/// This function should not return an error.
61+
pub async fn get_public_handler(app_data: WebAppData) -> ServiceResult<impl Responder> {
62+
let public_settings = app_data.settings_service.get_public().await;
8263

83-
let _ = app_data.cfg.update_settings(payload.into_inner()).await;
64+
Ok(HttpResponse::Ok().json(OkResponse { data: public_settings }))
65+
}
8466

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

87-
Ok(HttpResponse::Ok().json(OkResponse { data: &*settings }))
75+
Ok(HttpResponse::Ok().json(OkResponse { data: site_name }))
8876
}

src/services/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod about;
22
pub mod category;
33
pub mod proxy;
4+
pub mod settings;
45
pub mod user;

src/services/settings.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::sync::Arc;
2+
3+
use super::user::DbUserRepository;
4+
use crate::config::{Configuration, ConfigurationPublic, TorrustBackend};
5+
use crate::errors::ServiceError;
6+
use crate::models::user::UserId;
7+
8+
pub struct Service {
9+
configuration: Arc<Configuration>,
10+
user_repository: Arc<DbUserRepository>,
11+
}
12+
13+
impl Service {
14+
#[must_use]
15+
pub fn new(configuration: Arc<Configuration>, user_repository: Arc<DbUserRepository>) -> Service {
16+
Service {
17+
configuration,
18+
user_repository,
19+
}
20+
}
21+
22+
/// It gets all the settings.
23+
///
24+
/// # Errors
25+
///
26+
/// It returns an error if the user does not have the required permissions.
27+
pub async fn get_all(&self, user_id: &UserId) -> Result<TorrustBackend, ServiceError> {
28+
let user = self.user_repository.get_compact_user(user_id).await?;
29+
30+
// Check if user is administrator
31+
// todo: extract authorization service
32+
if !user.administrator {
33+
return Err(ServiceError::Unauthorized);
34+
}
35+
36+
Ok(self.configuration.get_all().await)
37+
}
38+
39+
/// It updates all the settings.
40+
///
41+
/// # Errors
42+
///
43+
/// It returns an error if the user does not have the required permissions.
44+
pub async fn update_all(&self, torrust_backend: TorrustBackend, user_id: &UserId) -> Result<TorrustBackend, ServiceError> {
45+
let user = self.user_repository.get_compact_user(user_id).await?;
46+
47+
// Check if user is administrator
48+
// todo: extract authorization service
49+
if !user.administrator {
50+
return Err(ServiceError::Unauthorized);
51+
}
52+
53+
let _ = self.configuration.update_settings(torrust_backend).await;
54+
55+
Ok(self.configuration.get_all().await)
56+
}
57+
58+
/// It gets only the public settings.
59+
///
60+
/// # Errors
61+
///
62+
/// It returns an error if the user does not have the required permissions.
63+
pub async fn get_public(&self) -> ConfigurationPublic {
64+
self.configuration.get_public().await
65+
}
66+
67+
/// It gets the site name from the settings.
68+
///
69+
/// # Errors
70+
///
71+
/// It returns an error if the user does not have the required permissions.
72+
pub async fn get_site_name(&self) -> String {
73+
self.configuration.get_site_name().await
74+
}
75+
}

0 commit comments

Comments
 (0)