From 0a9765174eb153c5afcdeddbcdb70cd58b4c5c9c Mon Sep 17 00:00:00 2001 From: Julia Seweryn Date: Tue, 29 Oct 2024 12:41:36 +0100 Subject: [PATCH 1/7] grafana_restore --- database/src/tables/registered_app/select.rs | 16 +++ database/src/tables/team/select.rs | 6 ++ server/src/bin/grafana_restore.rs | 108 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 server/src/bin/grafana_restore.rs diff --git a/database/src/tables/registered_app/select.rs b/database/src/tables/registered_app/select.rs index 87765983..10a2bf37 100644 --- a/database/src/tables/registered_app/select.rs +++ b/database/src/tables/registered_app/select.rs @@ -34,4 +34,20 @@ impl Db { .await .map_err(|e| e.into()); } + + pub async fn get_registered_app_by_team_id( + &self, + team_id: &String, + ) -> Result, DbError> { + let query = format!( + "SELECT * FROM {REGISTERED_APPS_TABLE_NAME} WHERE team_id = $1 AND deactivated_at IS NULL" + ); + let typed_query = query_as::<_, DbRegisteredApp>(&query); + + return typed_query + .bind(&team_id) + .fetch_all(&self.connection_pool) + .await + .map_err(|e| e.into()); + } } diff --git a/database/src/tables/team/select.rs b/database/src/tables/team/select.rs index 848ea4a3..eeb031f9 100644 --- a/database/src/tables/team/select.rs +++ b/database/src/tables/team/select.rs @@ -109,4 +109,10 @@ impl Db { .await .map_err(|e| e.into()); } + pub async fn get_all_teams(&self) -> Result, DbError> { + let query = format!("SELECT * FROM {TEAM_TABLE_NAME} WHERE deactivated_at IS NULL"); + let typed_query = query_as::<_, Team>(&query); + + return typed_query.fetch_all(&self.connection_pool).await.map_err(|e| e.into()); + } } diff --git a/server/src/bin/grafana_restore.rs b/server/src/bin/grafana_restore.rs new file mode 100644 index 00000000..bfaadae1 --- /dev/null +++ b/server/src/bin/grafana_restore.rs @@ -0,0 +1,108 @@ +use core::panic; +use database::db::Db; +use openapi::apis::configuration::Configuration; +use server::env::{GF_SECURITY_ADMIN_PASSWORD, GF_SECURITY_ADMIN_USER, GRAFANA_BASE_PATH}; +use server::http::cloud::grafana_utils::add_user_to_team::handle_grafana_add_user_to_team; +use server::http::cloud::grafana_utils::create_new_app::handle_grafana_create_new_app; +use server::http::cloud::grafana_utils::create_new_team::handle_grafana_create_new_team; +use server::utils::import_template_dashboards; +use std::collections::HashSet; +use std::sync::Arc; + +// This script is used to restore the state of the Grafana instance +// Before running this script, clear the contents of the grafana-data folder +#[tokio::main] +async fn main() { + let db = Db::connect_to_the_pool().await; + let mut conf: Configuration = Configuration::new(); + conf.base_path = GRAFANA_BASE_PATH().to_string(); + conf.basic_auth = Some(( + GF_SECURITY_ADMIN_USER().to_string(), + Some(GF_SECURITY_ADMIN_PASSWORD().to_string()), + )); + + let grafana_client_conf = Arc::new(conf); + // Setup template dashboards + import_template_dashboards(&grafana_client_conf).await; + + let teams = match db.get_all_teams().await { + Ok(teams) => teams, + Err(e) => { + panic!("Failed to get teams. Error: {:?}", e); + } + }; + for team in teams { + // create teams + match handle_grafana_create_new_team( + &grafana_client_conf, + &team.team_admin_id, + &team.team_name, + ) + .await + { + Ok(id) => id, + Err(err) => { + panic!("Failed to create team in grafana: {:?}", err); + } + }; + + let privileges = match db.get_privileges_by_team_id(&team.team_id).await { + Ok(privileges) => privileges, + Err(e) => { + panic!("Failed to get privileges. Error: {:?}", e); + } + }; + let unique_user_ids: Vec = privileges + .into_iter() + .map(|privilege| privilege.user_id) + .collect::>() + .into_iter() + .collect(); + + for user_id in unique_user_ids { + let user_email = match db.get_user_by_user_id(&user_id).await { + Ok(Some(user)) => user.email, + Ok(None) => { + panic!("User not found. User ID: {:?}", user_id); + } + Err(e) => { + panic!("Failed to get user. Error: {:?}", e); + } + }; + // add users to teams + match handle_grafana_add_user_to_team(&grafana_client_conf, &team.team_id, &user_email) + .await + { + Ok(id) => id, + Err(err) => { + panic!("Failed to add user to team in grafana: {:?}", err); + } + }; + } + let apps = match db.get_registered_app_by_team_id(&team.team_id).await { + Ok(apps) => apps, + Err(e) => { + panic!("Failed to get apps. Error: {:?}", e); + } + }; + for app in apps { + let app_id = app.app_id.clone(); + let app_name = app.app_name.clone(); + // create apps + match handle_grafana_create_new_app( + &grafana_client_conf, + &app_id, + &app_name, + &team.team_id, + ) + .await + { + Ok(id) => id, + Err(err) => { + panic!("Failed to create app in grafana: {:?}", err); + } + }; + } + } + println!("Got it! Exiting..."); +} From 7e1dc67a7766de56916ac5e3fe4f7074775a5104 Mon Sep 17 00:00:00 2001 From: Julia Seweryn Date: Wed, 30 Oct 2024 13:11:21 +0100 Subject: [PATCH 2/7] fixed --- database/migrations/0002_team.sql | 1 + database/src/tables/team/select.rs | 13 ++++++-- database/src/tables/team/table_struct.rs | 4 ++- database/src/tables/team/update.rs | 24 ++++++++++++-- .../src/tables/user_app_privileges/select.rs | 1 + server/src/bin/grafana_restore.rs | 33 +++++++++++-------- server/src/http/cloud/accept_team_invite.rs | 18 +++++++++- server/src/http/cloud/delete_team.rs | 2 +- server/src/http/cloud/leave_team.rs | 2 +- server/src/http/cloud/register_new_app.rs | 2 +- server/src/http/cloud/register_new_team.rs | 6 +++- .../src/http/cloud/remove_user_from_team.rs | 2 +- 12 files changed, 82 insertions(+), 26 deletions(-) diff --git a/database/migrations/0002_team.sql b/database/migrations/0002_team.sql index 70405345..5065b679 100644 --- a/database/migrations/0002_team.sql +++ b/database/migrations/0002_team.sql @@ -1,5 +1,6 @@ CREATE TABLE team( team_id TEXT NOT NULL UNIQUE, + grafana_id TEXT NOT NULL UNIQUE, team_name TEXT NOT NULL, personal BOOLEAN NOT NULL, subscription subscription, diff --git a/database/src/tables/team/select.rs b/database/src/tables/team/select.rs index eeb031f9..42a7453c 100644 --- a/database/src/tables/team/select.rs +++ b/database/src/tables/team/select.rs @@ -11,7 +11,9 @@ impl Db { tx: Option<&mut Transaction<'_, sqlx::Postgres>>, team_id: &String, ) -> Result, DbError> { - let query = format!("SELECT * FROM {TEAM_TABLE_NAME} WHERE team_id = $1 AND deactivated_at IS NULL"); + let query = format!( + "SELECT * FROM {TEAM_TABLE_NAME} WHERE team_id = $1 AND deactivated_at IS NULL" + ); let typed_query = query_as::<_, Team>(&query); match tx { @@ -100,7 +102,9 @@ impl Db { } pub async fn get_team_by_admin_id(&self, admin_id: &String) -> Result, DbError> { - let query = format!("SELECT * FROM {TEAM_TABLE_NAME} WHERE team_admin_id = $1 AND deactivated_at IS NULL"); + let query = format!( + "SELECT * FROM {TEAM_TABLE_NAME} WHERE team_admin_id = $1 AND deactivated_at IS NULL" + ); let typed_query = query_as::<_, Team>(&query); return typed_query @@ -113,6 +117,9 @@ impl Db { let query = format!("SELECT * FROM {TEAM_TABLE_NAME} WHERE deactivated_at IS NULL"); let typed_query = query_as::<_, Team>(&query); - return typed_query.fetch_all(&self.connection_pool).await.map_err(|e| e.into()); + return typed_query + .fetch_all(&self.connection_pool) + .await + .map_err(|e| e.into()); } } diff --git a/database/src/tables/team/table_struct.rs b/database/src/tables/team/table_struct.rs index 51553e27..4d68f766 100644 --- a/database/src/tables/team/table_struct.rs +++ b/database/src/tables/team/table_struct.rs @@ -7,11 +7,12 @@ use sqlx::{ pub const TEAM_TABLE_NAME: &str = "team"; pub const TEAM_KEYS: &str = - "team_id, team_name, personal, subscription, team_admin_id, registration_timestamp, deactivated_at"; + "team_id, grafana_id, team_name, personal, subscription, team_admin_id, registration_timestamp, deactivated_at"; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Team { pub team_id: String, + pub grafana_id: String, pub personal: bool, pub team_name: String, // Subscription is required to get access to the statistics @@ -25,6 +26,7 @@ impl FromRow<'_, PgRow> for Team { fn from_row(row: &sqlx::postgres::PgRow) -> std::result::Result { Ok(Team { team_id: row.get("team_id"), + grafana_id: row.get("grafana_id"), team_name: row.get("team_name"), personal: row.get("personal"), subscription: row.get("subscription"), diff --git a/database/src/tables/team/update.rs b/database/src/tables/team/update.rs index a398db51..135ed10d 100644 --- a/database/src/tables/team/update.rs +++ b/database/src/tables/team/update.rs @@ -16,11 +16,12 @@ impl Db { team: &Team, ) -> Result<(), DbError> { let query_body = format!( - "INSERT INTO {TEAM_TABLE_NAME} ({TEAM_KEYS}) VALUES ($1, $2, $3, $4, $5, $6, NULL)" + "INSERT INTO {TEAM_TABLE_NAME} ({TEAM_KEYS}) VALUES ($1, $2, $3, $4, $5, $6, $7, NULL)" ); let query_result = query(&query_body) .bind(&team.team_id) + .bind(&team.grafana_id) .bind(&team.team_name) .bind(&team.personal) .bind(&team.subscription) @@ -37,11 +38,12 @@ impl Db { pub async fn create_new_team(&self, team: &Team) -> Result<(), DbError> { let query_body = format!( - "INSERT INTO {TEAM_TABLE_NAME} ({TEAM_KEYS}) VALUES ($1, $2, $3, $4, $5, $6, NULL)" + "INSERT INTO {TEAM_TABLE_NAME} ({TEAM_KEYS}) VALUES ($1, $2, $3, $4, $5, $6, $7, NULL)" ); let query_result = query(&query_body) .bind(&team.team_id) + .bind(&team.grafana_id) .bind(&team.team_name) .bind(&team.personal) .bind(&team.subscription) @@ -96,6 +98,23 @@ impl Db { Err(e) => Err(e).map_err(|e| e.into()), } } + + pub async fn update_grafana_id(&self, team_id: &str, grafana_id: &str) -> Result<(), DbError> { + let query_body = format!( + "UPDATE {TEAM_TABLE_NAME} SET grafana_id = $1 WHERE team_id = $2 AND deactivated_at IS NULL", + ); + + let query_result = query(&query_body) + .bind(grafana_id) + .bind(team_id) + .execute(&self.connection_pool) + .await; + + match query_result { + Ok(_) => Ok(()), + Err(e) => Err(e).map_err(|e| e.into()), + } + } } #[cfg(feature = "cloud_integration_tests")] @@ -121,6 +140,7 @@ mod tests { // Create team and register app let team = Team { team_id: "test_team_id".to_string(), + grafana_id: "test_grafana_id".to_string(), team_name: "test_team_name".to_string(), personal: false, subscription: None, diff --git a/database/src/tables/user_app_privileges/select.rs b/database/src/tables/user_app_privileges/select.rs index 9c27c82d..e6cd7696 100644 --- a/database/src/tables/user_app_privileges/select.rs +++ b/database/src/tables/user_app_privileges/select.rs @@ -163,6 +163,7 @@ impl Db { for row in rows { let team = Team { team_id: row.get("team_id"), + grafana_id: row.get("grafana_id"), personal: row.get("personal"), team_name: row.get("team_name"), subscription: row.get("subscription"), diff --git a/server/src/bin/grafana_restore.rs b/server/src/bin/grafana_restore.rs index bfaadae1..7a789288 100644 --- a/server/src/bin/grafana_restore.rs +++ b/server/src/bin/grafana_restore.rs @@ -40,7 +40,11 @@ async fn main() { ) .await { - Ok(id) => id, + Ok(id) => { + if let Err(err) = db.update_grafana_id(&team.team_id, &id.to_string()).await { + panic!("Failed to update grafana id in database: {:?}", err); + } + } Err(err) => { panic!("Failed to create team in grafana: {:?}", err); } @@ -59,19 +63,20 @@ async fn main() { .into_iter() .collect(); - for user_id in unique_user_ids { - let user_email = match db.get_user_by_user_id(&user_id).await { - Ok(Some(user)) => user.email, - Ok(None) => { - panic!("User not found. User ID: {:?}", user_id); - } - Err(e) => { - panic!("Failed to get user. Error: {:?}", e); - } - }; + let users_emails = match db.get_users_emails_by_ids(&unique_user_ids).await { + Ok(emails) => emails, + Err(e) => { + panic!("Failed to get users emails. Error: {:?}", e); + } + }; + for (_, user_email) in users_emails { // add users to teams - match handle_grafana_add_user_to_team(&grafana_client_conf, &team.team_id, &user_email) - .await + match handle_grafana_add_user_to_team( + &grafana_client_conf, + &team.grafana_id, + &user_email, + ) + .await { Ok(id) => id, Err(err) => { @@ -93,7 +98,7 @@ async fn main() { &grafana_client_conf, &app_id, &app_name, - &team.team_id, + &team.grafana_id, ) .await { diff --git a/server/src/http/cloud/accept_team_invite.rs b/server/src/http/cloud/accept_team_invite.rs index c34818c4..512ce3d5 100644 --- a/server/src/http/cloud/accept_team_invite.rs +++ b/server/src/http/cloud/accept_team_invite.rs @@ -101,10 +101,26 @@ pub async fn accept_team_invite( } } + let grafana_team_id = match db.get_team_by_team_id(None, &request.team_id).await { + Ok(Some(team)) => team.grafana_id, + Ok(None) => { + return Err(( + StatusCode::BAD_REQUEST, + CloudApiErrors::TeamDoesNotExist.to_string(), + )); + } + Err(err) => { + error!("Failed to get team by team_id: {:?}", err); + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + CloudApiErrors::DatabaseError.to_string(), + )); + } + }; // Grafana add user to the team if is_env_production() { if let Err(err) = - handle_grafana_add_user_to_team(&grafana_conf, &request.team_id, &user.email).await + handle_grafana_add_user_to_team(&grafana_conf, &grafana_team_id, &user.email).await { error!("Failed to add user to the team in grafana: {:?}", err); return Err(( diff --git a/server/src/http/cloud/delete_team.rs b/server/src/http/cloud/delete_team.rs index 4975d90c..a21c2501 100644 --- a/server/src/http/cloud/delete_team.rs +++ b/server/src/http/cloud/delete_team.rs @@ -153,7 +153,7 @@ pub async fn delete_team( // Grafana, delete team // TODO, fix this by fixing methods for setting up grafana datasource if is_env_production() { - if let Err(err) = handle_grafana_delete_team(&grafana_conf, &request.team_id).await { + if let Err(err) = handle_grafana_delete_team(&grafana_conf, &team.grafana_id).await { error!("Failed to delete team from grafana: {:?}", err); return Err(( StatusCode::INTERNAL_SERVER_ERROR, diff --git a/server/src/http/cloud/leave_team.rs b/server/src/http/cloud/leave_team.rs index 239bdab5..10682e48 100644 --- a/server/src/http/cloud/leave_team.rs +++ b/server/src/http/cloud/leave_team.rs @@ -108,7 +108,7 @@ pub async fn leave_team( if is_env_production() { if let Err(err) = handle_grafana_remove_user_from_team( &grafana_conf, - &request.team_id, + &team.grafana_id, &user.email, ) .await diff --git a/server/src/http/cloud/register_new_app.rs b/server/src/http/cloud/register_new_app.rs index 458dfd1d..5688a25f 100644 --- a/server/src/http/cloud/register_new_app.rs +++ b/server/src/http/cloud/register_new_app.rs @@ -116,7 +116,7 @@ pub async fn register_new_app( &grafana_conf, &request.app_name, &app_id, - &team.team_id, + &team.grafana_id, ) .await { diff --git a/server/src/http/cloud/register_new_team.rs b/server/src/http/cloud/register_new_team.rs index 0b10cdd6..712a2842 100644 --- a/server/src/http/cloud/register_new_team.rs +++ b/server/src/http/cloud/register_new_team.rs @@ -17,6 +17,7 @@ use openapi::apis::configuration::Configuration; use serde::{Deserialize, Serialize}; use std::sync::Arc; use ts_rs::TS; +use uuid7::uuid7; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS, Validate)] #[ts(export)] @@ -141,10 +142,13 @@ pub async fn register_new_team( } } } + // Generate a new app id + let team_id = uuid7().to_string(); // Create a new team let team = Team { - team_id: grafana_team_id.to_string(), + team_id: team_id.to_string(), + grafana_id: grafana_team_id.to_string(), team_name: request.team_name.clone(), team_admin_id: user_id.clone(), subscription: None, diff --git a/server/src/http/cloud/remove_user_from_team.rs b/server/src/http/cloud/remove_user_from_team.rs index bdc11d06..7e31d6ef 100644 --- a/server/src/http/cloud/remove_user_from_team.rs +++ b/server/src/http/cloud/remove_user_from_team.rs @@ -110,7 +110,7 @@ pub async fn remove_user_from_team( if is_env_production() { if let Err(err) = handle_grafana_remove_user_from_team( &grafana_conf, - &request.team_id, + &team.grafana_id, &request.user_email, ) .await From 1891e6f2c72211d18083d718d0a40aabe3af654c Mon Sep 17 00:00:00 2001 From: Julia Seweryn Date: Wed, 30 Oct 2024 13:16:21 +0100 Subject: [PATCH 3/7] fixed --- database/src/tables/test_utils.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/database/src/tables/test_utils.rs b/database/src/tables/test_utils.rs index 571c5a25..7343415e 100644 --- a/database/src/tables/test_utils.rs +++ b/database/src/tables/test_utils.rs @@ -97,6 +97,7 @@ pub mod test_utils { let team = Team { team_id: team_id.clone(), + grafana_id: "test_grafana_id".to_string(), team_name: "test_team_name".to_string(), personal: false, subscription: None, From 2fef7534ee96cd775c75d4db1864d0a02c0601a3 Mon Sep 17 00:00:00 2001 From: Julia Seweryn Date: Wed, 30 Oct 2024 13:22:36 +0100 Subject: [PATCH 4/7] fixed --- database/src/tables/user_app_privileges/update.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/database/src/tables/user_app_privileges/update.rs b/database/src/tables/user_app_privileges/update.rs index f647e7bd..344b16f6 100644 --- a/database/src/tables/user_app_privileges/update.rs +++ b/database/src/tables/user_app_privileges/update.rs @@ -371,6 +371,7 @@ mod tests { let team = Team { team_id: team_id.clone(), + grafana_id: "test_grafana_id".to_string(), team_name: "test_team_name".to_string(), personal: false, subscription: None, From 3c1359c1626aade41fd9fc2a60c81e5d2d3ed0c1 Mon Sep 17 00:00:00 2001 From: Julia Seweryn Date: Wed, 30 Oct 2024 13:31:42 +0100 Subject: [PATCH 5/7] fixed --- database/src/tables/user_app_privileges/update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/src/tables/user_app_privileges/update.rs b/database/src/tables/user_app_privileges/update.rs index 344b16f6..700fa216 100644 --- a/database/src/tables/user_app_privileges/update.rs +++ b/database/src/tables/user_app_privileges/update.rs @@ -371,7 +371,7 @@ mod tests { let team = Team { team_id: team_id.clone(), - grafana_id: "test_grafana_id".to_string(), + grafana_id: "test_grafana_id_2".to_string(), team_name: "test_team_name".to_string(), personal: false, subscription: None, From 709b44e4809bef288a1a3a0e2e30c9fb40e97ebb Mon Sep 17 00:00:00 2001 From: Julia Seweryn Date: Wed, 30 Oct 2024 14:25:50 +0100 Subject: [PATCH 6/7] fixed --- database/migrations/0002_team.sql | 2 +- database/src/tables/registered_app/select.rs | 16 ---------------- database/src/tables/team/update.rs | 12 ++++++++++++ server/src/bin/grafana_restore.rs | 6 +++++- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/database/migrations/0002_team.sql b/database/migrations/0002_team.sql index 5065b679..ed4fd046 100644 --- a/database/migrations/0002_team.sql +++ b/database/migrations/0002_team.sql @@ -1,6 +1,6 @@ CREATE TABLE team( team_id TEXT NOT NULL UNIQUE, - grafana_id TEXT NOT NULL UNIQUE, + grafana_id TEXT UNIQUE, team_name TEXT NOT NULL, personal BOOLEAN NOT NULL, subscription subscription, diff --git a/database/src/tables/registered_app/select.rs b/database/src/tables/registered_app/select.rs index 10a2bf37..87765983 100644 --- a/database/src/tables/registered_app/select.rs +++ b/database/src/tables/registered_app/select.rs @@ -34,20 +34,4 @@ impl Db { .await .map_err(|e| e.into()); } - - pub async fn get_registered_app_by_team_id( - &self, - team_id: &String, - ) -> Result, DbError> { - let query = format!( - "SELECT * FROM {REGISTERED_APPS_TABLE_NAME} WHERE team_id = $1 AND deactivated_at IS NULL" - ); - let typed_query = query_as::<_, DbRegisteredApp>(&query); - - return typed_query - .bind(&team_id) - .fetch_all(&self.connection_pool) - .await - .map_err(|e| e.into()); - } } diff --git a/database/src/tables/team/update.rs b/database/src/tables/team/update.rs index 135ed10d..9db0a7a7 100644 --- a/database/src/tables/team/update.rs +++ b/database/src/tables/team/update.rs @@ -115,6 +115,18 @@ impl Db { Err(e) => Err(e).map_err(|e| e.into()), } } + + pub async fn clear_all_grafana_ids(&self) -> Result<(), DbError> { + let query_body = + format!("UPDATE {TEAM_TABLE_NAME} SET grafana_id = NULL WHERE deactivated_at IS NULL",); + + let query_result = query(&query_body).execute(&self.connection_pool).await; + + match query_result { + Ok(_) => Ok(()), + Err(e) => Err(e).map_err(|e| e.into()), + } + } } #[cfg(feature = "cloud_integration_tests")] diff --git a/server/src/bin/grafana_restore.rs b/server/src/bin/grafana_restore.rs index 7a789288..efd4d1bf 100644 --- a/server/src/bin/grafana_restore.rs +++ b/server/src/bin/grafana_restore.rs @@ -25,6 +25,10 @@ async fn main() { // Setup template dashboards import_template_dashboards(&grafana_client_conf).await; + if let Err(err) = db.clear_all_grafana_ids().await { + panic!("Failed to clear grafana ids in database: {:?}", err); + } + let teams = match db.get_all_teams().await { Ok(teams) => teams, Err(e) => { @@ -84,7 +88,7 @@ async fn main() { } }; } - let apps = match db.get_registered_app_by_team_id(&team.team_id).await { + let apps = match db.get_registered_apps_by_team_id(&team.team_id).await { Ok(apps) => apps, Err(e) => { panic!("Failed to get apps. Error: {:?}", e); From f61d142aeafe9afe92165d77c894fc0f92680f2c Mon Sep 17 00:00:00 2001 From: Julia Seweryn Date: Mon, 4 Nov 2024 14:19:28 +0100 Subject: [PATCH 7/7] fixed --- database/src/tables/team/table_struct.rs | 4 +++- database/src/tables/team/update.rs | 3 +-- database/src/tables/user_app_privileges/select.rs | 4 ++-- server/src/bin/grafana_restore.rs | 13 +++++-------- server/src/http/cloud/accept_team_invite.rs | 4 ++-- server/src/http/cloud/cancel_team_user_invite.rs | 4 ++-- server/src/http/cloud/cancel_user_team_invite.rs | 4 ++-- server/src/http/cloud/change_user_privileges.rs | 4 ++-- server/src/http/cloud/delete_team.rs | 4 ++-- server/src/http/cloud/get_team_metadata.rs | 4 ++-- server/src/http/cloud/get_team_user_invites.rs | 4 ++-- server/src/http/cloud/get_team_users_privileges.rs | 4 ++-- server/src/http/cloud/get_user_joined_teams.rs | 1 + server/src/http/cloud/invite_user_to_team.rs | 4 ++-- server/src/http/cloud/leave_team.rs | 4 ++-- server/src/http/cloud/register_new_app.rs | 4 ++-- server/src/http/cloud/register_new_team.rs | 2 +- server/src/http/cloud/remove_user_from_team.rs | 4 ++-- server/src/http/cloud/utils.rs | 13 ------------- server/src/structs/cloud/joined_team.rs | 1 + 20 files changed, 38 insertions(+), 51 deletions(-) diff --git a/database/src/tables/team/table_struct.rs b/database/src/tables/team/table_struct.rs index 4d68f766..756d7acd 100644 --- a/database/src/tables/team/table_struct.rs +++ b/database/src/tables/team/table_struct.rs @@ -26,7 +26,9 @@ impl FromRow<'_, PgRow> for Team { fn from_row(row: &sqlx::postgres::PgRow) -> std::result::Result { Ok(Team { team_id: row.get("team_id"), - grafana_id: row.get("grafana_id"), + grafana_id: row + .try_get::, _>("grafana_id")? + .unwrap_or_default(), team_name: row.get("team_name"), personal: row.get("personal"), subscription: row.get("subscription"), diff --git a/database/src/tables/team/update.rs b/database/src/tables/team/update.rs index 9db0a7a7..4f274cb2 100644 --- a/database/src/tables/team/update.rs +++ b/database/src/tables/team/update.rs @@ -117,8 +117,7 @@ impl Db { } pub async fn clear_all_grafana_ids(&self) -> Result<(), DbError> { - let query_body = - format!("UPDATE {TEAM_TABLE_NAME} SET grafana_id = NULL WHERE deactivated_at IS NULL",); + let query_body = format!("UPDATE {TEAM_TABLE_NAME} SET grafana_id = NULL",); let query_result = query(&query_body).execute(&self.connection_pool).await; diff --git a/database/src/tables/user_app_privileges/select.rs b/database/src/tables/user_app_privileges/select.rs index e6cd7696..cd39f118 100644 --- a/database/src/tables/user_app_privileges/select.rs +++ b/database/src/tables/user_app_privileges/select.rs @@ -114,7 +114,7 @@ impl Db { // 17.10.2024 Hubert: "If this ever breaks, I will write comments." let query = format!( "WITH RelevantTeams AS ( - SELECT DISTINCT t.team_id, t.team_name, t.personal, t.subscription, + SELECT DISTINCT t.team_id, t.grafana_id, t.team_name, t.personal, t.subscription, t.registration_timestamp, gu.email AS team_admin_email, gu.user_id AS team_admin_id, t.deactivated_at, CASE @@ -127,7 +127,7 @@ impl Db { JOIN {USERS_TABLE_NAME} gu ON t.team_admin_id = gu.user_id WHERE (t.team_admin_id = $1 OR uap.user_id = $1) AND t.deactivated_at IS NULL ) - SELECT rt.team_id, rt.team_name, rt.personal, rt.subscription, rt.registration_timestamp, + SELECT rt.team_id, rt.grafana_id, rt.team_name, rt.personal, rt.subscription, rt.registration_timestamp, rt.team_admin_email, rt.team_admin_id, ra.app_id, ra.app_name, ra.whitelisted_domains, ra.ack_public_keys, ra.registration_timestamp AS app_registration_timestamp, uap.user_id, uap.privilege_level, uap.creation_timestamp AS privilege_creation_timestamp, diff --git a/server/src/bin/grafana_restore.rs b/server/src/bin/grafana_restore.rs index efd4d1bf..4855f7b4 100644 --- a/server/src/bin/grafana_restore.rs +++ b/server/src/bin/grafana_restore.rs @@ -37,7 +37,7 @@ async fn main() { }; for team in teams { // create teams - match handle_grafana_create_new_team( + let grafana_id = match handle_grafana_create_new_team( &grafana_client_conf, &team.team_admin_id, &team.team_name, @@ -48,6 +48,7 @@ async fn main() { if let Err(err) = db.update_grafana_id(&team.team_id, &id.to_string()).await { panic!("Failed to update grafana id in database: {:?}", err); } + id.to_string() } Err(err) => { panic!("Failed to create team in grafana: {:?}", err); @@ -75,12 +76,8 @@ async fn main() { }; for (_, user_email) in users_emails { // add users to teams - match handle_grafana_add_user_to_team( - &grafana_client_conf, - &team.grafana_id, - &user_email, - ) - .await + match handle_grafana_add_user_to_team(&grafana_client_conf, &grafana_id, &user_email) + .await { Ok(id) => id, Err(err) => { @@ -102,7 +99,7 @@ async fn main() { &grafana_client_conf, &app_id, &app_name, - &team.grafana_id, + &grafana_id, ) .await { diff --git a/server/src/http/cloud/accept_team_invite.rs b/server/src/http/cloud/accept_team_invite.rs index 512ce3d5..8b475403 100644 --- a/server/src/http/cloud/accept_team_invite.rs +++ b/server/src/http/cloud/accept_team_invite.rs @@ -1,6 +1,6 @@ use super::{ grafana_utils::add_user_to_team::handle_grafana_add_user_to_team, - utils::{custom_validate_team_id, validate_request}, + utils::{custom_validate_uuid, validate_request}, }; use crate::{ env::is_env_production, middlewares::auth_middleware::UserId, @@ -19,7 +19,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpAcceptTeamInviteRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, } diff --git a/server/src/http/cloud/cancel_team_user_invite.rs b/server/src/http/cloud/cancel_team_user_invite.rs index 1bb670ef..3a416166 100644 --- a/server/src/http/cloud/cancel_team_user_invite.rs +++ b/server/src/http/cloud/cancel_team_user_invite.rs @@ -1,4 +1,4 @@ -use super::utils::{custom_validate_team_id, validate_request}; +use super::utils::{custom_validate_uuid, validate_request}; use crate::{ middlewares::auth_middleware::UserId, structs::cloud::{api_cloud_errors::CloudApiErrors, team_invite::TeamInvite}, @@ -15,7 +15,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpCancelTeamUserInviteRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, #[garde(email)] pub user_email: String, diff --git a/server/src/http/cloud/cancel_user_team_invite.rs b/server/src/http/cloud/cancel_user_team_invite.rs index cb4521e6..1554c3a1 100644 --- a/server/src/http/cloud/cancel_user_team_invite.rs +++ b/server/src/http/cloud/cancel_user_team_invite.rs @@ -1,4 +1,4 @@ -use super::utils::{custom_validate_team_id, validate_request}; +use super::utils::{custom_validate_uuid, validate_request}; use crate::{ middlewares::auth_middleware::UserId, structs::cloud::api_cloud_errors::CloudApiErrors, }; @@ -14,7 +14,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpCancelUserTeamInviteRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, } diff --git a/server/src/http/cloud/change_user_privileges.rs b/server/src/http/cloud/change_user_privileges.rs index 2abe1325..a5e34d9d 100644 --- a/server/src/http/cloud/change_user_privileges.rs +++ b/server/src/http/cloud/change_user_privileges.rs @@ -1,4 +1,4 @@ -use super::utils::{custom_validate_team_id, custom_validate_uuid, validate_request}; +use super::utils::{custom_validate_uuid, validate_request}; use crate::{ middlewares::auth_middleware::UserId, structs::cloud::{ @@ -36,7 +36,7 @@ pub struct PrivilegeChange { #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpChangeUsersPrivilegesRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, #[garde(dive)] pub privileges_changes: Vec, diff --git a/server/src/http/cloud/delete_team.rs b/server/src/http/cloud/delete_team.rs index a21c2501..44a68fd0 100644 --- a/server/src/http/cloud/delete_team.rs +++ b/server/src/http/cloud/delete_team.rs @@ -1,4 +1,4 @@ -use super::utils::{custom_validate_team_id, validate_request}; +use super::utils::{custom_validate_uuid, validate_request}; use crate::{ env::is_env_production, http::cloud::grafana_utils::delete_team::handle_grafana_delete_team, @@ -18,7 +18,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpDeleteTeamRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, } diff --git a/server/src/http/cloud/get_team_metadata.rs b/server/src/http/cloud/get_team_metadata.rs index 77dcf006..4196e84e 100644 --- a/server/src/http/cloud/get_team_metadata.rs +++ b/server/src/http/cloud/get_team_metadata.rs @@ -1,4 +1,4 @@ -use super::utils::custom_validate_team_id; +use super::utils::custom_validate_uuid; use crate::{ middlewares::auth_middleware::UserId, structs::cloud::{ @@ -24,7 +24,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpGetTeamMetadataRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, } diff --git a/server/src/http/cloud/get_team_user_invites.rs b/server/src/http/cloud/get_team_user_invites.rs index 0ebed4d1..3152e7f4 100644 --- a/server/src/http/cloud/get_team_user_invites.rs +++ b/server/src/http/cloud/get_team_user_invites.rs @@ -1,4 +1,4 @@ -use super::utils::{custom_validate_team_id, validate_request}; +use super::utils::{custom_validate_uuid, validate_request}; use crate::{ middlewares::auth_middleware::UserId, structs::cloud::{api_cloud_errors::CloudApiErrors, team_invite::TeamInvite}, @@ -19,7 +19,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpGetTeamUserInvitesRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, } diff --git a/server/src/http/cloud/get_team_users_privileges.rs b/server/src/http/cloud/get_team_users_privileges.rs index 4576ee98..d87c77c4 100644 --- a/server/src/http/cloud/get_team_users_privileges.rs +++ b/server/src/http/cloud/get_team_users_privileges.rs @@ -1,4 +1,4 @@ -use super::utils::custom_validate_team_id; +use super::utils::custom_validate_uuid; use crate::{ middlewares::auth_middleware::UserId, structs::cloud::{api_cloud_errors::CloudApiErrors, team_user_privilege::TeamUserPrivilege}, @@ -19,7 +19,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpGetTeamUsersPrivilegesRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, } diff --git a/server/src/http/cloud/get_user_joined_teams.rs b/server/src/http/cloud/get_user_joined_teams.rs index 8b3b8630..299ae389 100644 --- a/server/src/http/cloud/get_user_joined_teams.rs +++ b/server/src/http/cloud/get_user_joined_teams.rs @@ -76,6 +76,7 @@ pub async fn get_user_joined_teams( // Parse joined team let joined_team = JoinedTeam { team_id: team.team_id.clone(), + grafana_id: team.grafana_id, team_name: team.team_name, created_at: team.registration_timestamp, creator_email: admin_email, diff --git a/server/src/http/cloud/invite_user_to_team.rs b/server/src/http/cloud/invite_user_to_team.rs index 0642c4ba..7c7c0019 100644 --- a/server/src/http/cloud/invite_user_to_team.rs +++ b/server/src/http/cloud/invite_user_to_team.rs @@ -1,4 +1,4 @@ -use super::utils::{custom_validate_team_id, validate_request}; +use super::utils::{custom_validate_uuid, validate_request}; use crate::{ mailer::{ mail_requests::{SendEmailRequest, TeamInviteNotification}, @@ -21,7 +21,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpInviteUserToTeamRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, #[garde(email)] pub user_email: String, diff --git a/server/src/http/cloud/leave_team.rs b/server/src/http/cloud/leave_team.rs index 10682e48..7f9c7d5f 100644 --- a/server/src/http/cloud/leave_team.rs +++ b/server/src/http/cloud/leave_team.rs @@ -1,6 +1,6 @@ use super::{ grafana_utils::remove_user_from_the_team::handle_grafana_remove_user_from_team, - utils::{custom_validate_team_id, validate_request}, + utils::{custom_validate_uuid, validate_request}, }; use crate::{ env::is_env_production, @@ -24,7 +24,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpLeaveTeamRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, #[garde(alphanumeric)] pub device: String, diff --git a/server/src/http/cloud/register_new_app.rs b/server/src/http/cloud/register_new_app.rs index 5688a25f..858926fd 100644 --- a/server/src/http/cloud/register_new_app.rs +++ b/server/src/http/cloud/register_new_app.rs @@ -1,6 +1,6 @@ use super::{ grafana_utils::create_new_app::handle_grafana_create_new_app, - utils::{custom_validate_name, custom_validate_team_id, validate_request}, + utils::{custom_validate_name, custom_validate_uuid, validate_request}, }; use crate::{ env::is_env_production, middlewares::auth_middleware::UserId, @@ -23,7 +23,7 @@ use uuid7::uuid7; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpRegisterNewAppRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, #[garde(custom(custom_validate_name))] pub app_name: String, diff --git a/server/src/http/cloud/register_new_team.rs b/server/src/http/cloud/register_new_team.rs index 712a2842..d2e460c2 100644 --- a/server/src/http/cloud/register_new_team.rs +++ b/server/src/http/cloud/register_new_team.rs @@ -166,7 +166,7 @@ pub async fn register_new_team( } return Ok(Json(HttpRegisterNewTeamResponse { - team_id: grafana_team_id.to_string(), + team_id: team_id.to_string(), })); } Err(err) => { diff --git a/server/src/http/cloud/remove_user_from_team.rs b/server/src/http/cloud/remove_user_from_team.rs index 7e31d6ef..51ba31d7 100644 --- a/server/src/http/cloud/remove_user_from_team.rs +++ b/server/src/http/cloud/remove_user_from_team.rs @@ -1,6 +1,6 @@ use super::{ grafana_utils::remove_user_from_the_team::handle_grafana_remove_user_from_team, - utils::{custom_validate_team_id, validate_request}, + utils::{custom_validate_uuid, validate_request}, }; use crate::{ env::is_env_production, @@ -24,7 +24,7 @@ use ts_rs::TS; #[ts(export)] #[serde(rename_all = "camelCase")] pub struct HttpRemoveUserFromTeamRequest { - #[garde(custom(custom_validate_team_id))] + #[garde(custom(custom_validate_uuid))] pub team_id: String, #[garde(email)] pub user_email: String, diff --git a/server/src/http/cloud/utils.rs b/server/src/http/cloud/utils.rs index a806269a..04c0d6b7 100644 --- a/server/src/http/cloud/utils.rs +++ b/server/src/http/cloud/utils.rs @@ -49,19 +49,6 @@ pub fn custom_validate_uuid(string_uuid: &String, _context: &()) -> garde::Resul Ok(()) } -pub fn custom_validate_team_id(string_id: &String, _context: &()) -> garde::Result { - // For now we are using i64 returned from grafana as team_id, hopefully this will be changed to UUID - match i64::from_str(string_id) { - Ok(id) => { - if id < 0 { - return Err(garde::Error::new("Invalid ID format".to_string())); - } - } - Err(_) => return Err(garde::Error::new("Invalid ID format".to_string())), - } - Ok(()) -} - pub fn custom_validate_name(name: &String, _context: &()) -> garde::Result { NAME_REGEX .is_match(name) diff --git a/server/src/structs/cloud/joined_team.rs b/server/src/structs/cloud/joined_team.rs index 3b4117c7..c81ecc49 100644 --- a/server/src/structs/cloud/joined_team.rs +++ b/server/src/structs/cloud/joined_team.rs @@ -9,6 +9,7 @@ pub type TeamId = String; #[serde(rename_all = "camelCase")] pub struct JoinedTeam { pub team_id: TeamId, + pub grafana_id: String, pub team_name: String, pub creator_email: String, pub created_at: DateTime,