Improve environment variable handling and reading (#5389)
* wip: better env var reading * move most env vars to env.rs * migrate more env vars * more migration * more migrations * More migration * 🦀 dotenvy is gone (almost) * 🦀 dotenvy is gone 🦀 * Fix mural source account env var handling * Remove defaults from admin key vars * dummy commit to update github pr * fix ci
This commit is contained in:
@@ -12,6 +12,7 @@ use crate::database::models::{
|
||||
};
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::database::{PgPool, PgTransaction};
|
||||
use crate::env::ENV;
|
||||
use crate::models::billing::{
|
||||
ChargeStatus, ChargeType, PaymentPlatform, Price, PriceDuration,
|
||||
ProductMetadata, SubscriptionMetadata, SubscriptionStatus,
|
||||
@@ -913,10 +914,10 @@ async fn unprovision_subscriptions(
|
||||
let res = reqwest::Client::new()
|
||||
.post(format!(
|
||||
"{}/modrinth/v0/servers/{}/suspend",
|
||||
dotenvy::var("ARCHON_URL")?,
|
||||
ENV.ARCHON_URL,
|
||||
server_id
|
||||
))
|
||||
.header("X-Master-Key", dotenvy::var("PYRO_API_KEY")?)
|
||||
.header("X-Master-Key", &ENV.PYRO_API_KEY)
|
||||
.json(&serde_json::json!({
|
||||
"reason": if charge.status == ChargeStatus::Cancelled || charge.status == ChargeStatus::Expiring {
|
||||
"cancelled"
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::database::models::notifications_template_item::NotificationTemplate;
|
||||
use crate::database::models::user_item::DBUser;
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::database::{PgPool, PgTransaction};
|
||||
use crate::env::ENV;
|
||||
use crate::models::notifications::{NotificationBody, NotificationType};
|
||||
use crate::models::v3::notifications::{
|
||||
NotificationChannel, NotificationDeliveryStatus,
|
||||
@@ -36,16 +37,16 @@ impl Mailer {
|
||||
) -> Result<Arc<AsyncSmtpTransport<Tokio1Executor>>, MailError> {
|
||||
let maybe_transport = match self {
|
||||
Mailer::Uninitialized => {
|
||||
let username = dotenvy::var("SMTP_USERNAME")?;
|
||||
let password = dotenvy::var("SMTP_PASSWORD")?;
|
||||
let host = dotenvy::var("SMTP_HOST")?;
|
||||
let port =
|
||||
dotenvy::var("SMTP_PORT")?.parse::<u16>().unwrap_or(465);
|
||||
let username = &ENV.SMTP_USERNAME;
|
||||
let password = &ENV.SMTP_PASSWORD;
|
||||
let host = &ENV.SMTP_HOST;
|
||||
let port = ENV.SMTP_PORT;
|
||||
|
||||
let creds = (!username.is_empty())
|
||||
.then(|| Credentials::new(username, password));
|
||||
let creds = (!username.is_empty()).then(|| {
|
||||
Credentials::new(username.clone(), password.clone())
|
||||
});
|
||||
|
||||
let tls_setting = match dotenvy::var("SMTP_TLS")?.as_str() {
|
||||
let tls_setting = match ENV.SMTP_TLS.as_str() {
|
||||
"none" => Tls::None,
|
||||
"opportunistic_start_tls" => Tls::Opportunistic(
|
||||
TlsParameters::new(host.to_string())?,
|
||||
@@ -65,7 +66,7 @@ impl Mailer {
|
||||
};
|
||||
|
||||
let mut mailer =
|
||||
AsyncSmtpTransport::<Tokio1Executor>::relay(&host)?
|
||||
AsyncSmtpTransport::<Tokio1Executor>::relay(host)?
|
||||
.port(port)
|
||||
.tls(tls_setting);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::database::models::{
|
||||
DBOrganization, DBProject, DBUser, DatabaseError,
|
||||
};
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::env::ENV;
|
||||
use crate::models::v3::notifications::NotificationBody;
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::error::Context;
|
||||
@@ -96,10 +97,18 @@ pub struct MailingIdentity {
|
||||
impl MailingIdentity {
|
||||
pub fn from_env() -> dotenvy::Result<Self> {
|
||||
Ok(Self {
|
||||
from_name: dotenvy::var("SMTP_FROM_NAME")?,
|
||||
from_address: dotenvy::var("SMTP_FROM_ADDRESS")?,
|
||||
reply_name: dotenvy::var("SMTP_REPLY_TO_NAME").ok(),
|
||||
reply_address: dotenvy::var("SMTP_REPLY_TO_ADDRESS").ok(),
|
||||
from_name: ENV.SMTP_FROM_NAME.clone(),
|
||||
from_address: ENV.SMTP_FROM_ADDRESS.clone(),
|
||||
reply_name: if ENV.SMTP_REPLY_TO_NAME.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ENV.SMTP_REPLY_TO_NAME.clone())
|
||||
},
|
||||
reply_address: if ENV.SMTP_REPLY_TO_ADDRESS.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ENV.SMTP_REPLY_TO_ADDRESS.clone())
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -558,9 +567,7 @@ async fn collect_template_variables(
|
||||
NotificationBody::ResetPassword { flow } => {
|
||||
let url = format!(
|
||||
"{}/{}?flow={}",
|
||||
dotenvy::var("SITE_URL")?,
|
||||
dotenvy::var("SITE_RESET_PASSWORD_PATH")?,
|
||||
flow
|
||||
ENV.SITE_URL, ENV.SITE_RESET_PASSWORD_PATH, flow
|
||||
);
|
||||
|
||||
map.insert(RESETPASSWORD_URL, url);
|
||||
@@ -571,9 +578,7 @@ async fn collect_template_variables(
|
||||
NotificationBody::VerifyEmail { flow } => {
|
||||
let url = format!(
|
||||
"{}/{}?flow={}",
|
||||
dotenvy::var("SITE_URL")?,
|
||||
dotenvy::var("SITE_VERIFY_EMAIL_PATH")?,
|
||||
flow
|
||||
ENV.SITE_URL, ENV.SITE_VERIFY_EMAIL_PATH, flow
|
||||
);
|
||||
|
||||
map.insert(VERIFYEMAIL_URL, url);
|
||||
@@ -603,11 +608,7 @@ async fn collect_template_variables(
|
||||
}
|
||||
|
||||
NotificationBody::PaymentFailed { amount, service } => {
|
||||
let url = format!(
|
||||
"{}/{}",
|
||||
dotenvy::var("SITE_URL")?,
|
||||
dotenvy::var("SITE_BILLING_PATH")?,
|
||||
);
|
||||
let url = format!("{}/{}", ENV.SITE_URL, ENV.SITE_BILLING_PATH,);
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert(PAYMENTFAILED_AMOUNT, amount.clone());
|
||||
@@ -748,8 +749,7 @@ async fn dynamic_email_body(
|
||||
key: &str,
|
||||
) -> Result<String, ApiError> {
|
||||
get_or_set_cached_dynamic_html(redis, key, || async {
|
||||
let site_url = dotenvy::var("SITE_URL")
|
||||
.wrap_internal_err("SITE_URL is not set")?;
|
||||
let site_url = &ENV.SITE_URL;
|
||||
let site_url = site_url.trim_end_matches('/');
|
||||
|
||||
let url = format!("{site_url}/_internal/templates/email/dynamic");
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::database::PgPool;
|
||||
use crate::database::models::notification_item::NotificationBuilder;
|
||||
use crate::database::models::thread_item::ThreadMessageBuilder;
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::env::ENV;
|
||||
use crate::models::ids::ProjectId;
|
||||
use crate::models::notifications::NotificationBody;
|
||||
use crate::models::pack::{PackFile, PackFileHash, PackFormat};
|
||||
@@ -454,7 +455,7 @@ impl AutomatedModerationQueue {
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let res = client
|
||||
.post(format!("{}/v1/fingerprints", dotenvy::var("FLAME_ANVIL_URL")?))
|
||||
.post(format!("{}/v1/fingerprints", ENV.FLAME_ANVIL_URL))
|
||||
.json(&serde_json::json!({
|
||||
"fingerprints": hashes.iter().filter_map(|x| x.3).collect::<Vec<u32>>()
|
||||
}))
|
||||
@@ -553,11 +554,11 @@ impl AutomatedModerationQueue {
|
||||
continue;
|
||||
}
|
||||
|
||||
let flame_projects = if flame_files.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
let res = client
|
||||
.post(format!("{}v1/mods", dotenvy::var("FLAME_ANVIL_URL")?))
|
||||
let flame_projects = if flame_files.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
let res = client
|
||||
.post(format!("{}v1/mods", ENV.FLAME_ANVIL_URL))
|
||||
.json(&serde_json::json!({
|
||||
"modIds": flame_files.iter().map(|x| x.1).collect::<Vec<_>>()
|
||||
}))
|
||||
@@ -664,16 +665,16 @@ impl AutomatedModerationQueue {
|
||||
.insert_many(members.into_iter().map(|x| x.user_id).collect(), &mut transaction, &redis)
|
||||
.await?;
|
||||
|
||||
if let Ok(webhook_url) = dotenvy::var("MODERATION_SLACK_WEBHOOK") {
|
||||
if !ENV.MODERATION_SLACK_WEBHOOK.is_empty() {
|
||||
crate::util::webhook::send_slack_project_webhook(
|
||||
project.inner.id.into(),
|
||||
&pool,
|
||||
&redis,
|
||||
webhook_url,
|
||||
&ENV.MODERATION_SLACK_WEBHOOK,
|
||||
Some(
|
||||
format!(
|
||||
"*<{}/user/AutoMod|AutoMod>* changed project status from *{}* to *Rejected*",
|
||||
dotenvy::var("SITE_URL")?,
|
||||
ENV.SITE_URL,
|
||||
&project.inner.status.as_friendly_str(),
|
||||
)
|
||||
.to_string(),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::database::PgPool;
|
||||
use crate::env::ENV;
|
||||
use chrono::{Datelike, Duration, TimeZone, Utc};
|
||||
use eyre::{Context, Result, eyre};
|
||||
use rust_decimal::{Decimal, dec};
|
||||
@@ -62,11 +63,7 @@ pub async fn process_affiliate_payouts(postgres: &PgPool) -> Result<()> {
|
||||
.await
|
||||
.wrap_err("failed to fetch charges awaiting affiliate payout")?;
|
||||
|
||||
let default_affiliate_revenue_split =
|
||||
dotenvy::var("DEFAULT_AFFILIATE_REVENUE_SPLIT")
|
||||
.wrap_err("no env var `DEFAULT_AFFILIATE_REVENUE_SPLIT`")?
|
||||
.parse::<Decimal>()
|
||||
.wrap_err("`DEFAULT_AFFILIATE_REVENUE_SPLIT` is not a decimal")?;
|
||||
let default_affiliate_revenue_split = ENV.DEFAULT_AFFILIATE_REVENUE_SPLIT;
|
||||
|
||||
let (
|
||||
mut insert_usap_charges,
|
||||
|
||||
@@ -8,6 +8,7 @@ use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
database::models::payout_item::DBPayout,
|
||||
env::ENV,
|
||||
models::payouts::{
|
||||
PayoutMethod, PayoutMethodFee, PayoutMethodType, PayoutStatus,
|
||||
TremendousCurrency, TremendousDetails, TremendousForexResponse,
|
||||
@@ -210,7 +211,7 @@ pub(super) async fn execute(
|
||||
"products": [
|
||||
method_id,
|
||||
],
|
||||
"campaign_id": dotenvy::var("TREMENDOUS_CAMPAIGN_ID")?,
|
||||
"campaign_id": ENV.TREMENDOUS_CAMPAIGN_ID.as_str(),
|
||||
}]
|
||||
});
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@ use crate::database::models::notification_item::NotificationBuilder;
|
||||
use crate::database::models::payouts_values_notifications;
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::database::{PgPool, PgTransaction};
|
||||
use crate::env::ENV;
|
||||
use crate::models::payouts::{
|
||||
PayoutDecimal, PayoutInterval, PayoutMethod, PayoutMethodType,
|
||||
TremendousForexResponse,
|
||||
};
|
||||
use crate::models::projects::MonetizationStatus;
|
||||
use crate::routes::ApiError;
|
||||
use crate::util::env::env_var;
|
||||
use crate::util::error::Context;
|
||||
use crate::util::webhook::{
|
||||
PayoutSourceAlertType, send_slack_payout_source_alert_webhook,
|
||||
@@ -76,21 +76,18 @@ impl Default for PayoutsQueue {
|
||||
}
|
||||
|
||||
pub fn create_muralpay_client() -> Result<muralpay::Client> {
|
||||
let api_url = env_var("MURALPAY_API_URL")?;
|
||||
let api_key = env_var("MURALPAY_API_KEY")?;
|
||||
let transfer_api_key = env_var("MURALPAY_TRANSFER_API_KEY")?;
|
||||
Ok(muralpay::Client::new(api_url, api_key, transfer_api_key))
|
||||
Ok(muralpay::Client::new(
|
||||
&ENV.MURALPAY_API_URL,
|
||||
ENV.MURALPAY_API_KEY.as_str(),
|
||||
ENV.MURALPAY_TRANSFER_API_KEY.as_str(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn create_muralpay() -> Result<MuralPayConfig> {
|
||||
let client = create_muralpay_client()?;
|
||||
let source_account_id = env_var("MURALPAY_SOURCE_ACCOUNT_ID")?
|
||||
.parse::<muralpay::AccountId>()
|
||||
.wrap_err("failed to parse source account ID")?;
|
||||
|
||||
Ok(MuralPayConfig {
|
||||
client,
|
||||
source_account_id,
|
||||
source_account_id: ENV.MURALPAY_SOURCE_ACCOUNT_ID,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -185,11 +182,8 @@ impl PayoutsQueue {
|
||||
let mut creds = self.credential.write().await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let combined_key = format!(
|
||||
"{}:{}",
|
||||
dotenvy::var("PAYPAL_CLIENT_ID")?,
|
||||
dotenvy::var("PAYPAL_CLIENT_SECRET")?
|
||||
);
|
||||
let combined_key =
|
||||
format!("{}:{}", ENV.PAYPAL_CLIENT_ID, ENV.PAYPAL_CLIENT_SECRET);
|
||||
let formatted_key = format!(
|
||||
"Basic {}",
|
||||
base64::engine::general_purpose::STANDARD.encode(combined_key)
|
||||
@@ -206,7 +200,7 @@ impl PayoutsQueue {
|
||||
}
|
||||
|
||||
let credential: PaypalCredential = client
|
||||
.post(format!("{}oauth2/token", dotenvy::var("PAYPAL_API_URL")?))
|
||||
.post(format!("{}oauth2/token", ENV.PAYPAL_API_URL))
|
||||
.header("Accept", "application/json")
|
||||
.header("Accept-Language", "en_US")
|
||||
.header("Authorization", formatted_key)
|
||||
@@ -274,7 +268,7 @@ impl PayoutsQueue {
|
||||
if no_api_prefix.unwrap_or(false) {
|
||||
path.to_string()
|
||||
} else {
|
||||
format!("{}{path}", dotenvy::var("PAYPAL_API_URL")?)
|
||||
format!("{}{path}", ENV.PAYPAL_API_URL)
|
||||
},
|
||||
)
|
||||
.header(
|
||||
@@ -355,13 +349,10 @@ impl PayoutsQueue {
|
||||
) -> Result<X, ApiError> {
|
||||
let client = reqwest::Client::new();
|
||||
let mut request = client
|
||||
.request(
|
||||
method,
|
||||
format!("{}{path}", dotenvy::var("TREMENDOUS_API_URL")?),
|
||||
)
|
||||
.request(method, format!("{}{path}", ENV.TREMENDOUS_API_URL))
|
||||
.header(
|
||||
"Authorization",
|
||||
format!("Bearer {}", dotenvy::var("TREMENDOUS_API_KEY")?),
|
||||
format!("Bearer {}", ENV.TREMENDOUS_API_KEY),
|
||||
);
|
||||
|
||||
if let Some(body) = body {
|
||||
@@ -511,8 +502,8 @@ impl PayoutsQueue {
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let res = client
|
||||
.get(format!("{}accounts/cash", dotenvy::var("BREX_API_URL")?))
|
||||
.bearer_auth(&dotenvy::var("BREX_API_KEY")?)
|
||||
.get(format!("{}accounts/cash", ENV.BREX_API_URL))
|
||||
.bearer_auth(&ENV.BREX_API_KEY)
|
||||
.send()
|
||||
.await?
|
||||
.json::<BrexResponse>()
|
||||
@@ -538,16 +529,16 @@ impl PayoutsQueue {
|
||||
|
||||
pub async fn get_paypal_balance() -> Result<Option<AccountBalance>, ApiError>
|
||||
{
|
||||
let api_username = dotenvy::var("PAYPAL_NVP_USERNAME")?;
|
||||
let api_password = dotenvy::var("PAYPAL_NVP_PASSWORD")?;
|
||||
let api_signature = dotenvy::var("PAYPAL_NVP_SIGNATURE")?;
|
||||
let api_username = &ENV.PAYPAL_NVP_USERNAME;
|
||||
let api_password = &ENV.PAYPAL_NVP_PASSWORD;
|
||||
let api_signature = &ENV.PAYPAL_NVP_SIGNATURE;
|
||||
|
||||
let mut params = HashMap::new();
|
||||
params.insert("METHOD", "GetBalance");
|
||||
params.insert("VERSION", "204");
|
||||
params.insert("USER", &api_username);
|
||||
params.insert("PWD", &api_password);
|
||||
params.insert("SIGNATURE", &api_signature);
|
||||
params.insert("USER", api_username);
|
||||
params.insert("PWD", api_password);
|
||||
params.insert("SIGNATURE", api_signature);
|
||||
params.insert("RETURNALLCURRENCIES", "1");
|
||||
|
||||
let endpoint = "https://api-3t.paypal.com/nvp";
|
||||
@@ -870,7 +861,7 @@ pub async fn make_aditude_request(
|
||||
) -> Result<Vec<AditudePoints>, ApiError> {
|
||||
let request = reqwest::Client::new()
|
||||
.post("https://cloud.aditude.io/api/public/insights/metrics")
|
||||
.bearer_auth(&dotenvy::var("ADITUDE_API_KEY")?)
|
||||
.bearer_auth(&ENV.ADITUDE_API_KEY)
|
||||
.json(&serde_json::json!({
|
||||
"metrics": metrics,
|
||||
"range": range,
|
||||
@@ -1326,25 +1317,25 @@ pub async fn insert_bank_balances_and_webhook(
|
||||
if inserted {
|
||||
check_balance_with_webhook(
|
||||
"paypal",
|
||||
"PAYPAL_BALANCE_ALERT_THRESHOLD",
|
||||
ENV.PAYPAL_BALANCE_ALERT_THRESHOLD,
|
||||
paypal_result,
|
||||
)
|
||||
.await?;
|
||||
check_balance_with_webhook(
|
||||
"brex",
|
||||
"BREX_BALANCE_ALERT_THRESHOLD",
|
||||
ENV.BREX_BALANCE_ALERT_THRESHOLD,
|
||||
brex_result,
|
||||
)
|
||||
.await?;
|
||||
check_balance_with_webhook(
|
||||
"tremendous",
|
||||
"TREMENDOUS_BALANCE_ALERT_THRESHOLD",
|
||||
ENV.TREMENDOUS_BALANCE_ALERT_THRESHOLD,
|
||||
tremendous_result,
|
||||
)
|
||||
.await?;
|
||||
check_balance_with_webhook(
|
||||
"mural",
|
||||
"MURAL_BALANCE_ALERT_THRESHOLD",
|
||||
ENV.MURAL_BALANCE_ALERT_THRESHOLD,
|
||||
mural_result,
|
||||
)
|
||||
.await?;
|
||||
@@ -1357,14 +1348,11 @@ pub async fn insert_bank_balances_and_webhook(
|
||||
|
||||
async fn check_balance_with_webhook(
|
||||
source: &str,
|
||||
threshold_env_var_name: &str,
|
||||
threshold: u64,
|
||||
result: Result<Option<AccountBalance>, ApiError>,
|
||||
) -> Result<Option<AccountBalance>, ApiError> {
|
||||
let maybe_threshold = dotenvy::var(threshold_env_var_name)
|
||||
.ok()
|
||||
.and_then(|x| x.parse::<u64>().ok())
|
||||
.filter(|x| *x != 0);
|
||||
let payout_alert_webhook = dotenvy::var("PAYOUT_ALERT_SLACK_WEBHOOK")?;
|
||||
let maybe_threshold = if threshold > 0 { Some(threshold) } else { None };
|
||||
let payout_alert_webhook = &ENV.PAYOUT_ALERT_SLACK_WEBHOOK;
|
||||
|
||||
match &result {
|
||||
Ok(Some(account_balance)) => {
|
||||
@@ -1379,7 +1367,7 @@ async fn check_balance_with_webhook(
|
||||
threshold,
|
||||
current_balance: available,
|
||||
},
|
||||
&payout_alert_webhook,
|
||||
payout_alert_webhook,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@@ -1394,7 +1382,7 @@ async fn check_balance_with_webhook(
|
||||
source: source.to_owned(),
|
||||
display_error: error.to_string(),
|
||||
},
|
||||
&payout_alert_webhook,
|
||||
payout_alert_webhook,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user