Skip to content

Commit 45f3e0c

Browse files
committed
refactor: replace clap with manual env parsing and more
- add manual env parsing - import-papers: add cli arg for archive - import_papers.sh: delete copied archive file from container - frontend: add 'Contribute on GitHub' to footer
1 parent 750e711 commit 45f3e0c

File tree

6 files changed

+102
-31
lines changed

6 files changed

+102
-31
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ go.work.sum
1313

1414
frontend/public/pdf.worker.min.mjs
1515
*.log
16-
*.patch
16+
*.patch
17+
log

backend/import_papers.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ ARCHIVE_PATH="$1"
1010
SERVICE="iqps-backend"
1111
DEST_PATH="/app/qp.tar.gz"
1212

13+
if [[ ! -f "$ARCHIVE_PATH" ]]; then
14+
echo "Error: File '$ARCHIVE_PATH' not found."
15+
exit 1
16+
fi
17+
1318
echo "Copying '$ARCHIVE_PATH' to '$SERVICE'..."
1419
docker compose cp "$ARCHIVE_PATH" "$SERVICE":"$DEST_PATH"
1520

1621
echo "Running import-papers..."
1722
docker compose exec "$SERVICE" ./import-papers
1823

24+
echo "Deleting copied file from container..."
25+
docker compose exec "$SERVICE" rm -f "$DEST_PATH"
26+
1927
echo "Done!"

backend/src/bin/import-papers.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,41 @@ use tempfile::tempdir;
1313
use tracing::{info, warn};
1414
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt};
1515

16+
#[derive(Parser, Debug)]
17+
#[command(
18+
name = "import-papers",
19+
about = "Imports papers into the database from an archive.",
20+
version,
21+
author
22+
)]
23+
struct Args {
24+
/// Path to the .tar.gz file containing papers (e.g., qp.tar.gz)
25+
file: String,
26+
}
27+
1628
#[tokio::main]
1729
async fn main() -> Result<(), Box<dyn std::error::Error>> {
1830
if dotenvy::dotenv().is_ok() {
1931
println!("Loaded an existing .env file.");
2032
}
21-
let env_vars = env::EnvVars::parse()
33+
34+
let env_vars = env::EnvVars::parse()?
2235
.process()
2336
.expect("Failed to parse environment variables");
2437

38+
let args = Args::parse();
39+
if !Path::new(&args.file).exists() {
40+
eprintln!("Error: file '{}' not found.", args.file);
41+
std::process::exit(1);
42+
}
43+
2544
let database = db::Database::new(&env_vars)
2645
.await
2746
.expect("Failed to connect to database");
2847

2948
let dir = tempdir()?;
3049
let dir_path = dir.path();
31-
extract_tar_gz("qp.tar.gz", dir_path)?;
50+
extract_tar_gz(&args.file, dir_path)?;
3251

3352
let file = fs::File::open(dir_path.join("qp.json")).expect("Failed to open JSON file");
3453
let reader = BufReader::new(file);

backend/src/env.rs

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,95 +4,135 @@
44
55
use std::path::PathBuf;
66

7-
use clap::Parser;
87
use hmac::{digest::InvalidLength, Hmac, Mac};
98
use sha2::Sha256;
109

1110
use crate::pathutils::Paths;
1211

13-
#[derive(Parser, Clone)]
12+
#[derive(Clone)]
1413
pub struct EnvVars {
1514
// Database
16-
#[arg(env)]
1715
/// Database name
1816
pub db_name: String,
19-
#[arg(env)]
2017
/// Database hostname
2118
pub db_host: String,
22-
#[arg(env)]
2319
/// Database port
2420
pub db_port: String,
25-
#[arg(env)]
2621
/// Database username
2722
pub db_user: String,
28-
#[arg(env)]
2923
/// Database password
3024
pub db_password: String,
3125

3226
// Auth
33-
#[arg(env)]
3427
/// OAuth app client id (public token)
3528
pub gh_client_id: String,
36-
#[arg(env)]
3729
/// An org admin's Github token (with the `read:org` permission)
3830
pub gh_org_admin_token: String,
39-
#[arg(env)]
4031
/// JWT encryption secret (make it a long, randomized string)
4132
jwt_secret: String,
42-
#[arg(env)]
4333
/// OAuth app client secret
4434
pub gh_client_secret: String,
45-
#[arg(env, default_value = "")]
4635
/// Github organization name
4736
pub gh_org_name: String,
48-
#[arg(env, default_value = "")]
4937
/// Github organization team slug (this team has access to admin dashboard)
5038
pub gh_org_team_slug: String,
51-
#[arg(env, default_value = "")]
5239
/// The usernames of the admins (additional to org team members, comma separated)
5340
pub gh_admin_usernames: String,
54-
#[arg(env, default_value = "")]
5541
/// URL of Slack webhook for sending notifications
5642
pub slack_webhook_url: String,
5743

5844
// Other configs
59-
#[arg(env, default_value = "10")]
6045
/// Maximum number of papers that can be uploaded at a time
6146
pub max_upload_limit: usize,
62-
#[arg(env, default_value = "./log/application.log")]
6347
/// Location where logs are stored
6448
pub log_location: PathBuf,
6549

6650
// Paths
67-
#[arg(env, default_value = "https://static.metakgp.org")]
6851
/// The URL of the static files server (odin's vault)
6952
static_files_url: String,
70-
#[arg(env, default_value = "/srv/static")]
7153
/// The path where static files are served from
7254
static_file_storage_location: PathBuf,
73-
#[arg(env, default_value = "/iqps/uploaded")]
7455
/// The path where uploaded papers are stored temporarily, relative to the `static_file_storage_location`
7556
uploaded_qps_path: PathBuf,
76-
#[arg(env, default_value = "/peqp/qp")]
7757
/// The path where library papers (scrapped) are stored, relative to the `static_file_storage_location`
7858
library_qps_path: PathBuf,
7959

8060
// Server
81-
#[arg(env, default_value = "8080")]
8261
/// The port the server listens on
8362
pub server_port: i32,
8463

8564
// CORS
86-
#[arg(env, default_value = "https://qp.metakgp.org,http://localhost:5173")]
8765
/// List of origins allowed (as a list of values separated by commas `origin1, origin2`)
8866
pub cors_allowed_origins: String,
8967

90-
#[arg(skip)]
9168
/// All paths must be handled using this
9269
pub paths: Paths,
9370
}
9471

95-
impl EnvVars {
72+
impl EnvVars {
73+
/// Parses the environment variables into the struct
74+
pub fn parse() -> Result<Self, Box<dyn std::error::Error>> {
75+
let db_name = std::env::var("DB_NAME")?;
76+
let db_host = std::env::var("DB_HOST")?;
77+
let db_port = std::env::var("DB_PORT")?;
78+
let db_user = std::env::var("DB_USER")?;
79+
let db_password = std::env::var("DB_PASSWORD")?;
80+
let gh_client_id = std::env::var("GH_CLIENT_ID")?;
81+
let gh_org_admin_token = std::env::var("GH_ORG_ADMIN_TOKEN")?;
82+
let jwt_secret = std::env::var("JWT_SECRET")?;
83+
let gh_client_secret = std::env::var("GH_CLIENT_SECRET")?;
84+
let gh_org_name = std::env::var("GH_ORG_NAME").unwrap_or_default();
85+
let gh_org_team_slug = std::env::var("GH_ORG_TEAM_SLUG").unwrap_or_default();
86+
let gh_admin_usernames = std::env::var("GH_ADMIN_USERNAMES").unwrap_or_default();
87+
let slack_webhook_url = std::env::var("SLACK_WEBHOOK_URL").unwrap_or_default();
88+
let max_upload_limit = std::env::var("MAX_UPLOAD_LIMIT")
89+
.unwrap_or_else(|_| "10".to_string())
90+
.parse::<usize>()?;
91+
let log_location = std::env::var("LOG_LOCATION")
92+
.unwrap_or_else(|_| "./log/application.log".to_string())
93+
.into();
94+
let static_files_url = std::env::var("STATIC_FILES_URL")
95+
.unwrap_or_else(|_| "https://static.metakgp.org".to_string());
96+
let static_file_storage_location = std::env::var("STATIC_FILE_STORAGE_LOCATION")
97+
.unwrap_or_else(|_| "/srv/static".to_string())
98+
.into();
99+
let uploaded_qps_path = std::env::var("UPLOADED_QPS_PATH")
100+
.unwrap_or_else(|_| "/iqps/uploaded".to_string())
101+
.into();
102+
let library_qps_path = std::env::var("LIBRARY_QPS_PATH")
103+
.unwrap_or_else(|_| "/peqp/qp".to_string())
104+
.into();
105+
let server_port = std::env::var("SERVER_PORT")
106+
.unwrap_or_else(|_| "8080".to_string())
107+
.parse::<i32>()?;
108+
let cors_allowed_origins = std::env::var("CORS_ALLOWED_ORIGINS")
109+
.unwrap_or_else(|_| "https://qp.metakgp.org,http://localhost:5173".to_string());
110+
Ok(Self {
111+
db_name,
112+
db_host,
113+
db_port,
114+
db_user,
115+
db_password,
116+
gh_client_id,
117+
gh_org_admin_token,
118+
jwt_secret,
119+
gh_client_secret,
120+
gh_org_name,
121+
gh_org_team_slug,
122+
gh_admin_usernames,
123+
slack_webhook_url,
124+
max_upload_limit,
125+
log_location,
126+
static_files_url,
127+
static_file_storage_location,
128+
uploaded_qps_path,
129+
library_qps_path,
130+
server_port,
131+
cors_allowed_origins,
132+
paths: Paths::default(),
133+
})
134+
}
135+
96136
/// Processes the environment variables after reading.
97137
pub fn process(mut self) -> Result<Self, Box<dyn std::error::Error>> {
98138
self.paths = Paths::new(

backend/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
2222
}
2323

2424
// Read environment variables
25-
let env_vars = env::EnvVars::parse().process()?;
25+
let env_vars = env::EnvVars::parse()?.process()?;
2626

2727
// Initialize logger
2828
let (append_writer, _guard) = tracing_appender::non_blocking(

frontend/src/components/Common/Common.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import './styles/common_styles.scss';
44
import { IconType } from 'react-icons';
55

66
export function Footer() {
7-
return <h3 className="meta-footer">Made with ❤️ and {"</>"} by <a href="https://github.com/metakgp/iqps-go" target="_blank">MetaKGP</a></h3>;
7+
return <h3 className="meta-footer">
8+
Contribute on <a href="https://github.com/metakgp/iqps-go" target="_blank">GitHub</a> |
9+
Made with ❤️ and {"</>"} by <a href="https://github.com/metakgp" target="_blank">MetaKGP</a>
10+
</h3>;
811
}
912

1013
interface ILinkCommonProps {
@@ -46,4 +49,4 @@ export function Header(props: IHeaderProps) {
4649

4750
export function Navbar() {
4851
return <></>;
49-
}
52+
}

0 commit comments

Comments
 (0)