Rewrite merge code to fix tests

This commit is contained in:
Felix Ableitner 2021-02-22 18:57:15 +01:00
parent 62c9be5b56
commit 59cce4a1f5
6 changed files with 126 additions and 86 deletions

View file

@ -583,7 +583,9 @@ impl Perform for GetSiteConfig {
// Only let admins read this
is_admin(context.pool(), user.id).await?;
let config_hjson = Settings::read_config_file()?;
// TODO: should make the response field optional?
// or include env vars, but then we cant really save it
let config_hjson = Settings::read_config_file().unwrap_or("".to_string());
Ok(GetSiteConfigResponse { config_hjson })
}

View file

@ -48,7 +48,7 @@ pub(in crate::settings) fn parse_from_env() -> SettingsOpt {
admin_username: env_var("SETUP__ADMIN_USERNAME"),
admin_password: env_var("SETUP__ADMIN_PASSWORD"),
admin_email: Some(env_var("SETUP__ADMIN_EMAIL")),
site_name: env_var("SETUP__ADMIN_SITE_NAME"),
site_name: env_var("SETUP__SITE_NAME"),
}),
database: Some(DatabaseConfigOpt {
user: env_var("DATABASE__USER"),

View file

@ -1,107 +1,141 @@
use crate::settings::{structs::*, structs_opt::*};
pub(in crate::settings) trait Merge<T> {
fn merge(&mut self, opt: T);
fn merge(self, opt: T) -> Self;
}
impl Merge<SettingsOpt> for Settings {
fn merge(&mut self, opt: SettingsOpt) {
overwrite_if_some(&mut self.hostname, opt.hostname);
overwrite_if_some(&mut self.bind, opt.bind);
overwrite_if_some(&mut self.port, opt.port);
overwrite_if_some(&mut self.tls_enabled, opt.tls_enabled);
overwrite_if_some(&mut self.jwt_secret, opt.jwt_secret);
overwrite_if_some(&mut self.pictrs_url, opt.pictrs_url);
overwrite_if_some(&mut self.iframely_url, opt.iframely_url);
merge_if_some(&mut self.captcha, opt.captcha);
merge_if_some(&mut self.rate_limit, opt.rate_limit);
merge_if_some_opt(&mut self.email, opt.email);
merge_if_some_opt(&mut self.setup, opt.setup);
merge_if_some(&mut self.federation, opt.federation);
merge_if_some(&mut self.database, opt.database);
fn merge(self, opt: SettingsOpt) -> Self {
Settings {
setup: merge_structs(self.setup, opt.setup),
database: merge_structs(self.database, opt.database),
hostname: opt.hostname.unwrap_or(self.hostname),
bind: opt.bind.unwrap_or(self.bind),
port: opt.port.unwrap_or(self.port),
tls_enabled: opt.tls_enabled.unwrap_or(self.tls_enabled),
jwt_secret: opt.jwt_secret.unwrap_or(self.jwt_secret),
pictrs_url: opt.pictrs_url.unwrap_or(self.pictrs_url),
iframely_url: opt.iframely_url.unwrap_or(self.iframely_url),
rate_limit: merge_structs(self.rate_limit, opt.rate_limit),
email: merge_structs(self.email, opt.email),
federation: merge_structs(self.federation, opt.federation),
captcha: merge_structs(self.captcha, opt.captcha),
}
}
}
impl Merge<RateLimitConfigOpt> for RateLimitConfig {
fn merge(&mut self, opt: RateLimitConfigOpt) {
overwrite_if_some(&mut self.message, opt.message);
overwrite_if_some(&mut self.message_per_second, opt.message_per_second);
overwrite_if_some(&mut self.post, opt.post);
overwrite_if_some(&mut self.post_per_second, opt.post_per_second);
overwrite_if_some(&mut self.register, opt.register);
overwrite_if_some(&mut self.register_per_second, opt.register_per_second);
overwrite_if_some(&mut self.image, opt.image);
overwrite_if_some(&mut self.image_per_second, opt.image_per_second);
fn merge(self, opt: RateLimitConfigOpt) -> Self {
RateLimitConfig {
message: opt.message.unwrap_or(self.message),
message_per_second: opt.message_per_second.unwrap_or(self.message_per_second),
post: opt.post.unwrap_or(self.post),
post_per_second: opt.post_per_second.unwrap_or(self.post_per_second),
register: opt.register.unwrap_or(self.register),
register_per_second: opt.register_per_second.unwrap_or(self.register_per_second),
image: opt.image.unwrap_or(self.image),
image_per_second: opt.image_per_second.unwrap_or(self.image_per_second),
}
}
}
impl Merge<SetupOpt> for Setup {
fn merge(&mut self, opt: SetupOpt) {
overwrite_if_some(&mut self.admin_username, opt.admin_username);
overwrite_if_some(&mut self.admin_password, opt.admin_password);
overwrite_if_some(&mut self.admin_email, opt.admin_email);
overwrite_if_some(&mut self.site_name, opt.site_name);
impl Merge<SetupOpt> for Option<Setup> {
fn merge(self, opt: SetupOpt) -> Self {
if let Some(setup) = self {
Some(Setup {
admin_username: opt.admin_username.unwrap_or(setup.admin_username),
admin_password: opt.admin_password.unwrap_or(setup.admin_password),
admin_email: opt.admin_email.unwrap_or(setup.admin_email),
site_name: opt.site_name.unwrap_or(setup.site_name),
})
} else if let (Some(admin_username), Some(admin_password), Some(site_name)) =
(opt.admin_username, opt.admin_password, opt.site_name)
{
Some(Setup {
admin_username,
admin_password,
admin_email: opt.admin_email.flatten(),
site_name,
})
} else {
None
}
}
}
impl Merge<EmailConfigOpt> for EmailConfig {
fn merge(&mut self, opt: EmailConfigOpt) {
overwrite_if_some(&mut self.smtp_server, opt.smtp_server);
overwrite_if_some(&mut self.smtp_login, opt.smtp_login);
overwrite_if_some(&mut self.smtp_password, opt.smtp_password);
overwrite_if_some(&mut self.smtp_from_address, opt.smtp_from_address);
overwrite_if_some(&mut self.use_tls, opt.use_tls);
impl Merge<EmailConfigOpt> for Option<EmailConfig> {
fn merge(self, opt: EmailConfigOpt) -> Self {
if let Some(email_config) = self {
Some(EmailConfig {
smtp_server: opt.smtp_server.unwrap_or(email_config.smtp_server),
smtp_login: opt.smtp_login.unwrap_or(email_config.smtp_login),
smtp_password: opt.smtp_password.unwrap_or(email_config.smtp_password),
smtp_from_address: opt
.smtp_from_address
.unwrap_or(email_config.smtp_from_address),
use_tls: opt.use_tls.unwrap_or(email_config.use_tls),
})
} else if let (Some(smtp_server), Some(smtp_from_address), Some(use_tls)) =
(opt.smtp_server, opt.smtp_from_address, opt.use_tls)
{
Some(EmailConfig {
smtp_server,
smtp_login: opt
.smtp_login
.or(self.clone().map(|s| s.smtp_login))
.flatten(),
smtp_password: opt
.smtp_password
.or(self.map(|s| s.smtp_password))
.flatten(),
smtp_from_address,
use_tls,
})
} else {
None
}
}
}
impl Merge<DatabaseConfigOpt> for DatabaseConfig {
fn merge(&mut self, opt: DatabaseConfigOpt) {
overwrite_if_some(&mut self.user, opt.user);
overwrite_if_some(&mut self.password, opt.password);
overwrite_if_some(&mut self.host, opt.host);
overwrite_if_some(&mut self.port, opt.port);
overwrite_if_some(&mut self.database, opt.database);
overwrite_if_some(&mut self.pool_size, opt.pool_size);
fn merge(self, opt: DatabaseConfigOpt) -> Self {
DatabaseConfig {
user: opt.user.unwrap_or(self.user),
password: opt.password.unwrap_or(self.password),
host: opt.host.unwrap_or(self.host),
port: opt.port.unwrap_or(self.port),
database: opt.database.unwrap_or(self.database),
pool_size: opt.pool_size.unwrap_or(self.pool_size),
}
}
}
impl Merge<FederationConfigOpt> for FederationConfig {
fn merge(&mut self, opt: FederationConfigOpt) {
overwrite_if_some(&mut self.enabled, opt.enabled);
overwrite_if_some(&mut self.allowed_instances, opt.allowed_instances);
overwrite_if_some(&mut self.blocked_instances, opt.blocked_instances);
fn merge(self, opt: FederationConfigOpt) -> Self {
FederationConfig {
enabled: opt.enabled.unwrap_or(self.enabled),
allowed_instances: opt.allowed_instances.unwrap_or(self.allowed_instances),
blocked_instances: opt.blocked_instances.unwrap_or(self.blocked_instances),
}
}
}
impl Merge<CaptchaConfigOpt> for CaptchaConfig {
fn merge(&mut self, opt: CaptchaConfigOpt) {
overwrite_if_some(&mut self.enabled, opt.enabled);
overwrite_if_some(&mut self.difficulty, opt.difficulty);
}
}
fn overwrite_if_some<T>(lhs: &mut T, rhs: Option<T>) {
if let Some(x) = rhs {
*lhs = x;
}
}
fn merge_if_some<T, U>(lhs: &mut T, rhs: Option<U>)
where
T: Merge<U>,
{
if let Some(x) = rhs {
lhs.merge(x);
}
}
fn merge_if_some_opt<T, U>(lhs: &mut Option<T>, rhs: Option<U>)
where
T: Merge<U>,
{
if let Some(x) = rhs {
if let Some(y) = lhs {
y.merge(x)
fn merge(self, opt: CaptchaConfigOpt) -> Self {
CaptchaConfig {
enabled: opt.enabled.unwrap_or(self.enabled),
difficulty: opt.difficulty.unwrap_or(self.difficulty),
}
}
}
fn merge_structs<T, U>(lhs: T, rhs: Option<U>) -> T
where
T: Merge<U> + std::clone::Clone,
{
if let Some(x) = rhs {
lhs.merge(x)
} else {
lhs.to_owned()
}
}

View file

@ -10,7 +10,7 @@ use crate::{
};
use anyhow::{anyhow, Context};
use deser_hjson::from_str;
use std::{env, fs, io::Error, sync::RwLock};
use std::{env, fs, sync::RwLock};
pub mod defaults;
mod environment;
@ -39,10 +39,12 @@ impl Settings {
let mut config = Settings::default();
// Read the config file
config.merge(from_str::<SettingsOpt>(&Self::read_config_file()?)?);
if let Some(config_file) = &Self::read_config_file() {
config = config.merge(from_str::<SettingsOpt>(config_file)?);
}
// Read env vars
config.merge(parse_from_env());
config = config.merge(parse_from_env());
if config.hostname == Settings::default().hostname {
return Err(anyhow!("Hostname variable is not set!").into());
@ -68,8 +70,8 @@ impl Settings {
env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
}
pub fn read_config_file() -> Result<String, Error> {
fs::read_to_string(Self::get_config_location())
pub fn read_config_file() -> Option<String> {
fs::read_to_string(Self::get_config_location()).ok()
}
pub fn get_allowed_instances(&self) -> Vec<String> {
@ -133,7 +135,7 @@ impl Settings {
)
}
pub fn save_config_file(data: &str) -> Result<String, Error> {
pub fn save_config_file(data: &str) -> Result<String, LemmyError> {
fs::write(CONFIG_FILE, data)?;
// Reload the new settings
@ -144,6 +146,6 @@ impl Settings {
Err(e) => panic!("{}", e),
};
Self::read_config_file()
Self::read_config_file().ok_or(anyhow!("Failed to read config").into())
}
}

View file

@ -39,6 +39,7 @@ services:
lemmy-alpha:
image: lemmy-federation:latest
environment:
- RUST_BACKTRACE=full
- LEMMY_HOSTNAME=lemmy-alpha:8541
- LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_alpha:5432/lemmy
- LEMMY_JWT_SECRET=changeme

View file

@ -8,4 +8,5 @@ for Item in alpha beta gamma delta epsilon ; do
sudo chown -R 991:991 volumes/pictrs_$Item
done
sudo docker-compose up
sudo docker-compose up -d
sudo docker-compose logs -f lemmy-alpha