From 143e4cb9f046f59f82a404e5f4cb65233608c0fc Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:22:57 +0200 Subject: [PATCH 01/19] Ivar fastball special. Reusable rust CI action with modular toolchain, target, components, and crates + caching --- .../actions/toolchain-cargo-cached/action.yml | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 .github/actions/toolchain-cargo-cached/action.yml diff --git a/.github/actions/toolchain-cargo-cached/action.yml b/.github/actions/toolchain-cargo-cached/action.yml new file mode 100644 index 00000000..ec175954 --- /dev/null +++ b/.github/actions/toolchain-cargo-cached/action.yml @@ -0,0 +1,99 @@ +name: 'Checkout, rust toolchain, and cache' +description: 'This action checks out the commit, sets up rust and installs dependencies. Uses caching internally.' + +inputs: + # Toolchain, targets, target, and components are passed into dtolnay/rust-toolchain + toolchain: + description: Rust toolchain specification -- see https://rust-lang.github.io/rustup/concepts/toolchains.html#toolchain-specification + required: true + default: "1.77.1" + targets: + description: Comma-separated list of target triples to install for this toolchain + required: false + target: + description: Alias for `targets` + required: false + components: + description: Comma-separated list of components to be additionally installed + required: false + + # Install additional crates. For example cargo-audit. + crates: + description: Comma-separated list of crates to be additionally installed + required: false + +runs: + using: 'composite' + steps: + - name: Checkout + uses: actions/checkout@v3 + + - id: toolchain-cache-key + run: | + : Get current year and week like "2024-w4" + date="$(date +'%Y-w%U')" + : construct toolchain cache key + toolchain_cache_key="$(echo -n "$components" | md5sum | awk '{ print $1 }')" + echo "cachekey=$toolchain_cache_key-$date" >> $GITHUB_OUTPUT + env: + components: ${{ inputs.components }} + shell: bash + + # Caching the toolchain, so we don't install rust for every commit/PR. + # Including the date from the previous step in the cache key means + # that the cache is invalidated on a weekly basis - so we're still + # up-to-date. + - name: Cache toolchain + # Don't cache if it's a scheduled job. + if: github.event_name != 'schedule' + id: toolchain-cache + uses: actions/cache@v3 + with: + path: | + ~/.rustup/settings.toml + ~/.rustup/toolchains/${{ inputs.toolchain }}-* + ~/.rustup/update-hashes/${{ inputs.toolchain }}-* + key: rust-toolchain-${{ inputs.toolchain }}-${{ steps.toolchain-cache-key.outputs.cachekey }} + + - name: Install rust toolchain + # Only install the toolchain if it isn't cached. + if: steps.toolchain-cache.outputs.cache-hit != 'true' + id: toolchain + # Pin on SHA for immutability. + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 + with: + toolchain: ${{ inputs.toolchain }} + targets: ${{ inputs.targets }} + target: ${{ inputs.target }} + components: ${{ inputs.components }} + + - id: cargo-crates-cachekey + run: | + : construct crate cache key + crates_cache_key="$(echo -n "$crates" | md5sum | awk '{ print $1 }')" + echo "cache_key=$crates_cache_key" >> $GITHUB_OUTPUT + env: + crates: ${{ inputs.crates }} + shell: bash + + # Pin on SHA for immutability. + - uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 + id: rust-cache + if: github.event_name != 'schedule' + with: + shared-key: ${{ steps.cargo-crates-cachekey.outputs.cachekey }} + + - name: Cargo install dependencies + # Only install crates if they aren't cached. + if: steps.rust-cache.outputs.cache-hit != 'true' + id: cargo-install + run: | + IFS=',' read -ra crates_array <<< "$crates" + for c in "${crates_array[@]}"; do + echo "::debug::cargo install $c" + cargo install $c; + done + unset IFS; + env: + crates: ${{ inputs.crates }} + shell: bash From a4042927b7a001f6e523a5a78898b63bd34fb687 Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:24:52 +0200 Subject: [PATCH 02/19] Add initial rust CI: testing with coverage report, and formatting/linting --- .github/workflows/rust.yaml | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/rust.yaml diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml new file mode 100644 index 00000000..fab1a939 --- /dev/null +++ b/.github/workflows/rust.yaml @@ -0,0 +1,38 @@ +name: Rust CI + +on: push + +defaults: + run: + working-directory: server + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUST_BACKTRACE: short + RUSTFLAGS: "-D warnings" + RUSTUP_MAX_RETRIES: 10 + +jobs: + coverage-and-linting: + name: Test coverage & linting + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Rust Toolchain + uses: ./.github/actions/toolchain-cargo-cached + with: + components: llvm-tools-preview, rustfmt, clippy + crates: cargo-llvm-cov + + - name: Tests & coverage + run: cargo llvm-cov test --no-fail-fast --workspace + + - name: Linting rustfmt + run: cargo fmt --all -- --check + + - name: Linting clippy + run: cargo clippy -- \ No newline at end of file From 1a8985ba780c71d9f57128fcddf9a364eb77c71b Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:53:19 +0200 Subject: [PATCH 03/19] Begin work of fixing tests, formatting, linting, etc --- server/config/default.toml | 5 ++ server/src/auth/mod.rs | 2 +- server/src/auth/models.rs | 3 +- server/src/auth/services.rs | 15 +++- server/src/llms/toxicity.rs | 21 +++-- server/src/rag/brave_search.rs | 94 ++++++++++++----------- server/src/rag/search.rs | 6 +- server/src/search/services.rs | 2 +- server/src/startup.rs | 2 +- server/src/users/models.rs | 39 +++++----- server/src/users/routes.rs | 30 ++++---- server/src/users/services.rs | 29 ++++--- server/tests/health_check.rs | 5 +- server/tests/search.rs | 135 +++++++++++---------------------- server/tests/users.rs | 7 +- 15 files changed, 190 insertions(+), 205 deletions(-) diff --git a/server/config/default.toml b/server/config/default.toml index d70c002b..4e7a9acc 100644 --- a/server/config/default.toml +++ b/server/config/default.toml @@ -16,18 +16,23 @@ top_p = 0.7 [openai] api_url = "https://api.openai.com/v1/chat/completions" model = "gpt-4o" +api_key = "" [query_rephraser] model = "mistralai/Mistral-7B-Instruct-v0.2" max_tokens = 100 +api_key = "" [llm] +toxicity_auth_token = "" toxicity_threshold = 0.75 [pubmed] url_prefix = "https://pubmed.ncbi.nlm.nih.gov" [brave] +subscription_key = "" +goggles_id = "" url = "https://api.search.brave.com/res/v1/web/search" count = 10 result_filter = "query,web" diff --git a/server/src/auth/mod.rs b/server/src/auth/mod.rs index bb88c625..aa297c89 100644 --- a/server/src/auth/mod.rs +++ b/server/src/auth/mod.rs @@ -5,5 +5,5 @@ pub mod models; pub mod oauth2; pub mod routes; pub mod services; -pub mod utils; pub(crate) mod sessions; +pub mod utils; diff --git a/server/src/auth/models.rs b/server/src/auth/models.rs index f1857a8d..3915102d 100644 --- a/server/src/auth/models.rs +++ b/server/src/auth/models.rs @@ -115,7 +115,8 @@ async fn oauth_authenticate( .map_err(BackendError::Reqwest)?; // Persist user in our database, so we can use `get_user`. - let user = sqlx::query_as!(User, + let user = sqlx::query_as!( + User, " insert into users (username, access_token) values ($1, $2) diff --git a/server/src/auth/services.rs b/server/src/auth/services.rs index 13a2a042..7fbe4e14 100644 --- a/server/src/auth/services.rs +++ b/server/src/auth/services.rs @@ -6,7 +6,10 @@ use color_eyre::eyre::eyre; use sqlx::PgPool; #[tracing::instrument(level = "debug", ret, err)] -pub async fn register(pool: PgPool, request: models::RegisterUserRequest) -> crate::Result { +pub async fn register( + pool: PgPool, + request: models::RegisterUserRequest, +) -> crate::Result { if let Some(password) = request.password { let password_hash = utils::hash_password(password).await?; let user = sqlx::query_as!( @@ -49,12 +52,16 @@ pub async fn register(pool: PgPool, request: models::RegisterUserRequest) -> cra } pub async fn is_email_whitelisted(pool: &PgPool, email: &String) -> crate::Result { - let whitelisted_email = sqlx::query_as!(models::WhitelistedEmail, "SELECT * FROM whitelisted_emails WHERE email = $1", email) + let whitelisted_email = sqlx::query_as!( + models::WhitelistedEmail, + "SELECT * FROM whitelisted_emails WHERE email = $1", + email + ) .fetch_one(pool) .await; match whitelisted_email { Ok(whitelisted_email) => Ok(whitelisted_email.approved), - _ => Ok(false) + _ => Ok(false), } - } +} diff --git a/server/src/llms/toxicity.rs b/server/src/llms/toxicity.rs index 23a4e53a..f4fd6ce2 100644 --- a/server/src/llms/toxicity.rs +++ b/server/src/llms/toxicity.rs @@ -1,8 +1,8 @@ use crate::llms::LLMSettings; use color_eyre::eyre::eyre; +use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use reqwest::Client; use serde::{Deserialize, Serialize}; -use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; #[derive(Debug, Serialize, Deserialize)] pub struct ToxicityInput { @@ -10,7 +10,7 @@ pub struct ToxicityInput { } #[derive(Debug, Serialize, Deserialize)] -struct ToxicityAPIResponse (pub Vec); +struct ToxicityAPIResponse(pub Vec); #[derive(Debug, Serialize, Deserialize)] struct ToxicityScore { @@ -25,8 +25,10 @@ pub async fn predict_toxicity( ) -> crate::Result { let mut headers = HeaderMap::new(); headers.insert( - HeaderName::from_bytes(b"Authorization").map_err(|e| eyre!("Failed to create header: {e}"))?, - HeaderValue::from_str(&llm_settings.toxicity_auth_token.expose()).map_err(|e| eyre!("Failed to create header: {e}"))?, + HeaderName::from_bytes(b"Authorization") + .map_err(|e| eyre!("Failed to create header: {e}"))?, + HeaderValue::from_str(&llm_settings.toxicity_auth_token.expose()) + .map_err(|e| eyre!("Failed to create header: {e}"))?, ); let client = Client::new(); @@ -43,9 +45,12 @@ pub async fn predict_toxicity( .await .map_err(|e| eyre!("Failed to parse toxicity response: {e}"))?; - let toxicity_score = toxicity_api_response.into_iter().find(|x| x.label == String::from("toxic")).unwrap_or(ToxicityScore { - score: 0.0, - label: String::from(""), - }); + let toxicity_score = toxicity_api_response + .into_iter() + .find(|x| x.label == String::from("toxic")) + .unwrap_or(ToxicityScore { + score: 0.0, + label: String::from(""), + }); Ok(toxicity_score.score > llm_settings.toxicity_threshold) } diff --git a/server/src/rag/brave_search.rs b/server/src/rag/brave_search.rs index 01e10728..7b081964 100644 --- a/server/src/rag/brave_search.rs +++ b/server/src/rag/brave_search.rs @@ -25,6 +25,54 @@ pub struct BraveAPIConfig { pub headers: HeaderMap, } +impl From for BraveAPIConfig { + fn from(brave_settings: BraveSettings) -> Self { + let queries = vec![ + (String::from("count"), brave_settings.count.to_string()), + ( + String::from("goggles_id"), + brave_settings.goggles_id.clone(), + ), + ( + String::from("result_filter"), + brave_settings.result_filter.clone(), + ), + ( + String::from("search_lang"), + brave_settings.search_lang.clone(), + ), + ( + String::from("extra_snippets"), + brave_settings.extra_snippets.to_string(), + ), + ( + String::from("safesearch"), + brave_settings.safesearch.clone(), + ), + ]; + + let headers = HeaderMap::from_iter( + vec![ + ("Accept", "application/json"), + ("Accept-Encoding", "gzip"), + ( + "X-Subscription-Token", + brave_settings.subscription_key.expose(), + ), + ] + .into_iter() + .map(|(k, v)| { + ( + HeaderName::from_bytes(k.as_bytes()).unwrap(), + HeaderValue::from_str(v).unwrap(), + ) + }), + ); + + BraveAPIConfig { queries, headers } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BraveWebSearchResult { pub title: String, @@ -46,52 +94,6 @@ struct BraveAPIResponse { pub web: BraveWebAPIResponse, } -pub fn prepare_brave_api_config(brave_settings: &BraveSettings) -> BraveAPIConfig { - let queries = vec![ - (String::from("count"), brave_settings.count.to_string()), - ( - String::from("goggles_id"), - brave_settings.goggles_id.clone(), - ), - ( - String::from("result_filter"), - brave_settings.result_filter.clone(), - ), - ( - String::from("search_lang"), - brave_settings.search_lang.clone(), - ), - ( - String::from("extra_snippets"), - brave_settings.extra_snippets.to_string(), - ), - ( - String::from("safesearch"), - brave_settings.safesearch.clone(), - ), - ]; - - let headers = HeaderMap::from_iter( - vec![ - ("Accept", "application/json"), - ("Accept-Encoding", "gzip"), - ( - "X-Subscription-Token", - brave_settings.subscription_key.expose(), - ), - ] - .into_iter() - .map(|(k, v)| { - ( - HeaderName::from_bytes(k.as_bytes()).unwrap(), - HeaderValue::from_str(v).unwrap(), - ) - }), - ); - - BraveAPIConfig { queries, headers } -} - #[tracing::instrument(level = "debug", ret, err)] pub async fn web_search( brave_settings: &BraveSettings, diff --git a/server/src/rag/search.rs b/server/src/rag/search.rs index 10c0a430..cd81f185 100644 --- a/server/src/rag/search.rs +++ b/server/src/rag/search.rs @@ -14,7 +14,7 @@ pub async fn search( brave_api_config: &brave_search::BraveAPIConfig, cache: &CachePool, agency_service: &mut AgencyServiceClient, - search_query: &String, + search_query: &str, ) -> crate::Result { if let Some(response) = cache.get(&search_query).await { return Ok(response); @@ -47,7 +47,7 @@ pub async fn search( let compressed_results = prompt_compression::compress( &settings.llm, prompt_compression::PromptCompressionInput { - query: search_query.clone(), + query: search_query.to_string(), target_token: 300, context_texts_list: retrieved_results.iter().map(|r| r.text.clone()).collect(), }, @@ -67,7 +67,7 @@ pub async fn search( async fn retrieve_result_from_agency( settings: &Settings, agency_service: &mut AgencyServiceClient, - search_query: &String, + search_query: &str, ) -> crate::Result> { let agency_service = Arc::new(agency_service.clone()); let query_embeddings = diff --git a/server/src/search/services.rs b/server/src/search/services.rs index 9000e9ce..8df4379b 100644 --- a/server/src/search/services.rs +++ b/server/src/search/services.rs @@ -10,7 +10,7 @@ pub async fn insert_new_search( pool: &PgPool, user_id: &Uuid, search_query_request: &api_models::SearchQueryRequest, - rephrased_query: &String, + rephrased_query: &str, ) -> crate::Result { let thread = match search_query_request.thread_id { Some(thread_id) => { diff --git a/server/src/startup.rs b/server/src/startup.rs index f702bd72..7d26f450 100644 --- a/server/src/startup.rs +++ b/server/src/startup.rs @@ -90,7 +90,7 @@ impl AppState { cache: CachePool::new(&settings.cache).await?, agency_service: agency_service_connect(settings.agency_api.expose()).await?, oauth2_clients: settings.oauth2_clients.clone(), - brave_config: brave_search::prepare_brave_api_config(&settings.brave), + brave_config: settings.brave.clone().into(), settings, openai_stream_regex: Regex::new(r#"\"content\":\"(.*?)\"}"#) .map_err(|e| eyre!("Failed to compile OpenAI stream regex: {}", e))?, diff --git a/server/src/users/models.rs b/server/src/users/models.rs index 4e058d2a..45a3073f 100644 --- a/server/src/users/models.rs +++ b/server/src/users/models.rs @@ -11,19 +11,19 @@ use std::fmt::Debug; #[derive(Serialize, Deserialize, Clone, Copy, Debug)] pub enum UserGroup { - Alpha, - Beta, - Public, + Alpha, + Beta, + Public, } // Move Public to top before public release impl From for UserGroup { - fn from(value: i32) -> Self { - match value { - 0 => UserGroup::Alpha, - 1 => UserGroup::Beta, - _ => UserGroup::Public, - } - } + fn from(value: i32) -> Self { + match value { + 0 => UserGroup::Alpha, + 1 => UserGroup::Beta, + _ => UserGroup::Public, + } + } } #[derive(sqlx::FromRow, Serialize, Clone, Debug)] @@ -117,7 +117,6 @@ pub struct UpdatePasswordRequest { pub new_password: Secret, } - #[derive(Serialize, Deserialize, Debug)] pub struct UpdateProfileRequest { pub username: Option, @@ -127,14 +126,16 @@ pub struct UpdateProfileRequest { pub company: Option, } - impl UpdateProfileRequest { pub fn has_any_value(&self) -> bool { - [self.username.is_some(), - self.email.is_some(), - self.fullname.is_some(), - self.title.is_some(), - self.company.is_some() - ].iter().any(|&x| x) + [ + self.username.is_some(), + self.email.is_some(), + self.fullname.is_some(), + self.title.is_some(), + self.company.is_some(), + ] + .iter() + .any(|&x| x) } -} \ No newline at end of file +} diff --git a/server/src/users/routes.rs b/server/src/users/routes.rs index 6efa7a35..703dfb31 100644 --- a/server/src/users/routes.rs +++ b/server/src/users/routes.rs @@ -1,14 +1,14 @@ -use crate::auth::AuthSession; use crate::auth::utils::verify_user_password; +use crate::auth::AuthSession; use crate::err::AppError; use crate::startup::AppState; -use crate::users::{User, UserRecord, models, services}; -use color_eyre::eyre::eyre; +use crate::users::{models, services, User, UserRecord}; +use axum::extract::State; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::routing::{get, patch}; -use axum::extract::State; use axum::{Form, Json, Router}; +use color_eyre::eyre::eyre; use sqlx::PgPool; #[tracing::instrument(level = "debug", skip_all, ret, err(Debug))] @@ -25,11 +25,11 @@ async fn get_user_handler(auth_session: AuthSession) -> crate::Result, user: User, - Json(update_profile_request): Json -) -> crate::Result> { + Json(update_profile_request): Json, +) -> crate::Result> { let user_id = user.user_id; if !update_profile_request.has_any_value() { - return Err(eyre!("At least one field has to be updated.").into()) + return Err(eyre!("At least one field has to be updated.").into()); } let updated_user = services::update_profile(&pool, &user_id, update_profile_request).await?; @@ -40,21 +40,23 @@ async fn update_profile_handler( async fn update_password_handler( State(pool): State, user: User, - Form(update_password_request): Form -) -> crate::Result { + Form(update_password_request): Form, +) -> crate::Result { let user_id = user.user_id; - if update_password_request.old_password.expose() == update_password_request.new_password.expose() { + if update_password_request.old_password.expose() + == update_password_request.new_password.expose() + { return Err(eyre!("Old and new password can not be the same.").into()); } match verify_user_password(Some(user), update_password_request.old_password) { Ok(Some(_user)) => { - services::update_password(&pool, &user_id, update_password_request.new_password).await?; + services::update_password(&pool, &user_id, update_password_request.new_password) + .await?; Ok((StatusCode::OK, ())) - }, - _ => Err(eyre!("Failed to authenticate old password").into()) - + } + _ => Err(eyre!("Failed to authenticate old password").into()), } } diff --git a/server/src/users/services.rs b/server/src/users/services.rs index 33f2c17d..bd75de29 100644 --- a/server/src/users/services.rs +++ b/server/src/users/services.rs @@ -1,5 +1,5 @@ -use crate::secrets::Secret; use crate::auth::utils::hash_password; +use crate::secrets::Secret; use crate::users::models; use sqlx::PgPool; use uuid::Uuid; @@ -11,8 +11,8 @@ pub async fn update_profile( update_profile_request: models::UpdateProfileRequest, ) -> crate::Result { let user = sqlx::query_as!( - models::User, - " + models::User, + " update users set username = coalesce($1::text, username), @@ -22,12 +22,12 @@ pub async fn update_profile( company = coalesce($5::text, company) where user_id = $6 returning * ", - update_profile_request.username, - update_profile_request.email, - update_profile_request.fullname, - update_profile_request.title, - update_profile_request.company, - user_id, + update_profile_request.username, + update_profile_request.email, + update_profile_request.fullname, + update_profile_request.title, + update_profile_request.company, + user_id, ) .fetch_one(pool) .await?; @@ -35,7 +35,6 @@ pub async fn update_profile( return Ok(user); } - #[tracing::instrument(level = "debug", ret, err)] pub async fn update_password( pool: &PgPool, @@ -44,13 +43,13 @@ pub async fn update_password( ) -> crate::Result<()> { let password_hash = hash_password(password).await?; sqlx::query_as!( - User, - "update users set password_hash = $1 where user_id = $2", - password_hash.expose(), - user_id + User, + "update users set password_hash = $1 where user_id = $2", + password_hash.expose(), + user_id ) .execute(pool) .await?; return Ok(()); -} \ No newline at end of file +} diff --git a/server/tests/health_check.rs b/server/tests/health_check.rs index 1fb3b8fb..4ef26fb8 100644 --- a/server/tests/health_check.rs +++ b/server/tests/health_check.rs @@ -15,12 +15,15 @@ async fn health_check_works(pool: PgPool) { let agency_service = agency_service_connect(&settings.agency_api.expose()) .await .unwrap(); + let brave_api_config = settings.brave.clone().into(); let state = AppState::new( pool, cache, agency_service, - settings.oauth2_clients.clone(), + vec![], settings, + brave_api_config, + regex::Regex::new("").unwrap(), ) .await .unwrap(); diff --git a/server/tests/search.rs b/server/tests/search.rs index bcbc139c..110b73cf 100644 --- a/server/tests/search.rs +++ b/server/tests/search.rs @@ -1,15 +1,11 @@ use server::auth::models::RegisterUserRequest; use server::auth::register; use server::cache::{CachePool, CacheSettings}; -use server::proto::{SearchResponse, Source}; +use server::rag::{search, SearchResponse, Source}; use server::search::{ - get_one_search_history, get_search_history, get_top_searches, insert_search_history, search, - update_search_reaction, -}; -use server::search::{ - SearchHistoryByIdRequest, SearchHistoryRequest, SearchQueryRequest, SearchReactionRequest, - TopSearchRequest, + get_one_search, insert_new_search, update_search_reaction, SearchByIdRequest, SourceType, }; +use server::search::{SearchQueryRequest, SearchReactionRequest}; use server::settings::Settings; use server::startup::agency_service_connect; use server::Result; @@ -24,35 +20,19 @@ async fn search_test() -> Result<()> { .await .unwrap(); let cache = CachePool::new(&settings.cache).await?; - - let search_query = SearchQueryRequest { - session_id: Some(Uuid::new_v4()), - query: "test".to_string(), - }; - - let search_result = search(&cache, &mut agency_service, &search_query).await; + let brave_api_config = settings.brave.clone().into(); + + let search_result = search( + &settings, + &brave_api_config, + &cache, + &mut agency_service, + "test", + ) + .await; assert!(search_result.is_ok()); - assert_eq!(search_result.unwrap().status, 200); - - Ok(()) -} - -#[tokio::test] -async fn top_searches_test() -> Result<()> { - let cache_settings = CacheSettings { - url: "redis://127.0.0.1/".to_string().into(), - enabled: true, - ttl: 3600, - max_sorted_size: 100, - }; - let cache = CachePool::new(&cache_settings).await?; - - let top_search_query = TopSearchRequest { limit: Some(1) }; - - let top_searches_result = get_top_searches(&cache, &top_search_query).await; - assert!(top_searches_result.is_ok()); - assert_eq!(top_searches_result.unwrap().len(), 1); + assert_eq!(search_result.unwrap().result, ""); Ok(()) } @@ -75,14 +55,17 @@ async fn insert_search_and_get_search_history_test(pool: PgPool) -> Result<()> { let user_id = new_user.user_id; let search_query = SearchQueryRequest { - session_id: Some(Uuid::new_v4()), - query: "test_query".to_string(), + thread_id: Some(Uuid::new_v4()), + query: "test-query".to_string(), }; - let search_response = SearchResponse { - status: 200, - result: "test_result".to_string(), + let rephrased_query = "test-rephrased-query"; + let expected_response = SearchResponse { + result: "test-result".to_string(), sources: vec![Source { - url: "test_url".to_string(), + url: "test-url".to_string(), + title: "test-title".to_string(), + description: "test-description".to_string(), + source_type: SourceType::Pdf, metadata: HashMap::from([ ("test_key1".to_string(), "test_value1".to_string()), ("test_key2".to_string(), "test_value2".to_string()), @@ -91,40 +74,20 @@ async fn insert_search_and_get_search_history_test(pool: PgPool) -> Result<()> { }; let search_insertion_result = - insert_search_history(&pool, &cache, &user_id, &search_query, &search_response).await; - - assert!(search_insertion_result.is_ok()); - - let one_search_history_request = SearchHistoryByIdRequest { - search_history_id: search_insertion_result.unwrap().search_history_id, - }; - - let one_search_history_result = - get_one_search_history(&pool, &user_id, &one_search_history_request).await; + insert_new_search(&pool, &user_id, &search_query, rephrased_query).await?; - assert!(one_search_history_result.is_ok()); - let one_search_history_result = one_search_history_result.unwrap(); - - assert_eq!(one_search_history_result.query, search_query.query); - assert_eq!(one_search_history_result.user_id, user_id); - assert_eq!(one_search_history_result.result, search_response.result); - assert_eq!(one_search_history_result.sources.0, search_response.sources); - - let search_history_request = SearchHistoryRequest { - limit: Some(1), - offset: Some(0), + let one_search_history_request = SearchByIdRequest { + search_id: search_insertion_result.search_id, }; - let search_history_result = get_search_history(&pool, &user_id, &search_history_request).await; - - assert!(&search_history_result.is_ok()); - let search_history_result = search_history_result.unwrap(); + let actual_response = get_one_search(&pool, &user_id, &one_search_history_request).await?; - assert_eq!(&search_history_result.len(), &1); - assert_eq!(&search_history_result[0].query, &search_query.query); - assert_eq!(search_history_result[0].user_id, user_id); - assert_eq!(search_history_result[0].result, search_response.result); - assert_eq!(search_history_result[0].sources.0, search_response.sources); + assert_eq!(actual_response.search.query, search_query.query); + assert_eq!(actual_response.search.result, expected_response.result); + assert_eq!(actual_response.sources.len(), 1); + let actual_source = actual_response.sources[0].clone(); + let expected_source = expected_response.sources[0].clone(); + assert_eq!(actual_source.title, expected_source.title); Ok(()) } @@ -147,42 +110,36 @@ async fn update_search_reaction_test(pool: PgPool) -> Result<()> { let user_id = new_user.user_id; let search_query = SearchQueryRequest { - session_id: None, - query: "test_query".to_string(), + thread_id: Some(Uuid::new_v4()), + query: "test-query".to_string(), }; - let search_response = SearchResponse { - status: 200, - result: "test_result".to_string(), + let rephrased_query = "test-rephrased-query"; + let expected_response = SearchResponse { + result: "test-result".to_string(), sources: vec![Source { - url: "test_url".to_string(), + url: "test-url".to_string(), + title: "test-title".to_string(), + description: "test-description".to_string(), + source_type: SourceType::Pdf, metadata: HashMap::from([ ("test_key1".to_string(), "test_value1".to_string()), ("test_key2".to_string(), "test_value2".to_string()), ]), }], }; - let search_insertion_result = - insert_search_history(&pool, &cache, &user_id, &search_query, &search_response).await; - - assert!(search_insertion_result.is_ok()); - let search_insertion_result = search_insertion_result.unwrap(); + insert_new_search(&pool, &user_id, &search_query, rephrased_query).await?; let search_reaction_request = SearchReactionRequest { - search_history_id: search_insertion_result.search_history_id, + search_id: search_insertion_result.search_id, reaction: true, }; let search_reaction_result = - update_search_reaction(&pool, &user_id, &search_reaction_request).await; - - assert!(&search_reaction_result.is_ok()); - let search_reaction_result = search_reaction_result.unwrap(); + update_search_reaction(&pool, &user_id, &search_reaction_request).await?; assert_eq!(&search_reaction_result.query, &search_query.query); - assert_eq!(&search_reaction_result.user_id, &user_id); - assert_eq!(&search_reaction_result.result, &search_response.result); - assert_eq!(&search_reaction_result.sources.0, &search_response.sources); + assert_eq!(&search_reaction_result.result, &expected_response.result); assert_eq!( search_reaction_result.reaction.unwrap(), search_reaction_request.reaction diff --git a/server/tests/users.rs b/server/tests/users.rs index f1eb3458..9281be25 100644 --- a/server/tests/users.rs +++ b/server/tests/users.rs @@ -53,12 +53,15 @@ async fn register_users_works(pool: PgPool) { let agency_service = agency_service_connect(&settings.agency_api.expose()) .await .unwrap(); + let brave_api_config = settings.brave.clone().into(); let state = AppState::new( - pool.clone(), + pool, cache, agency_service, - settings.oauth2_clients.clone(), + vec![], settings, + brave_api_config, + regex::Regex::new("").unwrap(), ) .await .unwrap(); From 4e02f4c245b83ad8957b8b97896817a355cea177 Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Tue, 25 Jun 2024 20:58:17 +0200 Subject: [PATCH 04/19] Install protoc --- .github/workflows/rust.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml index fab1a939..79fd6ce2 100644 --- a/.github/workflows/rust.yaml +++ b/.github/workflows/rust.yaml @@ -22,6 +22,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Install Protoc + uses: arduino/setup-protoc@v3 + - name: Setup Rust Toolchain uses: ./.github/actions/toolchain-cargo-cached with: From ae3fb953e6e6a749717a2c5625f47516bc6979dd Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Tue, 25 Jun 2024 21:50:23 +0200 Subject: [PATCH 05/19] Add paths filter for conditional CI on detected changes --- .../actions/toolchain-cargo-cached/action.yml | 2 +- .github/file-filters.yaml | 72 ++++++++++++++++++ .../workflows/{python.yaml => agency.yaml} | 5 +- .github/workflows/ci.yaml | 43 +++++++++++ .github/workflows/rust.yaml | 41 ---------- .github/workflows/server.yaml | 75 +++++++++++++++++++ 6 files changed, 193 insertions(+), 45 deletions(-) create mode 100644 .github/file-filters.yaml rename .github/workflows/{python.yaml => agency.yaml} (94%) create mode 100644 .github/workflows/ci.yaml delete mode 100644 .github/workflows/rust.yaml create mode 100644 .github/workflows/server.yaml diff --git a/.github/actions/toolchain-cargo-cached/action.yml b/.github/actions/toolchain-cargo-cached/action.yml index ec175954..ea57be66 100644 --- a/.github/actions/toolchain-cargo-cached/action.yml +++ b/.github/actions/toolchain-cargo-cached/action.yml @@ -26,7 +26,7 @@ runs: using: 'composite' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - id: toolchain-cache-key run: | diff --git a/.github/file-filters.yaml b/.github/file-filters.yaml new file mode 100644 index 00000000..80430239 --- /dev/null +++ b/.github/file-filters.yaml @@ -0,0 +1,72 @@ +# This is used by the action https://github.com/dorny/paths-filter + +# Changes to actions/workflows that can affect any of our project components. +action_changes: &action_changes + - '.github/actions/**/action.yaml' + - '.github/workflows/ci.yaml' + - '.github/file-filters.yaml' + +# Frontend +frontend_dependencies: &frontend_dependencies + - 'frontend/{package,now,vercel}.json' + - 'frontend/package-lock.json' + +eslint_config: &eslint_config + - 'frontend/.eslint*' + +frontend_workflow: &frontend_workflow + - '.github/workflows/frontend.yaml' + +frontend: &frontend + - *action_changes + - *frontend_dependencies + - *frontend_workflow + - *eslint_config + - 'frontend/**/*.[tj]{s,sx}' + - 'frontend/**/tsconfig*.json' + +proto: &proto + - 'proto/*.proto' + +# Agency +agency_dependencies: &agency_dependencies + - 'agency/pyproject.toml' + - 'agency/poetry.lock' + - 'agency/.python-version' + +agency_workflow: &agency_workflow + - '.github/workflows/agency.yaml' + +agency: &agency + - *action_changes + - *agency_dependencies + - *agency_workflow + - *proto + - 'agency/app/**/*.py' + +# Server +server_dependencies: &server_dependencies + - 'Cargo.toml' + - 'Cargo.lock' + - 'rust-toolchain.toml' + +server_workflow: &server_workflow + - '.github/workflows/server.yaml' + +server_migrations: &server_migrations + - 'server/migrations/**.sql' + +sqlx_query_cache: &sqlx_query_cache + - 'server/.sqlx/**.json' + +server_config: &server_config + - 'server/config/**.toml' + +server: &server + - *action_changes + - *server_dependencies + - *server_workflow + - *server_migrations + - *sqlx_query_cache + - *proto + - 'server/src/**/*.rs' \ No newline at end of file diff --git a/.github/workflows/python.yaml b/.github/workflows/agency.yaml similarity index 94% rename from .github/workflows/python.yaml rename to .github/workflows/agency.yaml index 86a8db49..ae29f05f 100644 --- a/.github/workflows/python.yaml +++ b/.github/workflows/agency.yaml @@ -1,7 +1,6 @@ -name: Python CI - +name: Agency CI on: - push: + workflow_call: defaults: run: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..0b600d01 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,43 @@ +name: CI + +on: push + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUST_BACKTRACE: short + RUSTFLAGS: "-D warnings" + RUSTUP_MAX_RETRIES: 10 + +jobs: + detect-changes: + name: Detect which files have changed + runs-on: ubuntu-latest + timeout-minutes: 3 + # Map a step output to a job output + outputs: + agency: ${{ steps.changes.outputs.agency }} + frontend: ${{ steps.changes.outputs.frontend }} + llmlingua_service: ${{ steps.changes.outputs.llmlingua_service }} + proto: ${{ steps.changes.outputs.proto }} + server: ${{ steps.changes.outputs.server }} + steps: + - uses: actions/checkout@v4 + + - name: Find changes + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 + id: changes + with: + token: ${{ github.token }} + filters: .github/file-filters.yaml + + agency: + if: needs.detect-changes.outputs.agency == 'true' + needs: detect-changes + uses: ./.github/workflows/agency.yaml + + server: + if: needs.detect-changes.outputs.server == 'true' + needs: detect-changes + uses: ./.github/workflows/server.yaml \ No newline at end of file diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml deleted file mode 100644 index 79fd6ce2..00000000 --- a/.github/workflows/rust.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: Rust CI - -on: push - -defaults: - run: - working-directory: server - -env: - CARGO_TERM_COLOR: always - CARGO_INCREMENTAL: 0 - CARGO_NET_RETRY: 10 - RUST_BACKTRACE: short - RUSTFLAGS: "-D warnings" - RUSTUP_MAX_RETRIES: 10 - -jobs: - coverage-and-linting: - name: Test coverage & linting - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install Protoc - uses: arduino/setup-protoc@v3 - - - name: Setup Rust Toolchain - uses: ./.github/actions/toolchain-cargo-cached - with: - components: llvm-tools-preview, rustfmt, clippy - crates: cargo-llvm-cov - - - name: Tests & coverage - run: cargo llvm-cov test --no-fail-fast --workspace - - - name: Linting rustfmt - run: cargo fmt --all -- --check - - - name: Linting clippy - run: cargo clippy -- \ No newline at end of file diff --git a/.github/workflows/server.yaml b/.github/workflows/server.yaml new file mode 100644 index 00000000..05c3980c --- /dev/null +++ b/.github/workflows/server.yaml @@ -0,0 +1,75 @@ +name: Rust Server CI +on: + workflow_call: + +defaults: + run: + working-directory: server + +env: + CARGO_TERM_COLOR: always + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUST_BACKTRACE: short + RUSTFLAGS: "-D warnings" + RUSTUP_MAX_RETRIES: 10 + +jobs: + detect-changes: + name: Detect which files have changed + runs-on: ubuntu-latest + timeout-minutes: 3 + # Map a step output to a job output + outputs: + agency: ${{ steps.changes.outputs.agency }} + frontend: ${{ steps.changes.outputs.frontend }} + llmlingua_service: ${{ steps.changes.outputs.llmlingua_service }} + proto: ${{ steps.changes.outputs.proto }} + server: ${{ steps.changes.outputs.server }} + steps: + - uses: actions/checkout@v4 + + - name: Find changes + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v2 + id: changes + with: + token: ${{ github.token }} + filters: .github/file-filters.yml + + coverage-and-linting: + name: Test coverage & linting + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: changes + with: + filters: | + src: + - 'src/**' + + # run only if some file in 'src' folder was changed + - if: steps.changes.outputs.src == 'true' + run: ... + + - name: Install Protoc + uses: arduino/setup-protoc@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Rust Toolchain + uses: ./.github/actions/toolchain-cargo-cached + with: + components: llvm-tools-preview, rustfmt, clippy + crates: cargo-llvm-cov + + - name: Tests & coverage + run: cargo llvm-cov test --no-fail-fast --workspace + + - name: Linting rustfmt + run: cargo fmt --all -- --check + + - name: Linting clippy + run: cargo clippy -- \ No newline at end of file From 29a353de569152d7534b5a4c434de4580aa9025b Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Tue, 25 Jun 2024 21:53:15 +0200 Subject: [PATCH 06/19] Remove redundant change detection from server.yaml action --- .github/workflows/server.yaml | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/.github/workflows/server.yaml b/.github/workflows/server.yaml index 05c3980c..c3330539 100644 --- a/.github/workflows/server.yaml +++ b/.github/workflows/server.yaml @@ -15,27 +15,6 @@ env: RUSTUP_MAX_RETRIES: 10 jobs: - detect-changes: - name: Detect which files have changed - runs-on: ubuntu-latest - timeout-minutes: 3 - # Map a step output to a job output - outputs: - agency: ${{ steps.changes.outputs.agency }} - frontend: ${{ steps.changes.outputs.frontend }} - llmlingua_service: ${{ steps.changes.outputs.llmlingua_service }} - proto: ${{ steps.changes.outputs.proto }} - server: ${{ steps.changes.outputs.server }} - steps: - - uses: actions/checkout@v4 - - - name: Find changes - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v2 - id: changes - with: - token: ${{ github.token }} - filters: .github/file-filters.yml - coverage-and-linting: name: Test coverage & linting runs-on: ubuntu-latest @@ -43,17 +22,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - uses: dorny/paths-filter@v3 - id: changes - with: - filters: | - src: - - 'src/**' - - # run only if some file in 'src' folder was changed - - if: steps.changes.outputs.src == 'true' - run: ... - - name: Install Protoc uses: arduino/setup-protoc@v3 with: From ae87a3828f895fde9d754cdbf44fca627ea9a36b Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:42:40 +0200 Subject: [PATCH 07/19] Rust tests are working again --- server/Cargo.lock | 1045 +++++++++++++++++++++++-- server/Cargo.toml | 35 +- server/build.rs | 2 +- server/src/auth/models.rs | 10 +- server/src/llms/prompt_compression.rs | 2 +- server/src/rag/search.rs | 4 +- server/src/search/services.rs | 2 +- server/tests/health_check.rs | 12 +- server/tests/search.rs | 136 ++-- server/tests/users.rs | 25 +- server/tests/utils.rs | 130 +++ 11 files changed, 1203 insertions(+), 200 deletions(-) create mode 100644 server/tests/utils.rs diff --git a/server/Cargo.lock b/server/Cargo.lock index c7db9408..cd4aef41 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" dependencies = [ "backtrace", ] @@ -81,6 +81,58 @@ dependencies = [ "password-hash", ] +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-compression" version = "0.4.9" @@ -94,6 +146,165 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-executor" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.3.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io 2.3.3", + "async-lock 3.4.0", + "blocking", + "futures-lite 2.3.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock 3.4.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.7.2", + "rustix 0.38.32", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-object-pool" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeb901c30ebc2fc4ab46395bbfbdba9542c16559d853645d75190c3056caf3bc" +dependencies = [ + "async-std", +] + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", + "cfg-if", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.32", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-signal" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +dependencies = [ + "async-io 2.3.3", + "async-lock 3.4.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.32", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -116,11 +327,17 @@ dependencies = [ "syn 2.0.53", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" -version = "0.1.78" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", @@ -136,6 +353,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -164,7 +387,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower", "tower-layer", "tower-service", @@ -172,9 +395,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", "axum-core 0.4.3", @@ -184,7 +407,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper 1.2.0", + "hyper 1.3.1", "hyper-util", "itoa", "matchit", @@ -197,7 +420,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tower", "tower-layer", @@ -237,7 +460,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower-layer", "tower-service", "tracing", @@ -249,7 +472,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" dependencies = [ - "axum 0.7.4", + "axum 0.7.5", "axum-core 0.4.3", "bytes", "futures-util", @@ -268,15 +491,15 @@ dependencies = [ [[package]] name = "axum-login" -version = "0.15.0" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f1d7775e438e00a773a3f3651cc46bdb7877a0b22e590289c0f8b5ed92f8f95" +checksum = "4012877d9672b7902aa6567960208756f68a09de81e988fa18fe369e92f90471" dependencies = [ "async-trait", - "axum 0.7.4", + "axum 0.7.5", "form_urlencoded", - "ring", "serde", + "subtle", "thiserror", "tower-cookies", "tower-layer", @@ -337,6 +560,17 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-cookies" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67bd8fd42c16bdb08688243dc5f0cc117a3ca9efeeaba3a345a18a6159ad96f7" +dependencies = [ + "lalrpop", + "lalrpop-util", + "regex", +] + [[package]] name = "bb8" version = "0.8.3" @@ -361,6 +595,21 @@ dependencies = [ "redis", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -394,6 +643,19 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite 2.3.0", + "piper", +] + [[package]] name = "bumpalo" version = "3.15.4" @@ -426,9 +688,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -477,7 +739,16 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.7.10", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", ] [[package]] @@ -628,11 +899,12 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.3" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28" dependencies = [ "cfg-if", + "crossbeam-utils", "hashbrown 0.14.3", "lock_api", "once_cell", @@ -683,6 +955,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dlv-list" version = "0.5.2" @@ -707,6 +1000,15 @@ dependencies = [ "serde", ] +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + [[package]] name = "encoding_rs" version = "0.8.33" @@ -749,6 +1051,38 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "eyre" version = "0.6.12" @@ -759,6 +1093,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.0.1" @@ -899,6 +1242,34 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -969,6 +1340,18 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.3.25" @@ -984,7 +1367,7 @@ dependencies = [ "indexmap 2.2.5", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.10", "tracing", ] @@ -1003,7 +1386,7 @@ dependencies = [ "indexmap 2.2.5", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.10", "tracing", ] @@ -1077,6 +1460,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1189,6 +1578,34 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "httpmock" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08ec9586ee0910472dec1a1f0f8acf52f0fdde93aea74d70d4a3107b4be0fd5b" +dependencies = [ + "assert-json-diff", + "async-object-pool", + "async-std", + "async-trait", + "base64 0.21.7", + "basic-cookies", + "crossbeam-utils", + "form_urlencoded", + "futures-util", + "hyper 0.14.28", + "lazy_static", + "levenshtein", + "log", + "regex", + "serde", + "serde_json", + "serde_regex", + "similar", + "tokio", + "url", +] + [[package]] name = "hyper" version = "0.14.28" @@ -1206,7 +1623,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -1215,9 +1632,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", @@ -1248,6 +1665,23 @@ dependencies = [ "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "rustls 0.23.7", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.4.1" @@ -1268,7 +1702,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.2.0", + "hyper 1.3.1", "hyper-util", "native-tls", "tokio", @@ -1287,9 +1721,9 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.0", - "hyper 1.2.0", + "hyper 1.3.1", "pin-project-lite", - "socket2", + "socket2 0.5.6", "tokio", "tower", "tower-service", @@ -1355,12 +1789,50 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -1396,6 +1868,46 @@ dependencies = [ "serde", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools 0.11.0", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax 0.8.2", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata 0.4.6", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1405,6 +1917,12 @@ dependencies = [ "spin 0.5.2", ] +[[package]] +name = "levenshtein" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" + [[package]] name = "libc" version = "0.2.153" @@ -1417,6 +1935,16 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + [[package]] name = "libsqlite3-sys" version = "0.27.0" @@ -1432,7 +1960,13 @@ dependencies = [ name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" @@ -1456,6 +1990,9 @@ name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +dependencies = [ + "value-bag", +] [[package]] name = "matchers" @@ -1544,6 +2081,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nom" version = "7.1.3" @@ -1623,7 +2166,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -1749,6 +2292,12 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1877,6 +2426,21 @@ dependencies = [ "indexmap 2.2.5", ] +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project" version = "1.1.5" @@ -1909,6 +2473,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -1936,6 +2511,37 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.32", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1948,6 +2554,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "prettyplease" version = "0.2.17" @@ -1969,12 +2581,22 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.4" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive 0.9.0", +] + +[[package]] +name = "prost" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.6", ] [[package]] @@ -1985,13 +2607,13 @@ checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" dependencies = [ "bytes", "heck", - "itertools", + "itertools 0.12.1", "log", "multimap", "once_cell", "petgraph", "prettyplease", - "prost", + "prost 0.12.6", "prost-types", "regex", "syn 2.0.53", @@ -2000,12 +2622,25 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.4" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.53", @@ -2017,7 +2652,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" dependencies = [ - "prost", + "prost 0.12.6", ] [[package]] @@ -2061,9 +2696,9 @@ dependencies = [ [[package]] name = "redis" -version = "0.25.3" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6472825949c09872e8f2c50bde59fcefc17748b6be5c90fd67cd8b4daca73bfd" +checksum = "e0d7a6955c7511f60f3ba9e86c6d02b3c3f144f8c24b288d1f4e18074ab8bbec" dependencies = [ "async-trait", "bytes", @@ -2080,10 +2715,10 @@ dependencies = [ "serde", "serde_json", "sha1_smol", - "socket2", + "socket2 0.5.6", "tokio", "tokio-rustls 0.25.0", - "tokio-util", + "tokio-util 0.7.10", "url", ] @@ -2096,6 +2731,17 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.5" @@ -2155,7 +2801,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", - "hyper-rustls", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -2168,7 +2814,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-rustls 0.24.1", @@ -2178,17 +2824,17 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg", + "winreg 0.50.0", ] [[package]] name = "reqwest" -version = "0.12.1" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e333b1eb9fe677f6893a9efcb0d277a2d3edd83f358a236b657c32301dc6e5f6" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "async-compression", - "base64 0.21.7", + "base64 0.22.0", "bytes", "encoding_rs", "futures-channel", @@ -2198,7 +2844,8 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "http-body-util", - "hyper 1.2.0", + "hyper 1.3.1", + "hyper-rustls 0.27.2", "hyper-tls", "hyper-util", "ipnet", @@ -2209,22 +2856,22 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 1.0.4", + "rustls-pemfile 2.1.2", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "system-configuration", "tokio", "tokio-native-tls", - "tokio-util", + "tokio-util 0.7.10", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "winreg", + "winreg 0.52.0", ] [[package]] @@ -2299,6 +2946,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.38.32" @@ -2308,7 +2969,7 @@ dependencies = [ "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] @@ -2338,6 +2999,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.3", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.7.0" @@ -2409,6 +3083,15 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.23" @@ -2471,7 +3154,7 @@ checksum = "5484316556650182f03b43d4c746ce0e3e48074a21e2f51244b648b6542e1066" dependencies = [ "httpdate", "native-tls", - "reqwest 0.12.1", + "reqwest 0.12.5", "sentry-backtrace", "sentry-contexts", "sentry-core", @@ -2587,18 +3270,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", @@ -2607,9 +3290,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa", "ryu", @@ -2626,6 +3309,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_regex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" +dependencies = [ + "regex", + "serde", +] + [[package]] name = "serde_spanned" version = "0.6.5" @@ -2653,7 +3346,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "axum 0.7.4", + "axum 0.7.5", "axum-extra", "axum-login", "bb8-redis", @@ -2663,28 +3356,30 @@ dependencies = [ "dashmap", "dotenvy", "futures", - "hyper 1.2.0", + "httpmock", + "hyper 1.3.1", "log", "oauth2", "once_cell", "openssl-sys", "password-auth", - "prost", + "prost 0.12.6", "rand", "redis", "regex", - "reqwest 0.12.1", + "reqwest 0.12.5", "sentry", "sentry-tower", "serde", "serde_json", "serde_urlencoded", "sqlx", + "tempfile", "thiserror", "time", "tokio", "tokio-stream", - "tonic", + "tonic 0.11.0", "tonic-build", "tower", "tower-http", @@ -2694,6 +3389,7 @@ dependencies = [ "tracing-logfmt", "tracing-subscriber", "uuid", + "wiremock-grpc", ] [[package]] @@ -2752,6 +3448,18 @@ dependencies = [ "rand_core", ] +[[package]] +name = "similar" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -2767,6 +3475,16 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.6" @@ -2808,7 +3526,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ - "itertools", + "itertools 0.12.1", "nom", "unicode_categories", ] @@ -2839,7 +3557,7 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener", + "event-listener 2.5.3", "futures-channel", "futures-core", "futures-intrusive", @@ -3018,6 +3736,19 @@ dependencies = [ "uuid", ] +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + [[package]] name = "stringprep" version = "0.1.4" @@ -3063,6 +3794,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + [[package]] name = "system-configuration" version = "0.5.1" @@ -3091,25 +3828,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand", - "rustix", + "fastrand 2.0.1", + "rustix 0.38.32", "windows-sys 0.52.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", @@ -3183,9 +3931,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -3195,7 +3943,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] @@ -3212,9 +3960,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -3252,6 +4000,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.7", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -3261,7 +4020,21 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.7.10", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", ] [[package]] @@ -3312,6 +4085,37 @@ dependencies = [ "winnow", ] +[[package]] +name = "tonic" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +dependencies = [ + "async-stream", + "async-trait", + "base64 0.13.1", + "bytes", + "futures-core", + "futures-util", + "h2 0.3.25", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.9.0", + "prost-derive 0.9.0", + "tokio", + "tokio-stream", + "tokio-util 0.6.10", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + [[package]] name = "tonic" version = "0.11.0" @@ -3330,7 +4134,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost", + "prost 0.12.6", "tokio", "tokio-stream", "tower", @@ -3366,7 +4170,7 @@ dependencies = [ "rand", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.10", "tower-layer", "tower-service", "tracing", @@ -3512,6 +4316,16 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -3620,6 +4434,12 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "unicode_categories" version = "0.1.1" @@ -3665,9 +4485,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "uuid" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" dependencies = [ "getrandom", "serde", @@ -3679,6 +4499,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3691,6 +4517,22 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -3833,6 +4675,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -4009,6 +4860,30 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wiremock-grpc" +version = "0.0.3-alpha2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319deda70ff78f1ee33c271bda813160ae13ef33bda15ebe66b5a377d1911ec9" +dependencies = [ + "http-body 0.4.6", + "log", + "prost 0.9.0", + "rand", + "tokio", + "tonic 0.6.2", +] + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/server/Cargo.toml b/server/Cargo.toml index 72c15865..797dd5e3 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -11,21 +11,21 @@ name = "server" path = "src/main.rs" [dependencies] -anyhow = { version = "1.0.81", features = ["backtrace"] } -async-trait = "0.1.78" -axum = { version = "0.7.4", features = ["macros"] } -axum-login = "0.15.0" -chrono = { version = "0.4.35", features = ["serde"] } +anyhow = { version = "1.0.86", features = ["backtrace"] } +async-trait = "0.1.80" +axum = { version = "0.7.5", features = ["macros"] } +axum-login = "0.15.3" +chrono = { version = "0.4.38", features = ["serde"] } color-eyre = "0.6.3" config = { version = "0.14.0", features = ["toml"] } dotenvy = "0.15.7" -hyper = { version = "1.2.0", features = ["full"] } +hyper = { version = "1.3.1", features = ["full"] } oauth2 = "4.4.2" once_cell = "1.19.0" password-auth = "1.0.0" -reqwest = { version = "0.12.1", features = ["json", "stream", "gzip"] } -serde = "1.0.197" -serde_json = "1.0.114" +reqwest = { version = "0.12.5", features = ["json", "stream", "gzip"] } +serde = "1.0.203" +serde_json = "1.0.118" serde_urlencoded = "0.7.1" sqlx = { version = "0.7.4", features = [ "postgres", @@ -35,8 +35,8 @@ sqlx = { version = "0.7.4", features = [ "uuid", "time", ] } -thiserror = "1.0.58" -tokio = { version = "1.36.0", features = ["full"] } +thiserror = "1.0.61" +tokio = { version = "1.38.0", features = ["full"] } tower-http = { version = "0.5.2", features = ["trace", "cors"] } tracing = "0.1.40" tower = "0.4.13" @@ -48,9 +48,9 @@ tracing-subscriber = { version = "0.3.18", features = [ "registry", "env-filter", ] } -uuid = { version = "1.8.0", features = ["serde", "v4"] } +uuid = { version = "1.9.1", features = ["serde", "v4"] } log = "0.4.21" -redis = { version = "0.25.3", features = [ +redis = { version = "0.25.4", features = [ "tokio-comp", "json", "tokio-rustls-comp", @@ -59,15 +59,20 @@ rand = "0.8.5" futures = "0.3.30" axum-extra = { version = "0.9.3", features = ["typed-header"] } tonic = "0.11.0" -prost = "0.12" +prost = "0.12.6" bb8-redis = "0.15.0" time = { version = "0.3.36", features = ["serde"] } -dashmap = { version = "5.5.3", features = ["inline", "serde"] } +dashmap = { version = "6.0.1", features = ["inline", "serde"] } tokio-stream = { version = "0.1.15", features = ["full"] } sentry = { version = "0.34.0", features = ["tracing"] } sentry-tower = { version = "0.34.0", features = ["http"] } regex = "1.10.5" +[dev-dependencies] +wiremock-grpc = "0.0.3-alpha2" +tempfile = "3.10.1" +httpmock = "0.7.0" + [dependencies.openssl-sys] version = "0.9.102" features = ["vendored"] diff --git a/server/build.rs b/server/build.rs index a12d0d52..4c50110e 100644 --- a/server/build.rs +++ b/server/build.rs @@ -13,7 +13,7 @@ fn main() -> Result<(), Box> { println!("cargo:rerun-if-changed=proto"); tonic_build::configure() - .build_server(false) + .build_server(true) .build_client(true) .type_attribute( "SearchInput", diff --git a/server/src/auth/models.rs b/server/src/auth/models.rs index 3915102d..ef91860e 100644 --- a/server/src/auth/models.rs +++ b/server/src/auth/models.rs @@ -211,6 +211,11 @@ pub enum BackendError { // Note that we've supplied our concrete backend here. pub type AuthSession = axum_login::AuthSession; +pub struct WhitelistedEmail { + pub email: String, + pub approved: bool, +} + #[cfg(test)] mod tests { use crate::auth::utils::dummy_verify_password; @@ -221,8 +226,3 @@ mod tests { assert!(dummy_verify_password(Secret::new("password")).is_ok()); } } - -pub struct WhitelistedEmail { - pub email: String, - pub approved: bool, -} diff --git a/server/src/llms/prompt_compression.rs b/server/src/llms/prompt_compression.rs index 063c07b8..fe7cd5e5 100644 --- a/server/src/llms/prompt_compression.rs +++ b/server/src/llms/prompt_compression.rs @@ -16,7 +16,7 @@ pub struct PromptCompressionOutput { } #[derive(Debug, Serialize, Deserialize)] -struct PromptCompressionAPIResponse { +pub struct PromptCompressionAPIResponse { pub response: PromptCompressionOutput, } diff --git a/server/src/rag/search.rs b/server/src/rag/search.rs index cd81f185..01bb5e42 100644 --- a/server/src/rag/search.rs +++ b/server/src/rag/search.rs @@ -16,13 +16,13 @@ pub async fn search( agency_service: &mut AgencyServiceClient, search_query: &str, ) -> crate::Result { - if let Some(response) = cache.get(&search_query).await { + if let Some(response) = cache.get(search_query).await { return Ok(response); } let (agency_results, fallback_results) = tokio::join!( retrieve_result_from_agency(settings, agency_service, search_query), - brave_search::web_search(&settings.brave, brave_api_config, &search_query), + brave_search::web_search(&settings.brave, brave_api_config, search_query), ); let mut retrieved_results = Vec::new(); diff --git a/server/src/search/services.rs b/server/src/search/services.rs index 8df4379b..90ba2800 100644 --- a/server/src/search/services.rs +++ b/server/src/search/services.rs @@ -53,7 +53,7 @@ pub async fn insert_new_search( pub async fn append_search_result( pool: &PgPool, search: &data_models::Search, - result_suffix: &String, + result_suffix: &str, ) -> crate::Result { // Only used by internal services, so no need to check if user_id is the owner of the search let search = sqlx::query_as!( diff --git a/server/tests/health_check.rs b/server/tests/health_check.rs index 4ef26fb8..c1e7e163 100644 --- a/server/tests/health_check.rs +++ b/server/tests/health_check.rs @@ -1,20 +1,18 @@ use axum::body::Body; use axum::http::{Request, StatusCode}; use server::cache::CachePool; -use sqlx::PgPool; -use tower::ServiceExt; - use server::routing::router; use server::settings::Settings; -use server::startup::{agency_service_connect, AppState}; +use server::startup::AppState; +use sqlx::PgPool; +use tower::ServiceExt; +mod utils; #[sqlx::test] async fn health_check_works(pool: PgPool) { let settings = Settings::new(); let cache = CachePool::new(&settings.cache).await.unwrap(); - let agency_service = agency_service_connect(&settings.agency_api.expose()) - .await - .unwrap(); + let (_, agency_service) = utils::agency_server_and_client_stub().await; let brave_api_config = settings.brave.clone().into(); let state = AppState::new( pool, diff --git a/server/tests/search.rs b/server/tests/search.rs index 110b73cf..1a0c9a6e 100644 --- a/server/tests/search.rs +++ b/server/tests/search.rs @@ -1,47 +1,69 @@ +use httpmock::prelude::POST; +use httpmock::MockServer; use server::auth::models::RegisterUserRequest; use server::auth::register; -use server::cache::{CachePool, CacheSettings}; -use server::rag::{search, SearchResponse, Source}; +use server::cache::CachePool; +use server::llms::{PromptCompressionAPIResponse, PromptCompressionOutput}; +use server::rag::search; use server::search::{ - get_one_search, insert_new_search, update_search_reaction, SearchByIdRequest, SourceType, + append_search_result, get_one_search, insert_new_search, update_search_reaction, + SearchByIdRequest, }; use server::search::{SearchQueryRequest, SearchReactionRequest}; use server::settings::Settings; -use server::startup::agency_service_connect; use server::Result; use sqlx::PgPool; -use std::collections::HashMap; -use uuid::Uuid; + +mod utils; #[tokio::test] async fn search_test() -> Result<()> { - let settings = Settings::new(); - let mut agency_service = agency_service_connect(&settings.agency_api.expose()) - .await - .unwrap(); + let mut settings = Settings::new(); + + let (server_future, mut agency_service) = utils::agency_server_and_client_stub().await; let cache = CachePool::new(&settings.cache).await?; let brave_api_config = settings.brave.clone().into(); - let search_result = search( - &settings, - &brave_api_config, - &cache, - &mut agency_service, - "test", - ) - .await; + // Mock compression server + let server = MockServer::start(); + settings.llm.prompt_compression_url = server.url("/compress"); + let compression_response = PromptCompressionAPIResponse { + response: PromptCompressionOutput { + compressed_prompt: "test-compressed-prompt".to_string(), + }, + }; + let _ = server.mock(|when, then| { + when.method(POST).path("/compress"); + + then.status(200) + .header("content-type", "application/json") + .json_body_obj(&compression_response); + }); + + let request_future = async { + let search_result = search( + &settings, + &brave_api_config, + &cache, + &mut agency_service, + "test", + ) + .await; + // Validate server response with assertions + assert_eq!(search_result.unwrap().result, "test-compressed-prompt"); + }; - assert!(search_result.is_ok()); - assert_eq!(search_result.unwrap().result, ""); + // Wait for completion, when the client request future completes + tokio::select! { + _ = server_future => panic!("server returned first"), + _ = request_future => (), + } Ok(()) } #[sqlx::test] async fn insert_search_and_get_search_history_test(pool: PgPool) -> Result<()> { - let settings = Settings::new(); - let cache = CachePool::new(&settings.cache).await?; - let new_user = register( pool.clone(), RegisterUserRequest { @@ -55,48 +77,31 @@ async fn insert_search_and_get_search_history_test(pool: PgPool) -> Result<()> { let user_id = new_user.user_id; let search_query = SearchQueryRequest { - thread_id: Some(Uuid::new_v4()), + thread_id: None, query: "test-query".to_string(), }; let rephrased_query = "test-rephrased-query"; - let expected_response = SearchResponse { - result: "test-result".to_string(), - sources: vec![Source { - url: "test-url".to_string(), - title: "test-title".to_string(), - description: "test-description".to_string(), - source_type: SourceType::Pdf, - metadata: HashMap::from([ - ("test_key1".to_string(), "test_value1".to_string()), - ("test_key2".to_string(), "test_value2".to_string()), - ]), - }], - }; - let search_insertion_result = - insert_new_search(&pool, &user_id, &search_query, rephrased_query).await?; - - let one_search_history_request = SearchByIdRequest { - search_id: search_insertion_result.search_id, - }; + let search_result = insert_new_search(&pool, &user_id, &search_query, rephrased_query).await?; + let search_id = search_result.search_id; + let one_search_history_request = SearchByIdRequest { search_id }; let actual_response = get_one_search(&pool, &user_id, &one_search_history_request).await?; - assert_eq!(actual_response.search.query, search_query.query); - assert_eq!(actual_response.search.result, expected_response.result); - assert_eq!(actual_response.sources.len(), 1); - let actual_source = actual_response.sources[0].clone(); - let expected_source = expected_response.sources[0].clone(); - assert_eq!(actual_source.title, expected_source.title); + assert_eq!(actual_response.sources.len(), 0); + + // update the search result + append_search_result(&pool, &search_result, "updated-result").await?; + + let updated_response = get_one_search(&pool, &user_id, &one_search_history_request).await?; + assert_eq!(updated_response.search.query, search_query.query); + assert_eq!(updated_response.search.result, "updated-result"); Ok(()) } #[sqlx::test] async fn update_search_reaction_test(pool: PgPool) -> Result<()> { - let settings = Settings::new(); - let cache = CachePool::new(&settings.cache).await?; - let new_user = register( pool.clone(), RegisterUserRequest { @@ -110,28 +115,15 @@ async fn update_search_reaction_test(pool: PgPool) -> Result<()> { let user_id = new_user.user_id; let search_query = SearchQueryRequest { - thread_id: Some(Uuid::new_v4()), + thread_id: None, query: "test-query".to_string(), }; let rephrased_query = "test-rephrased-query"; - let expected_response = SearchResponse { - result: "test-result".to_string(), - sources: vec![Source { - url: "test-url".to_string(), - title: "test-title".to_string(), - description: "test-description".to_string(), - source_type: SourceType::Pdf, - metadata: HashMap::from([ - ("test_key1".to_string(), "test_value1".to_string()), - ("test_key2".to_string(), "test_value2".to_string()), - ]), - }], - }; - let search_insertion_result = - insert_new_search(&pool, &user_id, &search_query, rephrased_query).await?; + let search_result = insert_new_search(&pool, &user_id, &search_query, rephrased_query).await?; + let search_id = search_result.search_id; let search_reaction_request = SearchReactionRequest { - search_id: search_insertion_result.search_id, + search_id, reaction: true, }; @@ -139,11 +131,7 @@ async fn update_search_reaction_test(pool: PgPool) -> Result<()> { update_search_reaction(&pool, &user_id, &search_reaction_request).await?; assert_eq!(&search_reaction_result.query, &search_query.query); - assert_eq!(&search_reaction_result.result, &expected_response.result); - assert_eq!( - search_reaction_result.reaction.unwrap(), - search_reaction_request.reaction - ); + assert_eq!(search_reaction_result.reaction, Some(true)); Ok(()) } diff --git a/server/tests/users.rs b/server/tests/users.rs index 9281be25..9999df2e 100644 --- a/server/tests/users.rs +++ b/server/tests/users.rs @@ -2,17 +2,18 @@ use axum::body::Body; use axum::http::header::CONTENT_TYPE; use axum::http::{Request, StatusCode}; use server::auth::models::RegisterUserRequest; -use server::auth::register; +use server::auth::{register, WhitelistedEmail}; use server::cache::CachePool; use server::routing::router; use server::settings::Settings; -use server::startup::agency_service_connect; use server::startup::AppState; use server::users::selectors::get_user; use server::Result; use sqlx::PgPool; use tower::ServiceExt; +mod utils; + /// Helper function to create a GET request for a given URI. fn _send_get_request(uri: &str) -> Request { Request::builder() @@ -48,11 +49,18 @@ async fn register_and_get_users_test(pool: PgPool) -> Result<()> { #[sqlx::test] async fn register_users_works(pool: PgPool) { + let WhitelistedEmail { email, .. } = sqlx::query_as!( + WhitelistedEmail, + "insert into whitelisted_emails (email, approved) values ($1, true) returning *", + "my-email@email.com", + ) + .fetch_one(&pool) + .await + .unwrap(); + let settings = Settings::new(); let cache = CachePool::new(&settings.cache).await.unwrap(); - let agency_service = agency_service_connect(&settings.agency_api.expose()) - .await - .unwrap(); + let (_, agency_service) = utils::agency_server_and_client_stub().await; let brave_api_config = settings.brave.clone().into(); let state = AppState::new( pool, @@ -65,11 +73,10 @@ async fn register_users_works(pool: PgPool) { ) .await .unwrap(); - let router = router(state).unwrap(); let form = &[ - ("email", "my-email@email.com"), + ("email", email.as_str()), ("username", "my-username"), ("password", "my-password"), ]; @@ -87,7 +94,7 @@ async fn register_users_works(pool: PgPool) { assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); let form = &[ - ("email", "another-email@email.com"), + ("email", "not-whitelisted-email"), ("username", "another-username"), ("access_token", "my-access-token"), ]; @@ -98,5 +105,5 @@ async fn register_users_works(pool: PgPool) { .unwrap(); let response = router.oneshot(request).await.unwrap(); - assert_eq!(response.status(), StatusCode::CREATED); + assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR); } diff --git a/server/tests/utils.rs b/server/tests/utils.rs new file mode 100644 index 00000000..65341f28 --- /dev/null +++ b/server/tests/utils.rs @@ -0,0 +1,130 @@ +use async_trait::async_trait; +use oauth2::http::Uri; +use server::proto::agency_service_client::AgencyServiceClient; +use server::proto::agency_service_server::{AgencyService, AgencyServiceServer}; +use server::proto::{Embeddings, EmbeddingsOutput, PubmedResponse, PubmedSource, SearchInput}; +use std::future::Future; +use std::sync::Arc; +use tempfile::NamedTempFile; +use tokio::net::{UnixListener, UnixStream}; +use tokio_stream::wrappers::UnixListenerStream; +use tonic::transport::{Channel, Endpoint, Server}; +use tonic::{Request, Response, Status}; +use tower::service_fn; + +struct MockAgencyServer { + pubmed_parent_search_response: PubmedResponse, + pubmed_cluster_search_response: PubmedResponse, + embeddings_compute_response: EmbeddingsOutput, +} + +impl MockAgencyServer { + fn set_pubmed_parent_search_response(&mut self, response: PubmedResponse) { + self.pubmed_parent_search_response = response + } + fn set_pubmed_cluster_search_response(&mut self, response: PubmedResponse) { + self.pubmed_cluster_search_response = response + } + fn set_embeddings_compute_response(&mut self, response: EmbeddingsOutput) { + self.embeddings_compute_response = response + } +} + +#[async_trait] +impl AgencyService for MockAgencyServer { + async fn pubmed_parent_search( + &self, + _: Request, + ) -> std::result::Result, Status> { + Ok(Response::new(self.pubmed_parent_search_response.clone())) + } + + async fn pubmed_cluster_search( + &self, + _: Request, + ) -> std::result::Result, Status> { + Ok(Response::new(self.pubmed_cluster_search_response.clone())) + } + + async fn embeddings_compute( + &self, + _: Request, + ) -> std::result::Result, Status> { + Ok(Response::new(self.embeddings_compute_response.clone())) + } +} + +pub async fn agency_server_and_client_stub() -> ( + impl Future + Sized, + AgencyServiceClient, +) { + let socket = NamedTempFile::new().unwrap(); + let socket = Arc::new(socket.into_temp_path()); + std::fs::remove_file(&*socket).unwrap(); + + let uds = UnixListener::bind(&*socket).unwrap(); + let stream = UnixListenerStream::new(uds); + + let mock_server = MockAgencyServer { + pubmed_parent_search_response: PubmedResponse { + status: 200, + sources: vec![PubmedSource { + pubmed_id: "test-pubmed-id".to_string(), + title: "test-title".to_string(), + r#abstract: "test-abstract".to_string(), + embeddings: Some(Embeddings { + dense_embedding: vec![], + sparse_embedding: vec![], + sparse_indices: vec![], + }), + }], + }, + pubmed_cluster_search_response: PubmedResponse { + status: 200, + sources: vec![PubmedSource { + pubmed_id: "test-pubmed-id".to_string(), + title: "test-title".to_string(), + r#abstract: "test-abstract".to_string(), + embeddings: Some(Embeddings { + dense_embedding: vec![], + sparse_embedding: vec![], + sparse_indices: vec![], + }), + }], + }, + embeddings_compute_response: EmbeddingsOutput { + status: 200, + embeddings: Some(Embeddings { + dense_embedding: vec![], + sparse_embedding: vec![], + sparse_indices: vec![], + }), + }, + }; + + let agency_service_server = AgencyServiceServer::new(mock_server); + let server = async { + let server = Server::builder() + .add_service(agency_service_server) + .serve_with_incoming(stream) + .await; + // Server must be running fine... + assert!(server.is_ok()); + server.unwrap() + }; + let socket = Arc::clone(&socket); + // Connect to the server over a Unix socket + // The URL will be ignored. + let channel = Endpoint::try_from("http://[::1]") + .unwrap() + .connect_with_connector(service_fn(move |_: Uri| { + let socket = Arc::clone(&socket); + async move { UnixStream::connect(&*socket).await } + })) + .await + .unwrap(); + + let client = AgencyServiceClient::new(channel); + + (server, client) +} From 643e948242054a517adf962f6fe5625de86e5997 Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:49:03 +0200 Subject: [PATCH 08/19] run cargo sqlx prepare --- .github/workflows/ci.yaml | 2 +- ...1793e2f9709a3c5108fef9dab8381c9b2ee45.json | 64 ++++++++++++++ ...c2bea1b9d6ae31aa55c0093024948f1ad17a4.json | 54 ++++++++++++ ...507ccb830f5e9ab6602c127d09261d4b375be.json | 30 ++++++- ...b45e788e6f3b415b8f72e48927ec5f99b8fe3.json | 87 +++++++++++++++++++ ...edd08e05bc2e7758e22f966111422199698d0.json | 28 ++++++ ...fb6db10aec38671ebe21c8a579d81ffc699d8.json | 30 ++++++- ...7af0c79fb04c8b5358aa753a2e714b7a44a87.json | 53 +++++++++++ ...46e2c6e90e002c4c6b3d0c94990716704a2e5.json | 15 ++++ ...7d6ea0cd38db47cb2266d8ce7ac69e62e3b1.json} | 29 +++---- ...8876af384eee82317f2be5ad4b0ff0914c273.json | 30 ++++++- ...8128fe0f468e4451ff7ea20579a978a5d611a.json | 54 ++++++++++++ ...df21dcb69147824e73b46eb5b7ea30445556f.json | 15 ++++ ...ce69e7367eff2653379ef731cb55dac6fbd3b.json | 71 +++++++++++++++ ...e24d4a1803ab24474b6e4af2ddaf5f6f00e0.json} | 23 +++-- ...dd19c2f98b8864475f40a435735c741d8041e.json | 53 +++++++++++ ...e0202da7e320a49cd7c20da94c3e3e7afc009.json | 83 ++++++++++++++++++ ...6607695a29ede2f87547cb16ecfd87ba4e11.json} | 22 ++--- ...4c8befba5e3782645d76322d5105d69a697a9.json | 64 ++++++++++++++ ...1939a4e9bb5fbaf1232a5fde29021ed5170e.json} | 24 ++--- ...ae68a39614b768962d123b010c50b940b793d.json | 30 ++++++- ...6203a91427b1e379a362e79ffe90f824c677b.json | 68 +++++++++++++++ ...35782e6651c01a3427ddd9b00ac12d2cb624e.json | 72 +++++++++++++++ 23 files changed, 938 insertions(+), 63 deletions(-) create mode 100644 server/.sqlx/query-086da61a1f6ccebc6d22fd851641793e2f9709a3c5108fef9dab8381c9b2ee45.json create mode 100644 server/.sqlx/query-0961dde5db6d46ac22f13788dc8c2bea1b9d6ae31aa55c0093024948f1ad17a4.json create mode 100644 server/.sqlx/query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json create mode 100644 server/.sqlx/query-23983f172d02392576f15d93037edd08e05bc2e7758e22f966111422199698d0.json create mode 100644 server/.sqlx/query-32bf4f350636d69dd46edda4d0c7af0c79fb04c8b5358aa753a2e714b7a44a87.json create mode 100644 server/.sqlx/query-4b0680a60905901c8376bf4224e46e2c6e90e002c4c6b3d0c94990716704a2e5.json rename server/.sqlx/{query-a101d3708b8506c9af02ee42596fe07202b5c5f4de22a80fd504364c130cb496.json => query-575b567031740fcf4c95cd7322917d6ea0cd38db47cb2266d8ce7ac69e62e3b1.json} (65%) create mode 100644 server/.sqlx/query-6c38286ebb64920001a97cebf488128fe0f468e4451ff7ea20579a978a5d611a.json create mode 100644 server/.sqlx/query-71e0c5d19a0d0245b6ef6e2a2dcdf21dcb69147824e73b46eb5b7ea30445556f.json create mode 100644 server/.sqlx/query-730b2ccd9219ad6dfbe89e08220ce69e7367eff2653379ef731cb55dac6fbd3b.json rename server/.sqlx/{query-a3300cb44e90f76b4f9acefc227fc8a0a8686a250812fe534bce9bd610c15867.json => query-7f3aa259bd32b4d8ce02e5d1995ce24d4a1803ab24474b6e4af2ddaf5f6f00e0.json} (68%) create mode 100644 server/.sqlx/query-8603a35934ee458072e089b7994dd19c2f98b8864475f40a435735c741d8041e.json create mode 100644 server/.sqlx/query-9081b38306b54a242d282d9c41ce0202da7e320a49cd7c20da94c3e3e7afc009.json rename server/.sqlx/{query-29ef534c8dec3b0822559ee28a5301acd854ff1669e6b6a70c81fd50c952e998.json => query-9e24ef47cd1ad6bb87d66a3ede876607695a29ede2f87547cb16ecfd87ba4e11.json} (70%) create mode 100644 server/.sqlx/query-bc82472e3df0b99af83ab2dcf824c8befba5e3782645d76322d5105d69a697a9.json rename server/.sqlx/{query-50cf2fc244b2b5d3fa484577a2056e3f2d9e03c3dd8996ae95887576791aff9a.json => query-ce09df1d8db96f4d5fe17991e9f71939a4e9bb5fbaf1232a5fde29021ed5170e.json} (69%) create mode 100644 server/.sqlx/query-e286bbdbfb6172ea31377a2464a6203a91427b1e379a362e79ffe90f824c677b.json create mode 100644 server/.sqlx/query-ea69f3b1335e367b3492111c43c35782e6651c01a3427ddd9b00ac12d2cb624e.json diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0b600d01..2922840a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ env: jobs: detect-changes: - name: Detect which files have changed + name: Detect file changes runs-on: ubuntu-latest timeout-minutes: 3 # Map a step output to a job output diff --git a/server/.sqlx/query-086da61a1f6ccebc6d22fd851641793e2f9709a3c5108fef9dab8381c9b2ee45.json b/server/.sqlx/query-086da61a1f6ccebc6d22fd851641793e2f9709a3c5108fef9dab8381c9b2ee45.json new file mode 100644 index 00000000..2d1ef726 --- /dev/null +++ b/server/.sqlx/query-086da61a1f6ccebc6d22fd851641793e2f9709a3c5108fef9dab8381c9b2ee45.json @@ -0,0 +1,64 @@ +{ + "db_name": "PostgreSQL", + "query": "select s.* from sources s inner join search_sources ss on s.source_id = ss.source_id where ss.search_id = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "source_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "source_type", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "metadata", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + true, + false, + false + ] + }, + "hash": "086da61a1f6ccebc6d22fd851641793e2f9709a3c5108fef9dab8381c9b2ee45" +} diff --git a/server/.sqlx/query-0961dde5db6d46ac22f13788dc8c2bea1b9d6ae31aa55c0093024948f1ad17a4.json b/server/.sqlx/query-0961dde5db6d46ac22f13788dc8c2bea1b9d6ae31aa55c0093024948f1ad17a4.json new file mode 100644 index 00000000..b5940061 --- /dev/null +++ b/server/.sqlx/query-0961dde5db6d46ac22f13788dc8c2bea1b9d6ae31aa55c0093024948f1ad17a4.json @@ -0,0 +1,54 @@ +{ + "db_name": "PostgreSQL", + "query": "select * from threads where user_id = $1 order by created_at desc limit $2 offset $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "thread_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "context", + "type_info": "Jsonb" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + false + ] + }, + "hash": "0961dde5db6d46ac22f13788dc8c2bea1b9d6ae31aa55c0093024948f1ad17a4" +} diff --git a/server/.sqlx/query-0c93e9ca88f7f70aab04284e467507ccb830f5e9ab6602c127d09261d4b375be.json b/server/.sqlx/query-0c93e9ca88f7f70aab04284e467507ccb830f5e9ab6602c127d09261d4b375be.json index ed87c7b8..183cfd65 100644 --- a/server/.sqlx/query-0c93e9ca88f7f70aab04284e467507ccb830f5e9ab6602c127d09261d4b375be.json +++ b/server/.sqlx/query-0c93e9ca88f7f70aab04284e467507ccb830f5e9ab6602c127d09261d4b375be.json @@ -20,21 +20,41 @@ }, { "ordinal": 3, + "name": "fullname", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "company", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "user_group", + "type_info": "Int4" + }, + { + "ordinal": 7, "name": "password_hash", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 8, "name": "access_token", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 9, "name": "created_at", "type_info": "Timestamptz" }, { - "ordinal": 6, + "ordinal": 10, "name": "updated_at", "type_info": "Timestamptz" } @@ -52,6 +72,10 @@ false, true, true, + true, + false, + true, + true, false, true ] diff --git a/server/.sqlx/query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json b/server/.sqlx/query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json new file mode 100644 index 00000000..097a3d6d --- /dev/null +++ b/server/.sqlx/query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json @@ -0,0 +1,87 @@ +{ + "db_name": "PostgreSQL", + "query": "\n update users\n set\n username = coalesce($1::text, username),\n email = coalesce($2::text, email),\n fullname = coalesce($3::text, fullname),\n title = coalesce($4::text, title),\n company = coalesce($5::text, company)\n where user_id = $6 returning *\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "username", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "email", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "fullname", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "company", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "user_group", + "type_info": "Int4" + }, + { + "ordinal": 7, + "name": "password_hash", + "type_info": "Text" + }, + { + "ordinal": 8, + "name": "access_token", + "type_info": "Text" + }, + { + "ordinal": 9, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 10, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Text", + "Text", + "Uuid" + ] + }, + "nullable": [ + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + true + ] + }, + "hash": "16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3" +} diff --git a/server/.sqlx/query-23983f172d02392576f15d93037edd08e05bc2e7758e22f966111422199698d0.json b/server/.sqlx/query-23983f172d02392576f15d93037edd08e05bc2e7758e22f966111422199698d0.json new file mode 100644 index 00000000..9beda6c0 --- /dev/null +++ b/server/.sqlx/query-23983f172d02392576f15d93037edd08e05bc2e7758e22f966111422199698d0.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT * FROM whitelisted_emails WHERE email = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "email", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "approved", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "23983f172d02392576f15d93037edd08e05bc2e7758e22f966111422199698d0" +} diff --git a/server/.sqlx/query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json b/server/.sqlx/query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json index be9070f7..12771f98 100644 --- a/server/.sqlx/query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json +++ b/server/.sqlx/query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json @@ -20,21 +20,41 @@ }, { "ordinal": 3, + "name": "fullname", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "company", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "user_group", + "type_info": "Int4" + }, + { + "ordinal": 7, "name": "password_hash", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 8, "name": "access_token", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 9, "name": "created_at", "type_info": "Timestamptz" }, { - "ordinal": 6, + "ordinal": 10, "name": "updated_at", "type_info": "Timestamptz" } @@ -50,6 +70,10 @@ false, true, true, + true, + false, + true, + true, false, true ] diff --git a/server/.sqlx/query-32bf4f350636d69dd46edda4d0c7af0c79fb04c8b5358aa753a2e714b7a44a87.json b/server/.sqlx/query-32bf4f350636d69dd46edda4d0c7af0c79fb04c8b5358aa753a2e714b7a44a87.json new file mode 100644 index 00000000..6422440a --- /dev/null +++ b/server/.sqlx/query-32bf4f350636d69dd46edda4d0c7af0c79fb04c8b5358aa753a2e714b7a44a87.json @@ -0,0 +1,53 @@ +{ + "db_name": "PostgreSQL", + "query": "insert into threads (user_id, title) values ($1, $2) returning *", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "thread_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "context", + "type_info": "Jsonb" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Varchar" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + false + ] + }, + "hash": "32bf4f350636d69dd46edda4d0c7af0c79fb04c8b5358aa753a2e714b7a44a87" +} diff --git a/server/.sqlx/query-4b0680a60905901c8376bf4224e46e2c6e90e002c4c6b3d0c94990716704a2e5.json b/server/.sqlx/query-4b0680a60905901c8376bf4224e46e2c6e90e002c4c6b3d0c94990716704a2e5.json new file mode 100644 index 00000000..c5d6ccdc --- /dev/null +++ b/server/.sqlx/query-4b0680a60905901c8376bf4224e46e2c6e90e002c4c6b3d0c94990716704a2e5.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "insert into search_sources (search_id, source_id) select * from unnest($1::uuid[], $2::uuid[])", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "UuidArray", + "UuidArray" + ] + }, + "nullable": [] + }, + "hash": "4b0680a60905901c8376bf4224e46e2c6e90e002c4c6b3d0c94990716704a2e5" +} diff --git a/server/.sqlx/query-a101d3708b8506c9af02ee42596fe07202b5c5f4de22a80fd504364c130cb496.json b/server/.sqlx/query-575b567031740fcf4c95cd7322917d6ea0cd38db47cb2266d8ce7ac69e62e3b1.json similarity index 65% rename from server/.sqlx/query-a101d3708b8506c9af02ee42596fe07202b5c5f4de22a80fd504364c130cb496.json rename to server/.sqlx/query-575b567031740fcf4c95cd7322917d6ea0cd38db47cb2266d8ce7ac69e62e3b1.json index efecdaae..a975fea8 100644 --- a/server/.sqlx/query-a101d3708b8506c9af02ee42596fe07202b5c5f4de22a80fd504364c130cb496.json +++ b/server/.sqlx/query-575b567031740fcf4c95cd7322917d6ea0cd38db47cb2266d8ce7ac69e62e3b1.json @@ -1,27 +1,27 @@ { "db_name": "PostgreSQL", - "query": "insert into search_history (user_id, session_id, query, result, sources) values ($1, $2, $3, $4, $5) returning *", + "query": "insert into searches (thread_id, query, rephrased_query, result) values ($1, $2, $3, $4) returning *", "describe": { "columns": [ { "ordinal": 0, - "name": "search_history_id", + "name": "search_id", "type_info": "Uuid" }, { "ordinal": 1, - "name": "user_id", + "name": "thread_id", "type_info": "Uuid" }, { "ordinal": 2, - "name": "session_id", - "type_info": "Uuid" + "name": "query", + "type_info": "Varchar" }, { "ordinal": 3, - "name": "query", - "type_info": "Text" + "name": "rephrased_query", + "type_info": "Varchar" }, { "ordinal": 4, @@ -30,8 +30,8 @@ }, { "ordinal": 5, - "name": "sources", - "type_info": "Jsonb" + "name": "media_urls", + "type_info": "TextArray" }, { "ordinal": 6, @@ -52,10 +52,9 @@ "parameters": { "Left": [ "Uuid", - "Uuid", - "Text", - "Text", - "Jsonb" + "Varchar", + "Varchar", + "Text" ] }, "nullable": [ @@ -64,11 +63,11 @@ false, false, false, - false, + true, true, false, false ] }, - "hash": "a101d3708b8506c9af02ee42596fe07202b5c5f4de22a80fd504364c130cb496" + "hash": "575b567031740fcf4c95cd7322917d6ea0cd38db47cb2266d8ce7ac69e62e3b1" } diff --git a/server/.sqlx/query-65b1487c46bb050524858ef3ebf8876af384eee82317f2be5ad4b0ff0914c273.json b/server/.sqlx/query-65b1487c46bb050524858ef3ebf8876af384eee82317f2be5ad4b0ff0914c273.json index 8bb2891b..d2ae29c0 100644 --- a/server/.sqlx/query-65b1487c46bb050524858ef3ebf8876af384eee82317f2be5ad4b0ff0914c273.json +++ b/server/.sqlx/query-65b1487c46bb050524858ef3ebf8876af384eee82317f2be5ad4b0ff0914c273.json @@ -20,21 +20,41 @@ }, { "ordinal": 3, + "name": "fullname", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "company", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "user_group", + "type_info": "Int4" + }, + { + "ordinal": 7, "name": "password_hash", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 8, "name": "access_token", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 9, "name": "created_at", "type_info": "Timestamptz" }, { - "ordinal": 6, + "ordinal": 10, "name": "updated_at", "type_info": "Timestamptz" } @@ -50,6 +70,10 @@ false, true, true, + true, + false, + true, + true, false, true ] diff --git a/server/.sqlx/query-6c38286ebb64920001a97cebf488128fe0f468e4451ff7ea20579a978a5d611a.json b/server/.sqlx/query-6c38286ebb64920001a97cebf488128fe0f468e4451ff7ea20579a978a5d611a.json new file mode 100644 index 00000000..3fb7a51d --- /dev/null +++ b/server/.sqlx/query-6c38286ebb64920001a97cebf488128fe0f468e4451ff7ea20579a978a5d611a.json @@ -0,0 +1,54 @@ +{ + "db_name": "PostgreSQL", + "query": "update threads set title = $1 where thread_id = $2 and user_id = $3 returning *", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "thread_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "context", + "type_info": "Jsonb" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Varchar", + "Uuid", + "Uuid" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + false + ] + }, + "hash": "6c38286ebb64920001a97cebf488128fe0f468e4451ff7ea20579a978a5d611a" +} diff --git a/server/.sqlx/query-71e0c5d19a0d0245b6ef6e2a2dcdf21dcb69147824e73b46eb5b7ea30445556f.json b/server/.sqlx/query-71e0c5d19a0d0245b6ef6e2a2dcdf21dcb69147824e73b46eb5b7ea30445556f.json new file mode 100644 index 00000000..9080a218 --- /dev/null +++ b/server/.sqlx/query-71e0c5d19a0d0245b6ef6e2a2dcdf21dcb69147824e73b46eb5b7ea30445556f.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "update users set password_hash = $1 where user_id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Uuid" + ] + }, + "nullable": [] + }, + "hash": "71e0c5d19a0d0245b6ef6e2a2dcdf21dcb69147824e73b46eb5b7ea30445556f" +} diff --git a/server/.sqlx/query-730b2ccd9219ad6dfbe89e08220ce69e7367eff2653379ef731cb55dac6fbd3b.json b/server/.sqlx/query-730b2ccd9219ad6dfbe89e08220ce69e7367eff2653379ef731cb55dac6fbd3b.json new file mode 100644 index 00000000..5efc7b04 --- /dev/null +++ b/server/.sqlx/query-730b2ccd9219ad6dfbe89e08220ce69e7367eff2653379ef731cb55dac6fbd3b.json @@ -0,0 +1,71 @@ +{ + "db_name": "PostgreSQL", + "query": "select s.* from searches s where s.thread_id = $1 order by s.created_at desc limit $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "search_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "thread_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "query", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "rephrased_query", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "result", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "media_urls", + "type_info": "TextArray" + }, + { + "ordinal": 6, + "name": "reaction", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + true, + false, + false + ] + }, + "hash": "730b2ccd9219ad6dfbe89e08220ce69e7367eff2653379ef731cb55dac6fbd3b" +} diff --git a/server/.sqlx/query-a3300cb44e90f76b4f9acefc227fc8a0a8686a250812fe534bce9bd610c15867.json b/server/.sqlx/query-7f3aa259bd32b4d8ce02e5d1995ce24d4a1803ab24474b6e4af2ddaf5f6f00e0.json similarity index 68% rename from server/.sqlx/query-a3300cb44e90f76b4f9acefc227fc8a0a8686a250812fe534bce9bd610c15867.json rename to server/.sqlx/query-7f3aa259bd32b4d8ce02e5d1995ce24d4a1803ab24474b6e4af2ddaf5f6f00e0.json index 1fd4ecf7..e4d4b58d 100644 --- a/server/.sqlx/query-a3300cb44e90f76b4f9acefc227fc8a0a8686a250812fe534bce9bd610c15867.json +++ b/server/.sqlx/query-7f3aa259bd32b4d8ce02e5d1995ce24d4a1803ab24474b6e4af2ddaf5f6f00e0.json @@ -1,27 +1,27 @@ { "db_name": "PostgreSQL", - "query": "update search_history set reaction = $1 where search_history_id = $2 and user_id = $3 returning *", + "query": "select s.* from searches s inner join threads t on s.thread_id = t.thread_id where s.search_id = $1 and t.user_id = $2", "describe": { "columns": [ { "ordinal": 0, - "name": "search_history_id", + "name": "search_id", "type_info": "Uuid" }, { "ordinal": 1, - "name": "user_id", + "name": "thread_id", "type_info": "Uuid" }, { "ordinal": 2, - "name": "session_id", - "type_info": "Uuid" + "name": "query", + "type_info": "Varchar" }, { "ordinal": 3, - "name": "query", - "type_info": "Text" + "name": "rephrased_query", + "type_info": "Varchar" }, { "ordinal": 4, @@ -30,8 +30,8 @@ }, { "ordinal": 5, - "name": "sources", - "type_info": "Jsonb" + "name": "media_urls", + "type_info": "TextArray" }, { "ordinal": 6, @@ -51,7 +51,6 @@ ], "parameters": { "Left": [ - "Bool", "Uuid", "Uuid" ] @@ -62,11 +61,11 @@ false, false, false, - false, + true, true, false, false ] }, - "hash": "a3300cb44e90f76b4f9acefc227fc8a0a8686a250812fe534bce9bd610c15867" + "hash": "7f3aa259bd32b4d8ce02e5d1995ce24d4a1803ab24474b6e4af2ddaf5f6f00e0" } diff --git a/server/.sqlx/query-8603a35934ee458072e089b7994dd19c2f98b8864475f40a435735c741d8041e.json b/server/.sqlx/query-8603a35934ee458072e089b7994dd19c2f98b8864475f40a435735c741d8041e.json new file mode 100644 index 00000000..9c6d5e6a --- /dev/null +++ b/server/.sqlx/query-8603a35934ee458072e089b7994dd19c2f98b8864475f40a435735c741d8041e.json @@ -0,0 +1,53 @@ +{ + "db_name": "PostgreSQL", + "query": "select * from threads where thread_id = $1 and user_id = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "thread_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "context", + "type_info": "Jsonb" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Uuid" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + false + ] + }, + "hash": "8603a35934ee458072e089b7994dd19c2f98b8864475f40a435735c741d8041e" +} diff --git a/server/.sqlx/query-9081b38306b54a242d282d9c41ce0202da7e320a49cd7c20da94c3e3e7afc009.json b/server/.sqlx/query-9081b38306b54a242d282d9c41ce0202da7e320a49cd7c20da94c3e3e7afc009.json new file mode 100644 index 00000000..b950d30f --- /dev/null +++ b/server/.sqlx/query-9081b38306b54a242d282d9c41ce0202da7e320a49cd7c20da94c3e3e7afc009.json @@ -0,0 +1,83 @@ +{ + "db_name": "PostgreSQL", + "query": "\n insert into users (username, access_token)\n values ($1, $2)\n on conflict(username) do update\n set access_token = excluded.access_token\n returning *\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "user_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "username", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "email", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "fullname", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "company", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "user_group", + "type_info": "Int4" + }, + { + "ordinal": 7, + "name": "password_hash", + "type_info": "Text" + }, + { + "ordinal": 8, + "name": "access_token", + "type_info": "Text" + }, + { + "ordinal": 9, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 10, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + true + ] + }, + "hash": "9081b38306b54a242d282d9c41ce0202da7e320a49cd7c20da94c3e3e7afc009" +} diff --git a/server/.sqlx/query-29ef534c8dec3b0822559ee28a5301acd854ff1669e6b6a70c81fd50c952e998.json b/server/.sqlx/query-9e24ef47cd1ad6bb87d66a3ede876607695a29ede2f87547cb16ecfd87ba4e11.json similarity index 70% rename from server/.sqlx/query-29ef534c8dec3b0822559ee28a5301acd854ff1669e6b6a70c81fd50c952e998.json rename to server/.sqlx/query-9e24ef47cd1ad6bb87d66a3ede876607695a29ede2f87547cb16ecfd87ba4e11.json index cd101ce5..42550503 100644 --- a/server/.sqlx/query-29ef534c8dec3b0822559ee28a5301acd854ff1669e6b6a70c81fd50c952e998.json +++ b/server/.sqlx/query-9e24ef47cd1ad6bb87d66a3ede876607695a29ede2f87547cb16ecfd87ba4e11.json @@ -1,27 +1,27 @@ { "db_name": "PostgreSQL", - "query": "select * from search_history where user_id = $1 order by created_at desc limit $2 offset $3", + "query": "select * from searches where thread_id = $1 order by created_at desc limit $2 offset $3", "describe": { "columns": [ { "ordinal": 0, - "name": "search_history_id", + "name": "search_id", "type_info": "Uuid" }, { "ordinal": 1, - "name": "user_id", + "name": "thread_id", "type_info": "Uuid" }, { "ordinal": 2, - "name": "session_id", - "type_info": "Uuid" + "name": "query", + "type_info": "Varchar" }, { "ordinal": 3, - "name": "query", - "type_info": "Text" + "name": "rephrased_query", + "type_info": "Varchar" }, { "ordinal": 4, @@ -30,8 +30,8 @@ }, { "ordinal": 5, - "name": "sources", - "type_info": "Jsonb" + "name": "media_urls", + "type_info": "TextArray" }, { "ordinal": 6, @@ -62,11 +62,11 @@ false, false, false, - false, + true, true, false, false ] }, - "hash": "29ef534c8dec3b0822559ee28a5301acd854ff1669e6b6a70c81fd50c952e998" + "hash": "9e24ef47cd1ad6bb87d66a3ede876607695a29ede2f87547cb16ecfd87ba4e11" } diff --git a/server/.sqlx/query-bc82472e3df0b99af83ab2dcf824c8befba5e3782645d76322d5105d69a697a9.json b/server/.sqlx/query-bc82472e3df0b99af83ab2dcf824c8befba5e3782645d76322d5105d69a697a9.json new file mode 100644 index 00000000..2bb325c3 --- /dev/null +++ b/server/.sqlx/query-bc82472e3df0b99af83ab2dcf824c8befba5e3782645d76322d5105d69a697a9.json @@ -0,0 +1,64 @@ +{ + "db_name": "PostgreSQL", + "query": "select s.* from sources s inner join search_sources ss on s.source_id = ss.source_id where ss.search_id = any($1::uuid[])", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "source_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "source_type", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "metadata", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "UuidArray" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + true, + false, + false + ] + }, + "hash": "bc82472e3df0b99af83ab2dcf824c8befba5e3782645d76322d5105d69a697a9" +} diff --git a/server/.sqlx/query-50cf2fc244b2b5d3fa484577a2056e3f2d9e03c3dd8996ae95887576791aff9a.json b/server/.sqlx/query-ce09df1d8db96f4d5fe17991e9f71939a4e9bb5fbaf1232a5fde29021ed5170e.json similarity index 69% rename from server/.sqlx/query-50cf2fc244b2b5d3fa484577a2056e3f2d9e03c3dd8996ae95887576791aff9a.json rename to server/.sqlx/query-ce09df1d8db96f4d5fe17991e9f71939a4e9bb5fbaf1232a5fde29021ed5170e.json index 0bdadd53..e3cc173e 100644 --- a/server/.sqlx/query-50cf2fc244b2b5d3fa484577a2056e3f2d9e03c3dd8996ae95887576791aff9a.json +++ b/server/.sqlx/query-ce09df1d8db96f4d5fe17991e9f71939a4e9bb5fbaf1232a5fde29021ed5170e.json @@ -1,27 +1,27 @@ { "db_name": "PostgreSQL", - "query": "select * from search_history where user_id = $1 and search_history_id = $2", + "query": "update searches set result = result || $1 where search_id = $2 returning *", "describe": { "columns": [ { "ordinal": 0, - "name": "search_history_id", + "name": "search_id", "type_info": "Uuid" }, { "ordinal": 1, - "name": "user_id", + "name": "thread_id", "type_info": "Uuid" }, { "ordinal": 2, - "name": "session_id", - "type_info": "Uuid" + "name": "query", + "type_info": "Varchar" }, { "ordinal": 3, - "name": "query", - "type_info": "Text" + "name": "rephrased_query", + "type_info": "Varchar" }, { "ordinal": 4, @@ -30,8 +30,8 @@ }, { "ordinal": 5, - "name": "sources", - "type_info": "Jsonb" + "name": "media_urls", + "type_info": "TextArray" }, { "ordinal": 6, @@ -51,7 +51,7 @@ ], "parameters": { "Left": [ - "Uuid", + "Text", "Uuid" ] }, @@ -61,11 +61,11 @@ false, false, false, - false, + true, true, false, false ] }, - "hash": "50cf2fc244b2b5d3fa484577a2056e3f2d9e03c3dd8996ae95887576791aff9a" + "hash": "ce09df1d8db96f4d5fe17991e9f71939a4e9bb5fbaf1232a5fde29021ed5170e" } diff --git a/server/.sqlx/query-d0f1d876f53f8a9fd2ba4cde9b6ae68a39614b768962d123b010c50b940b793d.json b/server/.sqlx/query-d0f1d876f53f8a9fd2ba4cde9b6ae68a39614b768962d123b010c50b940b793d.json index f30f6740..97b54b35 100644 --- a/server/.sqlx/query-d0f1d876f53f8a9fd2ba4cde9b6ae68a39614b768962d123b010c50b940b793d.json +++ b/server/.sqlx/query-d0f1d876f53f8a9fd2ba4cde9b6ae68a39614b768962d123b010c50b940b793d.json @@ -20,21 +20,41 @@ }, { "ordinal": 3, + "name": "fullname", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 5, + "name": "company", + "type_info": "Varchar" + }, + { + "ordinal": 6, + "name": "user_group", + "type_info": "Int4" + }, + { + "ordinal": 7, "name": "password_hash", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 8, "name": "access_token", "type_info": "Text" }, { - "ordinal": 5, + "ordinal": 9, "name": "created_at", "type_info": "Timestamptz" }, { - "ordinal": 6, + "ordinal": 10, "name": "updated_at", "type_info": "Timestamptz" } @@ -52,6 +72,10 @@ false, true, true, + true, + false, + true, + true, false, true ] diff --git a/server/.sqlx/query-e286bbdbfb6172ea31377a2464a6203a91427b1e379a362e79ffe90f824c677b.json b/server/.sqlx/query-e286bbdbfb6172ea31377a2464a6203a91427b1e379a362e79ffe90f824c677b.json new file mode 100644 index 00000000..7ce09d8e --- /dev/null +++ b/server/.sqlx/query-e286bbdbfb6172ea31377a2464a6203a91427b1e379a362e79ffe90f824c677b.json @@ -0,0 +1,68 @@ +{ + "db_name": "PostgreSQL", + "query": "insert into sources (title, description, url, source_type, metadata) select * from unnest($1::text[], $2::text[], $3::text[], $4::int[], $5::jsonb[]) on conflict (url) do update set title = excluded.title, description = excluded.description, source_type = excluded.source_type, metadata = excluded.metadata returning *", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "source_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "url", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "title", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "description", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "source_type", + "type_info": "Int4" + }, + { + "ordinal": 5, + "name": "metadata", + "type_info": "Jsonb" + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "TextArray", + "TextArray", + "TextArray", + "Int4Array", + "JsonbArray" + ] + }, + "nullable": [ + false, + false, + false, + true, + false, + true, + false, + false + ] + }, + "hash": "e286bbdbfb6172ea31377a2464a6203a91427b1e379a362e79ffe90f824c677b" +} diff --git a/server/.sqlx/query-ea69f3b1335e367b3492111c43c35782e6651c01a3427ddd9b00ac12d2cb624e.json b/server/.sqlx/query-ea69f3b1335e367b3492111c43c35782e6651c01a3427ddd9b00ac12d2cb624e.json new file mode 100644 index 00000000..c4f89fc4 --- /dev/null +++ b/server/.sqlx/query-ea69f3b1335e367b3492111c43c35782e6651c01a3427ddd9b00ac12d2cb624e.json @@ -0,0 +1,72 @@ +{ + "db_name": "PostgreSQL", + "query": "update searches s set reaction = $1 from threads t where s.search_id = $2 and s.thread_id = t.thread_id and t.user_id = $3 returning s.*", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "search_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "thread_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "query", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "rephrased_query", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "result", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "media_urls", + "type_info": "TextArray" + }, + { + "ordinal": 6, + "name": "reaction", + "type_info": "Bool" + }, + { + "ordinal": 7, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "updated_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Bool", + "Uuid", + "Uuid" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + true, + false, + false + ] + }, + "hash": "ea69f3b1335e367b3492111c43c35782e6651c01a3427ddd9b00ac12d2cb624e" +} From bb2dede80aef614f810007a1ac437f6d8857168a Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:56:18 +0200 Subject: [PATCH 09/19] Add whitelist email to sqlx prepared statements --- .github/workflows/server.yaml | 2 ++ ...01be4971a2172e924a19f2ac87ee1ccd676cc.json | 28 +++++++++++++++++++ server/src/auth/models.rs | 1 + server/src/users/services.rs | 12 ++++++++ server/tests/users.rs | 12 ++------ 5 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 server/.sqlx/query-d20668931a9349cda924525d36901be4971a2172e924a19f2ac87ee1ccd676cc.json diff --git a/.github/workflows/server.yaml b/.github/workflows/server.yaml index c3330539..6755bcf2 100644 --- a/.github/workflows/server.yaml +++ b/.github/workflows/server.yaml @@ -35,6 +35,8 @@ jobs: - name: Tests & coverage run: cargo llvm-cov test --no-fail-fast --workspace + env: + SQLX_OFFLINE: true - name: Linting rustfmt run: cargo fmt --all -- --check diff --git a/server/.sqlx/query-d20668931a9349cda924525d36901be4971a2172e924a19f2ac87ee1ccd676cc.json b/server/.sqlx/query-d20668931a9349cda924525d36901be4971a2172e924a19f2ac87ee1ccd676cc.json new file mode 100644 index 00000000..0d397ddd --- /dev/null +++ b/server/.sqlx/query-d20668931a9349cda924525d36901be4971a2172e924a19f2ac87ee1ccd676cc.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "insert into whitelisted_emails (email, approved) values ($1, true) returning *", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "email", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "approved", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "d20668931a9349cda924525d36901be4971a2172e924a19f2ac87ee1ccd676cc" +} diff --git a/server/src/auth/models.rs b/server/src/auth/models.rs index ef91860e..526cc9aa 100644 --- a/server/src/auth/models.rs +++ b/server/src/auth/models.rs @@ -211,6 +211,7 @@ pub enum BackendError { // Note that we've supplied our concrete backend here. pub type AuthSession = axum_login::AuthSession; +#[derive(Debug)] pub struct WhitelistedEmail { pub email: String, pub approved: bool, diff --git a/server/src/users/services.rs b/server/src/users/services.rs index bd75de29..05b9fa30 100644 --- a/server/src/users/services.rs +++ b/server/src/users/services.rs @@ -1,4 +1,5 @@ use crate::auth::utils::hash_password; +use crate::auth::WhitelistedEmail; use crate::secrets::Secret; use crate::users::models; use sqlx::PgPool; @@ -53,3 +54,14 @@ pub async fn update_password( return Ok(()); } + +#[tracing::instrument(level = "debug", ret, err)] +pub async fn whitelist_email(pool: &PgPool, email: &str) -> crate::Result { + Ok(sqlx::query_as!( + WhitelistedEmail, + "insert into whitelisted_emails (email, approved) values ($1, true) returning *", + "my-email@email.com", + ) + .fetch_one(pool) + .await?) +} diff --git a/server/tests/users.rs b/server/tests/users.rs index 9999df2e..4ffbd43a 100644 --- a/server/tests/users.rs +++ b/server/tests/users.rs @@ -8,6 +8,7 @@ use server::routing::router; use server::settings::Settings; use server::startup::AppState; use server::users::selectors::get_user; +use server::users::services::whitelist_email; use server::Result; use sqlx::PgPool; use tower::ServiceExt; @@ -46,17 +47,10 @@ async fn register_and_get_users_test(pool: PgPool) -> Result<()> { Ok(()) } - #[sqlx::test] async fn register_users_works(pool: PgPool) { - let WhitelistedEmail { email, .. } = sqlx::query_as!( - WhitelistedEmail, - "insert into whitelisted_emails (email, approved) values ($1, true) returning *", - "my-email@email.com", - ) - .fetch_one(&pool) - .await - .unwrap(); + let WhitelistedEmail { email, .. } = + whitelist_email(&pool, "my-email@email.com").await.unwrap(); let settings = Settings::new(); let cache = CachePool::new(&settings.cache).await.unwrap(); From 223ed9abcde8115ed4d2f0c44c2aeddee3ca6413 Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Wed, 3 Jul 2024 15:56:59 +0200 Subject: [PATCH 10/19] Various CI fixes --- .github/actions/toolchain-cargo-cached/action.yml | 11 ++++++++++- .github/workflows/agency.yaml | 8 ++++++-- .github/workflows/ci.yaml | 1 + .github/workflows/server.yaml | 10 ++++++++++ server/Dockerfile_sqlx | 2 ++ server/sqlx-test-docker-compose.yaml | 15 +++++++++++++++ 6 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 server/Dockerfile_sqlx create mode 100644 server/sqlx-test-docker-compose.yaml diff --git a/.github/actions/toolchain-cargo-cached/action.yml b/.github/actions/toolchain-cargo-cached/action.yml index ea57be66..97952694 100644 --- a/.github/actions/toolchain-cargo-cached/action.yml +++ b/.github/actions/toolchain-cargo-cached/action.yml @@ -22,6 +22,14 @@ inputs: description: Comma-separated list of crates to be additionally installed required: false + cached-workspaces: + description: | + The cargo workspaces and target directory configuration. + Has the form `$workspace -> $target`. The `$target` part is treated as a directory + default: ". -> target" + default: ". -> target" + required: false + runs: using: 'composite' steps: @@ -47,7 +55,7 @@ runs: # Don't cache if it's a scheduled job. if: github.event_name != 'schedule' id: toolchain-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.rustup/settings.toml @@ -82,6 +90,7 @@ runs: if: github.event_name != 'schedule' with: shared-key: ${{ steps.cargo-crates-cachekey.outputs.cachekey }} + workspaces: ${{ inputs.cached-workspaces }} - name: Cargo install dependencies # Only install crates if they aren't cached. diff --git a/.github/workflows/agency.yaml b/.github/workflows/agency.yaml index ae29f05f..cd480b18 100644 --- a/.github/workflows/agency.yaml +++ b/.github/workflows/agency.yaml @@ -13,8 +13,12 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install poetry - run: pipx install poetry + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: "1.8.3" + virtualenvs-create: true + virtualenvs-in-project: true - uses: actions/setup-python@v5 with: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2922840a..77da928c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,6 +29,7 @@ jobs: uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 id: changes with: + base: main token: ${{ github.token }} filters: .github/file-filters.yaml diff --git a/.github/workflows/server.yaml b/.github/workflows/server.yaml index 6755bcf2..1c98f714 100644 --- a/.github/workflows/server.yaml +++ b/.github/workflows/server.yaml @@ -27,16 +27,26 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} + # Copy proto files + - run: cp -r ../proto ./proto + - name: Setup Rust Toolchain uses: ./.github/actions/toolchain-cargo-cached with: components: llvm-tools-preview, rustfmt, clippy crates: cargo-llvm-cov + cached-workspaces: server -> target + + - run: | + docker compose -f sqlx-test-docker-compose.yaml run -d -p 5432:5432 --name postgres postgres + docker exec postgres bash -c "until pg_isready; do sleep 1; done" - name: Tests & coverage run: cargo llvm-cov test --no-fail-fast --workspace env: + DATABASE_URL: postgres://postgres:password@localhost:5432/curieo_search SQLX_OFFLINE: true + SQLX_OFFLINE_DIR: .sqlx - name: Linting rustfmt run: cargo fmt --all -- --check diff --git a/server/Dockerfile_sqlx b/server/Dockerfile_sqlx new file mode 100644 index 00000000..c6a1397c --- /dev/null +++ b/server/Dockerfile_sqlx @@ -0,0 +1,2 @@ +ARG VERSION +FROM postgres:${VERSION}-alpine \ No newline at end of file diff --git a/server/sqlx-test-docker-compose.yaml b/server/sqlx-test-docker-compose.yaml new file mode 100644 index 00000000..5b7addd3 --- /dev/null +++ b/server/sqlx-test-docker-compose.yaml @@ -0,0 +1,15 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: Dockerfile_sqlx + args: + VERSION: 14 + ports: + - 5432 + environment: + POSTGRES_DB: curieo_search + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password \ No newline at end of file From f85d98607f2339ad90c9c9384bde54f01afc0f1e Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:48:35 +0200 Subject: [PATCH 11/19] Works locally with nektos act --- .github/workflows/agency.yaml | 2 +- .github/workflows/server.yaml | 4 ++-- server/sqlx-test-docker-compose.yaml | 10 ++-------- server/tests/utils.rs | 12 ------------ 4 files changed, 5 insertions(+), 23 deletions(-) diff --git a/.github/workflows/agency.yaml b/.github/workflows/agency.yaml index cd480b18..3286d11e 100644 --- a/.github/workflows/agency.yaml +++ b/.github/workflows/agency.yaml @@ -26,7 +26,7 @@ jobs: python-version-file: "agency/.python-version" - name: Install dependencies - run: poetry install + run: source $VENV & poetry install - name: Linting & formatting run: make lint & make fmt-check diff --git a/.github/workflows/server.yaml b/.github/workflows/server.yaml index 1c98f714..1651d2d7 100644 --- a/.github/workflows/server.yaml +++ b/.github/workflows/server.yaml @@ -38,8 +38,8 @@ jobs: cached-workspaces: server -> target - run: | - docker compose -f sqlx-test-docker-compose.yaml run -d -p 5432:5432 --name postgres postgres - docker exec postgres bash -c "until pg_isready; do sleep 1; done" + docker compose -f sqlx-test-docker-compose.yaml run -d -p 5432:5432 --name sqlx_postgres sqlx_postgres + docker exec sqlx_postgres bash -c "until pg_isready; do sleep 1; done" - name: Tests & coverage run: cargo llvm-cov test --no-fail-fast --workspace diff --git a/server/sqlx-test-docker-compose.yaml b/server/sqlx-test-docker-compose.yaml index 5b7addd3..8c2bb7a8 100644 --- a/server/sqlx-test-docker-compose.yaml +++ b/server/sqlx-test-docker-compose.yaml @@ -1,12 +1,6 @@ -version: "3" - services: - postgres: - build: - context: . - dockerfile: Dockerfile_sqlx - args: - VERSION: 14 + sqlx_postgres: + image: postgres:14-alpine ports: - 5432 environment: diff --git a/server/tests/utils.rs b/server/tests/utils.rs index 65341f28..0543d17f 100644 --- a/server/tests/utils.rs +++ b/server/tests/utils.rs @@ -18,18 +18,6 @@ struct MockAgencyServer { embeddings_compute_response: EmbeddingsOutput, } -impl MockAgencyServer { - fn set_pubmed_parent_search_response(&mut self, response: PubmedResponse) { - self.pubmed_parent_search_response = response - } - fn set_pubmed_cluster_search_response(&mut self, response: PubmedResponse) { - self.pubmed_cluster_search_response = response - } - fn set_embeddings_compute_response(&mut self, response: EmbeddingsOutput) { - self.embeddings_compute_response = response - } -} - #[async_trait] impl AgencyService for MockAgencyServer { async fn pubmed_parent_search( From 4f1e309b2510c55ee2ec6cdd96356ab59f8c6809 Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:35:12 +0200 Subject: [PATCH 12/19] Fix clippy --- server/src/llms/query_rephraser.rs | 2 +- server/src/llms/summarizer.rs | 8 ++++---- server/src/llms/toxicity.rs | 4 ++-- server/src/rag/brave_search.rs | 25 +++++++++++-------------- server/src/rag/pre_process.rs | 2 +- server/src/rag/search.rs | 4 ++-- server/src/rag/utils.rs | 4 ++-- server/src/search/routes.rs | 24 ++++++++++++------------ server/src/search/services.rs | 4 ++-- 9 files changed, 37 insertions(+), 40 deletions(-) diff --git a/server/src/llms/query_rephraser.rs b/server/src/llms/query_rephraser.rs index 3e5ca629..d14cb0ae 100644 --- a/server/src/llms/query_rephraser.rs +++ b/server/src/llms/query_rephraser.rs @@ -62,7 +62,7 @@ pub async fn rephrase_query( headers.insert( HeaderName::from_bytes(b"Authorization") .map_err(|e| eyre!("Failed to create header: {e}"))?, - HeaderValue::from_str(&settings.api_key.expose()) + HeaderValue::from_str(settings.api_key.expose()) .map_err(|e| eyre!("Failed to create header: {e}"))?, ); diff --git a/server/src/llms/summarizer.rs b/server/src/llms/summarizer.rs index dca90e03..bafaaf65 100644 --- a/server/src/llms/summarizer.rs +++ b/server/src/llms/summarizer.rs @@ -61,7 +61,7 @@ fn prepare_llm_context_string( Question: {}\n\nSolution draft: {}\n\nAnswer:", summarizer_input.query, summarizer_input.retrieved_result), parameters: SummarizerParams { model: Some(settings.model.clone()), - max_new_tokens: Some(settings.max_new_tokens.clone()), + max_new_tokens: Some(settings.max_new_tokens), temperature: Some(settings.temperature), top_p: Some(settings.top_p), }, @@ -97,7 +97,7 @@ pub async fn generate_text_with_llm( let chunk = chunk.map_err(|e| eyre!("Failed to read chunk: {e}"))?; let chunk = &chunk[5..chunk.len() - 2]; - let summarizer_api_response = serde_json::from_slice::(&chunk) + let summarizer_api_response = serde_json::from_slice::(chunk) .map_err(|e| eyre!("Failed to parse summarizer response: {e}"))?; if !summarizer_api_response.token.special { @@ -115,7 +115,7 @@ pub async fn generate_text_with_llm( }) .await; - if let Ok(_) = tx_response { + if tx_response.is_ok() { buffer.clear(); } } @@ -230,7 +230,7 @@ pub async fn generate_text_with_openai( }) .await; - if let Ok(_) = tx_response { + if tx_response.is_ok() { buffer.clear(); } } diff --git a/server/src/llms/toxicity.rs b/server/src/llms/toxicity.rs index f4fd6ce2..c498da5b 100644 --- a/server/src/llms/toxicity.rs +++ b/server/src/llms/toxicity.rs @@ -27,7 +27,7 @@ pub async fn predict_toxicity( headers.insert( HeaderName::from_bytes(b"Authorization") .map_err(|e| eyre!("Failed to create header: {e}"))?, - HeaderValue::from_str(&llm_settings.toxicity_auth_token.expose()) + HeaderValue::from_str(llm_settings.toxicity_auth_token.expose()) .map_err(|e| eyre!("Failed to create header: {e}"))?, ); let client = Client::new(); @@ -47,7 +47,7 @@ pub async fn predict_toxicity( let toxicity_score = toxicity_api_response .into_iter() - .find(|x| x.label == String::from("toxic")) + .find(|x| x.label == *"toxic") .unwrap_or(ToxicityScore { score: 0.0, label: String::from(""), diff --git a/server/src/rag/brave_search.rs b/server/src/rag/brave_search.rs index 7b081964..95cce192 100644 --- a/server/src/rag/brave_search.rs +++ b/server/src/rag/brave_search.rs @@ -147,20 +147,17 @@ fn convert_to_retrieved_result(result: BraveWebSearchResult) -> RetrievedResult url: result.url, description: result.description, source_type: SourceType::Url, - metadata: HashMap::from_iter( - vec![ - ( - "page_age".to_string(), - result.page_age.unwrap_or("".to_string()), - ), - ("age".to_string(), result.age.unwrap_or("".to_string())), - ( - "language".to_string(), - result.language.unwrap_or("".to_string()), - ), - ] - .into_iter(), - ), + metadata: HashMap::from_iter(vec![ + ( + "page_age".to_string(), + result.page_age.unwrap_or("".to_string()), + ), + ("age".to_string(), result.age.unwrap_or("".to_string())), + ( + "language".to_string(), + result.language.unwrap_or("".to_string()), + ), + ]), }, } } diff --git a/server/src/rag/pre_process.rs b/server/src/rag/pre_process.rs index 54acc960..905ff1a0 100644 --- a/server/src/rag/pre_process.rs +++ b/server/src/rag/pre_process.rs @@ -65,7 +65,7 @@ pub async fn rephrase_query( let last_n_searches = match search_query_request.thread_id { Some(thread_id) => { search_services::get_last_n_searches( - &pool, + pool, settings.search.max_search_context, &thread_id, ) diff --git a/server/src/rag/search.rs b/server/src/rag/search.rs index 01bb5e42..c0f27443 100644 --- a/server/src/rag/search.rs +++ b/server/src/rag/search.rs @@ -13,7 +13,7 @@ pub async fn search( settings: &Settings, brave_api_config: &brave_search::BraveAPIConfig, cache: &CachePool, - agency_service: &mut AgencyServiceClient, + agency_service: &AgencyServiceClient, search_query: &str, ) -> crate::Result { if let Some(response) = cache.get(search_query).await { @@ -66,7 +66,7 @@ pub async fn search( #[tracing::instrument(level = "debug", ret, err)] async fn retrieve_result_from_agency( settings: &Settings, - agency_service: &mut AgencyServiceClient, + agency_service: &AgencyServiceClient, search_query: &str, ) -> crate::Result> { let agency_service = Arc::new(agency_service.clone()); diff --git a/server/src/rag/utils.rs b/server/src/rag/utils.rs index 327395cb..5d3232ad 100644 --- a/server/src/rag/utils.rs +++ b/server/src/rag/utils.rs @@ -1,4 +1,4 @@ -pub fn cosine_similarity(v1: &Vec, v2: &Vec) -> f64 { +pub fn cosine_similarity(v1: &[f64], v2: &[f64]) -> f64 { if v1.len() != v2.len() { return 0.0; } @@ -11,5 +11,5 @@ pub fn cosine_similarity(v1: &Vec, v2: &Vec) -> f64 { return 0.0; } - return dot_product / magnitude_product; + dot_product / magnitude_product } diff --git a/server/src/search/routes.rs b/server/src/search/routes.rs index 541b257b..edd7f516 100644 --- a/server/src/search/routes.rs +++ b/server/src/search/routes.rs @@ -1,8 +1,6 @@ -use crate::cache::CachePool; -use crate::proto::agency_service_client::AgencyServiceClient; use crate::rag::{self, post_process, pre_process}; use crate::search::{api_models, services}; -use crate::settings::Settings; + use crate::startup::AppState; use crate::users::User; use axum::extract::{Query, State}; @@ -14,22 +12,24 @@ use axum::{Json, Router}; use color_eyre::eyre::eyre; use futures::stream::StreamExt; use futures::Stream; -use regex::Regex; + use sqlx::PgPool; use std::convert::Infallible; use std::sync::Arc; use tokio::sync::mpsc; use tokio_stream::wrappers::ReceiverStream; -use tonic::transport::Channel; #[tracing::instrument(level = "debug", skip_all, ret, err(Debug))] async fn get_search_query_handler( - State(settings): State, - State(brave_api_config): State, + State(AppState { + cache, + agency_service, + settings, + brave_config, + openai_stream_regex, + .. + }): State, State(pool): State, - State(cache): State, - State(mut agency_service): State>, - State(openai_stream_regex): State, user: User, Query(search_query_request): Query, ) -> crate::Result>>> { @@ -52,9 +52,9 @@ async fn get_search_query_handler( services::insert_new_search(&pool, &user_id, &search_query_request, &rephrased_query), rag::search( &settings, - &brave_api_config, + &brave_config, &cache, - &mut agency_service, + &agency_service, &rephrased_query ) ); diff --git a/server/src/search/services.rs b/server/src/search/services.rs index 90ba2800..ff46dc04 100644 --- a/server/src/search/services.rs +++ b/server/src/search/services.rs @@ -74,14 +74,14 @@ pub async fn add_search_sources( search: &data_models::Search, sources: &Vec, ) -> crate::Result> { - if sources.len() == 0 { + if sources.is_empty() { return Err(eyre!("No sources to add").into()); } // remove duplicates with same url let mut hash_set: HashSet<&String> = sources.iter().map(|s| &s.url).collect(); let sources = sources - .into_iter() + .iter() .filter(|s| match hash_set.contains(&s.url) { true => { hash_set.remove(&s.url); From 3ff00e35335c65a1b7bab0f783afee7f718bf1d3 Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:19:15 +0200 Subject: [PATCH 13/19] Remove redundant dependencies --- server/Cargo.lock | 128 +++++----------------------------------------- server/Cargo.toml | 1 - 2 files changed, 13 insertions(+), 116 deletions(-) diff --git a/server/Cargo.lock b/server/Cargo.lock index cd4aef41..c25a34a2 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -739,7 +739,7 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util 0.7.10", + "tokio-util", ] [[package]] @@ -1367,7 +1367,7 @@ dependencies = [ "indexmap 2.2.5", "slab", "tokio", - "tokio-util 0.7.10", + "tokio-util", "tracing", ] @@ -1386,7 +1386,7 @@ dependencies = [ "indexmap 2.2.5", "slab", "tokio", - "tokio-util 0.7.10", + "tokio-util", "tracing", ] @@ -1815,15 +1815,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.11.0" @@ -2579,16 +2570,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive 0.9.0", -] - [[package]] name = "prost" version = "0.12.6" @@ -2596,7 +2577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.6", + "prost-derive", ] [[package]] @@ -2613,26 +2594,13 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost 0.12.6", + "prost", "prost-types", "regex", "syn 2.0.53", "tempfile", ] -[[package]] -name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "prost-derive" version = "0.12.6" @@ -2652,7 +2620,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" dependencies = [ - "prost 0.12.6", + "prost", ] [[package]] @@ -2718,7 +2686,7 @@ dependencies = [ "socket2 0.5.6", "tokio", "tokio-rustls 0.25.0", - "tokio-util 0.7.10", + "tokio-util", "url", ] @@ -2864,7 +2832,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-util 0.7.10", + "tokio-util", "tower-service", "url", "wasm-bindgen", @@ -3363,7 +3331,7 @@ dependencies = [ "once_cell", "openssl-sys", "password-auth", - "prost 0.12.6", + "prost", "rand", "redis", "regex", @@ -3379,7 +3347,7 @@ dependencies = [ "time", "tokio", "tokio-stream", - "tonic 0.11.0", + "tonic", "tonic-build", "tower", "tower-http", @@ -3389,7 +3357,6 @@ dependencies = [ "tracing-logfmt", "tracing-subscriber", "uuid", - "wiremock-grpc", ] [[package]] @@ -4020,21 +3987,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", - "tokio-util 0.7.10", -] - -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", + "tokio-util", ] [[package]] @@ -4085,37 +4038,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tonic" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" -dependencies = [ - "async-stream", - "async-trait", - "base64 0.13.1", - "bytes", - "futures-core", - "futures-util", - "h2 0.3.25", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost 0.9.0", - "prost-derive 0.9.0", - "tokio", - "tokio-stream", - "tokio-util 0.6.10", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - [[package]] name = "tonic" version = "0.11.0" @@ -4134,7 +4056,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.12.6", + "prost", "tokio", "tokio-stream", "tower", @@ -4170,7 +4092,7 @@ dependencies = [ "rand", "slab", "tokio", - "tokio-util 0.7.10", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -4316,16 +4238,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -4870,20 +4782,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "wiremock-grpc" -version = "0.0.3-alpha2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "319deda70ff78f1ee33c271bda813160ae13ef33bda15ebe66b5a377d1911ec9" -dependencies = [ - "http-body 0.4.6", - "log", - "prost 0.9.0", - "rand", - "tokio", - "tonic 0.6.2", -] - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/server/Cargo.toml b/server/Cargo.toml index 797dd5e3..a399d6fb 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -69,7 +69,6 @@ sentry-tower = { version = "0.34.0", features = ["http"] } regex = "1.10.5" [dev-dependencies] -wiremock-grpc = "0.0.3-alpha2" tempfile = "3.10.1" httpmock = "0.7.0" From d6030fd62b94658d65bd26061e66650560d006cc Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:26:11 +0200 Subject: [PATCH 14/19] Tiniest brave related code improvement --- server/src/rag/brave_search.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server/src/rag/brave_search.rs b/server/src/rag/brave_search.rs index 95cce192..62069c4e 100644 --- a/server/src/rag/brave_search.rs +++ b/server/src/rag/brave_search.rs @@ -135,10 +135,7 @@ pub async fn web_search( } fn convert_to_retrieved_result(result: BraveWebSearchResult) -> RetrievedResult { - let extra_snippets = match result.extra_snippets { - Some(snippets) => snippets, - None => vec![], - }; + let extra_snippets = result.extra_snippets.unwrap_or_default(); RetrievedResult { text: result.description.clone() + "\n\n" + extra_snippets.join("\n\n").as_str(), From 6ab9dcc6f589c3b3f53f85356398fe90618a259b Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Thu, 4 Jul 2024 10:41:31 +0200 Subject: [PATCH 15/19] sqlx prepare --- ...b52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename server/.sqlx/{query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json => query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json} (77%) diff --git a/server/.sqlx/query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json b/server/.sqlx/query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json similarity index 77% rename from server/.sqlx/query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json rename to server/.sqlx/query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json index 097a3d6d..22acb7dc 100644 --- a/server/.sqlx/query-16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3.json +++ b/server/.sqlx/query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n update users\n set\n username = coalesce($1::text, username),\n email = coalesce($2::text, email),\n fullname = coalesce($3::text, fullname),\n title = coalesce($4::text, title),\n company = coalesce($5::text, company)\n where user_id = $6 returning *\n ", + "query": "\n update users\n set\n username = coalesce($1::text, username),\n email = coalesce($2::text, email),\n fullname = coalesce($3::text, fullname),\n title = coalesce($4::text, title),\n company = coalesce($5::text, company)\n where user_id = $6 returning *\n ", "describe": { "columns": [ { @@ -83,5 +83,5 @@ true ] }, - "hash": "16ab4584237414a8b3f1011fb10b45e788e6f3b415b8f72e48927ec5f99b8fe3" + "hash": "aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283" } From 048e83949f6802552d18d4db695a4f77c70e13a0 Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Thu, 4 Jul 2024 11:19:15 +0200 Subject: [PATCH 16/19] Clippy --- server/src/auth/routes.rs | 18 +++++++++--------- server/src/auth/services.rs | 6 +++--- server/src/err.rs | 8 ++++---- server/src/rag/pre_process.rs | 8 ++++++-- server/src/rag/pubmed_search.rs | 14 ++++++-------- server/src/rag/search.rs | 2 +- server/src/search/services.rs | 2 +- server/src/users/routes.rs | 13 ++++++++----- 8 files changed, 38 insertions(+), 33 deletions(-) diff --git a/server/src/auth/routes.rs b/server/src/auth/routes.rs index 44f1c99e..617b965d 100644 --- a/server/src/auth/routes.rs +++ b/server/src/auth/routes.rs @@ -25,7 +25,7 @@ async fn register_handler( .map_err(|e| AuthError::InvalidData(format!("Invalid data: {}", e)))?; if !services::is_email_whitelisted(&pool, &request.email).await? { - return Err(AuthError::NotWhitelisted(format!("This email is not whitelisted!")).into()); + return Err(AuthError::NotWhitelisted("This email is not whitelisted!".to_string()).into()); } services::register(pool, request) .await @@ -42,12 +42,12 @@ async fn login_handler( .await { Ok(Some(user)) => user, - Ok(None) => return Err(AuthError::Unauthorized(format!("Invalid credentials")).into()), - Err(_) => return Err(AuthError::Other(format!("Could not authenticate user")).into()), + Ok(None) => return Err(AuthError::Unauthorized("Invalid credentials".to_string()).into()), + Err(_) => return Err(AuthError::Other("Could not authenticate user".to_string()).into()), }; if auth_session.login(&user).await.is_err() { - return Err(AuthError::Other(format!("Could not login user")).into()); + return Err(AuthError::Other("Could not login user".to_string()).into()); } //if let Credentials::Password(_pw_creds) = creds { // if let Some(ref next) = pw_creds.next { @@ -108,7 +108,7 @@ pub async fn oauth_callback_handler( ) -> crate::Result { let Ok(Some(old_state)) = session.get(CSRF_STATE_KEY).await else { return Err( - AuthError::Unauthorized(format!("Session did not contain old csrf state")).into(), + AuthError::Unauthorized("Session did not contain old csrf state".to_string()).into(), ); }; @@ -120,12 +120,12 @@ pub async fn oauth_callback_handler( let user = match auth_session.authenticate(creds).await { Ok(Some(user)) => user, - Ok(None) => return Err(AuthError::Unauthorized(format!("Invalid credentials")).into()), - Err(_) => return Err(AuthError::Other(format!("Could not authenticate user")).into()), + Ok(None) => return Err(AuthError::Unauthorized("Invalid credentials".to_string()).into()), + Err(_) => return Err(AuthError::Other("Could not authenticate user".to_string()).into()), }; if auth_session.login(&user).await.is_err() { - return Err(AuthError::Other(format!("Could not login user")).into()); + return Err(AuthError::Other("Could not login user".to_string()).into()); } if let Ok(Some(next)) = session.remove::(NEXT_URL_KEY).await { @@ -151,7 +151,7 @@ async fn get_session_handler(auth_session: AuthSession) -> crate::Result Router { diff --git a/server/src/auth/services.rs b/server/src/auth/services.rs index f7a28b40..a89a13f6 100644 --- a/server/src/auth/services.rs +++ b/server/src/auth/services.rs @@ -64,9 +64,9 @@ pub async fn register( return Ok(user.into()); } - Err(AuthError::InvalidData(format!( - "Either password or access_token must be provided to create a user" - )) + Err(AuthError::InvalidData( + "Either password or access_token must be provided to create a user".to_string(), + ) .into()) } diff --git a/server/src/err.rs b/server/src/err.rs index 66f69e15..b61b906b 100644 --- a/server/src/err.rs +++ b/server/src/err.rs @@ -51,10 +51,10 @@ impl AppError { }, AppError::SearchError(err) => match err { - SearchError::ToxicQuery(_) => format!("toxic_query"), - SearchError::InvalidData(_) => format!("invalid_data"), - SearchError::NoResults(_) | SearchError::NoSources(_) => format!("no_results"), - _ => format!("internal_server_error"), + SearchError::ToxicQuery(_) => "toxic_query".to_string(), + SearchError::InvalidData(_) => "invalid_data".to_string(), + SearchError::NoResults(_) | SearchError::NoSources(_) => "no_results".to_string(), + _ => "internal_server_error".to_string(), }, AppError::UserError(err) => match err { UserError::InvalidData(_) => "invalid_data".to_string(), diff --git a/server/src/rag/pre_process.rs b/server/src/rag/pre_process.rs index afdb6ebb..9ee96876 100644 --- a/server/src/rag/pre_process.rs +++ b/server/src/rag/pre_process.rs @@ -24,11 +24,15 @@ pub async fn compute_embeddings( .into_inner(); if response.status != 200 { - return Err(SearchError::AgencyFailure("Failed to get embeddings".to_string()).into()); + return Err(SearchError::AgencyFailure( + "Failed to get embeddings".to_string(), + )); } match response.embeddings { - None => Err(SearchError::AgencyFailure("No embeddings found".to_string()).into()), + None => Err(SearchError::AgencyFailure( + "No embeddings found".to_string(), + )), Some(embeddings) => Ok(embeddings), } } diff --git a/server/src/rag/pubmed_search.rs b/server/src/rag/pubmed_search.rs index 092e7803..dd6060bb 100644 --- a/server/src/rag/pubmed_search.rs +++ b/server/src/rag/pubmed_search.rs @@ -43,10 +43,9 @@ pub async fn pubmed_parent_search( .into_inner(); if response.status != 200 { - return Err(SearchError::AgencyFailure(format!( - "Failed to get pubmed parent search results" - )) - .into()); + return Err(SearchError::AgencyFailure( + "Failed to get pubmed parent search results".to_string(), + )); } Ok(response.sources) @@ -66,10 +65,9 @@ pub async fn pubmed_cluster_search( .into_inner(); if response.status != 200 { - return Err(SearchError::AgencyFailure(format!( - "Failed to get pubmed cluster search results" - )) - .into()); + return Err(SearchError::AgencyFailure( + "Failed to get pubmed cluster search results".to_string(), + )); } Ok(response.sources) diff --git a/server/src/rag/search.rs b/server/src/rag/search.rs index 9fedbdaf..8007cd2f 100644 --- a/server/src/rag/search.rs +++ b/server/src/rag/search.rs @@ -40,7 +40,7 @@ pub async fn search( } if retrieved_results.is_empty() { - return Err(SearchError::NoSources(format!("No sources found")).into()); + return Err(SearchError::NoSources("No sources found".to_string())); } let compressed_results = prompt_compression::compress( diff --git a/server/src/search/services.rs b/server/src/search/services.rs index f51beffc..1e2c33f5 100644 --- a/server/src/search/services.rs +++ b/server/src/search/services.rs @@ -76,7 +76,7 @@ pub async fn add_search_sources( sources: &Vec, ) -> Result> { if sources.is_empty() { - return Err(SearchError::NoSources("No sources to add".to_string()).into()); + return Err(SearchError::NoSources("No sources to add".to_string())); } // remove duplicates with same url diff --git a/server/src/users/routes.rs b/server/src/users/routes.rs index d88f7d2e..51b21405 100644 --- a/server/src/users/routes.rs +++ b/server/src/users/routes.rs @@ -23,7 +23,7 @@ async fn update_profile_handler( let user_id = user.user_id; if !update_profile_request.has_any_value() { return Err( - UserError::InvalidData(format!("At least one field has to be updated.")).into(), + UserError::InvalidData("At least one field has to be updated.".to_string()).into(), ); } let updated_user = services::update_profile(&pool, &user_id, update_profile_request).await?; @@ -42,9 +42,10 @@ async fn update_password_handler( if update_password_request.old_password.expose() == update_password_request.new_password.expose() { - return Err( - UserError::InvalidData(format!("Old and new password can not be the same.")).into(), - ); + return Err(UserError::InvalidData( + "Old and new password can not be the same.".to_string(), + ) + .into()); } match verify_user_password(Some(user), update_password_request.old_password) { @@ -53,7 +54,9 @@ async fn update_password_handler( .await?; Ok(()) } - _ => Err(UserError::InvalidPassword(format!("Failed to authenticate old password")).into()), + _ => Err( + UserError::InvalidPassword("Failed to authenticate old password".to_string()).into(), + ), } } From d5875f3e51ea02fc129e9510e2fdd744ecd795db Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Thu, 4 Jul 2024 11:21:50 +0200 Subject: [PATCH 17/19] sqlx prepare --- ...da9f89136769bfc2cb8dda67a758edd1f955fbbe691620ffd2.json} | 6 ++---- ...0801bfb74dc0774d4ac615d4d1269a44eb31b0d3184ad44a2c.json} | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) rename server/.sqlx/{query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json => query-e9d050c9eca89fda9f89136769bfc2cb8dda67a758edd1f955fbbe691620ffd2.json} (75%) rename server/.sqlx/{query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json => query-efb7df3755e3da0801bfb74dc0774d4ac615d4d1269a44eb31b0d3184ad44a2c.json} (89%) diff --git a/server/.sqlx/query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json b/server/.sqlx/query-e9d050c9eca89fda9f89136769bfc2cb8dda67a758edd1f955fbbe691620ffd2.json similarity index 75% rename from server/.sqlx/query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json rename to server/.sqlx/query-e9d050c9eca89fda9f89136769bfc2cb8dda67a758edd1f955fbbe691620ffd2.json index 22acb7dc..0812575e 100644 --- a/server/.sqlx/query-aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283.json +++ b/server/.sqlx/query-e9d050c9eca89fda9f89136769bfc2cb8dda67a758edd1f955fbbe691620ffd2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n update users\n set\n username = coalesce($1::text, username),\n email = coalesce($2::text, email),\n fullname = coalesce($3::text, fullname),\n title = coalesce($4::text, title),\n company = coalesce($5::text, company)\n where user_id = $6 returning *\n ", + "query": "\n update users\n set\n\n fullname = coalesce($1::text, fullname),\n title = coalesce($2::text, title),\n company = coalesce($3::text, company)\n where user_id = $4 returning *\n ", "describe": { "columns": [ { @@ -61,8 +61,6 @@ ], "parameters": { "Left": [ - "Text", - "Text", "Text", "Text", "Text", @@ -83,5 +81,5 @@ true ] }, - "hash": "aef296c82f2db52d1b9213f1c0e76665ad39685158f62eb525019b3f41c14283" + "hash": "e9d050c9eca89fda9f89136769bfc2cb8dda67a758edd1f955fbbe691620ffd2" } diff --git a/server/.sqlx/query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json b/server/.sqlx/query-efb7df3755e3da0801bfb74dc0774d4ac615d4d1269a44eb31b0d3184ad44a2c.json similarity index 89% rename from server/.sqlx/query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json rename to server/.sqlx/query-efb7df3755e3da0801bfb74dc0774d4ac615d4d1269a44eb31b0d3184ad44a2c.json index 12771f98..915bf354 100644 --- a/server/.sqlx/query-2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8.json +++ b/server/.sqlx/query-efb7df3755e3da0801bfb74dc0774d4ac615d4d1269a44eb31b0d3184ad44a2c.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "select * from users where username = $1 and password_hash is not null", + "query": "select * from users where email = $1 and password_hash is not null", "describe": { "columns": [ { @@ -78,5 +78,5 @@ true ] }, - "hash": "2af097ecfc139606f581858bfebfb6db10aec38671ebe21c8a579d81ffc699d8" + "hash": "efb7df3755e3da0801bfb74dc0774d4ac615d4d1269a44eb31b0d3184ad44a2c" } From 59580d28f218d7426a0b835c5728b05d93b419ef Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Thu, 4 Jul 2024 12:05:30 +0200 Subject: [PATCH 18/19] tracing level debug -> info --- server/src/auth/services.rs | 2 +- server/src/rag/brave_search.rs | 2 +- server/src/users/services.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/auth/services.rs b/server/src/auth/services.rs index a89a13f6..0d2d5ce8 100644 --- a/server/src/auth/services.rs +++ b/server/src/auth/services.rs @@ -4,7 +4,7 @@ use crate::err::ResultExt; use crate::users::{User, UserRecord}; use sqlx::PgPool; -#[tracing::instrument(level = "debug", ret, err)] +#[tracing::instrument(level = "info", ret, err)] pub async fn register( pool: PgPool, request: api_models::RegisterUserRequest, diff --git a/server/src/rag/brave_search.rs b/server/src/rag/brave_search.rs index bd8a332f..abb2b631 100644 --- a/server/src/rag/brave_search.rs +++ b/server/src/rag/brave_search.rs @@ -93,7 +93,7 @@ struct BraveAPIResponse { pub web: BraveWebAPIResponse, } -#[tracing::instrument(level = "debug", ret, err)] +#[tracing::instrument(level = "info", ret, err)] pub async fn web_search( brave_settings: &BraveSettings, brave_api_config: &BraveAPIConfig, diff --git a/server/src/users/services.rs b/server/src/users/services.rs index 168a6b44..3eeeebb8 100644 --- a/server/src/users/services.rs +++ b/server/src/users/services.rs @@ -54,7 +54,7 @@ pub async fn update_password( return Ok(()); } -#[tracing::instrument(level = "debug", ret, err)] +#[tracing::instrument(level = "info", ret, err)] pub async fn whitelist_email(pool: &PgPool, email: &str) -> crate::Result { Ok(sqlx::query_as!( WhitelistedEmail, From ebbc3bba73745687e539fd644cf0f4b66496805a Mon Sep 17 00:00:00 2001 From: Ivar Flakstad <69173633+ivarflakstad@users.noreply.github.com> Date: Thu, 4 Jul 2024 12:06:03 +0200 Subject: [PATCH 19/19] Actually use email parameter in whitelist_email fn --- server/src/users/services.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/users/services.rs b/server/src/users/services.rs index 3eeeebb8..8ba900aa 100644 --- a/server/src/users/services.rs +++ b/server/src/users/services.rs @@ -59,7 +59,7 @@ pub async fn whitelist_email(pool: &PgPool, email: &str) -> crate::Result