3 Commits
Author SHA1 Message Date
phoenix 3423c1eeb1 Update rust (#20)
Rust Build / Rustfmt (push) Successful in 48s
Rust Build / Check (push) Successful in 1m30s
Rust Build / Test Suite (push) Successful in 2m29s
Rust Build / Clippy (push) Successful in 1m47s
Rust Build / build (push) Successful in 2m13s
Rust Build / Check (pull_request) Successful in 3m34s
Rust Build / Rustfmt (pull_request) Successful in 36s
Rust Build / Clippy (pull_request) Successful in 38s
Reviewed-on: phoenix/textsender_auth#20
2026-07-06 22:03:16 -04:00
phoenix 21bfaf7657 Update dependencies (#19)
Rust Build / Rustfmt (push) Successful in 50s
Rust Build / Check (push) Successful in 1m7s
Rust Build / Test Suite (push) Failing after 2m2s
Rust Build / Clippy (push) Successful in 1m27s
Rust Build / build (push) Successful in 1m30s
Reviewed-on: phoenix/textsender_auth#19
2026-07-04 20:00:46 -04:00
phoenix 9dba08f179 Get User profile endpoint (#18)
Rust Build / Rustfmt (push) Successful in 38s
Rust Build / Test Suite (push) Failing after 1m43s
Rust Build / Check (push) Successful in 1m52s
Rust Build / Clippy (push) Successful in 1m10s
Rust Build / build (push) Successful in 2m4s
Rust Build / Rustfmt (pull_request) Successful in 1m9s
Rust Build / Clippy (pull_request) Successful in 1m17s
Rust Build / Check (pull_request) Successful in 1m36s
Reviewed-on: phoenix/textsender_auth#18
2026-07-01 22:37:25 -04:00
14 changed files with 328 additions and 977 deletions
+2 -1
View File
@@ -7,4 +7,5 @@ DB_AUTH_PORT=5432
DB_AUTH_SSLMODE=disable
DATABASE_URL=postgres://${DB_AUTH_USER}:${DB_AUTH_PASSWORD}@${DB_AUTH_HOST}:${DB_AUTH_PORT}/${DB_AUTH_NAME}
ENABLE_REGISTRATION=true
ALLOWED_ORIGINS="http://textsender.com"
ALLOWED_ORIGINS="http://textsender.com,http://localhost:5173,http://localhost:9080"
APP_ENV=production
+2 -1
View File
@@ -7,4 +7,5 @@ DB_AUTH_PORT=5432
DB_AUTH_SSLMODE=disable
DATABASE_URL=postgres://${DB_AUTH_USER}:${DB_AUTH_PASSWORD}@${DB_AUTH_HOST}:${DB_AUTH_PORT}/${DB_AUTH_NAME}
ENABLE_REGISTRATION=true
ALLOWED_ORIGINS="http://textsender.com"
ALLOWED_ORIGINS="http://textsender.com,http://localhost:5173,http://localhost:9080"
APP_ENV=production
+6 -6
View File
@@ -14,10 +14,10 @@ jobs:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
@@ -35,10 +35,10 @@ jobs:
name: Rustfmt
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: |
@@ -55,10 +55,10 @@ jobs:
name: Clippy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: |
+10 -10
View File
@@ -14,10 +14,10 @@ jobs:
name: Check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
@@ -51,10 +51,10 @@ jobs:
--health-retries 5
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
# --- Add this step for explicit verification ---
- name: Verify Docker Environment
@@ -94,10 +94,10 @@ jobs:
name: Rustfmt
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
- run: rustup component add rustfmt
- run: |
@@ -114,10 +114,10 @@ jobs:
name: Clippy
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
- run: rustup component add clippy
- run: |
@@ -134,10 +134,10 @@ jobs:
name: build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: 1.96
toolchain: 1.96.1
- uses: Swatinem/rust-cache@v2
- run: |
mkdir -p ~/.ssh
Generated
+61 -889
View File
File diff suppressed because it is too large Load Diff
+7 -12
View File
@@ -1,8 +1,8 @@
[package]
name = "textsender_auth"
version = "0.2.0"
version = "0.2.2"
edition = "2024"
rust-version = "1.96"
rust-version = "1.96.1"
[dependencies]
axum = { version = "0.8.9" }
@@ -10,21 +10,16 @@ serde = { version = "1.0.228", features = ["derive"] }
serde_json = { version = "1.0.150" }
tokio = { version = "1.52.3", features = ["rt-multi-thread"] }
tracing-subscriber = { version = "0.3.23" }
tower = { version = "0.5.3", features = ["full"] }
tower-http = { version = "0.6.11", features = ["cors"] }
hyper = { version = "1.10.1" }
tower-http = { version = "0.7.0", features = ["cors"] }
sqlx = { version = "0.9.0", features = ["runtime-tokio", "tls-native-tls", "postgres", "time", "uuid"] }
uuid = { version = "1.23.3", features = ["v4", "serde"] }
argon2 = { version = "0.5.3", features = ["std"] } # Use the latest 0.5.x version
rand = { version = "0.10.1" }
time = { version = "0.3.49", features = ["macros", "serde"] }
argon2 = { version = "0.5.3", features = ["std"] }
time = { version = "0.3.53", features = ["macros", "serde"] }
josekit = { version = "0.10.3" }
utoipa = { version = "5.5.0", features = ["axum_extras"] }
utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] }
textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.4.10", features = ["config", "user"] }
textsender_models = { git = "ssh://git@git.kundeng.us/phoenix/textsender_models.git", tag = "v0.5.1", features = ["config", "user"] }
[dev-dependencies]
http-body-util = { version = "0.1.3" }
tower = { version = "0.5.3", features = ["full"] }
url = { version = "2.5.8" }
once_cell = { version = "1.21.4" } # Useful for lazy initialization in tests/app setup
async-std = { version = "1.13.2" }
+1 -1
View File
@@ -1,7 +1,7 @@
# Stage 1: Build the application
# Use a specific Rust version for reproducibility. Choose one that matches your development environment.
# Using slim variant for smaller base image
FROM rust:1.96 as builder
FROM rust:1.96.1 as builder
# Set the working directory inside the container
WORKDIR /usr/src/app
+87 -15
View File
@@ -96,11 +96,19 @@ pub mod response {
pub async fn extract(
response: axum::response::Response,
) -> Result<LoginResponse, std::io::Error> {
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.unwrap();
let _parsed_body: LoginResponse = serde_json::from_slice(&body).unwrap();
todo!("Add code to convert axum::Response to this type");
let body = match axum::body::to_bytes(response.into_body(), usize::MAX).await {
Ok(body) => body,
Err(err) => {
return Err(std::io::Error::other(err));
}
};
let parsed_body: LoginResponse = match serde_json::from_slice(&body) {
Ok(body) => body,
Err(err) => {
return Err(std::io::Error::other(err));
}
};
Ok(parsed_body)
}
#[derive(Deserialize, Serialize, utoipa::ToSchema)]
@@ -120,6 +128,12 @@ pub mod response {
pub message: String,
pub data: Vec<textsender_models::user::User>,
}
#[derive(Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct GetUserProfileResponse {
pub message: String,
pub data: Vec<textsender_models::user::UserProfile>,
}
}
/// Endpoint for a user login
@@ -186,10 +200,20 @@ pub async fn user_login(
Ok(matches) => {
if matches {
// Create token
let key = textsender_models::envy::environment::get_secret_key()
.await
.value;
let cst = token_stuff::create_token(&key, &user.id).unwrap();
let key =
textsender_models::envy::environment::get_secret_key().value;
let cst = match token_stuff::create_token(&key, &user.id) {
Ok(token) => token,
Err(_err) => {
return (
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
axum::Json(response::LoginResponse {
message: String::from("Error creating token"),
data: Vec::new(),
}),
);
}
};
if token_stuff::verify_token(&key, &cst.access_token) {
let current_time = time::OffsetDateTime::now_utc();
@@ -326,9 +350,8 @@ pub async fn service_user_login(
if matches {
// Create token
println!("Creating token");
let key = textsender_models::envy::environment::get_secret_key()
.await
.value;
let key =
textsender_models::envy::environment::get_secret_key().value;
let cst =
token_stuff::create_token(&key, &service_user.id).unwrap();
@@ -433,9 +456,7 @@ pub async fn refresh_token(
}),
)
} else {
let key = textsender_models::envy::environment::get_secret_key()
.await
.value;
let key = textsender_models::envy::environment::get_secret_key().value;
if token_stuff::verify_token(&key, &payload.access_token) {
match token_stuff::extract_id_from_token(&key, &payload.access_token) {
Ok(id) => {
@@ -796,3 +817,54 @@ pub async fn update_name_of_user(
}
}
}
/// Endpoint to get User Profile
#[utoipa::path(
delete,
path = super::endpoints::GET_USER_PROFILE,
params(("id" = uuid::Uuid, Path, description = "User Id")),
responses(
(status = 200, description = "Deleted", body = response::GetUserProfileResponse),
(status = 400, description = "Bad request", body = response::GetUserProfileResponse),
(status = 500, description = "Error", body = response::GetUserProfileResponse)
)
)]
pub async fn get_user_profile(
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
axum::extract::Path(id): axum::extract::Path<uuid::Uuid>,
) -> (
axum::http::StatusCode,
axum::Json<response::GetUserProfileResponse>,
) {
let mut response = response::GetUserProfileResponse::default();
if id.is_nil() {
response.message = String::from("Invalid");
return (axum::http::StatusCode::BAD_REQUEST, axum::Json(response));
}
match repo::user::get_with_id(&pool, &id).await {
Ok(user) => {
let user_profile = textsender_models::user::UserProfile {
user_id: user.id,
phone_number: user.phone_number,
firstname: user.firstname,
lastname: user.lastname,
last_login: user.last_login,
created: user.created,
username: user.username,
};
response.message = String::from(super::messages::SUCCESSFUL_MESSAGE);
response.data.push(user_profile);
(axum::http::StatusCode::OK, axum::Json(response))
}
Err(err) => {
eprintln!("Error: {err:?}");
response.message = String::from("Bad request");
(
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
axum::Json(response),
)
}
}
}
+2
View File
@@ -19,4 +19,6 @@ pub mod endpoints {
pub const UPDATE_PASSWORD: &str = "/api/v1/user/password/update";
/// Endpoint constant for updating user's name
pub const UPDATE_USER_NAME: &str = "/api/v1/user/name/update";
/// Endpoint constant for getting user profile
pub const GET_USER_PROFILE: &str = "/api/v1/user/profile/{id}";
}
+2 -4
View File
@@ -80,7 +80,7 @@ pub fn generate_the_salt() -> (
responses(
(status = 201, description = "User created", body = response::Response),
(status = 404, description = "User already exists", body = response::Response),
(status = 400, description = "Issue creating user", body = response::Response)
(status = 500, description = "Issue creating user", body = response::Response)
)
)]
pub async fn register_user(
@@ -105,9 +105,7 @@ pub async fn register_user(
let mut user = textsender_models::user::User {
username: payload.username.clone(),
password: payload.password.clone(),
// email: payload.email.clone(),
phone_number: payload.phone_number.clone(),
// email_verified: true,
..Default::default()
};
@@ -183,7 +181,7 @@ pub async fn register_user(
/// Checks to see if registration is enabled
async fn is_registration_enabled() -> Result<bool, std::io::Error> {
let key = String::from("ENABLE_REGISTRATION");
let var = textsender_models::envy::environment::get_env(&key).await;
let var = textsender_models::envy::environment::get_env(&key);
let parsed_value = var.value.to_uppercase();
if parsed_value == "TRUE" {
+1 -3
View File
@@ -1,9 +1,7 @@
use sqlx::postgres::PgPoolOptions;
pub async fn create_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let database_url = textsender_models::envy::environment::get_db_url()
.await
.value;
let database_url = textsender_models::envy::environment::get_db_url().value;
println!("Database url: {database_url}");
PgPoolOptions::new()
+18 -6
View File
@@ -24,9 +24,12 @@ pub mod init {
paths(
common_callers::endpoint::db_ping, common_callers::endpoint::root,
register_caller::register_user, login_caller::user_login,
login_caller::get_user_profile,
),
components(schemas(common_callers::response::TestResult,
register_responses::Response, login_responses::LoginResponse)),
register_responses::Response, login_responses::LoginResponse,
login_responses::GetUserProfileResponse,
)),
tags(
(name = "TextSender Auth API", description = "Auth API for TextSender API")
)
@@ -35,18 +38,18 @@ pub mod init {
mod cors {
pub async fn configure_cors() -> tower_http::cors::CorsLayer {
// Start building the CORS layer with common settings
let cors = tower_http::cors::CorsLayer::new()
.allow_methods([
axum::http::Method::GET,
axum::http::Method::PATCH,
axum::http::Method::POST,
axum::http::Method::PUT,
axum::http::Method::DELETE,
]) // Specify allowed methods:cite[2]
])
.allow_headers([
axum::http::header::CONTENT_TYPE,
axum::http::header::AUTHORIZATION,
]) // Specify allowed headers:cite[2]
])
.allow_credentials(true) // If you need to send cookies or authentication headers:cite[2]
.max_age(std::time::Duration::from_secs(3600)); // Cache the preflight response for 1 hour:cite[2]
@@ -54,7 +57,7 @@ pub mod init {
match std::env::var(textsender_models::envy::keys::APP_ENV).as_deref() {
Ok("production") => {
let allowed_origins_env =
textsender_models::envy::environment::get_allowed_origins().await;
textsender_models::envy::environment::get_allowed_origins();
match textsender_models::envy::utility::delimitize(&allowed_origins_env) {
Ok(alwd) => {
let allowed_origins: Vec<axum::http::HeaderValue> = alwd
@@ -76,6 +79,12 @@ pub mod init {
cors.allow_origin(vec![
"http://localhost:4200".parse().unwrap(),
"http://127.0.0.1:4200".parse().unwrap(),
"http://localhost:5173".parse().unwrap(),
"http://127.0.0.1:5173".parse().unwrap(),
"http://localhost:9080".parse().unwrap(),
"http://127.0.0.1:9080".parse().unwrap(),
"http://localhost:9081".parse().unwrap(),
"http://127.0.0.1:9081".parse().unwrap(),
])
}
}
@@ -83,7 +92,6 @@ pub mod init {
}
pub async fn routes() -> Router {
// build our application with a route
Router::new()
.route(
callers::endpoints::DBTEST,
@@ -118,6 +126,10 @@ pub mod init {
callers::endpoints::UPDATE_USER_NAME,
patch(callers::login::update_name_of_user),
)
.route(
callers::endpoints::GET_USER_PROFILE,
get(callers::login::get_user_profile),
)
.layer(cors::configure_cors().await)
}
+15 -18
View File
@@ -17,7 +17,7 @@ pub fn get_expiration(issued: &time::OffsetDateTime) -> Result<time::OffsetDateT
}
pub fn create_token(
provided_key: &String,
provided_key: &str,
id: &uuid::Uuid,
) -> Result<textsender_models::token::CreateTokenResult, josekit::JoseError> {
let resource = textsender_models::token::TokenResource {
@@ -26,11 +26,11 @@ pub fn create_token(
audiences: vec![String::from(AUDIENCE)],
user_id: *id,
};
textsender_models::token::create_token(provided_key, &resource, time::Duration::hours(4))
textsender_models::token::create_token(provided_key, resource, time::Duration::hours(4))
}
pub fn create_service_token(
provided: &String,
provided: &str,
id: &uuid::Uuid,
) -> Result<textsender_models::token::CreateTokenResult, josekit::JoseError> {
let resource = textsender_models::token::TokenResource {
@@ -39,11 +39,11 @@ pub fn create_service_token(
audiences: vec![String::from(AUDIENCE)],
user_id: *id,
};
textsender_models::token::create_token(provided, &resource, time::Duration::hours(1))
textsender_models::token::create_token(provided, resource, time::Duration::hours(1))
}
pub fn create_service_refresh_token(
key: &String,
key: &str,
id: &uuid::Uuid,
) -> Result<textsender_models::token::CreateTokenResult, josekit::JoseError> {
let resource = textsender_models::token::TokenResource {
@@ -52,10 +52,10 @@ pub fn create_service_refresh_token(
audiences: vec![String::from(AUDIENCE)],
user_id: *id,
};
textsender_models::token::create_token(key, &resource, time::Duration::hours(4))
textsender_models::token::create_token(key, resource, time::Duration::hours(4))
}
pub fn verify_token(key: &String, token: &String) -> bool {
pub fn verify_token(key: &str, token: &str) -> bool {
match get_payload(key, token) {
Ok((payload, _header)) => match payload.subject() {
Some(_sub) => true,
@@ -65,7 +65,7 @@ pub fn verify_token(key: &String, token: &String) -> bool {
}
}
pub fn extract_id_from_token(key: &String, token: &String) -> Result<uuid::Uuid, std::io::Error> {
pub fn extract_id_from_token(key: &str, token: &str) -> Result<uuid::Uuid, std::io::Error> {
match get_payload(key, token) {
Ok((payload, _header)) => match payload.claim("user_id") {
Some(id) => match uuid::Uuid::parse_str(id.as_str().unwrap()) {
@@ -83,7 +83,7 @@ pub const APP_SUBJECT: &str = "Something random";
pub const SERVICE_TOKEN_TYPE: &str = "Textsender_Service";
pub const SERVICE_SUBJECT: &str = "Service random";
pub fn get_token_type(key: &String, token: &String) -> Result<String, std::io::Error> {
pub fn get_token_type(key: &str, token: &str) -> Result<String, std::io::Error> {
match get_payload(key, token) {
Ok((payload, _header)) => match payload.subject() {
Some(subject) => {
@@ -101,13 +101,13 @@ pub fn get_token_type(key: &String, token: &String) -> Result<String, std::io::E
}
}
pub fn is_token_type_valid(token_type: &String) -> bool {
pub fn is_token_type_valid(token_type: &str) -> bool {
token_type == SERVICE_TOKEN_TYPE
}
fn get_payload(
key: &String,
token: &String,
key: &str,
token: &str,
) -> Result<(josekit::jwt::JwtPayload, josekit::jws::JwsHeader), josekit::JoseError> {
let ver = Hs256.verifier_from_bytes(key.as_bytes()).unwrap();
jwt::decode_with_verifier(token, &ver)
@@ -119,14 +119,11 @@ mod tests {
#[test]
fn test_tokenize() {
let rt = tokio::runtime::Runtime::new().unwrap();
let special_key = rt
.block_on(textsender_models::envy::environment::get_secret_key())
.value;
let special_key = textsender_models::envy::environment::get_secret_key();
let id = uuid::Uuid::new_v4();
match create_token(&special_key, &id) {
match create_token(&special_key.value, &id) {
Ok(cst) => {
let result = verify_token(&special_key, &cst.access_token);
let result = verify_token(&special_key.value, &cst.access_token);
assert!(result, "Token not verified");
}
Err(err) => {
+114 -11
View File
@@ -9,9 +9,7 @@ mod db_mgr {
pub const LIMIT: usize = 6;
pub async fn get_pool() -> Result<sqlx::PgPool, sqlx::Error> {
let tm_db_url = textsender_models::envy::environment::get_db_url()
.await
.value;
let tm_db_url = textsender_models::envy::environment::get_db_url().value;
let tm_options = sqlx::postgres::PgConnectOptions::from_str(&tm_db_url).unwrap();
sqlx::PgPool::connect_with(tm_options).await
}
@@ -23,9 +21,7 @@ mod db_mgr {
}
pub async fn connect_to_db(db_name: &str) -> Result<sqlx::PgPool, sqlx::Error> {
let db_url = textsender_models::envy::environment::get_db_url()
.await
.value;
let db_url = textsender_models::envy::environment::get_db_url().value;
let options = sqlx::postgres::PgConnectOptions::from_str(&db_url)?.database(db_name);
sqlx::PgPool::connect_with(options).await
}
@@ -35,7 +31,10 @@ mod db_mgr {
db_name: &str,
) -> Result<(), sqlx::Error> {
let create_query = format!("CREATE DATABASE {}", db_name);
match sqlx::query(&create_query).execute(template_pool).await {
match sqlx::query(sqlx::AssertSqlSafe(create_query))
.execute(template_pool)
.await
{
Ok(_) => Ok(()),
Err(e) => Err(e),
}
@@ -47,14 +46,14 @@ mod db_mgr {
db_name: &str,
) -> Result<(), sqlx::Error> {
let drop_query = format!("DROP DATABASE IF EXISTS {} WITH (FORCE)", db_name);
sqlx::query(&drop_query).execute(template_pool).await?;
sqlx::query(sqlx::AssertSqlSafe(drop_query))
.execute(template_pool)
.await?;
Ok(())
}
pub async fn get_database_name() -> Result<String, Box<dyn std::error::Error>> {
let database_url = textsender_models::envy::environment::get_db_url()
.await
.value;
let database_url = textsender_models::envy::environment::get_db_url().value;
let parsed_url = url::Url::parse(&database_url)?;
if parsed_url.scheme() == "postgres" || parsed_url.scheme() == "postgresql" {
@@ -225,6 +224,29 @@ pub mod requests {
Err(err) => Err(err),
}
}
/// Function to call get user profile endpoint
pub async fn get_user_profile(
app: &axum::Router,
user_id: &uuid::Uuid,
) -> Result<axum::response::Response, axum::http::Error> {
let url = super::util::format_url_with_value(
textsender_auth::callers::endpoints::GET_USER_PROFILE,
user_id,
);
match axum::http::Request::builder()
.method(axum::http::Method::GET)
.uri(url)
.header(axum::http::header::CONTENT_TYPE, "application/json")
.body(axum::body::Body::empty())
{
Ok(req) => match app.clone().oneshot(req).await {
Ok(resp) => Ok(resp),
Err(err) => Err(axum::http::Error::from(err)),
},
Err(err) => Err(err),
}
}
}
/// Test user firstname
@@ -272,6 +294,11 @@ mod util {
Err(err) => Err(std::io::Error::other(err.to_string())),
}
}
pub fn format_url_with_value(endpoint: &str, value: &uuid::Uuid) -> String {
let last = endpoint.len() - 5;
format!("{}/{value}", &endpoint[0..last])
}
}
mod flow {
@@ -989,3 +1016,79 @@ async fn test_update_name_of_password() {
}
}
}
#[tokio::test]
async fn test_get_user_profile() {
let tm_pool = db_mgr::get_pool().await.unwrap();
let db_name = db_mgr::generate_db_name().await;
match db_mgr::create_database(&tm_pool, &db_name).await {
Ok(_) => {
println!("Success");
}
Err(e) => {
assert!(false, "Error: {:?}", e.to_string());
}
}
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
db::init::migrations(&pool).await;
let app = init::routes().await.layer(axum::Extension(pool));
let user_id = match flow::register_user(&app).await {
Ok(user) => match flow::login_user(&app, &user.username, TEST_PASSWORD).await {
Ok(login_result) => {
assert_eq!(
false,
login_result.access_token.is_empty(),
"Access token is empty when it should not be"
);
login_result.user_id
}
Err(err) => {
assert!(false, "Error: {err:?}");
uuid::Uuid::nil()
}
},
Err(err) => {
assert!(false, "Error: {err:?}");
uuid::Uuid::nil()
}
};
assert_eq!(false, user_id.is_nil(), "User Id should not be empty");
match requests::get_user_profile(&app, &user_id).await {
Ok(response) => {
match util::convert_response::<
textsender_auth::callers::login::response::GetUserProfileResponse,
>(response)
.await
{
Ok(response) => {
assert_eq!(false, response.data.is_empty(), "No User Profile found");
let user_profile = &response.data[0];
assert_eq!(
TEST_USERNAME, user_profile.username,
"Username does not match"
);
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
}
}
Err(err) => {
assert!(false, "Error: {err:?}");
}
}
match db_mgr::drop_database(&tm_pool, &db_name).await {
Ok(()) => {}
Err(err) => {
assert!(false, "Error: {err:?}");
}
}
}