Skip to content
22 changes: 12 additions & 10 deletions src/api/routes/bots/bot/achievements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ async fn get_bot_achievements(
bot_id = %bot_id,
"Admin access granted for bot achievements",
);
} else if ctx.is_bot() && ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to access achievements of another bot",
);
return Err(ApiError::Forbidden);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to access achievements of another bot",
);
return Err(ApiError::Forbidden);
}
} else if ctx.is_user() {
let user_id = ctx.user_id.as_deref().ok_or(ApiError::Unauthorized)?;
if !bot.has_access(user_id) {
Expand Down Expand Up @@ -155,7 +157,7 @@ async fn create_achievement(
);
return Err(ApiError::Forbidden);
}
} else if !ctx.is_user() {
} else {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
Expand Down Expand Up @@ -315,7 +317,7 @@ async fn update_achievement(
);
return Err(ApiError::Forbidden);
}
} else if !ctx.is_user() {
} else {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
Expand Down Expand Up @@ -454,7 +456,7 @@ async fn delete_achievement(
);
return Err(ApiError::Forbidden);
}
} else if !ctx.is_user() {
} else {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
Expand Down
80 changes: 51 additions & 29 deletions src/api/routes/bots/bot/events/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ use apistos::{
api_operation,
web::{ServiceConfig, delete, get, patch, resource, scope},
};
use mongodb::bson::DateTime;
use tracing::{error, info, warn};

use crate::{
api::middleware::Authenticated,
domain::error::{ApiError, ApiResult},
openapi::schemas::{CustomEventPayload, CustomEventUpdatePayload, MessageResponse},
openapi::schemas::{CustomEventResponse, CustomEventUpdatePayload, MessageResponse},
repository::{CustomEventUpdate, Repositories},
utils::{discord::Snowflake, logger::LogCode},
};
Expand All @@ -22,7 +23,7 @@ async fn get_event(
auth: Authenticated,
repos: Data<Repositories>,
path: Path<(String, String)>,
) -> ApiResult<Json<CustomEventPayload>> {
) -> ApiResult<Json<CustomEventResponse>> {
let (id, event_key) = path.into_inner();
let bot_id = Snowflake::try_from(id)?.into_inner();

Expand All @@ -44,14 +45,16 @@ async fn get_event(
event_key = %event_key,
"Admin access granted for retrieving custom event",
);
} else if ctx.is_bot() && ctx.bot_id.as_deref() != Some(&bot_id) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
event_key = %event_key,
"Bot access denied for retrieving custom event",
);
return Err(ApiError::Forbidden);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
event_key = %event_key,
"Bot access denied for retrieving custom event",
);
return Err(ApiError::Forbidden);
}
} else if ctx.is_user() {
let user_id = ctx.user_id.as_deref().ok_or(ApiError::Unauthorized)?;
if !bot.has_access(user_id) {
Expand Down Expand Up @@ -100,7 +103,22 @@ async fn get_event(
))
})?;

Ok(Json(CustomEventPayload::from(event)))
let current_date = DateTime::now();
let start_of_hour = DateTime::from_millis(
current_date.timestamp_millis() - (current_date.timestamp_millis() % 3600000),
);

let stats = repos
.bot_stats
.find_last_event_occurence(&bot_id, &event_key)
.await?;

let current_value = stats
.filter(|s| event.default_value.is_none() || s.date == start_of_hour)
.and_then(|s| s.custom_events.get(&event_key).copied())
.or(event.default_value);

Ok(Json(CustomEventResponse::new(event, current_value)))
}

#[api_operation(
Expand All @@ -113,7 +131,7 @@ async fn update_event(
repos: Data<Repositories>,
body: Json<CustomEventUpdatePayload>,
path: Path<(String, String)>,
) -> ApiResult<Json<CustomEventPayload>> {
) -> ApiResult<Json<CustomEventResponse>> {
let (id, event_key) = path.into_inner();
let bot_id = Snowflake::try_from(id)?.into_inner();

Expand All @@ -135,14 +153,16 @@ async fn update_event(
event_key = %event_key,
"Admin access granted for updating custom event",
);
} else if ctx.is_bot() && ctx.bot_id.as_deref() != Some(&bot_id) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
event_key = %event_key,
"Bot access denied for updating custom event",
);
return Err(ApiError::Forbidden);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
event_key = %event_key,
"Bot access denied for updating custom event",
);
return Err(ApiError::Forbidden);
}
} else if ctx.is_user() {
let user_id = ctx.user_id.as_deref().ok_or(ApiError::Unauthorized)?;
if !bot.has_access(user_id) {
Expand Down Expand Up @@ -219,7 +239,7 @@ async fn update_event(
"Custom event updated successfully",
);

Ok(Json(CustomEventPayload::from(update_result)))
Ok(Json(CustomEventResponse::from(update_result)))
}

#[api_operation(
Expand Down Expand Up @@ -253,14 +273,16 @@ async fn delete_event(
event_key = %event_key,
"Admin access granted for deleting custom event",
);
} else if ctx.is_bot() && ctx.bot_id.as_deref() != Some(&bot_id) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
event_key = %event_key,
"Bot access denied for deleting custom event",
);
return Err(ApiError::Forbidden);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
event_key = %event_key,
"Bot access denied for deleting custom event",
);
return Err(ApiError::Forbidden);
}
} else if ctx.is_user() {
let user_id = ctx.user_id.as_deref().ok_or(ApiError::Unauthorized)?;
if !bot.has_access(user_id) {
Expand Down
42 changes: 23 additions & 19 deletions src/api/routes/bots/bot/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
error::{ApiError, ApiResult},
models::CustomEvent,
},
openapi::schemas::CustomEventPayload,
openapi::schemas::{CustomEventPayload, CustomEventResponse},
repository::Repositories,
utils::{discord::Snowflake, logger::LogCode},
};
Expand All @@ -27,7 +27,7 @@ async fn get_all_events(
auth: Authenticated,
repos: Data<Repositories>,
id: Path<String>,
) -> ApiResult<Json<Vec<CustomEventPayload>>> {
) -> ApiResult<Json<Vec<CustomEventResponse>>> {
let bot_id = Snowflake::try_from(id.into_inner())?.into_inner();

info!(
Expand All @@ -53,13 +53,15 @@ async fn get_all_events(
bot_id = %bot_id,
"Admin access granted for retrieving all custom events",
);
} else if ctx.is_bot() && ctx.bot_id.as_deref() != Some(&bot_id) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to retrieve custom events for a different bot",
);
return Err(ApiError::Forbidden);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to retrieve custom events for a different bot",
);
return Err(ApiError::Forbidden);
}
} else if ctx.is_user() {
let user_id = ctx.user_id.as_deref().ok_or(ApiError::Unauthorized)?;
if !bot.has_access(user_id) {
Expand Down Expand Up @@ -91,7 +93,7 @@ async fn get_all_events(

let events = repos.custom_events.find_by_bot_id(&bot_id).await?;

let event_responses = events.into_iter().map(CustomEventPayload::from).collect();
let event_responses = events.into_iter().map(CustomEventResponse::from).collect();

info!(
code = %LogCode::Request,
Expand All @@ -112,7 +114,7 @@ async fn create_event(
repos: Data<Repositories>,
event: Json<CustomEventPayload>,
id: Path<String>,
) -> ApiResult<Json<CustomEventPayload>> {
) -> ApiResult<Json<CustomEventResponse>> {
let bot_id = Snowflake::try_from(id.into_inner())?.into_inner();

let bot = repos.bots.find_by_id(&bot_id).await?.ok_or_else(|| {
Expand All @@ -132,13 +134,15 @@ async fn create_event(
bot_id = %bot_id,
"Admin access granted for creating custom event",
);
} else if ctx.is_bot() && ctx.bot_id.as_deref() != Some(&bot_id) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to create custom event for a different bot",
);
return Err(ApiError::Forbidden);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to create custom event for a different bot",
);
return Err(ApiError::Forbidden);
}
} else if ctx.is_user() {
let user_id = ctx.user_id.as_deref().ok_or(ApiError::Unauthorized)?;
if !bot.has_access(user_id) {
Expand Down Expand Up @@ -213,7 +217,7 @@ async fn create_event(
"Custom event created successfully",
);

Ok(Json(CustomEventPayload::from(new_event)))
Ok(Json(CustomEventResponse::from(new_event)))
}

pub fn configure(cfg: &mut ServiceConfig) {
Expand Down
63 changes: 34 additions & 29 deletions src/api/routes/bots/bot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@ async fn get_bot(
bot_id = %bot_id,
"Admin access granted for bot details",
);
} else if ctx.is_bot() && ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to access details of another bot",
);
return Err(ApiError::Forbidden);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Bot attempting to access details of another bot",
);
return Err(ApiError::Forbidden);
}
} else if ctx.is_user() {
let user_id = ctx.user_id.as_deref().ok_or(ApiError::Unauthorized)?;
if !bot.has_access(user_id) {
Expand Down Expand Up @@ -245,9 +247,33 @@ async fn patch_bot(
"Attempting to update bot",
);

let bot = repos.bots.find_by_id(&bot_id).await?.ok_or_else(|| {
info!(
code = %LogCode::Request,
bot_id = %bot_id,
"Bot not found for update",
);
ApiError::NotFound(format!("Bot with ID {} not found", bot_id))
})?;

let ctx = &auth;

if !(ctx.is_admin() || ctx.is_bot() && ctx.bot_id.as_deref() == Some(bot_id.as_str())) {
if ctx.is_admin() {
info!(
code = %LogCode::AdminAction,
bot_id = %bot_id,
"Admin access granted to update bot",
);
} else if ctx.is_bot() {
if ctx.token.as_deref() != Some(&bot.token) {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
"Unauthorized bot update attempt",
);
return Err(ApiError::Forbidden);
}
} else {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
Expand All @@ -257,15 +283,6 @@ async fn patch_bot(
return Err(ApiError::Forbidden);
}

let bot = repos.bots.find_by_id(&bot_id).await?.ok_or_else(|| {
info!(
code = %LogCode::Request,
bot_id = %bot_id,
"Bot not found for update",
);
ApiError::NotFound(format!("Bot with ID {} not found", bot_id))
})?;

if bot.suspended && !ctx.is_admin() {
warn!(
code = %LogCode::Forbidden,
Expand All @@ -275,18 +292,6 @@ async fn patch_bot(
return Err(ApiError::BotSuspended);
}

if ctx.is_bot() {
let auth_token = ctx.token.as_deref().ok_or(ApiError::InvalidToken)?;
if bot.token() != auth_token {
warn!(
code = %LogCode::InvalidToken,
bot_id = %bot_id,
"Bot token mismatch during update",
);
return Err(ApiError::InvalidToken);
}
}

let update_data = body.into_inner();

let mut update = BotUpdate::default();
Expand Down
2 changes: 1 addition & 1 deletion src/api/routes/bots/bot/reports/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async fn get_subscriptions(
);
return Err(ApiError::Forbidden);
}
} else if !ctx.is_user() {
} else {
warn!(
code = %LogCode::Forbidden,
bot_id = %bot_id,
Expand Down
Loading