Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ publish = false

[dependencies]
axum = { version = "0.8.7", features = ["macros"] }
chrono = "0.4.42"
chrono = { version = "0.4.42", features = ["serde"] }
colored = "3.0.0"
deadpool-postgres = { version = "0.14.1", features = ["serde"] }
dotenvy = "0.15.7"
Expand All @@ -30,7 +30,7 @@ uuid = { version = "1.18.1", features = ["v7", "serde"] }
reqwest = { version = "0.12.24", features = ["json"] }
tower = "0.5.2"
ntest = "0.9.3"
axum-extra = { version = "0.12.2", features = ["cookie"] }
axum-extra = { version = "0.12.2", features = ["cookie", "erased-json"] }
jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] }
anyhow = "1.0.100"
axum-macros = "0.5.0"
Expand Down
56 changes: 47 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,19 @@ mod pre_definitions;
mod tests;

use std::{fmt, sync::Arc};
use axum::{Json, body::Body, response::{IntoResponse, Response}};
use axum::{body::Body, response::{IntoResponse, Response}};
use axum_extra::response::ErasedJson;
use deadpool_postgres::{Pool, tokio_postgres};
use local_ip_address::local_ip;
use postgres::NoTls;
use reqwest::{StatusCode};
use serde::Serialize;
use tokio::net::TcpListener;
use colored::Colorize;
use uuid::Uuid;
use thiserror::Error;

use crate::{pre_definitions::initialize_pre_defined_actions, pre_definitions::initialize_pre_defined_roles, resources::{access_policy::{AccessPolicy, AccessPolicyError}, action::{Action, ActionError}, app::{App, AppError}, app_authorization::{AppAuthorization, AppAuthorizationError}, app_authorization_credential::{AppAuthorizationCredential, AppAuthorizationCredentialError}, app_credential::{AppCredential, AppCredentialError}, group::{Group, GroupError}, http_transaction::{HTTPTransaction, HTTPTransactionError}, item::{Item, ItemError}, milestone::{Milestone, MilestoneError}, project::{Project, ProjectError}, role::{Role, RoleError}, role_memberships::{RoleMembership, RoleMembershipError}, server_log_entry::{ServerLogEntry, ServerLogEntryError}, session::{Session, SessionError}, user::{User, UserError}, workspace::{Workspace, WorkspaceError}}};
use crate::{pre_definitions::{initialize_pre_defined_actions, initialize_pre_defined_roles}, resources::{access_policy::{AccessPolicy, AccessPolicyError}, action::{Action, ActionError}, action_log_entry::{ActionLogEntry, ActionLogEntryError}, app::{App, AppError}, app_authorization::{AppAuthorization, AppAuthorizationError}, app_authorization_credential::{AppAuthorizationCredential, AppAuthorizationCredentialError}, app_credential::{AppCredential, AppCredentialError}, group::{Group, GroupError}, group_membership::{GroupMembership, GroupMembershipError}, http_transaction::{HTTPTransaction, HTTPTransactionError}, item::{Item, ItemError}, milestone::{Milestone, MilestoneError}, project::{Project, ProjectError}, role::{Role, RoleError}, role_memberships::{RoleMembership, RoleMembershipError}, server_log_entry::{ServerLogEntry, ServerLogEntryError}, session::{Session, SessionError}, user::{User, UserError}, workspace::{Workspace, WorkspaceError}}};

const DEFAULT_APP_PORT: i16 = 8080;
const DEFAULT_MAXIMUM_POSTGRES_CONNECTION_COUNT: u32 = 5;
Expand Down Expand Up @@ -94,6 +96,9 @@ pub enum SlashstepServerError {
#[error(transparent)]
GroupError(#[from] GroupError),

#[error(transparent)]
GroupMembershipError(#[from] GroupMembershipError),

#[error(transparent)]
AppError(#[from] AppError),

Expand All @@ -112,9 +117,15 @@ pub enum SlashstepServerError {
#[error(transparent)]
ActionError(#[from] ActionError),

#[error(transparent)]
ActionLogEntryError(#[from] ActionLogEntryError),

#[error(transparent)]
AppAuthorizationError(#[from] AppAuthorizationError),

#[error(transparent)]
ServerLogEntryError(#[from] ServerLogEntryError),

#[error(transparent)]
AppAuthorizationCredentialError(#[from] AppAuthorizationCredentialError),

Expand Down Expand Up @@ -157,21 +168,27 @@ pub async fn initialize_required_tables(postgres_client: &mut deadpool_postgres:

// Because the access_policies table depends on other tables, we need to initialize them in a specific order.
HTTPTransaction::initialize_http_transactions_table(postgres_client).await?;
ServerLogEntry::initialize_server_log_entries_table(postgres_client).await?;
User::initialize_users_table(postgres_client).await?;
Session::initialize_sessions_table(postgres_client).await?;
Group::initialize_groups_table(postgres_client).await?;
App::initialize_apps_table(postgres_client).await?;
GroupMembership::initialize_app_authorizations_table(postgres_client).await?;
Workspace::initialize_workspaces_table(postgres_client).await?;
Project::initialize_projects_table(postgres_client).await?;
Role::initialize_roles_table(postgres_client).await?;
RoleMembership::initialize_role_memberships_table(postgres_client).await?;
Item::initialize_items_table(postgres_client).await?;
Action::initialize_actions_table(postgres_client).await?;
AppCredential::initialize_app_credentials_table(postgres_client).await?;
AppAuthorization::initialize_app_authorizations_table(postgres_client).await?;
AppAuthorizationCredential::initialize_app_authorization_credentials_table(postgres_client).await?;
Milestone::initialize_milestones_table(postgres_client).await?;
ActionLogEntry::initialize_action_log_entries_table(postgres_client).await?;
AccessPolicy::initialize_access_policies_table(postgres_client).await?;
RoleMembership::initialize_role_memberships_table(postgres_client).await?;

let query = include_str!("./queries/action_log_entries/add_access_policies_reference.sql");
postgres_client.execute(query, &[]).await?;

return Ok(());

Expand All @@ -184,8 +201,15 @@ pub enum HTTPError {
NotFoundError(Option<String>),
ConflictError(Option<String>),
BadRequestError(Option<String>),
NotImplementedError(Option<String>),
InternalServerError(Option<String>),
UnauthorizedError(Option<String>)
UnauthorizedError(Option<String>),
UnprocessableEntity(Option<String>)
}

#[derive(Debug, Serialize)]
pub struct HTTPErrorBody {
pub message: String
}

impl fmt::Display for HTTPError {
Expand All @@ -197,8 +221,10 @@ impl fmt::Display for HTTPError {
HTTPError::ForbiddenError(message) => write!(f, "{}", message.to_owned().unwrap_or("Forbidden.".to_string())),
HTTPError::GoneError(message) => write!(f, "{}", message.to_owned().unwrap_or("Gone.".to_string())),
HTTPError::BadRequestError(message) => write!(f, "{}", message.to_owned().unwrap_or("Bad request.".to_string())),
HTTPError::NotImplementedError(message) => write!(f, "{}", message.to_owned().unwrap_or("Not implemented.".to_string())),
HTTPError::InternalServerError(message) => write!(f, "{}", message.to_owned().unwrap_or("Internal server error.".to_string())),
HTTPError::UnauthorizedError(message) => write!(f, "{}", message.to_owned().unwrap_or("Unauthorized.".to_string()))
HTTPError::UnauthorizedError(message) => write!(f, "{}", message.to_owned().unwrap_or("Unauthorized.".to_string())),
HTTPError::UnprocessableEntity(message) => write!(f, "{}", message.to_owned().unwrap_or("Unprocessable entity.".to_string()))
}
}

Expand All @@ -220,11 +246,17 @@ impl IntoResponse for HTTPError {

HTTPError::UnauthorizedError(message) => (StatusCode::UNAUTHORIZED, message.unwrap_or("Unauthorized.".to_string())),

HTTPError::InternalServerError(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Something bad happened on our side. Please try again later.".to_string())
HTTPError::NotImplementedError(message) => (StatusCode::NOT_IMPLEMENTED, message.unwrap_or("Not implemented.".to_string())),

HTTPError::UnprocessableEntity(message) => (StatusCode::UNPROCESSABLE_ENTITY, message.unwrap_or("Unprocessable entity.".to_string())),

HTTPError::InternalServerError(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Something bad happened on our side. Please try again later.".to_string()),

};

return (status_code, Json(serde_json::json!({"message": error_message}))).into_response();
return (status_code, ErasedJson::pretty(HTTPErrorBody {
message: error_message
})).into_response();

}
}
Expand Down Expand Up @@ -269,11 +301,14 @@ async fn create_database_pool() -> Result<deadpool_postgres::Pool, SlashstepServ
let host = get_environment_variable("POSTGRESQL_HOST")?;
let username = get_environment_variable("POSTGRESQL_USERNAME")?;
let database_name = get_environment_variable("POSTGRESQL_DATABASE_NAME")?;
let password_path = get_environment_variable("POSTGRESQL_PASSWORD_PATH")?;
let password = std::fs::read_to_string(password_path)?;

let mut postgres_config = tokio_postgres::Config::new();
postgres_config.host(host);
postgres_config.user(username);
postgres_config.dbname(database_name);
postgres_config.password(password);
let manager_config = deadpool_postgres::ManagerConfig {
recycling_method: deadpool_postgres::RecyclingMethod::Fast
};
Expand Down Expand Up @@ -318,8 +353,11 @@ async fn main() -> Result<(), SlashstepServerError> {
database_pool: Arc::new(pool),
};

let _ = initialize_pre_defined_actions(&mut state.database_pool.get().await?).await?;
let _ = initialize_pre_defined_roles(&mut state.database_pool.get().await?).await?;
let mut postgres_client = state.database_pool.get().await?;
initialize_required_tables(&mut postgres_client).await?;
initialize_pre_defined_actions(&mut postgres_client).await?;
initialize_pre_defined_roles(&mut postgres_client).await?;
drop(postgres_client); // Drop the client to release the connection back to the pool. For some reason, this doesn't happen automatically.

let app_port = get_app_port_string();
let router = routes::get_router(state.clone()).with_state(state);
Expand Down

This file was deleted.

97 changes: 0 additions & 97 deletions src/queries/access-policies/initialize-access-policies-table.sql

This file was deleted.

This file was deleted.

Loading