haste_health/commands/
server.rs

1use clap::Subcommand;
2use haste_config::{Config, get_config};
3use haste_fhir_client::FHIRClient;
4use haste_fhir_model::r4::generated::{
5    resources::{Resource, ResourceType, User},
6    terminology::UserRole,
7    types::FHIRString,
8};
9use haste_fhir_operation_error::OperationOutcomeError;
10use haste_fhir_search::SearchEngine;
11use haste_jwt::{ProjectId, TenantId};
12use haste_repository::admin::Migrate;
13use haste_server::{
14    ServerEnvironmentVariables,
15    auth_n::oidc::utilities::set_user_password,
16    fhir_client::ServerCTX,
17    load_artifacts, server, services,
18    tenants::{SubscriptionTier, create_tenant},
19};
20use std::sync::Arc;
21
22#[derive(Subcommand, Debug)]
23pub enum ServerCommands {
24    Start {
25        #[arg(short, long)]
26        port: Option<u16>,
27    },
28
29    Tenant {
30        #[command(subcommand)]
31        command: TenantCommands,
32    },
33
34    User {
35        #[command(subcommand)]
36        command: UserCommands,
37    },
38
39    Migrate {
40        #[command(subcommand)]
41        command: MigrationCommands,
42    },
43}
44
45#[derive(Subcommand, Debug)]
46pub enum MigrationCommands {
47    Artifacts {},
48    Repo {},
49    Search {},
50    All,
51}
52
53#[derive(Subcommand, Debug)]
54pub enum TenantCommands {
55    Create {
56        #[arg(short, long)]
57        id: String,
58        #[arg(short, long)]
59        subscription_tier: Option<SubscriptionTier>,
60    },
61}
62
63#[derive(Subcommand, Debug)]
64pub enum UserCommands {
65    Create {
66        #[arg(short, long)]
67        email: String,
68        #[arg(short, long)]
69        password: String,
70        #[arg(short, long)]
71        tenant: String,
72    },
73}
74
75async fn migrate_repo(
76    config: Arc<dyn Config<ServerEnvironmentVariables>>,
77) -> Result<(), OperationOutcomeError> {
78    let services = services::create_services(config).await?;
79    services.repo.migrate().await?;
80    Ok(())
81}
82
83async fn migrate_search(
84    config: Arc<dyn Config<ServerEnvironmentVariables>>,
85) -> Result<(), OperationOutcomeError> {
86    let services = services::create_services(config).await?;
87    services
88        .search
89        .migrate(&haste_repository::types::SupportedFHIRVersions::R4)
90        .await?;
91    Ok(())
92}
93
94async fn migrate_artifacts(
95    config: Arc<dyn Config<ServerEnvironmentVariables>>,
96) -> Result<(), OperationOutcomeError> {
97    let initial = config
98        .get(ServerEnvironmentVariables::AllowArtifactMutations)
99        .unwrap_or("false".to_string());
100    config.set(
101        ServerEnvironmentVariables::AllowArtifactMutations,
102        "true".to_string(),
103    )?;
104    load_artifacts::load_artifacts(config.clone()).await?;
105    config.set(ServerEnvironmentVariables::AllowArtifactMutations, initial)?;
106    Ok(())
107}
108
109pub async fn server(command: &ServerCommands) -> Result<(), OperationOutcomeError> {
110    let config = get_config::<ServerEnvironmentVariables>("environment".into());
111
112    match &command {
113        ServerCommands::Start { port } => server::serve(port.unwrap_or(3000)).await,
114        ServerCommands::Migrate { command } => match command {
115            MigrationCommands::Artifacts {} => migrate_artifacts(config).await,
116            MigrationCommands::Repo {} => migrate_repo(config).await,
117            MigrationCommands::Search {} => migrate_search(config).await,
118            MigrationCommands::All => {
119                migrate_repo(config.clone()).await?;
120                migrate_search(config.clone()).await?;
121                migrate_artifacts(config).await?;
122                Ok(())
123            }
124        },
125        ServerCommands::Tenant { command } => match command {
126            TenantCommands::Create {
127                id,
128                subscription_tier,
129            } => {
130                let services = services::create_services(config).await?;
131                create_tenant(
132                    services,
133                    Some(id.clone()),
134                    id,
135                    &subscription_tier.clone().unwrap_or(SubscriptionTier::Free),
136                )
137                .await?;
138
139                Ok(())
140            }
141        },
142        ServerCommands::User { command } => match command {
143            UserCommands::Create {
144                email,
145                password,
146                tenant,
147            } => {
148                let services = services::create_services(config)
149                    .await?
150                    .transaction()
151                    .await?;
152
153                let tenant = TenantId::new(tenant.clone());
154
155                let ctx = Arc::new(ServerCTX::system(
156                    tenant.clone(),
157                    ProjectId::System,
158                    services.fhir_client.clone(),
159                ));
160
161                let user = services
162                    .fhir_client
163                    .create(
164                        ctx,
165                        ResourceType::User,
166                        Resource::User(User {
167                            role: Box::new(UserRole::Admin(None)),
168                            email: Some(Box::new(FHIRString {
169                                value: Some(email.clone()),
170                                ..Default::default()
171                            })),
172                            ..Default::default()
173                        }),
174                    )
175                    .await?;
176
177                let user = match user {
178                    Resource::User(user) => user,
179                    _ => panic!("Created resource is not a User"),
180                };
181
182                let user_id = user.id.clone().unwrap();
183
184                set_user_password(&*services.repo, &tenant, email, &user_id, password).await?;
185
186                services.commit().await?;
187
188                Ok(())
189            }
190        },
191    }
192}