mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 05:26:59 +00:00
refactor(delta): port routes to core webhook models
This commit is contained in:
60
Cargo.lock
generated
60
Cargo.lock
generated
@@ -2867,7 +2867,10 @@ dependencies = [
|
||||
"mongodb",
|
||||
"nanoid",
|
||||
"once_cell",
|
||||
"redis-kiss",
|
||||
"revolt-models",
|
||||
"revolt-permissions",
|
||||
"revolt-presence",
|
||||
"revolt-result",
|
||||
"revolt_optional_struct",
|
||||
"rocket",
|
||||
@@ -2902,6 +2905,7 @@ dependencies = [
|
||||
"revolt-database",
|
||||
"revolt-models",
|
||||
"revolt-quark",
|
||||
"revolt-result",
|
||||
"revolt_rocket_okapi",
|
||||
"rocket",
|
||||
"rocket_authifier",
|
||||
@@ -2911,7 +2915,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"ulid 0.4.1",
|
||||
"url",
|
||||
"validator 0.14.0",
|
||||
"validator 0.16.0",
|
||||
"vergen",
|
||||
]
|
||||
|
||||
@@ -2919,10 +2923,10 @@ dependencies = [
|
||||
name = "revolt-models"
|
||||
version = "0.0.2"
|
||||
dependencies = [
|
||||
"revolt-database",
|
||||
"revolt-presence",
|
||||
"revolt_optional_struct",
|
||||
"schemars",
|
||||
"serde",
|
||||
"validator 0.16.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2981,6 +2985,7 @@ dependencies = [
|
||||
"redis-kiss",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"revolt-models",
|
||||
"revolt-presence",
|
||||
"revolt-result",
|
||||
"revolt_okapi",
|
||||
@@ -2995,7 +3000,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"ulid 0.5.0",
|
||||
"validator 0.14.0",
|
||||
"validator 0.16.0",
|
||||
"web-push",
|
||||
]
|
||||
|
||||
@@ -3003,8 +3008,12 @@ dependencies = [
|
||||
name = "revolt-result"
|
||||
version = "0.0.2"
|
||||
dependencies = [
|
||||
"revolt_okapi",
|
||||
"revolt_rocket_okapi",
|
||||
"rocket",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4378,23 +4387,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d0f08911ab0fee2c5009580f04615fa868898ee57de10692a45da0c3bcc3e5e"
|
||||
dependencies = [
|
||||
"idna",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"url",
|
||||
"validator_derive",
|
||||
"validator_types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator"
|
||||
version = "0.15.0"
|
||||
@@ -4411,10 +4403,26 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator_derive"
|
||||
version = "0.14.0"
|
||||
name = "validator"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d85135714dba11a1bd0b3eb1744169266f1a38977bf4e3ff5e2e1acb8c2b7eee"
|
||||
checksum = "32ad5bf234c7d3ad1042e5252b7eddb2c4669ee23f32c7dd0e9b7705f07ef591"
|
||||
dependencies = [
|
||||
"idna",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"url",
|
||||
"validator_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "validator_derive"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af"
|
||||
dependencies = [
|
||||
"if_chain",
|
||||
"lazy_static",
|
||||
@@ -4428,9 +4436,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "validator_types"
|
||||
version = "0.14.0"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ded9d97e1d42327632f5f3bae6403c04886e2de3036261ef42deebd931a6a291"
|
||||
checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 1.0.107",
|
||||
|
||||
@@ -31,7 +31,7 @@ nanoid = "0.4.0"
|
||||
# serde
|
||||
serde_json = "1.0.57"
|
||||
serde = { version = "1.0.115", features = ["derive"] }
|
||||
validator = { version = "0.14", features = ["derive"] }
|
||||
validator = { version = "0.16", features = ["derive"] }
|
||||
|
||||
# async
|
||||
futures = "0.3.8"
|
||||
@@ -56,8 +56,9 @@ revolt_rocket_okapi = { version = "0.9.1", features = [ "swagger" ] }
|
||||
revolt-quark = { path = "../quark" }
|
||||
|
||||
# core
|
||||
revolt-database = { path = "../core/database", features = [ "rocket-impl" ] }
|
||||
revolt-models = { path = "../core/models", features = [ "schemas", "redis-is-patched" ] }
|
||||
revolt-database = { path = "../core/database", features = [ "rocket-impl", "redis-is-patched" ] }
|
||||
revolt-models = { path = "../core/models", features = [ "schemas", "validator" ] }
|
||||
revolt-result = { path = "../core/result", features = [ "rocket", "okapi" ] }
|
||||
|
||||
[build-dependencies]
|
||||
vergen = "7.5.0"
|
||||
|
||||
@@ -23,11 +23,12 @@ pub async fn fetch_bot(
|
||||
}
|
||||
|
||||
Ok(Json(FetchBotResponse {
|
||||
user: revolt_models::v0::User::from(
|
||||
db.fetch_user(&bot.id).await.map_err(Error::from_core)?,
|
||||
None,
|
||||
)
|
||||
.await,
|
||||
user: db
|
||||
.fetch_user(&bot.id)
|
||||
.await
|
||||
.map_err(Error::from_core)?
|
||||
.into(None)
|
||||
.await,
|
||||
bot: bot.into(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ pub async fn fetch_public_bot(
|
||||
}
|
||||
|
||||
let user = db.fetch_user(&bot.id).await.map_err(Error::from_core)?;
|
||||
Ok(Json(PublicBot::from(bot, user)))
|
||||
Ok(Json(bot.into_public_bot(user)))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use revolt_quark::{models::{User, Webhook, File, Channel}, perms, Db, Error, Permission, Ref, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use revolt_database::{Database, Webhook};
|
||||
use revolt_quark::{
|
||||
models::{Channel, User},
|
||||
perms, Db, Error, Permission, Ref, Result,
|
||||
};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
use validator::Validate;
|
||||
@@ -10,46 +14,56 @@ pub struct CreateWebhookBody {
|
||||
name: String,
|
||||
|
||||
#[validate(length(min = 1, max = 128))]
|
||||
avatar: Option<String>
|
||||
avatar: Option<String>,
|
||||
}
|
||||
|
||||
/// # Creates a webhook
|
||||
///
|
||||
/// creates a webhook which 3rd party platforms can use to send messages
|
||||
/// Creates a webhook which 3rd party platforms can use to send messages
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[post("/<target>/webhooks", data = "<data>")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref, data: Json<CreateWebhookBody>) -> Result<Json<Webhook>> {
|
||||
pub async fn req(
|
||||
db: &State<Database>,
|
||||
legacy_db: &Db,
|
||||
user: User,
|
||||
target: Ref,
|
||||
data: Json<CreateWebhookBody>,
|
||||
) -> Result<Json<revolt_models::v0::Webhook>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
|
||||
let channel = target.as_channel(db).await?;
|
||||
let channel = target.as_channel(legacy_db).await?;
|
||||
|
||||
if !matches!(channel, Channel::TextChannel { .. } | Channel::Group { .. }) {
|
||||
return Err(Error::InvalidOperation)
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
|
||||
let mut permissions = perms(&user).channel(&channel);
|
||||
permissions
|
||||
.has_permission(db, Permission::ManageWebhooks)
|
||||
.has_permission(legacy_db, Permission::ManageWebhooks)
|
||||
.await?;
|
||||
|
||||
let webhook_id = Ulid::new().to_string();
|
||||
|
||||
let avatar = match &data.avatar {
|
||||
Some(id) => Some(File::use_avatar(db, id, &webhook_id).await?),
|
||||
None => None
|
||||
Some(id) => Some(
|
||||
db.find_and_use_attachment(id, "avatars", "user", &webhook_id)
|
||||
.await
|
||||
.map_err(Error::from_core)?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let webhook = Webhook {
|
||||
id: webhook_id,
|
||||
name: data.name,
|
||||
avatar,
|
||||
channel: channel.id().to_string(),
|
||||
token: Some(nanoid::nanoid!(64))
|
||||
channel_id: channel.id().to_string(),
|
||||
token: Some(nanoid::nanoid!(64)),
|
||||
};
|
||||
|
||||
webhook.create(db).await?;
|
||||
webhook.create(db).await.map_err(Error::from_core)?;
|
||||
|
||||
Ok(Json(webhook))
|
||||
Ok(Json(webhook.into()))
|
||||
}
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
use revolt_quark::{models::{User, Webhook}, perms, Db, Permission, Ref, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use revolt_database::Database;
|
||||
use revolt_models::v0::Webhook;
|
||||
use revolt_quark::{models::User, perms, Db, Error, Permission, Ref, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Gets all webhooks
|
||||
///
|
||||
/// gets all webhooks inside the channel
|
||||
/// Gets all webhooks inside the channel
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[get("/<target>/webhooks")]
|
||||
pub async fn req(db: &Db, user: User, target: Ref) -> Result<Json<Vec<Webhook>>> {
|
||||
let channel = target.as_channel(db).await?;
|
||||
#[get("/<channel_id>/webhooks")]
|
||||
pub async fn req(
|
||||
db: &State<Database>,
|
||||
legacy_db: &Db,
|
||||
user: User,
|
||||
channel_id: Ref,
|
||||
) -> Result<Json<Vec<Webhook>>> {
|
||||
let channel = channel_id.as_channel(legacy_db).await?;
|
||||
let mut permissions = perms(&user).channel(&channel);
|
||||
permissions
|
||||
.has_permission(db, Permission::ManageWebhooks)
|
||||
.has_permission(legacy_db, Permission::ManageWebhooks)
|
||||
.await?;
|
||||
|
||||
let webhooks = db.fetch_webhooks_for_channel(channel.id()).await?;
|
||||
|
||||
Ok(Json(webhooks))
|
||||
Ok(Json(
|
||||
db.fetch_webhooks_for_channel(channel.id())
|
||||
.await
|
||||
.map_err(Error::from_core)?
|
||||
.into_iter()
|
||||
.map(|v| v.into())
|
||||
.collect::<Vec<Webhook>>(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
use revolt_quark::{Db, Ref, Result, EmptyResponse, models::User, perms, Permission};
|
||||
use revolt_database::Database;
|
||||
use revolt_quark::{models::User, perms, Db, Error, Permission, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
/// # Deletes a webhook
|
||||
///
|
||||
/// deletes a webhook
|
||||
/// Deletes a webhook
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[delete("/<target>")]
|
||||
pub async fn webhook_delete(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
|
||||
let webhook = target.as_webhook(db).await?;
|
||||
#[delete("/<webhook_id>")]
|
||||
pub async fn webhook_delete(
|
||||
db: &State<Database>,
|
||||
legacy_db: &Db,
|
||||
user: User,
|
||||
webhook_id: String,
|
||||
) -> Result<EmptyResponse> {
|
||||
let webhook = db
|
||||
.fetch_webhook(&webhook_id)
|
||||
.await
|
||||
.map_err(Error::from_core)?;
|
||||
|
||||
let channel = Ref::from_unchecked(webhook.channel.clone()).as_channel(db).await?;
|
||||
let channel = legacy_db.fetch_channel(&webhook.channel_id).await?;
|
||||
|
||||
perms(&user)
|
||||
.channel(&channel)
|
||||
.throw_permission(db, Permission::ManageWebhooks)
|
||||
.throw_permission(legacy_db, Permission::ManageWebhooks)
|
||||
.await?;
|
||||
|
||||
webhook.delete(db).await?;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
webhook
|
||||
.delete(db)
|
||||
.await
|
||||
.map(|_| EmptyResponse)
|
||||
.map_err(Error::from_core)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
use revolt_quark::{Db, Ref, Result, EmptyResponse, Error};
|
||||
use revolt_database::Database;
|
||||
use revolt_result::Result;
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
/// # Deletes a webhook
|
||||
///
|
||||
/// deletes a webhook with a token
|
||||
/// Deletes a webhook with a token
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[delete("/<target>/<token>")]
|
||||
pub async fn webhook_delete_token(db: &Db, target: Ref, token: String) -> Result<EmptyResponse> {
|
||||
let webhook = target.as_webhook(db).await?;
|
||||
|
||||
(webhook.token.as_deref() == Some(&token))
|
||||
.then_some(())
|
||||
.ok_or(Error::InvalidCredentials)?;
|
||||
|
||||
webhook.delete(db).await?;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
#[delete("/<webhook_id>/<token>")]
|
||||
pub async fn webhook_delete_token(
|
||||
db: &State<Database>,
|
||||
webhook_id: String,
|
||||
token: String,
|
||||
) -> Result<EmptyResponse> {
|
||||
let webhook = db.fetch_webhook(&webhook_id).await?;
|
||||
webhook.assert_token(&token)?;
|
||||
webhook.delete(db).await.map(|_| EmptyResponse)
|
||||
}
|
||||
|
||||
@@ -1,60 +1,65 @@
|
||||
use revolt_quark::{Db, Ref, Result, Error, models::{webhook::{FieldsWebhook, Webhook, PartialWebhook}, File, User}, Permission, perms};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use revolt_database::{Database, PartialWebhook};
|
||||
use revolt_models::v0::{DataEditWebhook, Webhook};
|
||||
use revolt_quark::{models::User, perms, Db, Error, Permission, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate, JsonSchema)]
|
||||
pub struct WebhookEditBody {
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: Option<String>,
|
||||
|
||||
#[validate(length(min = 1, max = 128))]
|
||||
avatar: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
remove: Vec<FieldsWebhook>
|
||||
}
|
||||
|
||||
/// # Edits a webhook
|
||||
///
|
||||
/// edits a webhook
|
||||
/// Edits a webhook
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[patch("/<target>", data="<data>")]
|
||||
pub async fn webhook_edit(db: &Db, target: Ref, user: User, data: Json<WebhookEditBody>) -> Result<Json<Webhook>> {
|
||||
#[patch("/<webhook_id>", data = "<data>")]
|
||||
pub async fn webhook_edit(
|
||||
db: &State<Database>,
|
||||
legacy_db: &Db,
|
||||
webhook_id: String,
|
||||
user: User,
|
||||
data: Json<DataEditWebhook>,
|
||||
) -> Result<Json<Webhook>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
|
||||
let mut webhook = target.as_webhook(db).await?;
|
||||
let mut webhook = db
|
||||
.fetch_webhook(&webhook_id)
|
||||
.await
|
||||
.map_err(Error::from_core)?;
|
||||
|
||||
let channel = Ref::from_unchecked(webhook.channel.clone()).as_channel(db).await?;
|
||||
let channel = legacy_db.fetch_channel(&webhook.channel_id).await?;
|
||||
|
||||
perms(&user)
|
||||
.channel(&channel)
|
||||
.throw_permission(db, Permission::ManageWebhooks)
|
||||
.throw_permission(legacy_db, Permission::ManageWebhooks)
|
||||
.await?;
|
||||
|
||||
if data.name.is_none()
|
||||
&& data.avatar.is_none()
|
||||
&& data.remove.is_empty()
|
||||
{
|
||||
return Ok(Json(webhook))
|
||||
if data.name.is_none() && data.avatar.is_none() && data.remove.is_empty() {
|
||||
return Ok(Json(webhook.into()));
|
||||
};
|
||||
|
||||
let mut partial = PartialWebhook::default();
|
||||
let DataEditWebhook {
|
||||
name,
|
||||
avatar,
|
||||
remove,
|
||||
} = data;
|
||||
|
||||
let WebhookEditBody { name, avatar, remove } = data;
|
||||
|
||||
if let Some(name) = name {
|
||||
partial.name = Some(name)
|
||||
}
|
||||
let mut partial = PartialWebhook {
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(avatar) = avatar {
|
||||
let file = File::use_avatar(db, &avatar, &webhook.id).await?;
|
||||
let file = db
|
||||
.find_and_use_attachment(&avatar, "avatars", "user", &webhook.id)
|
||||
.await
|
||||
.map_err(Error::from_core)?;
|
||||
|
||||
partial.avatar = Some(file)
|
||||
}
|
||||
|
||||
webhook.update(db, partial, remove).await?;
|
||||
webhook
|
||||
.update(db, partial, remove.into_iter().map(|v| v.into()).collect())
|
||||
.await
|
||||
.map_err(Error::from_core)?;
|
||||
|
||||
Ok(Json(webhook))
|
||||
Ok(Json(webhook.into()))
|
||||
}
|
||||
|
||||
@@ -1,57 +1,56 @@
|
||||
use revolt_quark::{Db, Ref, Result, Error, models::{webhook::{FieldsWebhook, Webhook, PartialWebhook}, File}};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use validator::Validate;
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
#[derive(Serialize, Deserialize, Validate, JsonSchema)]
|
||||
pub struct WebhookEditBody {
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: Option<String>,
|
||||
|
||||
#[validate(length(min = 1, max = 128))]
|
||||
avatar: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
remove: Vec<FieldsWebhook>
|
||||
}
|
||||
use revolt_database::{Database, PartialWebhook};
|
||||
use revolt_models::v0::{DataEditWebhook, Webhook};
|
||||
use revolt_models::validator::Validate;
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Edits a webhook
|
||||
///
|
||||
/// edits a webhook with a token
|
||||
/// Edits a webhook with a token
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[patch("/<target>/<token>", data="<data>")]
|
||||
pub async fn webhook_edit_token(db: &Db, target: Ref, token: String, data: Json<WebhookEditBody>) -> Result<Json<Webhook>> {
|
||||
#[patch("/<webhook_id>/<token>", data = "<data>")]
|
||||
pub async fn webhook_edit_token(
|
||||
db: &State<Database>,
|
||||
webhook_id: String,
|
||||
token: String,
|
||||
data: Json<DataEditWebhook>,
|
||||
) -> Result<Json<Webhook>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
data.validate().map_err(|error| {
|
||||
create_error!(FailedValidation {
|
||||
error: error.to_string()
|
||||
})
|
||||
})?;
|
||||
|
||||
let mut webhook = target.as_webhook(db).await?;
|
||||
let mut webhook = db.fetch_webhook(&webhook_id).await?;
|
||||
webhook.assert_token(&token)?;
|
||||
|
||||
(webhook.token.as_deref() == Some(&token))
|
||||
.then_some(())
|
||||
.ok_or(Error::InvalidCredentials)?;
|
||||
|
||||
if data.name.is_none()
|
||||
&& data.avatar.is_none()
|
||||
&& data.remove.is_empty()
|
||||
{
|
||||
return Ok(Json(webhook))
|
||||
if data.name.is_none() && data.avatar.is_none() && data.remove.is_empty() {
|
||||
return Ok(Json(webhook.into()));
|
||||
};
|
||||
|
||||
let mut partial = PartialWebhook::default();
|
||||
let DataEditWebhook {
|
||||
name,
|
||||
avatar,
|
||||
remove,
|
||||
} = data;
|
||||
|
||||
let WebhookEditBody { name, avatar, remove } = data;
|
||||
|
||||
if let Some(name) = name {
|
||||
partial.name = Some(name)
|
||||
}
|
||||
let mut partial = PartialWebhook {
|
||||
name,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(avatar) = avatar {
|
||||
let file = File::use_avatar(db, &avatar, &webhook.id).await?;
|
||||
let file = db
|
||||
.find_and_use_attachment(&avatar, "avatars", "user", &webhook.id)
|
||||
.await?;
|
||||
|
||||
partial.avatar = Some(file)
|
||||
}
|
||||
|
||||
webhook.update(db, partial, remove).await?;
|
||||
webhook
|
||||
.update(db, partial, remove.into_iter().map(|v| v.into()).collect())
|
||||
.await?;
|
||||
|
||||
Ok(Json(webhook))
|
||||
Ok(Json(webhook.into()))
|
||||
}
|
||||
|
||||
@@ -1,26 +1,47 @@
|
||||
use revolt_quark::{Db, Ref, Result, Error, models::message::{Message, DataMessageSend}, web::idempotency::IdempotencyKey, types::push::MessageAuthor};
|
||||
use rocket::serde::json::Json;
|
||||
use revolt_database::Database;
|
||||
use revolt_quark::{
|
||||
models::message::{DataMessageSend, Message},
|
||||
types::push::MessageAuthor,
|
||||
web::idempotency::IdempotencyKey,
|
||||
Db, Error, Result,
|
||||
};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use validator::Validate;
|
||||
|
||||
/// # Executes a webhook
|
||||
///
|
||||
/// executes a webhook and sends a message
|
||||
/// Executes a webhook and sends a message
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[post("/<target>/<token>", data="<data>")]
|
||||
pub async fn webhook_execute(db: &Db, target: Ref, token: String, data: Json<DataMessageSend>, idempotency: IdempotencyKey) -> Result<Json<Message>> {
|
||||
#[post("/<webhook_id>/<token>", data = "<data>")]
|
||||
pub async fn webhook_execute(
|
||||
db: &State<Database>,
|
||||
legacy_db: &Db,
|
||||
webhook_id: String,
|
||||
token: String,
|
||||
data: Json<DataMessageSend>,
|
||||
idempotency: IdempotencyKey,
|
||||
) -> Result<Json<Message>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
|
||||
let webhook = target.as_webhook(db).await?;
|
||||
let webhook = db
|
||||
.fetch_webhook(&webhook_id)
|
||||
.await
|
||||
.map_err(Error::from_core)?;
|
||||
|
||||
(webhook.token.as_deref() == Some(&token))
|
||||
.then_some(())
|
||||
.ok_or(Error::InvalidCredentials)?;
|
||||
webhook.assert_token(&token).map_err(Error::from_core)?;
|
||||
|
||||
let channel = Ref::from_unchecked(webhook.channel.clone()).as_channel(db).await?;
|
||||
let message = channel.send_message(db, data, MessageAuthor::Webhook(&webhook), idempotency).await?;
|
||||
let channel = legacy_db.fetch_channel(&webhook.channel_id).await?;
|
||||
let message = channel
|
||||
.send_message(
|
||||
legacy_db,
|
||||
data,
|
||||
MessageAuthor::Webhook(&webhook.into()),
|
||||
idempotency,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(message))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
use revolt_quark::{Db, Ref, Result, Error, models::{Message, message::SendableEmbed}, types::push::MessageAuthor};
|
||||
use rocket::{Request, request::FromRequest, http::Status};
|
||||
use revolt_rocket_okapi::{request::{OpenApiFromRequest, RequestHeaderInput}, revolt_okapi::openapi3::{Parameter, ParameterValue, MediaType}, gen::OpenApiGenerator};
|
||||
use revolt_database::Database;
|
||||
use revolt_models::v0::Webhook;
|
||||
use revolt_quark::{
|
||||
models::{message::SendableEmbed, Message},
|
||||
types::push::MessageAuthor,
|
||||
Db, Error, Result,
|
||||
};
|
||||
use revolt_rocket_okapi::{
|
||||
gen::OpenApiGenerator,
|
||||
request::{OpenApiFromRequest, RequestHeaderInput},
|
||||
revolt_okapi::openapi3::{MediaType, Parameter, ParameterValue},
|
||||
};
|
||||
use rocket::{http::Status, request::FromRequest, Request, State};
|
||||
use schemars::schema::SchemaObject;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
@@ -30,14 +40,14 @@ pub struct GithubUser {
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct GithubRepositorySecurityAndAnalysisStatus {
|
||||
status: String
|
||||
status: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct GithubRepositorySecurityAndAnalysis {
|
||||
advanced_security: GithubRepositorySecurityAndAnalysisStatus,
|
||||
secret_scanning: GithubRepositorySecurityAndAnalysisStatus,
|
||||
secret_scanning_push_protection: GithubRepositorySecurityAndAnalysisStatus
|
||||
secret_scanning_push_protection: GithubRepositorySecurityAndAnalysisStatus,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -55,7 +65,7 @@ pub struct GithubRepositoryCodeOfConduct {
|
||||
name: String,
|
||||
url: String,
|
||||
body: Option<String>,
|
||||
html_url: Option<String>
|
||||
html_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -64,7 +74,7 @@ pub struct GithubRepositoryPermissions {
|
||||
maintain: Option<bool>,
|
||||
push: Option<bool>,
|
||||
triage: Option<bool>,
|
||||
pull: Option<bool>
|
||||
pull: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -155,16 +165,15 @@ pub struct GithubRepository {
|
||||
watchers: Option<u32>,
|
||||
allow_forking: Option<bool>,
|
||||
web_commit_signoff_required: Option<bool>,
|
||||
security_and_analysis: Option<GithubRepositorySecurityAndAnalysis>
|
||||
security_and_analysis: Option<GithubRepositorySecurityAndAnalysis>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct CommitAuthor {
|
||||
date: Option<String>,
|
||||
email: Option<String>,
|
||||
name: String,
|
||||
username: Option<String>
|
||||
username: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -179,13 +188,13 @@ pub struct GithubCommit {
|
||||
removed: Option<Vec<String>>,
|
||||
timestamp: String,
|
||||
tree_id: String,
|
||||
url: String
|
||||
url: String,
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct GithubReactions {
|
||||
#[serde(rename="+1")]
|
||||
#[serde(rename = "+1")]
|
||||
plus_one: u32,
|
||||
#[serde(rename="-1")]
|
||||
#[serde(rename = "-1")]
|
||||
minus_one: u32,
|
||||
confused: u32,
|
||||
eyes: u32,
|
||||
@@ -194,7 +203,7 @@ pub struct GithubReactions {
|
||||
laugh: u32,
|
||||
rocket: u32,
|
||||
total_count: u32,
|
||||
url: String
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -212,7 +221,7 @@ pub struct GithubComment {
|
||||
reactions: Option<GithubReactions>,
|
||||
updated_at: Value,
|
||||
url: String,
|
||||
user: GithubUser
|
||||
user: GithubUser,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -221,7 +230,7 @@ pub struct GithubDiscussionComment {
|
||||
comment: GithubComment,
|
||||
child_comment_count: u32,
|
||||
parent_id: Option<u32>,
|
||||
repository_url: String
|
||||
repository_url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -235,7 +244,7 @@ pub struct GithubDiscussionCategory {
|
||||
created_at: Value,
|
||||
updated_at: Value,
|
||||
slug: String,
|
||||
is_answerable: bool
|
||||
is_answerable: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -243,8 +252,8 @@ pub struct GithubDiscussion {
|
||||
repository_url: String,
|
||||
category: GithubDiscussionCategory,
|
||||
answer_html_url: Option<String>,
|
||||
answer_chosen_at: Value, // ??
|
||||
answer_chosen_by: Value, // ??
|
||||
answer_chosen_at: Value, // ??
|
||||
answer_chosen_by: Value, // ??
|
||||
html_url: String,
|
||||
id: u32,
|
||||
node_id: String,
|
||||
@@ -260,7 +269,7 @@ pub struct GithubDiscussion {
|
||||
active_lock_reason: Option<String>,
|
||||
body: String,
|
||||
reactions: GithubReactions,
|
||||
timeline_url: String
|
||||
timeline_url: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -268,12 +277,12 @@ pub struct GithubDiscussion {
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum GithubDiscussionEvent {
|
||||
Created {
|
||||
discussion: GithubDiscussion
|
||||
discussion: GithubDiscussion,
|
||||
},
|
||||
Answered {
|
||||
discussion: GithubDiscussion,
|
||||
answer: GithubDiscussionComment
|
||||
}
|
||||
answer: GithubDiscussionComment,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -282,10 +291,10 @@ pub enum GithubDiscussionEvent {
|
||||
pub enum DiscussionCommentEvent {
|
||||
Created {
|
||||
comment: GithubDiscussionComment,
|
||||
discussion: GithubDiscussion
|
||||
discussion: GithubDiscussion,
|
||||
},
|
||||
Deleted {},
|
||||
Edited {}
|
||||
Edited {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -305,7 +314,7 @@ pub struct GithubMilestone {
|
||||
created_at: Value,
|
||||
updated_at: Value,
|
||||
closed_at: Option<Value>,
|
||||
due_on: Option<String>
|
||||
due_on: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -322,10 +331,9 @@ pub struct GithubAppPermissions {
|
||||
checks: Option<String>,
|
||||
metadata: Option<String>,
|
||||
contents: Option<String>,
|
||||
deployments: Option<String>
|
||||
deployments: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct GithubApp {
|
||||
id: u32,
|
||||
@@ -344,7 +352,7 @@ pub struct GithubApp {
|
||||
client_id: Option<String>,
|
||||
client_secret: Option<String>,
|
||||
webhook_secret: Option<String>,
|
||||
pem: Option<String>
|
||||
pem: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -380,7 +388,7 @@ pub struct GithubIssue {
|
||||
performed_via_github_app: Option<GithubApp>,
|
||||
author_association: String,
|
||||
reactions: Option<GithubReactions>,
|
||||
title: String
|
||||
title: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -389,10 +397,10 @@ pub struct GithubIssue {
|
||||
pub enum IssueCommentEvent {
|
||||
Created {
|
||||
comment: GithubComment,
|
||||
issue: GithubIssue
|
||||
issue: GithubIssue,
|
||||
},
|
||||
Deleted {},
|
||||
Edited {}
|
||||
Edited {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
@@ -400,32 +408,26 @@ pub enum IssueCommentEvent {
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum IssuesEvent {
|
||||
Assigned {},
|
||||
Closed {
|
||||
issue: GithubIssue
|
||||
},
|
||||
Closed { issue: GithubIssue },
|
||||
Deleted {},
|
||||
Demilestoned {},
|
||||
Edited {},
|
||||
Labeled {},
|
||||
Locked {},
|
||||
Milestoned {},
|
||||
Opened {
|
||||
issue: GithubIssue
|
||||
},
|
||||
Opened { issue: GithubIssue },
|
||||
Pinned {},
|
||||
Reopened {
|
||||
issue: GithubIssue
|
||||
},
|
||||
Reopened { issue: GithubIssue },
|
||||
Transferred {},
|
||||
Unassigned {},
|
||||
Unlabeled {},
|
||||
Unlocked {},
|
||||
Unpinned {}
|
||||
Unpinned {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct StarEvent {
|
||||
starred_at: Option<Value>
|
||||
starred_at: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -440,12 +442,12 @@ pub struct PushEvent {
|
||||
forced: bool,
|
||||
head_commit: Option<GithubCommit>,
|
||||
pusher: CommitAuthor,
|
||||
r#ref: String
|
||||
r#ref: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CommitCommentEvent {
|
||||
comment: GithubComment
|
||||
comment: GithubComment,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -453,19 +455,19 @@ pub struct CreateEvent {
|
||||
master_branch: String,
|
||||
pusher_type: String,
|
||||
r#ref: String,
|
||||
ref_type: String
|
||||
ref_type: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DeleteEvent {
|
||||
pusher_type: String,
|
||||
r#ref: String,
|
||||
ref_type: String
|
||||
ref_type: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct ForkEvent {
|
||||
forkee: GithubRepository
|
||||
forkee: GithubRepository,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -481,7 +483,7 @@ pub struct GithubTeam {
|
||||
permission: String,
|
||||
members_url: String,
|
||||
repositories_url: String,
|
||||
parent: Option<Box<GithubTeam>>
|
||||
parent: Option<Box<GithubTeam>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -490,17 +492,17 @@ pub struct GithubHead {
|
||||
r#ref: String,
|
||||
repo: GithubRepository,
|
||||
sha: String,
|
||||
user: Option<GithubUser>
|
||||
user: Option<GithubUser>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GithubHref {
|
||||
href: String
|
||||
href: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GithubLinks {
|
||||
#[serde(rename="self")]
|
||||
#[serde(rename = "self")]
|
||||
_self: GithubHref,
|
||||
html: GithubHref,
|
||||
comments: GithubHref,
|
||||
@@ -508,7 +510,7 @@ pub struct GithubLinks {
|
||||
statuses: GithubHref,
|
||||
issue: GithubHref,
|
||||
review_comments: GithubHref,
|
||||
review_comment: GithubHref
|
||||
review_comment: GithubHref,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -516,7 +518,7 @@ pub struct GithubAutoMerge {
|
||||
enabled_by: GithubUser,
|
||||
merge_method: String,
|
||||
commit_title: String,
|
||||
commit_message: String
|
||||
commit_message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -548,7 +550,7 @@ pub struct GithubPullRequest {
|
||||
_links: GithubLinks,
|
||||
author_association: String,
|
||||
auto_merge: Option<GithubAutoMerge>,
|
||||
draft: bool
|
||||
draft: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -559,7 +561,7 @@ pub enum PullRequestEvent {
|
||||
AutoMergeEnabled {},
|
||||
Closed {
|
||||
number: u32,
|
||||
pull_request: GithubPullRequest
|
||||
pull_request: GithubPullRequest,
|
||||
},
|
||||
ConvertedToDraft {},
|
||||
Demilestoned {},
|
||||
@@ -571,20 +573,19 @@ pub enum PullRequestEvent {
|
||||
Milestoned {},
|
||||
Opened {
|
||||
number: u32,
|
||||
pull_request: GithubPullRequest
|
||||
pull_request: GithubPullRequest,
|
||||
},
|
||||
ReadyForReview {},
|
||||
Reopened {
|
||||
number: u32,
|
||||
pull_request: GithubPullRequest
|
||||
|
||||
pull_request: GithubPullRequest,
|
||||
},
|
||||
ReviewRequestRemoved {},
|
||||
ReviewRequest {},
|
||||
Synchronized {},
|
||||
Unassigned {},
|
||||
Unlabeled {},
|
||||
Unlocked {}
|
||||
Unlocked {},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -601,14 +602,14 @@ pub enum BaseEvent {
|
||||
Fork(ForkEvent),
|
||||
IssueComment(IssueCommentEvent),
|
||||
Issues(IssuesEvent),
|
||||
PullRequest(PullRequestEvent)
|
||||
PullRequest(PullRequestEvent),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct _Event {
|
||||
action: Option<String>,
|
||||
sender: GithubUser,
|
||||
repository: GithubRepository
|
||||
repository: GithubRepository,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -616,7 +617,7 @@ pub struct Event {
|
||||
event: BaseEvent,
|
||||
action: Option<String>,
|
||||
sender: GithubUser,
|
||||
repository: GithubRepository
|
||||
repository: GithubRepository,
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
@@ -634,7 +635,7 @@ impl<'r> std::ops::Deref for EventHeader<'r> {
|
||||
impl<'r> FromRequest<'r> for EventHeader<'r> {
|
||||
type Error = Error;
|
||||
|
||||
async fn from_request(request: &'r Request<'_>) -> rocket::request::Outcome<Self,Self::Error> {
|
||||
async fn from_request(request: &'r Request<'_>) -> rocket::request::Outcome<Self, Self::Error> {
|
||||
let headers = request.headers();
|
||||
let Some(event) = headers.get_one("X-GitHub-Event") else {
|
||||
return rocket::request::Outcome::Failure((Status::BadRequest, Error::InvalidOperation))
|
||||
@@ -651,29 +652,30 @@ impl<'r> OpenApiFromRequest<'r> for EventHeader<'r> {
|
||||
_required: bool,
|
||||
) -> revolt_rocket_okapi::Result<RequestHeaderInput> {
|
||||
let mut content = schemars::Map::new();
|
||||
content.insert("X-Github-Event".to_string(), MediaType {
|
||||
schema: Some(SchemaObject {
|
||||
string: Some(Box::default()),
|
||||
..Default::default()
|
||||
}),
|
||||
example: None,
|
||||
examples: None,
|
||||
encoding: schemars::Map::new(),
|
||||
extensions: schemars::Map::new(),
|
||||
});
|
||||
content.insert(
|
||||
"X-Github-Event".to_string(),
|
||||
MediaType {
|
||||
schema: Some(SchemaObject {
|
||||
string: Some(Box::default()),
|
||||
..Default::default()
|
||||
}),
|
||||
example: None,
|
||||
examples: None,
|
||||
encoding: schemars::Map::new(),
|
||||
extensions: schemars::Map::new(),
|
||||
},
|
||||
);
|
||||
|
||||
Ok(RequestHeaderInput::Parameter(
|
||||
Parameter {
|
||||
name: "X-Github-Event".to_string(),
|
||||
location: "header".to_string(),
|
||||
required: true,
|
||||
description: Some("The name of the github event".to_string()),
|
||||
deprecated: false,
|
||||
allow_empty_value: false,
|
||||
value: ParameterValue::Content { content },
|
||||
extensions: schemars::Map::new()
|
||||
}
|
||||
))
|
||||
Ok(RequestHeaderInput::Parameter(Parameter {
|
||||
name: "X-Github-Event".to_string(),
|
||||
location: "header".to_string(),
|
||||
required: true,
|
||||
description: Some("The name of the github event".to_string()),
|
||||
deprecated: false,
|
||||
allow_empty_value: false,
|
||||
value: ParameterValue::Content { content },
|
||||
extensions: schemars::Map::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,53 +726,82 @@ fn convert_event(data: &str, event_name: &str) -> Result<Event> {
|
||||
"issue_comment" => BaseEvent::IssueComment(safe_from_str(data)?),
|
||||
"issues" => BaseEvent::Issues(safe_from_str(data)?),
|
||||
"pull_request" => BaseEvent::PullRequest(safe_from_str(data)?),
|
||||
_ => return Err(Error::InvalidOperation)
|
||||
_ => return Err(Error::InvalidOperation),
|
||||
};
|
||||
|
||||
let _Event { action, sender, repository } = event;
|
||||
let _Event {
|
||||
action,
|
||||
sender,
|
||||
repository,
|
||||
} = event;
|
||||
|
||||
Ok(Event {
|
||||
action,
|
||||
sender,
|
||||
repository,
|
||||
event: base_event
|
||||
event: base_event,
|
||||
})
|
||||
}
|
||||
|
||||
/// # Executes a webhook specific to github
|
||||
///
|
||||
/// executes a webhook specific to github and sends a message containg the relavent info about the event
|
||||
/// Executes a webhook specific to github and sends a message containing the relevant info about the event
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[post("/<target>/<token>/github", data="<data>")]
|
||||
pub async fn webhook_execute_github(db: &Db, target: Ref, token: String, event: EventHeader<'_>, data: String) -> Result<()> {
|
||||
let webhook = target.as_webhook(db).await?;
|
||||
#[post("/<webhook_id>/<token>/github", data = "<data>")]
|
||||
pub async fn webhook_execute_github(
|
||||
db: &State<Database>,
|
||||
legacy_db: &Db,
|
||||
webhook_id: String,
|
||||
token: String,
|
||||
event: EventHeader<'_>,
|
||||
data: String,
|
||||
) -> Result<()> {
|
||||
let webhook = db
|
||||
.fetch_webhook(&webhook_id)
|
||||
.await
|
||||
.map_err(Error::from_core)?;
|
||||
|
||||
(webhook.token.as_deref() == Some(&token))
|
||||
.then_some(())
|
||||
.ok_or(Error::InvalidCredentials)?;
|
||||
|
||||
let channel = db.fetch_channel(&webhook.channel).await?;
|
||||
webhook.assert_token(&token).map_err(Error::from_core)?;
|
||||
|
||||
let channel = legacy_db.fetch_channel(&webhook.channel_id).await?;
|
||||
let event = convert_event(&data, &event)?;
|
||||
|
||||
let sendable_embed = match event.event {
|
||||
BaseEvent::Star(_) => {
|
||||
if event.action.as_deref() != Some("created") { return Ok(()) };
|
||||
if event.action.as_deref() != Some("created") {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
SendableEmbed {
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] New star added]({})", event.repository.full_name, event.repository.html_url)),
|
||||
description: Some(format!(
|
||||
"#### [[{}] New star added]({})",
|
||||
event.repository.full_name, event.repository.html_url
|
||||
)),
|
||||
colour: Some(GREY.to_string()),
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
BaseEvent::Push( PushEvent { after, commits, compare, forced, r#ref, .. }) => {
|
||||
}
|
||||
BaseEvent::Push(PushEvent {
|
||||
after,
|
||||
commits,
|
||||
compare,
|
||||
forced,
|
||||
r#ref,
|
||||
..
|
||||
}) => {
|
||||
let Some(branch) = r#ref.split('/').nth(2) else { return Ok(()) };
|
||||
|
||||
if forced {
|
||||
let description = format!("#### [{}] Branch {} was force-pushed to {}\n[compare changes]({})", event.repository.full_name, branch, &after[0..=7], compare);
|
||||
let description = format!(
|
||||
"#### [{}] Branch {} was force-pushed to {}\n[compare changes]({})",
|
||||
event.repository.full_name,
|
||||
branch,
|
||||
&after[0..=7],
|
||||
compare
|
||||
);
|
||||
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
@@ -781,10 +812,24 @@ pub async fn webhook_execute_github(db: &Db, target: Ref, token: String, event:
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
let title = format!("[[{}:{}] {} new commit]({})", event.repository.full_name, branch, commits.len(), compare);
|
||||
let title = format!(
|
||||
"[[{}:{}] {} new commit]({})",
|
||||
event.repository.full_name,
|
||||
branch,
|
||||
commits.len(),
|
||||
compare
|
||||
);
|
||||
let commit_description = commits
|
||||
.into_iter()
|
||||
.map(|commit| format!("[`{}`]({}) {} - {}", &commit.id[0..=7], commit.url, shorten_text(&commit.message, 50), commit.author.name))
|
||||
.map(|commit| {
|
||||
format!(
|
||||
"[`{}`]({}) {} - {}",
|
||||
&commit.id[0..=7],
|
||||
commit.url,
|
||||
shorten_text(&commit.message, 50),
|
||||
commit.author.name
|
||||
)
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
@@ -797,193 +842,245 @@ pub async fn webhook_execute_github(db: &Db, target: Ref, token: String, event:
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
BaseEvent::CommitComment(CommitCommentEvent { comment }) => {
|
||||
let commit_id = match comment.commit_id {
|
||||
Some(id) => id[0..=7].to_string(),
|
||||
None => "".to_string()
|
||||
None => "".to_string(),
|
||||
};
|
||||
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] New comment on commit `{}`]({})\n{}", event.repository.full_name, commit_id, comment.html_url, shorten_text(&comment.body, 450))),
|
||||
description: Some(format!(
|
||||
"#### [[{}] New comment on commit `{}`]({})\n{}",
|
||||
event.repository.full_name,
|
||||
commit_id,
|
||||
comment.html_url,
|
||||
shorten_text(&comment.body, 450)
|
||||
)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
BaseEvent::Ping => {
|
||||
return Ok(())
|
||||
},
|
||||
BaseEvent::Create(CreateEvent { r#ref, ref_type, .. }) => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [{}] New {} created: {}", event.repository.full_name, ref_type, r#ref)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
BaseEvent::Delete( DeleteEvent { r#ref, ref_type, .. }) => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [{}] {} deleted: {}", event.repository.full_name, ref_type, r#ref)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
BaseEvent::Discussion(discussion_event) => {
|
||||
match discussion_event {
|
||||
GithubDiscussionEvent::Created { discussion } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [{}] New discussion #{}: {}\n{}", event.repository.full_name, discussion.number, discussion.title, shorten_text(&discussion.body, 450))),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
GithubDiscussionEvent::Answered { discussion, answer } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(answer.comment.user.avatar_url),
|
||||
url: Some(answer.comment.user.html_url),
|
||||
title: Some(answer.comment.user.login),
|
||||
description: Some(format!("#### [{}] discussion #{} marked answered: {}\n{}", event.repository.full_name, discussion.number, discussion.title, shorten_text(&answer.comment.body, 450))),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
BaseEvent::DiscussionComment(comment_event) => {
|
||||
match comment_event {
|
||||
DiscussionCommentEvent::Created { comment, discussion } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(comment.comment.user.avatar_url),
|
||||
url: Some(comment.comment.user.html_url),
|
||||
title: Some(comment.comment.user.login),
|
||||
description: Some(format!("[{}] New comment on discussion #{}: {}\n{}", event.repository.full_name, discussion.number, discussion.title, shorten_text(&comment.comment.body, 450))),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
_ => { return Ok(()) }
|
||||
}
|
||||
},
|
||||
BaseEvent::Fork(ForkEvent { forkee }) => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] Fork created: {}]({})", event.repository.full_name, forkee.full_name, forkee.html_url)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
BaseEvent::Issues(issue_event) => {
|
||||
match issue_event {
|
||||
IssuesEvent::Closed { issue } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] Issue Closed #{}: {}]({})", event.repository.full_name, issue.number, issue.title, issue.html_url)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
IssuesEvent::Opened { issue } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] Issue Opened #{}: {}]({})\n{}", event.repository.full_name, issue.number, issue.title, issue.html_url, shorten_text(&issue.body.unwrap_or_default(), 450))),
|
||||
colour: Some(ORANGE.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
IssuesEvent::Reopened { issue } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] Issue Reopened #{}: {}]({})", event.repository.full_name, issue.number, issue.html_url, issue.title)),
|
||||
colour: Some(GREEN.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
_ => { return Ok(()) }
|
||||
}
|
||||
},
|
||||
BaseEvent::IssueComment(comment_event) => {
|
||||
match comment_event {
|
||||
IssueCommentEvent::Created { comment, issue } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] New comment on issue #{}: {}]({})\n{}", event.repository.full_name, issue.number, issue.title, issue.html_url, shorten_text(&comment.body, 450))),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
_ => { return Ok(()) }
|
||||
}
|
||||
},
|
||||
BaseEvent::PullRequest(pull_request_event) => {
|
||||
match pull_request_event {
|
||||
PullRequestEvent::Closed { number, pull_request } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] Pull Request Closed #{}: {}]({})", event.repository.full_name, number, pull_request.title, pull_request.html_url)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
PullRequestEvent::Opened { number, pull_request } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] Pull Request Opened #{}: {}]({})\n{}", event.repository.full_name, number, pull_request.title, pull_request.html_url, shorten_text(&pull_request.body.unwrap_or_default(), 450))),
|
||||
colour: Some(ORANGE.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
PullRequestEvent::Reopened { number, pull_request } => {
|
||||
SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!("#### [[{}] Pull Request Reopened #{}: {}]({})", event.repository.full_name, number, pull_request.html_url, pull_request.title)),
|
||||
colour: Some(GREEN.to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
_ => { return Ok(()) }
|
||||
}
|
||||
}
|
||||
BaseEvent::Ping => return Ok(()),
|
||||
BaseEvent::Create(CreateEvent {
|
||||
r#ref, ref_type, ..
|
||||
}) => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [{}] New {} created: {}",
|
||||
event.repository.full_name, ref_type, r#ref
|
||||
)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
BaseEvent::Delete(DeleteEvent {
|
||||
r#ref, ref_type, ..
|
||||
}) => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [{}] {} deleted: {}",
|
||||
event.repository.full_name, ref_type, r#ref
|
||||
)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
BaseEvent::Discussion(discussion_event) => match discussion_event {
|
||||
GithubDiscussionEvent::Created { discussion } => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [{}] New discussion #{}: {}\n{}",
|
||||
event.repository.full_name,
|
||||
discussion.number,
|
||||
discussion.title,
|
||||
shorten_text(&discussion.body, 450)
|
||||
)),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
GithubDiscussionEvent::Answered { discussion, answer } => SendableEmbed {
|
||||
icon_url: Some(answer.comment.user.avatar_url),
|
||||
url: Some(answer.comment.user.html_url),
|
||||
title: Some(answer.comment.user.login),
|
||||
description: Some(format!(
|
||||
"#### [{}] discussion #{} marked answered: {}\n{}",
|
||||
event.repository.full_name,
|
||||
discussion.number,
|
||||
discussion.title,
|
||||
shorten_text(&answer.comment.body, 450)
|
||||
)),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
BaseEvent::DiscussionComment(comment_event) => match comment_event {
|
||||
DiscussionCommentEvent::Created {
|
||||
comment,
|
||||
discussion,
|
||||
} => SendableEmbed {
|
||||
icon_url: Some(comment.comment.user.avatar_url),
|
||||
url: Some(comment.comment.user.html_url),
|
||||
title: Some(comment.comment.user.login),
|
||||
description: Some(format!(
|
||||
"[{}] New comment on discussion #{}: {}\n{}",
|
||||
event.repository.full_name,
|
||||
discussion.number,
|
||||
discussion.title,
|
||||
shorten_text(&comment.comment.body, 450)
|
||||
)),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
_ => return Ok(()),
|
||||
},
|
||||
BaseEvent::Fork(ForkEvent { forkee }) => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] Fork created: {}]({})",
|
||||
event.repository.full_name, forkee.full_name, forkee.html_url
|
||||
)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
BaseEvent::Issues(issue_event) => match issue_event {
|
||||
IssuesEvent::Closed { issue } => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] Issue Closed #{}: {}]({})",
|
||||
event.repository.full_name, issue.number, issue.title, issue.html_url
|
||||
)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
IssuesEvent::Opened { issue } => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] Issue Opened #{}: {}]({})\n{}",
|
||||
event.repository.full_name,
|
||||
issue.number,
|
||||
issue.title,
|
||||
issue.html_url,
|
||||
shorten_text(&issue.body.unwrap_or_default(), 450)
|
||||
)),
|
||||
colour: Some(ORANGE.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
IssuesEvent::Reopened { issue } => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] Issue Reopened #{}: {}]({})",
|
||||
event.repository.full_name, issue.number, issue.html_url, issue.title
|
||||
)),
|
||||
colour: Some(GREEN.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
_ => return Ok(()),
|
||||
},
|
||||
BaseEvent::IssueComment(comment_event) => match comment_event {
|
||||
IssueCommentEvent::Created { comment, issue } => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] New comment on issue #{}: {}]({})\n{}",
|
||||
event.repository.full_name,
|
||||
issue.number,
|
||||
issue.title,
|
||||
issue.html_url,
|
||||
shorten_text(&comment.body, 450)
|
||||
)),
|
||||
colour: Some(LIGHT_ORANGE.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
_ => return Ok(()),
|
||||
},
|
||||
BaseEvent::PullRequest(pull_request_event) => match pull_request_event {
|
||||
PullRequestEvent::Closed {
|
||||
number,
|
||||
pull_request,
|
||||
} => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] Pull Request Closed #{}: {}]({})",
|
||||
event.repository.full_name, number, pull_request.title, pull_request.html_url
|
||||
)),
|
||||
colour: Some(GREY.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
PullRequestEvent::Opened {
|
||||
number,
|
||||
pull_request,
|
||||
} => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] Pull Request Opened #{}: {}]({})\n{}",
|
||||
event.repository.full_name,
|
||||
number,
|
||||
pull_request.title,
|
||||
pull_request.html_url,
|
||||
shorten_text(&pull_request.body.unwrap_or_default(), 450)
|
||||
)),
|
||||
colour: Some(ORANGE.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
PullRequestEvent::Reopened {
|
||||
number,
|
||||
pull_request,
|
||||
} => SendableEmbed {
|
||||
icon_url: Some(event.sender.avatar_url),
|
||||
url: Some(event.sender.html_url),
|
||||
title: Some(event.sender.login),
|
||||
description: Some(format!(
|
||||
"#### [[{}] Pull Request Reopened #{}: {}]({})",
|
||||
event.repository.full_name, number, pull_request.html_url, pull_request.title
|
||||
)),
|
||||
colour: Some(GREEN.to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
_ => return Ok(()),
|
||||
},
|
||||
};
|
||||
|
||||
let message_id = Ulid::new().to_string();
|
||||
|
||||
let embed = sendable_embed.into_embed(db, message_id.clone()).await?;
|
||||
let embed = sendable_embed
|
||||
.into_embed(legacy_db, message_id.clone())
|
||||
.await?;
|
||||
|
||||
let mut message = Message {
|
||||
id: message_id,
|
||||
author: webhook.id.clone(),
|
||||
channel: webhook.channel.clone(),
|
||||
channel: webhook.channel_id.clone(),
|
||||
embeds: Some(vec![embed]),
|
||||
webhook: Some(webhook.clone().into_message_webhook()),
|
||||
webhook: Some(std::convert::Into::<Webhook>::into(webhook.clone()).into()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
message.create(db, &channel, Some(MessageAuthor::Webhook(&webhook))).await
|
||||
message
|
||||
.create(
|
||||
legacy_db,
|
||||
&channel,
|
||||
Some(MessageAuthor::Webhook(&webhook.into())),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
use revolt_quark::{Db, Ref, Result, models::{Webhook, File}};
|
||||
use rocket::serde::json::Json;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
|
||||
// This route is used to get the info about the webhook by clients to get the name and avatar,
|
||||
// so this function cant return the token or require any permissions.
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct WebhookData {
|
||||
#[serde(rename = "_id")]
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub avatar: Option<File>,
|
||||
pub channel: String,
|
||||
}
|
||||
use revolt_database::Database;
|
||||
use revolt_models::v0::{ResponseWebhook, Webhook};
|
||||
use revolt_quark::{models::User, perms, Db, Error, Permission, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Gets a webhook
|
||||
///
|
||||
/// gets a webhook
|
||||
/// Gets a webhook
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[get("/<target>")]
|
||||
pub async fn webhook_fetch(db: &Db, target: Ref) -> Result<Json<WebhookData>> {
|
||||
let Webhook { id, name, avatar, channel, .. } = target.as_webhook(db).await?;
|
||||
#[get("/<webhook_id>")]
|
||||
pub async fn webhook_fetch(
|
||||
db: &State<Database>,
|
||||
legacy_db: &Db,
|
||||
webhook_id: String,
|
||||
user: User,
|
||||
) -> Result<Json<ResponseWebhook>> {
|
||||
let webhook = db
|
||||
.fetch_webhook(&webhook_id)
|
||||
.await
|
||||
.map_err(Error::from_core)?;
|
||||
|
||||
Ok(Json(WebhookData { id, name, avatar, channel }))
|
||||
let channel = legacy_db.fetch_channel(&webhook.channel_id).await?;
|
||||
|
||||
perms(&user)
|
||||
.channel(&channel)
|
||||
.throw_permission(legacy_db, Permission::ViewChannel)
|
||||
.await?;
|
||||
|
||||
Ok(Json(std::convert::Into::<Webhook>::into(webhook).into()))
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
use revolt_quark::{Db, Ref, Result, Error, models::Webhook};
|
||||
use rocket::serde::json::Json;
|
||||
use revolt_database::Database;
|
||||
use revolt_models::v0::Webhook;
|
||||
use revolt_result::Result;
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
/// # Gets a webhook
|
||||
///
|
||||
/// gets a webhook with a token
|
||||
/// Gets a webhook with a token
|
||||
#[openapi(tag = "Webhooks")]
|
||||
#[get("/<target>/<token>")]
|
||||
pub async fn webhook_fetch_token(db: &Db, target: Ref, token: String) -> Result<Json<Webhook>> {
|
||||
let webhook = target.as_webhook(db).await?;
|
||||
|
||||
(webhook.token.as_deref() == Some(&token))
|
||||
.then_some(())
|
||||
.ok_or(Error::InvalidCredentials)?;
|
||||
|
||||
Ok(Json(webhook))
|
||||
#[get("/<webhook_id>/<token>")]
|
||||
pub async fn webhook_fetch_token(
|
||||
db: &State<Database>,
|
||||
webhook_id: String,
|
||||
token: String,
|
||||
) -> Result<Json<Webhook>> {
|
||||
let webhook = db.fetch_webhook(&webhook_id).await?;
|
||||
webhook.assert_token(&token)?;
|
||||
Ok(Json(webhook.into()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user