Skip to content

Commit 3f975d8

Browse files
committed
feat: add feature webhook event
1 parent 853bcc2 commit 3f975d8

File tree

5 files changed

+71
-5
lines changed

5 files changed

+71
-5
lines changed

src/database/repository/mods.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
use crate::types::api::ApiError;
22
use sqlx::PgConnection;
33

4+
pub async fn is_featured(id: &str, conn: &mut PgConnection) -> Result<bool, ApiError> {
5+
Ok(sqlx::query!("SELECT featured FROM mods WHERE id = $1", id)
6+
.fetch_optional(&mut *conn)
7+
.await
8+
.map_err(|e| {
9+
log::error!("Failed to check if mod {} exists: {}", id, e);
10+
ApiError::DbError
11+
})?
12+
.map(|row| row.featured)
13+
.unwrap_or(false))
14+
}
15+
416
pub async fn exists(id: &str, conn: &mut PgConnection) -> Result<bool, ApiError> {
517
Ok(sqlx::query!("SELECT id FROM mods WHERE id = $1", id)
618
.fetch_optional(&mut *conn)

src/endpoints/mods.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use actix_web::{get, post, put, web, HttpResponse, Responder};
22
use serde::Deserialize;
33
use sqlx::Acquire;
44

5+
use crate::database::repository::developers;
6+
use crate::database::repository::mods;
7+
use crate::events::mod_feature::ModFeaturedEvent;
58
use crate::extractors::auth::Auth;
69
use crate::types::api::{create_download_link, ApiError, ApiResponse};
710
use crate::types::mod_json::ModJson;
@@ -10,6 +13,7 @@ use crate::types::models::incompatibility::Incompatibility;
1013
use crate::types::models::mod_entity::{download_geode_file, Mod, ModUpdate};
1114
use crate::types::models::mod_gd_version::{GDVersionEnum, VerPlatform};
1215
use crate::types::models::mod_version_status::ModVersionStatusEnum;
16+
use crate::webhook::discord::DiscordWebhook;
1317
use crate::AppData;
1418

1519
#[derive(Deserialize, Default)]
@@ -245,8 +249,10 @@ pub async fn update_mod(
245249
return Err(ApiError::Forbidden);
246250
}
247251
let mut pool = data.db.acquire().await.or(Err(ApiError::DbAcquireError))?;
252+
let id = path.into_inner();
253+
let featured = mods::is_featured(&id, &mut pool)?;
248254
let mut transaction = pool.begin().await.or(Err(ApiError::TransactionError))?;
249-
if let Err(e) = Mod::update_mod(&path, payload.featured, &mut transaction).await {
255+
if let Err(e) = Mod::update_mod(&id, payload.featured, &mut transaction).await {
250256
transaction
251257
.rollback()
252258
.await
@@ -258,5 +264,25 @@ pub async fn update_mod(
258264
.await
259265
.or(Err(ApiError::TransactionError))?;
260266

267+
if featured != payload.featured {
268+
let item = Mod::get_one(&id, true, &mut pool).await?;
269+
if let Some(item) = item {
270+
let owner = developers::get_owner_for_mod(&id, &mut pool).await?;
271+
let first_ver = item.versions.first();
272+
if let Some(ver) = first_ver {
273+
ModFeaturedEvent {
274+
id: item.id,
275+
name: ver.name.clone(),
276+
owner,
277+
admin: dev,
278+
base_url: data.app_url.clone(),
279+
featured: payload.featured,
280+
}
281+
.to_discord_webhook()
282+
.send(&data.webhook_url);
283+
}
284+
}
285+
}
286+
261287
Ok(HttpResponse::NoContent())
262288
}

src/events/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
pub mod mod_created;
1+
pub mod mod_created;
2+
pub mod mod_feature;

src/events/mod_feature.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use crate::types::models::developer::FetchedDeveloper;
2+
use crate::webhook::discord::{DiscordMessage, DiscordWebhook};
3+
4+
pub struct ModFeaturedEvent {
5+
pub id: String,
6+
pub name: String,
7+
pub owner: FetchedDeveloper,
8+
pub admin: FetchedDeveloper,
9+
pub base_url: String,
10+
pub featured: bool,
11+
}
12+
13+
impl DiscordWebhook for ModFeaturedEvent {
14+
fn to_discord_webhook(&self) -> DiscordMessage {
15+
let title = match self.featured {
16+
true => "Mod featured!",
17+
false => "Mod unfeatured...",
18+
};
19+
20+
DiscordMessage::new().embed(
21+
title,
22+
Some(&format!("https://geode-sdk.org/mods/{}\n\nOwned by: [{}](https://github.com/{})\nAction done by: [{}](https://github.com/{}))",
23+
self.id, self.owner.display_name, self.owner.username, self.admin.display_name, self.admin.username)),
24+
Some(&format!("{}/v1/mods/{}/logo", self.base_url, self.id)),
25+
)
26+
}
27+
}

src/types/models/mod_entity.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use std::{
3131
io::{Cursor, Read},
3232
str::FromStr,
3333
};
34+
use crate::database::repository::mods;
3435

3536
#[derive(Serialize, Debug, sqlx::FromRow)]
3637
pub struct Mod {
@@ -616,7 +617,8 @@ impl Mod {
616617
INNER JOIN mod_versions mv ON m.id = mv.mod_id
617618
INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id
618619
WHERE m.id = $1
619-
AND ($2 = false OR mvs.status = 'accepted')"#,
620+
AND ($2 = false OR mvs.status = 'accepted')
621+
ORDER BY mv.id DESC"#,
620622
id,
621623
only_accepted
622624
)
@@ -824,8 +826,6 @@ impl Mod {
824826
featured: bool,
825827
pool: &mut PgConnection,
826828
) -> Result<(), ApiError> {
827-
use crate::database::repository::*;
828-
829829
if !mods::exists(id, &mut *pool).await? {
830830
return Err(ApiError::NotFound(format!("Mod {} doesn't exist", id)));
831831
}

0 commit comments

Comments
 (0)