haste_health/commands/
server.rs1use 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}