mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-24 10:39:28 -04:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ddcd178c8 | ||
|
|
ae68604082 | ||
|
|
b15c27971b | ||
|
|
6e6eb4ea16 | ||
|
|
fdd9bafa1c | ||
|
|
c59401e33a | ||
|
|
9979bad85b |
@@ -36,6 +36,10 @@ pub enum StaffAuditAction {
|
||||
/// Staff sent a manual alert via the pager system.
|
||||
#[serde(rename = "send_alert")]
|
||||
SendAlert,
|
||||
|
||||
/// Staff edited a user's feature flags.
|
||||
#[serde(rename = "edit_user_feature_flags")]
|
||||
EditUserFeatureFlags,
|
||||
}
|
||||
|
||||
impl_enum_display_and_debug_using_to_str!(StaffAuditAction);
|
||||
@@ -51,6 +55,7 @@ impl StaffAuditAction {
|
||||
Self::UnbanUser => "unban_user",
|
||||
Self::AddWalletBankedBalance => "add_wallet_banked_balance",
|
||||
Self::SendAlert => "send_alert",
|
||||
Self::EditUserFeatureFlags => "edit_user_feature_flags",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +67,7 @@ impl StaffAuditAction {
|
||||
"unban_user" => Ok(Self::UnbanUser),
|
||||
"add_wallet_banked_balance" => Ok(Self::AddWalletBankedBalance),
|
||||
"send_alert" => Ok(Self::SendAlert),
|
||||
"edit_user_feature_flags" => Ok(Self::EditUserFeatureFlags),
|
||||
_ => Err(format!("invalid StaffAuditAction value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
@@ -74,6 +80,7 @@ impl StaffAuditAction {
|
||||
Self::UnbanUser,
|
||||
Self::AddWalletBankedBalance,
|
||||
Self::SendAlert,
|
||||
Self::EditUserFeatureFlags,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -94,6 +101,7 @@ mod tests {
|
||||
assert_serialization(StaffAuditAction::UnbanUser, "unban_user");
|
||||
assert_serialization(StaffAuditAction::AddWalletBankedBalance, "add_wallet_banked_balance");
|
||||
assert_serialization(StaffAuditAction::SendAlert, "send_alert");
|
||||
assert_serialization(StaffAuditAction::EditUserFeatureFlags, "edit_user_feature_flags");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -104,6 +112,7 @@ mod tests {
|
||||
assert_eq!(StaffAuditAction::UnbanUser.to_str(), "unban_user");
|
||||
assert_eq!(StaffAuditAction::AddWalletBankedBalance.to_str(), "add_wallet_banked_balance");
|
||||
assert_eq!(StaffAuditAction::SendAlert.to_str(), "send_alert");
|
||||
assert_eq!(StaffAuditAction::EditUserFeatureFlags.to_str(), "edit_user_feature_flags");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -114,12 +123,13 @@ mod tests {
|
||||
assert_eq!(StaffAuditAction::from_str("unban_user").unwrap(), StaffAuditAction::UnbanUser);
|
||||
assert_eq!(StaffAuditAction::from_str("add_wallet_banked_balance").unwrap(), StaffAuditAction::AddWalletBankedBalance);
|
||||
assert_eq!(StaffAuditAction::from_str("send_alert").unwrap(), StaffAuditAction::SendAlert);
|
||||
assert_eq!(StaffAuditAction::from_str("edit_user_feature_flags").unwrap(), StaffAuditAction::EditUserFeatureFlags);
|
||||
assert!(StaffAuditAction::from_str("invalid").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
const EXPECTED_COUNT: usize = 6;
|
||||
const EXPECTED_COUNT: usize = 7;
|
||||
assert_eq!(StaffAuditAction::all_variants().len(), EXPECTED_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,9 @@ use crate::http_server::endpoints::media_files::upsert_upload::write_engine_asse
|
||||
use crate::http_server::endpoints::media_files::upsert_upload::write_error::MediaFileWriteError;
|
||||
use crate::http_server::endpoints::media_files::upsert_upload::write_scene_file::write_scene_file_media_file_handler::*;
|
||||
use crate::http_server::endpoints::model_download::enqueue_gptsovits_model_download_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::edit_user_feature_flags_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::moderator_edit_user_feature_flags_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::moderator_list_all_available_user_feature_flags_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::moderator_list_user_feature_flags_handler::*;
|
||||
use crate::http_server::endpoints::moderation::staff_audit_logs::moderator_list_staff_audit_logs_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_bans::moderation_ban_user_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_for_user_handler::*;
|
||||
@@ -397,7 +399,9 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
|
||||
crate::http_server::endpoints::media_files::upsert_upload::write_engine_asset::write_engine_asset_media_file_handler::write_engine_asset_media_file_handler,
|
||||
crate::http_server::endpoints::media_files::upsert_upload::write_scene_file::write_scene_file_media_file_handler::write_scene_file_media_file_handler,
|
||||
crate::http_server::endpoints::model_download::enqueue_gptsovits_model_download_handler::enqueue_gptsovits_model_download_handler,
|
||||
crate::http_server::endpoints::moderation::user_feature_flags::edit_user_feature_flags_handler::edit_user_feature_flags_handler,
|
||||
crate::http_server::endpoints::moderation::user_feature_flags::moderator_edit_user_feature_flags_handler::moderator_edit_user_feature_flags_handler,
|
||||
crate::http_server::endpoints::moderation::user_feature_flags::moderator_list_all_available_user_feature_flags_handler::moderator_list_all_available_user_feature_flags_handler,
|
||||
crate::http_server::endpoints::moderation::user_feature_flags::moderator_list_user_feature_flags_handler::moderator_list_user_feature_flags_handler,
|
||||
crate::http_server::endpoints::prompts::create_prompt_handler::create_prompt_handler,
|
||||
crate::http_server::endpoints::prompts::get_prompt_handler::get_prompt_handler,
|
||||
crate::http_server::endpoints::service::status_alert_handler::status_alert_handler,
|
||||
|
||||
+3
-1
@@ -1 +1,3 @@
|
||||
pub mod edit_user_feature_flags_handler;
|
||||
pub mod moderator_edit_user_feature_flags_handler;
|
||||
pub mod moderator_list_all_available_user_feature_flags_handler;
|
||||
pub mod moderator_list_user_feature_flags_handler;
|
||||
|
||||
+64
-45
@@ -1,6 +1,7 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::iter::FromIterator;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::error::ResponseError;
|
||||
@@ -9,20 +10,27 @@ use actix_web::web::{Data, Json, Path};
|
||||
use actix_web::{HttpRequest, HttpResponse};
|
||||
use log::warn;
|
||||
use redis::{Client, Commands};
|
||||
use sqlx::Acquire;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::staff_audit_logs::staff_audit_action::StaffAuditAction;
|
||||
use enums::by_table::staff_audit_logs::staff_audit_entity_type::StaffAuditEntityType;
|
||||
use enums::by_table::users::user_feature_flag::UserFeatureFlag;
|
||||
use http_server_common::request::get_request_ip::get_request_ip;
|
||||
use mysql_queries::queries::staff_audit_logs::insert_staff_audit_log::{insert_staff_audit_log, InsertStaffAuditLogArgs};
|
||||
use mysql_queries::queries::users::user::get::get_user_token_by_username::get_user_token_by_username;
|
||||
use mysql_queries::queries::users::user::update::set_user_feature_flags::{set_user_feature_flags, SetUserFeatureFlagArgs};
|
||||
use mysql_queries::queries::users::user_profiles::get_user_profile_by_token::get_user_profile_by_token;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags;
|
||||
use artcraft_api_defs::common::responses::simple_generic_json_success::SimpleGenericJsonSuccess;
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::http_server::web_utils::response_success_helpers::simple_json_success;
|
||||
use crate::http_server::web_utils::user_session::require_moderator::{
|
||||
require_moderator, UseDatabase,
|
||||
};
|
||||
use crate::state::server_state::ServerState;
|
||||
use artcraft_api_defs::common::responses::simple_generic_json_success::SimpleGenericJsonSuccess;
|
||||
|
||||
/// For the URL PathInfo
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
@@ -94,7 +102,7 @@ impl fmt::Display for EditUserFeatureFlagsError {
|
||||
#[utoipa::path(
|
||||
post,
|
||||
tag = "Moderation",
|
||||
path = "/v1/moderation/user_feature_flags/{username_or_token}",
|
||||
path = "/v1/moderation/user_feature_flags/user/{username_or_token}",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = SimpleGenericJsonSuccess),
|
||||
(status = 401, description = "Unauthorized", body = EditUserFeatureFlagsError),
|
||||
@@ -106,66 +114,47 @@ impl fmt::Display for EditUserFeatureFlagsError {
|
||||
("request" = EditUserFeatureFlagsRequest, description = "Payload for Request"),
|
||||
)
|
||||
)]
|
||||
pub async fn edit_user_feature_flags_handler(
|
||||
pub async fn moderator_edit_user_feature_flags_handler(
|
||||
http_request: HttpRequest,
|
||||
path: Path<EditUserFeatureFlagPathInfo>,
|
||||
request: Json<EditUserFeatureFlagsRequest>,
|
||||
server_state: Data<Arc<ServerState>>,
|
||||
//redis_ttl_cache: Data<RedisTtlCache>,
|
||||
redis_pool: Data<r2d2::Pool<Client>>,
|
||||
) -> Result<HttpResponse, EditUserFeatureFlagsError> {
|
||||
|
||||
let maybe_user_session = server_state
|
||||
.session_checker
|
||||
.maybe_get_user_session(&http_request, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
|
||||
let user_session = match maybe_user_session {
|
||||
Some(session) => session,
|
||||
None => {
|
||||
return Err(EditUserFeatureFlagsError::Unauthorized);
|
||||
}
|
||||
};
|
||||
|
||||
if !user_session.can_ban_users {
|
||||
warn!("user is not allowed to add bans: {:?}", user_session.user_token.as_str());
|
||||
return Err(EditUserFeatureFlagsError::Unauthorized);
|
||||
}
|
||||
let user_session = require_moderator(
|
||||
&http_request,
|
||||
&server_state,
|
||||
UseDatabase::GrabNewConnection,
|
||||
).await.map_err(|err| {
|
||||
warn!("Moderator check failed: {:?}", err);
|
||||
EditUserFeatureFlagsError::Unauthorized
|
||||
})?;
|
||||
|
||||
let username_or_token = path.username_or_token.trim();
|
||||
|
||||
let user_token;
|
||||
|
||||
if username_or_token.starts_with(UserToken::token_prefix()) || username_or_token.starts_with("U:") {
|
||||
user_token = UserToken::new_from_str(username_or_token);
|
||||
let user_token = if username_or_token.starts_with(UserToken::token_prefix()) || username_or_token.starts_with("U:") {
|
||||
UserToken::new_from_str(username_or_token)
|
||||
} else {
|
||||
user_token = get_user_token_by_username(&username_or_token, &server_state.mysql_pool)
|
||||
get_user_token_by_username(username_or_token, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Could not get user token by username: {:?}", e);
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
}
|
||||
.ok_or(EditUserFeatureFlagsError::ServerError)?
|
||||
};
|
||||
|
||||
let user_profile = get_user_profile_by_token(&user_token, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Could not get user session by token: {:?}", e);
|
||||
warn!("Could not get user profile by token: {:?}", e);
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
.ok_or(EditUserFeatureFlagsError::ServerError)?;
|
||||
|
||||
let mut user_feature_flags =
|
||||
UserSessionFeatureFlags::new(user_profile.maybe_feature_flags.as_deref());
|
||||
UserSessionFeatureFlags::new(user_profile.maybe_feature_flags.as_deref());
|
||||
|
||||
match &request.action {
|
||||
EditUserFeatureFlagsOption::AddFlags { flags } => {
|
||||
@@ -189,6 +178,7 @@ pub async fn edit_user_feature_flags_handler(
|
||||
|
||||
let ip_address = get_request_ip(&http_request);
|
||||
|
||||
// Update the user's feature flags.
|
||||
set_user_feature_flags(SetUserFeatureFlagArgs {
|
||||
subject_user_token: &user_profile.user_token,
|
||||
maybe_feature_flags: user_feature_flags.maybe_serialize_string().as_deref(),
|
||||
@@ -201,16 +191,45 @@ pub async fn edit_user_feature_flags_handler(
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
|
||||
//if let Ok(mut redis) = redis_ttl_cache.get_connection() {
|
||||
// // TODO(bt,2024-04-20): This should be coordinated with other code.
|
||||
// let cache_key = format!("cache:userProfile:{}", user_profile.username);
|
||||
// let _r = redis.delete_from_cache(&cache_key);
|
||||
//}
|
||||
// Insert staff audit log.
|
||||
let mut mysql_connection = server_state.mysql_pool.acquire()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Could not acquire MySQL connection for audit log: {:?}", e);
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
|
||||
let mut transaction = mysql_connection.begin()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Could not start transaction for audit log: {:?}", e);
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
|
||||
let _audit_token = insert_staff_audit_log(InsertStaffAuditLogArgs {
|
||||
audit_action: StaffAuditAction::EditUserFeatureFlags,
|
||||
maybe_entity_type: Some(StaffAuditEntityType::User),
|
||||
maybe_entity_token: Some(user_profile.user_token.as_str()),
|
||||
staff_user_token: &user_session.user_token,
|
||||
actor_ip_address: &ip_address,
|
||||
mysql_executor: &mut *transaction,
|
||||
phantom: PhantomData,
|
||||
}).await.map_err(|err| {
|
||||
warn!("Failed to insert staff audit log: {:?}", err);
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
|
||||
transaction.commit()
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Could not commit audit log transaction: {:?}", e);
|
||||
EditUserFeatureFlagsError::ServerError
|
||||
})?;
|
||||
|
||||
// Invalidate Redis cache for the user profile.
|
||||
if let Ok(mut redis) = redis_pool.get() {
|
||||
// TODO(bt,2024-04-20): This should be coordinated with other code.
|
||||
let cache_key = format!("cache:userProfile:{}", user_profile.username);
|
||||
let _r : Result<Option<String>, _> = redis.del(&cache_key);
|
||||
let _r: Result<Option<String>, _> = redis.del(&cache_key);
|
||||
}
|
||||
|
||||
Ok(simple_json_success())
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::web::Json;
|
||||
use actix_web::{web, HttpRequest};
|
||||
use log::warn;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::users::user_feature_flag::UserFeatureFlag;
|
||||
|
||||
use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError;
|
||||
use crate::http_server::web_utils::user_session::require_moderator::{
|
||||
require_moderator, UseDatabase,
|
||||
};
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
// ── Response ──
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorListUserFeatureFlagsResponse {
|
||||
pub success: bool,
|
||||
pub feature_flags: Vec<FeatureFlagDescriptor>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct FeatureFlagDescriptor {
|
||||
/// Key the flag is identified by
|
||||
pub key: String,
|
||||
|
||||
/// Full name of the flag
|
||||
pub full_name: String,
|
||||
|
||||
/// Description of the flag
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
// ── Handler ──
|
||||
|
||||
/// List all available user feature flags.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
tag = "Moderation",
|
||||
path = "/v1/moderation/user_feature_flags/list",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = ModeratorListUserFeatureFlagsResponse),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
),
|
||||
)]
|
||||
pub async fn moderator_list_all_available_user_feature_flags_handler(
|
||||
http_request: HttpRequest,
|
||||
server_state: web::Data<Arc<ServerState>>,
|
||||
) -> Result<Json<ModeratorListUserFeatureFlagsResponse>, AdvancedCommonWebError> {
|
||||
let _user_session = require_moderator(
|
||||
&http_request,
|
||||
&server_state,
|
||||
UseDatabase::GrabNewConnection,
|
||||
).await.map_err(|err| {
|
||||
warn!("Moderator check failed: {:?}", err);
|
||||
AdvancedCommonWebError::NotAuthorized
|
||||
})?;
|
||||
|
||||
let feature_flags: Vec<FeatureFlagDescriptor> = UserFeatureFlag::all_variants()
|
||||
.into_iter()
|
||||
.map(|flag| FeatureFlagDescriptor {
|
||||
key: flag.to_str().to_string(),
|
||||
full_name: flag.name().to_string(),
|
||||
description: flag.description().to_string(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Json(ModeratorListUserFeatureFlagsResponse {
|
||||
success: true,
|
||||
feature_flags,
|
||||
}))
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::web::{Json, Path};
|
||||
use actix_web::{web, HttpRequest};
|
||||
use log::warn;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::users::user_feature_flag::UserFeatureFlag;
|
||||
use mysql_queries::queries::users::user::get::get_user_token_by_username::get_user_token_by_username;
|
||||
use mysql_queries::queries::users::user_profiles::get_user_profile_by_token::get_user_profile_by_token;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError;
|
||||
use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags;
|
||||
use crate::http_server::web_utils::user_session::require_moderator::{
|
||||
require_moderator, UseDatabase,
|
||||
};
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
// ── Request ──
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ListUserFeatureFlagsPathInfo {
|
||||
username_or_token: String,
|
||||
}
|
||||
|
||||
// ── Response ──
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorListUserFeatureFlagsResponse {
|
||||
pub success: bool,
|
||||
pub user_token: String,
|
||||
pub username: String,
|
||||
pub display_name: String,
|
||||
pub feature_flags: Vec<String>,
|
||||
}
|
||||
|
||||
// ── Handler ──
|
||||
|
||||
/// List the feature flags enabled for a specific user.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
tag = "Moderation",
|
||||
path = "/v1/moderation/user_feature_flags/user/{username_or_token}",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = ModeratorListUserFeatureFlagsResponse),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
(status = 400, description = "Bad input"),
|
||||
),
|
||||
params(
|
||||
("username_or_token" = String, Path, description = "Username or user token"),
|
||||
)
|
||||
)]
|
||||
pub async fn moderator_list_user_feature_flags_handler(
|
||||
http_request: HttpRequest,
|
||||
path: Path<ListUserFeatureFlagsPathInfo>,
|
||||
server_state: web::Data<Arc<ServerState>>,
|
||||
) -> Result<Json<ModeratorListUserFeatureFlagsResponse>, AdvancedCommonWebError> {
|
||||
let _user_session = require_moderator(
|
||||
&http_request,
|
||||
&server_state,
|
||||
UseDatabase::GrabNewConnection,
|
||||
).await.map_err(|err| {
|
||||
warn!("Moderator check failed: {:?}", err);
|
||||
AdvancedCommonWebError::NotAuthorized
|
||||
})?;
|
||||
|
||||
let username_or_token = path.username_or_token.trim();
|
||||
|
||||
let user_token = if username_or_token.starts_with(UserToken::token_prefix()) || username_or_token.starts_with("U:") {
|
||||
UserToken::new_from_str(username_or_token)
|
||||
} else {
|
||||
get_user_token_by_username(username_or_token, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("Could not get user token by username: {:?}", err);
|
||||
AdvancedCommonWebError::from_anyhow_error(err)
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
AdvancedCommonWebError::NotFound
|
||||
})?
|
||||
};
|
||||
|
||||
let user_profile = get_user_profile_by_token(&user_token, &server_state.mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("Could not get user profile by token: {:?}", err);
|
||||
AdvancedCommonWebError::from_anyhow_error(err)
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
AdvancedCommonWebError::NotFound
|
||||
})?;
|
||||
|
||||
let user_feature_flags =
|
||||
UserSessionFeatureFlags::new(user_profile.maybe_feature_flags.as_deref());
|
||||
|
||||
let flags: Vec<String> = user_feature_flags.clone_flags()
|
||||
.iter()
|
||||
.map(|flag| flag.to_str().to_string())
|
||||
.collect();
|
||||
|
||||
Ok(Json(ModeratorListUserFeatureFlagsResponse {
|
||||
success: true,
|
||||
user_token: user_profile.user_token.as_str().to_string(),
|
||||
username: user_profile.username,
|
||||
display_name: user_profile.display_name,
|
||||
feature_flags: flags,
|
||||
}))
|
||||
}
|
||||
+10
-3
@@ -36,7 +36,9 @@ use crate::http_server::endpoints::moderation::user::moderator_user_lookup_by_st
|
||||
use crate::http_server::endpoints::moderation::user::moderator_user_lookup_handler::moderator_user_lookup_handler;
|
||||
use crate::http_server::endpoints::moderation::alerts::moderation_send_alert_handler::moderation_send_alert_handler;
|
||||
use crate::http_server::endpoints::moderation::staff_audit_logs::moderator_list_staff_audit_logs_handler::moderator_list_staff_audit_logs_handler;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::edit_user_feature_flags_handler::edit_user_feature_flags_handler;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::moderator_edit_user_feature_flags_handler::moderator_edit_user_feature_flags_handler;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::moderator_list_all_available_user_feature_flags_handler::moderator_list_all_available_user_feature_flags_handler;
|
||||
use crate::http_server::endpoints::moderation::user_feature_flags::moderator_list_user_feature_flags_handler::moderator_list_user_feature_flags_handler;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_for_user_handler::moderator_list_user_session_impersonation_requests_for_user_handler;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_handler::moderator_list_user_session_impersonation_requests_handler;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_user_session_impersonation_request_handler::moderator_user_session_impersonation_request_handler;
|
||||
@@ -59,8 +61,13 @@ pub fn add_moderator_routes<T, B> (app: App<T>) -> App<T>
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
.service(web::resource("/user_feature_flags/{username_or_token}")
|
||||
.route(web::post().to(edit_user_feature_flags_handler))
|
||||
.service(web::resource("/user_feature_flags/list")
|
||||
.route(web::get().to(moderator_list_all_available_user_feature_flags_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(web::resource("/user_feature_flags/user/{username_or_token}")
|
||||
.route(web::get().to(moderator_list_user_feature_flags_handler))
|
||||
.route(web::post().to(moderator_edit_user_feature_flags_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
.service(web::scope("/users")
|
||||
|
||||
Reference in New Issue
Block a user