forked from jmug/stoatchat
inital webhook support
This commit is contained in:
@@ -11,7 +11,7 @@ pub async fn req(db: &Db, user: User, target: Ref, msg: Ref) -> Result<EmptyResp
|
||||
return Err(Error::NotFound);
|
||||
}
|
||||
|
||||
if message.author != user.id {
|
||||
if message.author.as_deref().unwrap_or_default() != user.id {
|
||||
perms(&user)
|
||||
.channel(&target.as_channel(db).await?)
|
||||
.throw_permission(db, Permission::ManageMessages)
|
||||
|
||||
@@ -43,7 +43,7 @@ pub async fn req(
|
||||
return Err(Error::NotFound);
|
||||
}
|
||||
|
||||
if message.author != user.id {
|
||||
if message.author.as_deref().unwrap_or_default() != user.id {
|
||||
return Err(Error::CannotEditMessage);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use revolt_quark::{
|
||||
},
|
||||
perms,
|
||||
web::idempotency::IdempotencyKey,
|
||||
Db, Error, Permission, Ref, Result,
|
||||
Db, Error, Permission, Ref, Result, types::push::MessageAuthor,
|
||||
};
|
||||
|
||||
use regex::Regex;
|
||||
@@ -22,31 +22,31 @@ pub struct DataMessageSend {
|
||||
///
|
||||
/// **This is deprecated and replaced by `Idempotency-Key`!**
|
||||
#[validate(length(min = 1, max = 64))]
|
||||
nonce: Option<String>,
|
||||
pub nonce: Option<String>,
|
||||
|
||||
/// Message content to send
|
||||
#[validate(length(min = 0, max = 2000))]
|
||||
content: Option<String>,
|
||||
pub content: Option<String>,
|
||||
/// Attachments to include in message
|
||||
#[validate(length(min = 1, max = 128))]
|
||||
attachments: Option<Vec<String>>,
|
||||
pub attachments: Option<Vec<String>>,
|
||||
/// Messages to reply to
|
||||
replies: Option<Vec<Reply>>,
|
||||
pub replies: Option<Vec<Reply>>,
|
||||
/// Embeds to include in message
|
||||
///
|
||||
/// Text embed content contributes to the content length cap
|
||||
#[validate(length(min = 1, max = 10))]
|
||||
embeds: Option<Vec<SendableEmbed>>,
|
||||
pub embeds: Option<Vec<SendableEmbed>>,
|
||||
/// Masquerade to apply to this message
|
||||
#[validate]
|
||||
masquerade: Option<Masquerade>,
|
||||
pub masquerade: Option<Masquerade>,
|
||||
/// Information about how this message should be interacted with
|
||||
interactions: Option<Interactions>,
|
||||
pub interactions: Option<Interactions>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
// ignoring I L O and U is intentional
|
||||
static ref RE_MENTION: Regex = Regex::new(r"<@([0-9A-HJKMNP-TV-Z]{26})>").unwrap();
|
||||
pub static ref RE_MENTION: Regex = Regex::new(r"<@([0-9A-HJKMNP-TV-Z]{26})>").unwrap();
|
||||
}
|
||||
|
||||
/// # Send Message
|
||||
@@ -86,7 +86,7 @@ pub async fn message_send(
|
||||
let mut message = Message {
|
||||
id: message_id.clone(),
|
||||
channel: channel.id().to_string(),
|
||||
author: user.id.clone(),
|
||||
author: Some(user.id.clone()),
|
||||
masquerade: data.masquerade,
|
||||
interactions: data.interactions.unwrap_or_default(),
|
||||
..Default::default()
|
||||
@@ -128,11 +128,11 @@ pub async fn message_send(
|
||||
for Reply { id, mention } in entries {
|
||||
let message = Ref::from_unchecked(id).as_message(db).await?;
|
||||
|
||||
replies.insert(message.id);
|
||||
|
||||
if mention {
|
||||
mentions.insert(message.author);
|
||||
mentions.insert(message.author_id().to_owned());
|
||||
}
|
||||
|
||||
replies.insert(message.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ pub async fn message_send(
|
||||
// 8. Pass-through nonce value for clients
|
||||
message.nonce = Some(idempotency.into_key());
|
||||
|
||||
message.create(db, &channel, Some(&user)).await?;
|
||||
message.create(db, &channel, Some(MessageAuthor::User(&user))).await?;
|
||||
|
||||
// Queue up a task for processing embeds
|
||||
if let Some(content) = &message.content {
|
||||
|
||||
@@ -19,11 +19,13 @@ mod message_query;
|
||||
mod message_query_stale;
|
||||
mod message_react;
|
||||
mod message_search;
|
||||
mod message_send;
|
||||
pub mod message_send;
|
||||
mod message_unreact;
|
||||
mod permissions_set;
|
||||
mod permissions_set_default;
|
||||
mod voice_join;
|
||||
mod webhook_create;
|
||||
mod webhook_fetch_all;
|
||||
|
||||
pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
@@ -49,6 +51,8 @@ pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
permissions_set_default::req,
|
||||
message_react::react_message,
|
||||
message_unreact::unreact_message,
|
||||
message_clear_reactions::clear_reactions
|
||||
message_clear_reactions::clear_reactions,
|
||||
webhook_create::req,
|
||||
webhook_fetch_all::req,
|
||||
]
|
||||
}
|
||||
|
||||
50
crates/delta/src/routes/channels/webhook_create.rs
Normal file
50
crates/delta/src/routes/channels/webhook_create.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use revolt_quark::{models::{User, Webhook, File}, perms, Db, Error, Permission, Ref, Result};
|
||||
use rocket::serde::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Validate, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct CreateWebhookBody {
|
||||
#[validate(length(min = 1, max = 32))]
|
||||
name: String,
|
||||
|
||||
#[validate(length(min = 1, max = 128))]
|
||||
avatar: Option<String>
|
||||
}
|
||||
|
||||
/// # Creates a webhook
|
||||
///
|
||||
/// 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>> {
|
||||
let data = data.into_inner();
|
||||
data.validate()
|
||||
.map_err(|error| Error::FailedValidation { error })?;
|
||||
|
||||
let channel = target.as_channel(db).await?;
|
||||
let mut permissions = perms(&user).channel(&channel);
|
||||
permissions
|
||||
.has_permission(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
|
||||
};
|
||||
|
||||
let webhook = Webhook {
|
||||
id: webhook_id,
|
||||
name: data.name,
|
||||
avatar,
|
||||
channel: channel.id().to_string(),
|
||||
token: nanoid::nanoid!(64)
|
||||
};
|
||||
|
||||
webhook.create(db).await?;
|
||||
|
||||
Ok(Json(webhook))
|
||||
}
|
||||
19
crates/delta/src/routes/channels/webhook_fetch_all.rs
Normal file
19
crates/delta/src/routes/channels/webhook_fetch_all.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use revolt_quark::{models::{User, Webhook}, perms, Db, Permission, Ref, Result};
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
/// # Gets all webhooks
|
||||
///
|
||||
/// 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?;
|
||||
let mut permissions = perms(&user).channel(&channel);
|
||||
permissions
|
||||
.has_permission(db, Permission::ManageWebhooks)
|
||||
.await?;
|
||||
|
||||
let webhooks = db.fetch_webhooks_for_channel(channel.id()).await?;
|
||||
|
||||
Ok(Json(webhooks))
|
||||
}
|
||||
Reference in New Issue
Block a user