Successfully move one "user" endpoint into new package

This commit is contained in:
Brandon Thomas committed 2022-09-01 17:25:13 -04:00
1 parent 273b5f3c4e
commit d047fa50a9
18 files changed
+417 -348

No files matched your search

Generated
+3
View File
@@ -4944,8 +4944,10 @@ dependencies = [
"base64 0.13.0",
"chrono",
"container_common",
"database_queries",
"dotenv",
"hmac 0.10.1",
"http_server_common",
"jwt",
"log",
"once_cell",
@@ -4954,6 +4956,7 @@ dependencies = [
"serde_derive",
"serde_json",
"sha2",
"sqlx",
"time 0.2.26",
"toml",
]
@@ -16,6 +16,8 @@ path = "src/lib.rs"
# Internal
container_common = { path = "../../lib/container_common" }
database_queries = { path = "../../lib/database_queries" }
http_server_common = { path = "../../lib/http_server_common" }
# External
anyhow = "1.0.40"
@@ -40,3 +42,9 @@ serde = "1.0.125"
serde_derive = "1.0.125"
serde_json = "1.0.64"
toml = "0.5.8"
# MySql Database
# "offline" supports typesafe builds without a live database
# "rustls" doesn't appear to work with IP addresses, per:
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
sqlx = { version = "0.5", features = [ "mysql", "runtime-actix-native-tls", "offline", "chrono" ] }
@@ -0,0 +1 @@
pub mod session_info;
@@ -1,16 +1,16 @@
// NB: Incrementally getting rid of build warnings...
#![forbid(unused_imports)]
#![forbid(unused_mut)]
#![forbid(unused_variables)]
//#![forbid(unused_imports)]
//#![forbid(unused_mut)]
//#![forbid(unused_variables)]
use actix_web::error::ResponseError;
use actix_web::http::StatusCode;
use actix_web::{web, HttpResponse, HttpRequest};
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::server_state::ServerState;
use crate::utils::session_checker::SessionChecker;
use http_server_common::response::response_error_helpers::to_simple_json_error;
use log::warn;
use sqlx::MySqlPool;
use std::fmt;
use std::sync::Arc;
#[derive(Serialize, Copy, Clone)]
#[serde(rename_all = "snake_case")]
@@ -104,17 +104,18 @@ impl fmt::Display for SessionInfoError {
pub async fn session_info_handler(
http_request: HttpRequest,
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, SessionInfoError>
mysql_pool: web::Data<MySqlPool>,
session_checker: web::Data<SessionChecker>,
) -> Result<HttpResponse, SessionInfoError>
{
let mut mysql_connection = server_state.mysql_pool.acquire()
let mut mysql_connection = mysql_pool.acquire()
.await
.map_err(|e| {
warn!("Could not acquire DB pool: {:?}", e);
SessionInfoError::ServerError
})?;
let maybe_user_session = server_state
.session_checker
let maybe_user_session = session_checker
.maybe_get_user_session_from_connection(&http_request, &mut mysql_connection)
.await
.map_err(|e| {
@@ -1 +1,4 @@
#[macro_use] extern crate serde_derive;
pub mod endpoints;
pub mod utils;
@@ -1 +1,2 @@
pub mod session_checker;
pub mod session_cookie_manager;
@@ -0,0 +1,78 @@
// NB: Incrementally getting rid of build warnings...
#![forbid(unused_imports)]
#![forbid(unused_mut)]
#![forbid(unused_variables)]
use actix_web::HttpRequest;
use container_common::anyhow_result::AnyhowResult;
use crate::utils::session_cookie_manager::SessionCookieManager;
use database_queries::queries::users::user_sessions::get_session_by_token::{get_session_by_token, SessionUserRecord};
use database_queries::queries::users::user_sessions::get_session_by_token_light::{get_session_by_token_light, SessionRecord};
use sqlx::pool::PoolConnection;
use sqlx::{MySqlPool, MySql};
#[derive(Clone)]
pub struct SessionChecker {
cookie_manager: SessionCookieManager,
}
impl SessionChecker {
pub fn new(cookie_manager: &SessionCookieManager) -> Self {
Self {
cookie_manager: cookie_manager.clone(),
}
}
#[deprecated = "Use the PoolConnection<MySql> method instead of the MySqlPool one."]
pub async fn maybe_get_session(
&self,
request: &HttpRequest,
pool: &MySqlPool
) -> AnyhowResult<Option<SessionRecord>>
{
let mut connection = pool.acquire().await?;
self.maybe_get_session_from_connection(request, &mut connection).await
}
pub async fn maybe_get_session_from_connection(
&self,
request: &HttpRequest,
mysql_connection: &mut PoolConnection<MySql>,
) -> AnyhowResult<Option<SessionRecord>>
{
let session_token = match self.cookie_manager.decode_session_token_from_request(request)? {
None => return Ok(None),
Some(session_token) => session_token,
};
get_session_by_token_light(mysql_connection, &session_token).await
}
#[deprecated = "Use the PoolConnection<MySql> method instead of the MySqlPool one."]
pub async fn maybe_get_user_session(
&self,
request: &HttpRequest,
pool: &MySqlPool,
) -> AnyhowResult<Option<SessionUserRecord>>
{
let mut connection = pool.acquire().await?;
self.maybe_get_user_session_from_connection(request, &mut connection).await
}
pub async fn maybe_get_user_session_from_connection(
&self,
request: &HttpRequest,
mysql_connection: &mut PoolConnection<MySql>,
) -> AnyhowResult<Option<SessionUserRecord>>
{
let session_token = match self.cookie_manager.decode_session_token_from_request(request)? {
None => return Ok(None),
Some(session_token) => session_token,
};
get_session_by_token(mysql_connection, &session_token).await
}
}
@@ -15,6 +15,16 @@ pub fn nullable_i8_to_bool(value: Option<i8>, default_value: bool) -> bool {
.unwrap_or(default_value)
}
pub fn nullable_i8_to_bool_default_false(value: Option<i8>) -> bool {
match value {
None => false,
Some(v) => match v {
0 => false,
_ => true,
}
}
}
/// Bool conversion, but retain nulls.
pub fn nullable_i8_to_optional_bool(value: Option<i8>) -> Option<bool> {
value.map(|v| i8_to_bool(v))
@@ -22,11 +32,7 @@ pub fn nullable_i8_to_optional_bool(value: Option<i8>) -> Option<bool> {
#[cfg(test)]
mod tests {
use crate::helpers::boolean_converters::{
i8_to_bool,
nullable_i8_to_bool,
nullable_i8_to_optional_bool
};
use crate::helpers::boolean_converters::{i8_to_bool, nullable_i8_to_bool, nullable_i8_to_bool_default_false, nullable_i8_to_optional_bool};
#[test]
fn test_i8_to_bool() {
@@ -52,6 +58,16 @@ mod tests {
assert_eq!(nullable_i8_to_bool(Some(-100), true), true);
}
#[test]
fn test_nullable_i8_to_bool_default_false() {
assert_eq!(nullable_i8_to_bool_default_false(None), false);
assert_eq!(nullable_i8_to_bool_default_false(Some(0)), false);
assert_eq!(nullable_i8_to_bool_default_false(Some(1)), true);
assert_eq!(nullable_i8_to_bool_default_false(Some(100)), true);
assert_eq!(nullable_i8_to_bool_default_false(Some(-100)), true);
}
#[test]
fn test_nullable_i8_to_optional_bool() {
assert_eq!(nullable_i8_to_optional_bool(None), None);
@@ -0,0 +1,231 @@
// NB: Incrementally getting rid of build warnings...
#![forbid(unused_imports)]
#![forbid(unused_mut)]
use anyhow::anyhow;
use container_common::anyhow_result::AnyhowResult;
use crate::column_types::record_visibility::RecordVisibility;
use crate::helpers::boolean_converters::{nullable_i8_to_optional_bool, i8_to_bool, nullable_i8_to_bool_default_false};
use log::warn;
use sqlx::MySql;
use sqlx::pool::PoolConnection;
pub struct SessionUserRecord {
pub user_token: String,
pub username: String,
pub display_name: String,
pub email_address: String,
pub email_confirmed: bool,
pub email_gravatar_hash: String,
// ===== PREFERENCES ===== //
pub disable_gravatar: bool,
pub auto_play_audio_preference: Option<bool>,
pub preferred_tts_result_visibility: RecordVisibility,
pub preferred_w2l_result_visibility: RecordVisibility,
pub auto_play_video_preference: Option<bool>,
// ===== ROLE ===== //
pub user_role_slug: String,
pub is_banned: bool,
// ===== PERMISSIONS FLAGS ===== //
// Usage
pub can_use_tts: bool,
pub can_use_w2l: bool,
pub can_delete_own_tts_results: bool,
pub can_delete_own_w2l_results: bool,
pub can_delete_own_account: bool,
// Contribution
pub can_upload_tts_models: bool,
pub can_upload_w2l_templates: bool,
pub can_delete_own_tts_models: bool,
pub can_delete_own_w2l_templates: bool,
// Moderation
pub can_approve_w2l_templates: bool,
pub can_edit_other_users_profiles: bool,
pub can_edit_other_users_tts_models: bool,
pub can_edit_other_users_w2l_templates: bool,
pub can_delete_other_users_tts_models: bool,
pub can_delete_other_users_tts_results: bool,
pub can_delete_other_users_w2l_templates: bool,
pub can_delete_other_users_w2l_results: bool,
pub can_ban_users: bool,
pub can_delete_users: bool,
}
pub async fn get_session_by_token(
mysql_connection: &mut PoolConnection<MySql>,
session_token: &str,
) -> AnyhowResult<Option<SessionUserRecord>> {
// NB: Lookup failure is Err(RowNotFound).
let maybe_user_record = sqlx::query_as!(
SessionUserRawDbRecord,
r#"
SELECT
users.token as user_token,
users.username,
users.display_name,
users.email_address,
users.email_confirmed,
users.email_gravatar_hash,
users.disable_gravatar,
users.auto_play_audio_preference,
users.auto_play_video_preference,
users.preferred_tts_result_visibility as `preferred_tts_result_visibility: crate::column_types::record_visibility::RecordVisibility`,
users.preferred_w2l_result_visibility as `preferred_w2l_result_visibility: crate::column_types::record_visibility::RecordVisibility`,
users.user_role_slug,
users.is_banned,
user_roles.can_use_tts,
user_roles.can_use_w2l,
user_roles.can_delete_own_tts_results,
user_roles.can_delete_own_w2l_results,
user_roles.can_delete_own_account,
user_roles.can_upload_tts_models,
user_roles.can_upload_w2l_templates,
user_roles.can_delete_own_tts_models,
user_roles.can_delete_own_w2l_templates,
user_roles.can_approve_w2l_templates,
user_roles.can_edit_other_users_profiles,
user_roles.can_edit_other_users_tts_models,
user_roles.can_edit_other_users_w2l_templates,
user_roles.can_delete_other_users_tts_models,
user_roles.can_delete_other_users_tts_results,
user_roles.can_delete_other_users_w2l_templates,
user_roles.can_delete_other_users_w2l_results,
user_roles.can_ban_users,
user_roles.can_delete_users
FROM users
LEFT OUTER JOIN user_sessions
ON users.token = user_sessions.user_token
LEFT OUTER JOIN user_roles
ON users.user_role_slug = user_roles.slug
WHERE user_sessions.token = ?
AND user_sessions.deleted_at IS NULL
AND users.user_deleted_at IS NULL
AND users.mod_deleted_at IS NULL
"#,
session_token,
)
.fetch_one(mysql_connection)
.await; // TODO: This will return error if it doesn't exist
match maybe_user_record {
Ok(raw_user_record) => {
let result_user_record = SessionUserRecord {
user_token: raw_user_record.user_token,
username: raw_user_record.username,
display_name: raw_user_record.display_name,
email_address: raw_user_record.email_address,
email_confirmed: i8_to_bool(raw_user_record.email_confirmed),
email_gravatar_hash: raw_user_record.email_gravatar_hash,
// Preference
disable_gravatar: i8_to_bool(raw_user_record.disable_gravatar),
auto_play_audio_preference: nullable_i8_to_optional_bool(raw_user_record.auto_play_audio_preference),
auto_play_video_preference: nullable_i8_to_optional_bool(raw_user_record.auto_play_video_preference),
user_role_slug: raw_user_record.user_role_slug,
preferred_tts_result_visibility: raw_user_record.preferred_tts_result_visibility,
preferred_w2l_result_visibility: raw_user_record.preferred_w2l_result_visibility,
is_banned: i8_to_bool(raw_user_record.is_banned),
// Usage
can_use_tts: nullable_i8_to_bool_default_false(raw_user_record.can_use_tts),
can_use_w2l: nullable_i8_to_bool_default_false(raw_user_record.can_use_w2l),
can_delete_own_tts_results: nullable_i8_to_bool_default_false(raw_user_record.can_delete_own_tts_results),
can_delete_own_w2l_results: nullable_i8_to_bool_default_false(raw_user_record.can_delete_own_w2l_results),
can_delete_own_account: nullable_i8_to_bool_default_false(raw_user_record.can_delete_own_account),
// Contribution
can_upload_tts_models: nullable_i8_to_bool_default_false(raw_user_record.can_upload_tts_models),
can_upload_w2l_templates: nullable_i8_to_bool_default_false(raw_user_record.can_upload_w2l_templates),
can_delete_own_tts_models: nullable_i8_to_bool_default_false(raw_user_record.can_delete_own_tts_models),
can_delete_own_w2l_templates: nullable_i8_to_bool_default_false(raw_user_record.can_delete_own_w2l_templates),
// Moderation
can_approve_w2l_templates: nullable_i8_to_bool_default_false(raw_user_record.can_approve_w2l_templates),
can_edit_other_users_profiles: nullable_i8_to_bool_default_false(raw_user_record.can_edit_other_users_profiles),
can_edit_other_users_tts_models: nullable_i8_to_bool_default_false(raw_user_record.can_edit_other_users_tts_models),
can_edit_other_users_w2l_templates: nullable_i8_to_bool_default_false(raw_user_record.can_edit_other_users_w2l_templates),
can_delete_other_users_tts_models: nullable_i8_to_bool_default_false(raw_user_record.can_delete_other_users_tts_models),
can_delete_other_users_tts_results: nullable_i8_to_bool_default_false(raw_user_record.can_delete_other_users_tts_results),
can_delete_other_users_w2l_templates: nullable_i8_to_bool_default_false(raw_user_record.can_delete_other_users_w2l_templates),
can_delete_other_users_w2l_results: nullable_i8_to_bool_default_false(raw_user_record.can_delete_other_users_w2l_results),
can_ban_users: nullable_i8_to_bool_default_false(raw_user_record.can_ban_users),
can_delete_users: nullable_i8_to_bool_default_false(raw_user_record.can_delete_users) ,
};
Ok(Some(result_user_record))
},
Err(err) => {
match err {
RowNotFound => {
warn!("Valid cookie; invalid session: {}", session_token);
Ok(None)
},
_ => {
warn!("Session query error: {:?}", err);
Err(anyhow!("session query error: {:?}", err))
}
}
}
}
}
struct SessionUserRawDbRecord {
user_token: String,
username: String,
display_name: String,
email_address: String,
email_confirmed: i8,
email_gravatar_hash: String,
disable_gravatar: i8,
auto_play_audio_preference: Option<i8>,
auto_play_video_preference: Option<i8>,
preferred_tts_result_visibility: RecordVisibility,
preferred_w2l_result_visibility: RecordVisibility,
user_role_slug: String,
is_banned: i8,
// NB: These are `Option` due to the JOIN not being compile-time assured.
// Usage
can_use_tts: Option<i8>,
can_use_w2l: Option<i8>,
can_delete_own_tts_results: Option<i8>,
can_delete_own_w2l_results: Option<i8>,
can_delete_own_account: Option<i8>,
// Contribution
can_upload_tts_models: Option<i8>,
can_upload_w2l_templates: Option<i8>,
can_delete_own_tts_models: Option<i8>,
can_delete_own_w2l_templates: Option<i8>,
// Moderation
can_approve_w2l_templates: Option<i8>,
can_edit_other_users_profiles: Option<i8>,
can_edit_other_users_tts_models: Option<i8>,
can_edit_other_users_w2l_templates: Option<i8>,
can_delete_other_users_tts_models: Option<i8>,
can_delete_other_users_tts_results: Option<i8>,
can_delete_other_users_w2l_templates: Option<i8>,
can_delete_other_users_w2l_results: Option<i8>,
can_ban_users: Option<i8>,
can_delete_users: Option<i8>,
}
@@ -0,0 +1,51 @@
// NB: Incrementally getting rid of build warnings...
#![forbid(unused_imports)]
#![forbid(unused_mut)]
use anyhow::anyhow;
use container_common::anyhow_result::AnyhowResult;
use log::warn;
use sqlx::MySql;
use sqlx::pool::PoolConnection;
pub struct SessionRecord {
pub session_token: String,
pub user_token: String,
}
pub async fn get_session_by_token_light(
mysql_connection: &mut PoolConnection<MySql>,
session_token: &str,
) -> AnyhowResult<Option<SessionRecord>> {
// NB: Lookup failure is Err(RowNotFound).
let maybe_session_record = sqlx::query_as!(
SessionRecord,
r#"
SELECT
token as session_token,
user_token
FROM user_sessions
WHERE token = ?
AND deleted_at IS NULL
"#,
session_token,
)
.fetch_one(mysql_connection)
.await;
match maybe_session_record {
Ok(session_record) => Ok(Some(session_record)),
Err(err) => {
match err {
RowNotFound => {
warn!("Valid cookie; invalid session: {}", session_token);
Ok(None)
},
_ => {
warn!("Session query error: {:?}", err);
Err(anyhow!("session query error: {:?}", err))
}
}
}
}
}
@@ -1 +1,3 @@
pub mod create_session;
pub mod create_session;
pub mod get_session_by_token;
pub mod get_session_by_token_light;
@@ -10,7 +10,6 @@ use chrono::{DateTime, Utc};
use crate::AnyhowResult;
use crate::http_server::web_utils::ip_address::get_request_ip;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::http_server::web_utils::session_checker::SessionRecord;
use crate::server_state::ServerState;
use crate::validations::passwords::validate_passwords;
use crate::validations::username::validate_username;
@@ -8,4 +8,3 @@ pub mod list_user_w2l_inference_results;
pub mod list_user_w2l_templates;
pub mod login;
pub mod logout;
pub mod session_info;
@@ -4,5 +4,4 @@ pub mod read_multipart_field_bytes;
pub mod redis_rate_limiter;
pub mod response_error_helpers;
pub mod response_success_helpers;
pub mod serialize_as_json_error;
pub mod session_checker;
pub mod serialize_as_json_error;
@@ -1,324 +0,0 @@
// NB: Incrementally getting rid of build warnings...
#![forbid(unused_imports)]
#![forbid(unused_mut)]
#![forbid(unused_variables)]
use actix_web::HttpRequest;
use anyhow::anyhow;
use crate::AnyhowResult;
use database_queries::column_types::record_visibility::RecordVisibility;
use database_queries::helpers::boolean_converters::{nullable_i8_to_optional_bool, i8_to_bool};
use log::warn;
use sqlx::error::Error::RowNotFound;
use sqlx::pool::PoolConnection;
use sqlx::{MySqlPool, MySql};
use users_component::utils::session_cookie_manager::SessionCookieManager;
#[derive(Clone)]
pub struct SessionChecker {
cookie_manager: SessionCookieManager,
}
pub struct SessionRecord {
pub session_token: String,
pub user_token: String,
}
pub struct SessionUserRecord {
pub user_token: String,
pub username: String,
pub display_name: String,
pub email_address: String,
pub email_confirmed: bool,
pub email_gravatar_hash: String,
// ===== PREFERENCES ===== //
pub disable_gravatar: bool,
pub auto_play_audio_preference: Option<bool>,
pub preferred_tts_result_visibility: RecordVisibility,
pub preferred_w2l_result_visibility: RecordVisibility,
pub auto_play_video_preference: Option<bool>,
// ===== ROLE ===== //
pub user_role_slug: String,
pub is_banned: bool,
// ===== PERMISSIONS FLAGS ===== //
// Usage
pub can_use_tts: bool,
pub can_use_w2l: bool,
pub can_delete_own_tts_results: bool,
pub can_delete_own_w2l_results: bool,
pub can_delete_own_account: bool,
// Contribution
pub can_upload_tts_models: bool,
pub can_upload_w2l_templates: bool,
pub can_delete_own_tts_models: bool,
pub can_delete_own_w2l_templates: bool,
// Moderation
pub can_approve_w2l_templates: bool,
pub can_edit_other_users_profiles: bool,
pub can_edit_other_users_tts_models: bool,
pub can_edit_other_users_w2l_templates: bool,
pub can_delete_other_users_tts_models: bool,
pub can_delete_other_users_tts_results: bool,
pub can_delete_other_users_w2l_templates: bool,
pub can_delete_other_users_w2l_results: bool,
pub can_ban_users: bool,
pub can_delete_users: bool,
}
pub struct SessionUserRawDbRecord {
pub user_token: String,
pub username: String,
pub display_name: String,
pub email_address: String,
pub email_confirmed: i8,
pub email_gravatar_hash: String,
pub disable_gravatar: i8,
pub auto_play_audio_preference: Option<i8>,
pub auto_play_video_preference: Option<i8>,
pub preferred_tts_result_visibility: RecordVisibility,
pub preferred_w2l_result_visibility: RecordVisibility,
pub user_role_slug: String,
pub is_banned: i8,
// NB: These are `Option` due to the JOIN not being compile-time assured.
// Usage
pub can_use_tts: Option<i8>,
pub can_use_w2l: Option<i8>,
pub can_delete_own_tts_results: Option<i8>,
pub can_delete_own_w2l_results: Option<i8>,
pub can_delete_own_account: Option<i8>,
// Contribution
pub can_upload_tts_models: Option<i8>,
pub can_upload_w2l_templates: Option<i8>,
pub can_delete_own_tts_models: Option<i8>,
pub can_delete_own_w2l_templates: Option<i8>,
// Moderation
pub can_approve_w2l_templates: Option<i8>,
pub can_edit_other_users_profiles: Option<i8>,
pub can_edit_other_users_tts_models: Option<i8>,
pub can_edit_other_users_w2l_templates: Option<i8>,
pub can_delete_other_users_tts_models: Option<i8>,
pub can_delete_other_users_tts_results: Option<i8>,
pub can_delete_other_users_w2l_templates: Option<i8>,
pub can_delete_other_users_w2l_results: Option<i8>,
pub can_ban_users: Option<i8>,
pub can_delete_users: Option<i8>,
}
impl SessionChecker {
pub fn new(cookie_manager: &SessionCookieManager) -> Self {
Self {
cookie_manager: cookie_manager.clone(),
}
}
pub async fn maybe_get_session(&self, request: &HttpRequest, pool: &MySqlPool)
-> AnyhowResult<Option<SessionRecord>>
{
let session_token = match self.cookie_manager.decode_session_token_from_request(request)? {
None => return Ok(None),
Some(session_token) => session_token,
};
// NB: Lookup failure is Err(RowNotFound).
let maybe_session_record = sqlx::query_as!(
SessionRecord,
r#"
SELECT
token as session_token,
user_token
FROM user_sessions
WHERE token = ?
AND deleted_at IS NULL
"#,
session_token.to_string(),
)
.fetch_one(pool)
.await; // TODO: This will return error if it doesn't exist
match maybe_session_record {
Ok(session_record) => {
Ok(Some(session_record))
},
Err(err) => {
match err {
RowNotFound => {
warn!("Valid cookie; invalid session: {}", session_token);
Ok(None)
},
_ => {
warn!("Session query error: {:?}", err);
Err(anyhow!("session query error: {:?}", err))
}
}
}
}
}
#[deprecated = "Use the PoolConnection<MySql> method instead of the MySqlPool one."]
pub async fn maybe_get_user_session(
&self,
request: &HttpRequest,
pool: &MySqlPool,
) -> AnyhowResult<Option<SessionUserRecord>>
{
let mut connection = pool.acquire().await?;
self.maybe_get_user_session_from_connection(request, &mut connection).await
}
pub async fn maybe_get_user_session_from_connection(
&self,
request: &HttpRequest,
mysql_connection: &mut PoolConnection<MySql>,
) -> AnyhowResult<Option<SessionUserRecord>>
{
let session_token = match self.cookie_manager.decode_session_token_from_request(request)? {
None => return Ok(None),
Some(session_token) => session_token,
};
// NB: Lookup failure is Err(RowNotFound).
let maybe_user_record = sqlx::query_as!(
SessionUserRawDbRecord,
r#"
SELECT
users.token as user_token,
users.username,
users.display_name,
users.email_address,
users.email_confirmed,
users.email_gravatar_hash,
users.disable_gravatar,
users.auto_play_audio_preference,
users.auto_play_video_preference,
users.preferred_tts_result_visibility as `preferred_tts_result_visibility: database_queries::column_types::record_visibility::RecordVisibility`,
users.preferred_w2l_result_visibility as `preferred_w2l_result_visibility: database_queries::column_types::record_visibility::RecordVisibility`,
users.user_role_slug,
users.is_banned,
user_roles.can_use_tts,
user_roles.can_use_w2l,
user_roles.can_delete_own_tts_results,
user_roles.can_delete_own_w2l_results,
user_roles.can_delete_own_account,
user_roles.can_upload_tts_models,
user_roles.can_upload_w2l_templates,
user_roles.can_delete_own_tts_models,
user_roles.can_delete_own_w2l_templates,
user_roles.can_approve_w2l_templates,
user_roles.can_edit_other_users_profiles,
user_roles.can_edit_other_users_tts_models,
user_roles.can_edit_other_users_w2l_templates,
user_roles.can_delete_other_users_tts_models,
user_roles.can_delete_other_users_tts_results,
user_roles.can_delete_other_users_w2l_templates,
user_roles.can_delete_other_users_w2l_results,
user_roles.can_ban_users,
user_roles.can_delete_users
FROM users
LEFT OUTER JOIN user_sessions
ON users.token = user_sessions.user_token
LEFT OUTER JOIN user_roles
ON users.user_role_slug = user_roles.slug
WHERE user_sessions.token = ?
AND user_sessions.deleted_at IS NULL
AND users.user_deleted_at IS NULL
AND users.mod_deleted_at IS NULL
"#,
session_token.to_string(),
)
.fetch_one(mysql_connection)
.await; // TODO: This will return error if it doesn't exist
match maybe_user_record {
Ok(raw_user_record) => {
let result_user_record = SessionUserRecord {
user_token: raw_user_record.user_token,
username: raw_user_record.username,
display_name: raw_user_record.display_name,
email_address: raw_user_record.email_address,
email_confirmed: i8_to_bool(raw_user_record.email_confirmed),
email_gravatar_hash: raw_user_record.email_gravatar_hash,
// Preference
disable_gravatar: i8_to_bool(raw_user_record.disable_gravatar),
auto_play_audio_preference: nullable_i8_to_optional_bool(raw_user_record.auto_play_audio_preference),
auto_play_video_preference: nullable_i8_to_optional_bool(raw_user_record.auto_play_video_preference),
user_role_slug: raw_user_record.user_role_slug,
preferred_tts_result_visibility: raw_user_record.preferred_tts_result_visibility,
preferred_w2l_result_visibility: raw_user_record.preferred_w2l_result_visibility,
is_banned: i8_to_bool(raw_user_record.is_banned),
// Usage
can_use_tts: convert_optional_db_bool_default_false(raw_user_record.can_use_tts),
can_use_w2l: convert_optional_db_bool_default_false(raw_user_record.can_use_w2l),
can_delete_own_tts_results: convert_optional_db_bool_default_false(raw_user_record.can_delete_own_tts_results),
can_delete_own_w2l_results: convert_optional_db_bool_default_false(raw_user_record.can_delete_own_w2l_results),
can_delete_own_account: convert_optional_db_bool_default_false(raw_user_record.can_delete_own_account),
// Contribution
can_upload_tts_models: convert_optional_db_bool_default_false(raw_user_record.can_upload_tts_models),
can_upload_w2l_templates: convert_optional_db_bool_default_false(raw_user_record.can_upload_w2l_templates),
can_delete_own_tts_models: convert_optional_db_bool_default_false(raw_user_record.can_delete_own_tts_models),
can_delete_own_w2l_templates: convert_optional_db_bool_default_false(raw_user_record.can_delete_own_w2l_templates),
// Moderation
can_approve_w2l_templates: convert_optional_db_bool_default_false(raw_user_record.can_approve_w2l_templates),
can_edit_other_users_profiles: convert_optional_db_bool_default_false(raw_user_record.can_edit_other_users_profiles),
can_edit_other_users_tts_models: convert_optional_db_bool_default_false(raw_user_record.can_edit_other_users_tts_models),
can_edit_other_users_w2l_templates: convert_optional_db_bool_default_false(raw_user_record.can_edit_other_users_w2l_templates),
can_delete_other_users_tts_models: convert_optional_db_bool_default_false(raw_user_record.can_delete_other_users_tts_models),
can_delete_other_users_tts_results: convert_optional_db_bool_default_false(raw_user_record.can_delete_other_users_tts_results),
can_delete_other_users_w2l_templates: convert_optional_db_bool_default_false(raw_user_record.can_delete_other_users_w2l_templates),
can_delete_other_users_w2l_results: convert_optional_db_bool_default_false(raw_user_record.can_delete_other_users_w2l_results),
can_ban_users: convert_optional_db_bool_default_false(raw_user_record.can_ban_users),
can_delete_users: convert_optional_db_bool_default_false(raw_user_record.can_delete_users) ,
};
Ok(Some(result_user_record))
},
Err(err) => {
match err {
RowNotFound => {
warn!("Valid cookie; invalid session: {}", session_token);
Ok(None)
},
_ => {
warn!("Session query error: {:?}", err);
Err(anyhow!("session query error: {:?}", err))
}
}
}
}
}
}
fn convert_optional_db_bool_default_false(value: Option<i8>) -> bool {
match value {
None => false,
Some(v) => match v {
0 => false,
_ => true,
}
}
}
+3 -2
View File
@@ -86,7 +86,6 @@ use crate::http_server::endpoints::users::list_user_w2l_inference_results::list_
use crate::http_server::endpoints::users::list_user_w2l_templates::list_user_w2l_templates_handler;
use crate::http_server::endpoints::users::login::login_handler;
use crate::http_server::endpoints::users::logout::logout_handler;
use crate::http_server::endpoints::users::session_info::session_info_handler;
use crate::http_server::endpoints::w2l::delete_w2l_result::delete_w2l_inference_result_handler;
use crate::http_server::endpoints::w2l::delete_w2l_template::delete_w2l_template_handler;
use crate::http_server::endpoints::w2l::edit_w2l_result::edit_w2l_inference_result_handler;
@@ -103,7 +102,6 @@ use crate::http_server::endpoints::w2l::list_w2l_templates::list_w2l_templates_h
use crate::http_server::endpoints::w2l::set_w2l_template_mod_approval::set_w2l_template_mod_approval_handler;
use crate::http_server::middleware::ip_filter_middleware::IpFilter;
use crate::http_server::web_utils::redis_rate_limiter::RedisRateLimiter;
use crate::http_server::web_utils::session_checker::SessionChecker;
use crate::routes::add_routes;
use crate::server_state::{ServerState, EnvConfig, TwitchOauthSecrets, TwitchOauth, RedisRateLimiters, InMemoryCaches};
use crate::threads::db_health_checker_thread::db_health_check_status::HealthCheckStatus;
@@ -128,6 +126,7 @@ use std::time::Duration;
use storage_buckets_common::bucket_client::BucketClient;
use tokio::runtime::Runtime;
use twitch_common::twitch_secrets::TwitchSecrets;
use users_component::utils::session_checker::SessionChecker;
use users_component::utils::session_cookie_manager::SessionCookieManager;
// TODO TODO TODO TODO
@@ -436,6 +435,8 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()>
let build_sha = std::fs::read_to_string("/GIT_SHA").unwrap_or(String::from("unknown"));
let app = App::new()
.app_data(web::Data::new(server_state_arc.mysql_pool.clone()))
.app_data(web::Data::new(server_state_arc.session_checker.clone()))
.app_data(server_state_arc.clone())
.wrap(build_common_cors_config())
.wrap(DefaultHeaders::new()
+1 -1
View File
@@ -76,7 +76,6 @@ use crate::http_server::endpoints::users::list_user_w2l_inference_results::list_
use crate::http_server::endpoints::users::list_user_w2l_templates::list_user_w2l_templates_handler;
use crate::http_server::endpoints::users::login::login_handler;
use crate::http_server::endpoints::users::logout::logout_handler;
use crate::http_server::endpoints::users::session_info::session_info_handler;
use crate::http_server::endpoints::vocoders::get_vocoder::get_vocoder_handler;
use crate::http_server::endpoints::vocoders::list_vocoders::list_vocoders_handler;
use crate::http_server::endpoints::voice_clone_requests::check_if_voice_clone_request_submitted::check_if_voice_clone_request_submitted_handler;
@@ -95,6 +94,7 @@ use crate::http_server::endpoints::w2l::get_w2l_template_use_count::get_w2l_temp
use crate::http_server::endpoints::w2l::get_w2l_upload_template_job_status::get_w2l_upload_template_job_status_handler;
use crate::http_server::endpoints::w2l::list_w2l_templates::list_w2l_templates_handler;
use crate::http_server::endpoints::w2l::set_w2l_template_mod_approval::set_w2l_template_mod_approval_handler;
use users_component::endpoints::session_info::session_info_handler;
pub fn add_routes<T, B> (app: App<T, B>) -> App<T, B>
where
@@ -2,7 +2,6 @@ use crate::StaticApiTokenSet;
use crate::http_server::endpoints::categories::list_tts_categories::DisplayCategory;
use crate::http_server::endpoints::tts::list_tts_models::TtsModelRecordForResponse;
use crate::http_server::web_utils::redis_rate_limiter::RedisRateLimiter;
use crate::http_server::web_utils::session_checker::SessionChecker;
use crate::threads::db_health_checker_thread::db_health_check_status::HealthCheckStatus;
use crate::threads::ip_banlist_set::IpBanlistSet;
use crate::util::encrypted_sort_id::SortKeyCrypto;
@@ -14,6 +13,7 @@ use memory_caching::single_item_ttl_cache::SingleItemTtlCache;
use r2d2_redis::{r2d2, RedisConnectionManager};
use sqlx::MySqlPool;
use storage_buckets_common::bucket_client::BucketClient;
use users_component::utils::session_checker::SessionChecker;
use users_component::utils::session_cookie_manager::SessionCookieManager;
/// State that is injected into every endpoint.