refactor: capture errors with line numbers

refactor: update file api
This commit is contained in:
Paul Makles
2024-09-29 14:37:08 +01:00
parent 4fd66b2719
commit 3080ec1f5a
22 changed files with 273 additions and 130 deletions

View File

@@ -14,6 +14,7 @@ use futures::{
FutureExt, SinkExt, StreamExt, TryStreamExt, FutureExt, SinkExt, StreamExt, TryStreamExt,
}; };
use redis_kiss::{PayloadType, REDIS_PAYLOAD_TYPE, REDIS_URI}; use redis_kiss::{PayloadType, REDIS_PAYLOAD_TYPE, REDIS_URI};
use revolt_config::report_internal_error;
use revolt_database::{ use revolt_database::{
events::{client::EventV1, server::ClientMessage}, events::{client::EventV1, server::ClientMessage},
Database, User, UserHint, Database, User, UserHint,
@@ -99,27 +100,21 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr)
let user_id = state.cache.user_id.clone(); let user_id = state.cache.user_id.clone();
// Notify socket we have authenticated. // Notify socket we have authenticated.
if let Err(err) = write.send(config.encode(&EventV1::Authenticated)).await { if report_internal_error!(write.send(config.encode(&EventV1::Authenticated)).await).is_err() {
error!("Failed to write: {err:?}");
sentry::capture_error(&err);
return; return;
} }
// Download required data to local cache and send Ready payload. // Download required data to local cache and send Ready payload.
let ready_payload = match state let ready_payload = match report_internal_error!(
.generate_ready_payload(db, config.get_ready_payload_fields()) state
.await .generate_ready_payload(db, config.get_ready_payload_fields())
{ .await
) {
Ok(ready_payload) => ready_payload, Ok(ready_payload) => ready_payload,
Err(err) => { Err(_) => return,
sentry::capture_error(&err);
return;
}
}; };
if let Err(err) = write.send(config.encode(&ready_payload)).await { if report_internal_error!(write.send(config.encode(&ready_payload)).await).is_err() {
error!("Failed to write: {err:?}");
sentry::capture_error(&err);
return; return;
} }
@@ -214,21 +209,16 @@ async fn listener(
write: &Mutex<WsWriter>, write: &Mutex<WsWriter>,
) { ) {
let redis_config = RedisConfig::from_url(&REDIS_URI).unwrap(); let redis_config = RedisConfig::from_url(&REDIS_URI).unwrap();
let subscriber = match fred::types::Builder::from_config(redis_config).build_subscriber_client() let subscriber = match report_internal_error!(
{ fred::types::Builder::from_config(redis_config).build_subscriber_client()
) {
Ok(subscriber) => subscriber, Ok(subscriber) => subscriber,
Err(err) => { Err(_) => return,
error!("Failed to build a subscriber: {err:?}");
sentry::capture_error(&err);
return;
}
}; };
if let Err(err) = subscriber.init().await { if report_internal_error!(subscriber.init().await).is_err() {
error!("Failed to init subscriber: {err:?}");
sentry::capture_error(&err);
return; return;
}; }
// Handle Redis connection dropping // Handle Redis connection dropping
let (clean_up_s, clean_up_r) = async_channel::bounded(1); let (clean_up_s, clean_up_r) = async_channel::bounded(1);
@@ -249,17 +239,13 @@ async fn listener(
// Check for state changes for subscriptions. // Check for state changes for subscriptions.
match state.apply_state().await { match state.apply_state().await {
SubscriptionStateChange::Reset => { SubscriptionStateChange::Reset => {
if let Err(err) = subscriber.unsubscribe_all().await { if report_internal_error!(subscriber.unsubscribe_all().await).is_err() {
error!("Unsubscribe all failed: {err:?}");
sentry::capture_error(&err);
break 'out; break 'out;
} }
let subscribed = state.subscribed.read().await; let subscribed = state.subscribed.read().await;
for id in subscribed.iter() { for id in subscribed.iter() {
if let Err(err) = subscriber.subscribe(id).await { if report_internal_error!(subscriber.subscribe(id).await).is_err() {
error!("Subscribe failed: {err:?}");
sentry::capture_error(&err);
break 'out; break 'out;
} }
} }
@@ -272,9 +258,7 @@ async fn listener(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
info!("{addr:?} unsubscribing from {id}"); info!("{addr:?} unsubscribing from {id}");
if let Err(err) = subscriber.unsubscribe(id).await { if report_internal_error!(subscriber.unsubscribe(id).await).is_err() {
error!("Unsubscribe failed: {err:?}");
sentry::capture_error(&err);
break 'out; break 'out;
} }
} }
@@ -283,9 +267,7 @@ async fn listener(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
info!("{addr:?} subscribing to {id}"); info!("{addr:?} subscribing to {id}");
if let Err(err) = subscriber.subscribe(id).await { if report_internal_error!(subscriber.subscribe(id).await).is_err() {
error!("Subscribe failed: {err:?}");
sentry::capture_error(&err);
break 'out; break 'out;
} }
} }
@@ -310,13 +292,9 @@ async fn listener(
_ = t2 => {}, _ = t2 => {},
message = t1 => { message = t1 => {
// Handle incoming events. // Handle incoming events.
let message = match message { let message = match report_internal_error!(message) {
Ok(message) => message, Ok(message) => message,
Err(e) => { Err(_) => break 'out
error!("Error while consuming pub/sub messages: {e:?}");
sentry::capture_error(&e);
break 'out;
}
}; };
let event = match *REDIS_PAYLOAD_TYPE { let event = match *REDIS_PAYLOAD_TYPE {
@@ -393,10 +371,7 @@ async fn listener(
} }
} }
if let Err(err) = subscriber.quit().await { report_internal_error!(subscriber.quit().await).ok();
error!("{}", err);
sentry::capture_error(&err);
}
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]

View File

@@ -6,7 +6,7 @@ use futures_locks::RwLock;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::Deserialize; use serde::Deserialize;
pub use sentry::capture_error; pub use sentry::{capture_error, capture_message, Level};
#[cfg(feature = "report-macros")] #[cfg(feature = "report-macros")]
#[macro_export] #[macro_export]
@@ -14,7 +14,10 @@ macro_rules! report_error {
( $expr: expr, $error: ident $( $tt:tt )? ) => { ( $expr: expr, $error: ident $( $tt:tt )? ) => {
$expr $expr
.inspect_err(|err| { .inspect_err(|err| {
$crate::capture_error(err); $crate::capture_message(
&format!("{err:?} ({}:{}:{})", file!(), line!(), column!()),
$crate::Level::Error,
);
}) })
.map_err(|_| ::revolt_result::create_error!($error)) .map_err(|_| ::revolt_result::create_error!($error))
}; };
@@ -26,7 +29,10 @@ macro_rules! report_internal_error {
( $expr: expr ) => { ( $expr: expr ) => {
$expr $expr
.inspect_err(|err| { .inspect_err(|err| {
$crate::capture_error(err); $crate::capture_message(
&format!("{err:?} ({}:{}:{})", file!(), line!(), column!()),
$crate::Level::Error,
);
}) })
.map_err(|_| ::revolt_result::create_error!(InternalError)) .map_err(|_| ::revolt_result::create_error!(InternalError))
}; };

View File

@@ -24,7 +24,9 @@ default = ["mongodb", "async-std-runtime", "tasks"]
[dependencies] [dependencies]
# Core # Core
revolt-config = { version = "0.7.16", path = "../config" } revolt-config = { version = "0.7.16", path = "../config", features = [
"report-macros",
] }
revolt-result = { version = "0.7.16", path = "../result" } revolt-result = { version = "0.7.16", path = "../result" }
revolt-models = { version = "0.7.16", path = "../models", features = [ revolt-models = { version = "0.7.16", path = "../models", features = [
"validator", "validator",

View File

@@ -5,7 +5,7 @@ use crate::{
bson::{doc, from_bson, from_document, to_document, Bson, DateTime, Document}, bson::{doc, from_bson, from_document, to_document, Bson, DateTime, Document},
options::FindOptions, options::FindOptions,
}, },
Invite, MongoDb, DISCRIMINATOR_SEARCH_SPACE, AbstractChannels, AbstractServers, Channel, Invite, MongoDb, DISCRIMINATOR_SEARCH_SPACE,
}; };
use bson::oid::ObjectId; use bson::oid::ObjectId;
use futures::StreamExt; use futures::StreamExt;
@@ -20,7 +20,7 @@ struct MigrationInfo {
revision: i32, revision: i32,
} }
pub const LATEST_REVISION: i32 = 29; pub const LATEST_REVISION: i32 = 30;
pub async fn migrate_database(db: &MongoDb) { pub async fn migrate_database(db: &MongoDb) {
let migrations = db.col::<Document>("migrations"); let migrations = db.col::<Document>("migrations");
@@ -1139,6 +1139,54 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
.expect("Failed to create attachment_hashes index."); .expect("Failed to create attachment_hashes index.");
} }
if revision <= 29 {
info!("Running migration [revision 29 / 29-09-2024]: Add creator_id to webhooks.");
#[derive(serde::Serialize, serde::Deserialize)]
struct WebhookShell {
_id: String,
channel_id: String,
}
let invites = db
.db()
.collection::<WebhookShell>("channel_webhooks")
.find(doc! {}, None)
.await
.expect("webhooks")
.filter_map(|s| async { s.ok() })
.collect::<Vec<WebhookShell>>()
.await;
for invite in invites {
let channel = db.fetch_channel(&invite.channel_id).await.expect("channel");
let creator_id = match channel {
Channel::Group { owner, .. } => owner,
Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => {
let server = db.fetch_server(&server).await.expect("server");
server.owner
}
_ => unreachable!("not server or group channel!"),
};
db.db()
.collection::<Document>("channel_webhooks")
.update_one(
doc! {
"_id": invite._id,
},
doc! {
"$set" : {
"creator_id": creator_id
}
},
None,
)
.await
.expect("update webhook");
}
}
// Need to migrate fields on attachments, change `user_id`, `object_id`, etc to `parent`. // Need to migrate fields on attachments, change `user_id`, `object_id`, etc to `parent`.
// Reminder to update LATEST_REVISION when adding new migrations. // Reminder to update LATEST_REVISION when adding new migrations.

View File

@@ -17,6 +17,9 @@ auto_derived_partial!(
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub avatar: Option<File>, pub avatar: Option<File>,
/// User that created this webhook
pub creator_id: String,
/// The channel this webhook belongs to /// The channel this webhook belongs to
pub channel_id: String, pub channel_id: String,
@@ -43,6 +46,7 @@ impl Default for Webhook {
id: Default::default(), id: Default::default(),
name: Default::default(), name: Default::default(),
avatar: None, avatar: None,
creator_id: Default::default(),
channel_id: Default::default(), channel_id: Default::default(),
permissions: Default::default(), permissions: Default::default(),
token: Default::default(), token: Default::default(),

View File

@@ -19,9 +19,11 @@ auto_derived_partial!(
/// When this file was uploaded /// When this file was uploaded
pub uploaded_at: Option<Timestamp>, // these are Option<>s to not break file uploads on legacy Autumn pub uploaded_at: Option<Timestamp>, // these are Option<>s to not break file uploads on legacy Autumn
/// ID of user who uploaded this file /// ID of user who uploaded this file
#[serde(skip_serializing_if = "Option::is_none")]
pub uploader_id: Option<String>, // these are Option<>s to not break file uploads on legacy Autumn pub uploader_id: Option<String>, // these are Option<>s to not break file uploads on legacy Autumn
/// What the file was used for /// What the file was used for
#[serde(skip_serializing_if = "Option::is_none")]
pub used_for: Option<FileUsedFor>, pub used_for: Option<FileUsedFor>,
/// Whether this file was deleted /// Whether this file was deleted
@@ -63,6 +65,7 @@ auto_derived!(
ServerBanner, ServerBanner,
Emoji, Emoji,
UserAvatar, UserAvatar,
WebhookAvatar,
UserProfileBackground, UserProfileBackground,
LegacyGroupIcon, LegacyGroupIcon,
ChannelIcon, ChannelIcon,
@@ -86,44 +89,154 @@ impl File {
} }
/// Use a file for a message attachment /// Use a file for a message attachment
pub async fn use_attachment(db: &Database, id: &str, parent: &str) -> Result<File> { pub async fn use_attachment(
db.find_and_use_attachment(id, "attachments", "message", parent) db: &Database,
.await id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"attachments",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::Message,
},
uploader_id.to_owned(),
)
.await
} }
/// Use a file for a user profile background /// Use a file for a user profile background
pub async fn use_background(db: &Database, id: &str, parent: &str) -> Result<File> { pub async fn use_background(
db.find_and_use_attachment(id, "backgrounds", "user", parent) db: &Database,
.await id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"backgrounds",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::UserProfileBackground,
},
uploader_id.to_owned(),
)
.await
} }
/// Use a file for a user avatar /// Use a file for a user avatar
pub async fn use_avatar(db: &Database, id: &str, parent: &str) -> Result<File> { pub async fn use_user_avatar(
db.find_and_use_attachment(id, "avatars", "user", parent) db: &Database,
.await id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"avatars",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::UserAvatar,
},
uploader_id.to_owned(),
)
.await
} }
/// Use a file for an icon /// Use a file for a webhook avatar
pub async fn use_icon(db: &Database, id: &str, parent: &str) -> Result<File> { pub async fn use_webhook_avatar(
db.find_and_use_attachment(id, "icons", "object", parent) db: &Database,
.await id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"avatars",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::WebhookAvatar,
},
uploader_id.to_owned(),
)
.await
} }
/// Use a file for a server icon /// Use a file for a server icon
pub async fn use_server_icon(db: &Database, id: &str, parent: &str) -> Result<File> { pub async fn use_server_icon(
db.find_and_use_attachment(id, "icons", "object", parent) db: &Database,
.await id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"icons",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::ServerIcon,
},
uploader_id.to_owned(),
)
.await
}
/// Use a file for a channel icon
pub async fn use_channel_icon(
db: &Database,
id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"icons",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::ChannelIcon,
},
uploader_id.to_owned(),
)
.await
} }
/// Use a file for a server banner /// Use a file for a server banner
pub async fn use_banner(db: &Database, id: &str, parent: &str) -> Result<File> { pub async fn use_server_banner(
db.find_and_use_attachment(id, "banners", "server", parent) db: &Database,
.await id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"banners",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::ServerBanner,
},
uploader_id.to_owned(),
)
.await
} }
/// Use a file for an emoji /// Use a file for an emoji
pub async fn use_emoji(db: &Database, id: &str, parent: &str) -> Result<File> { pub async fn use_emoji(
db.find_and_use_attachment(id, "emojis", "object", parent) db: &Database,
.await id: &str,
parent: &str,
uploader_id: &str,
) -> Result<File> {
db.find_and_use_attachment(
id,
"emojis",
FileUsedFor {
id: parent.to_owned(),
object_type: FileUsedForType::Emoji,
},
uploader_id.to_owned(),
)
.await
} }
} }

View File

@@ -2,6 +2,8 @@ use revolt_result::Result;
use crate::File; use crate::File;
use super::FileUsedFor;
mod mongodb; mod mongodb;
mod reference; mod reference;
@@ -18,8 +20,8 @@ pub trait AbstractAttachments: Sync + Send {
&self, &self,
id: &str, id: &str,
tag: &str, tag: &str,
parent_type: &str, used_for: FileUsedFor,
parent_id: &str, uploader_id: String,
) -> Result<File>; ) -> Result<File>;
/// Mark an attachment as having been reported. /// Mark an attachment as having been reported.

View File

@@ -1,7 +1,10 @@
use bson::to_document;
use bson::Document; use bson::Document;
use revolt_config::report_internal_error;
use revolt_result::Result; use revolt_result::Result;
use crate::File; use crate::File;
use crate::FileUsedFor;
use crate::MongoDb; use crate::MongoDb;
use super::AbstractAttachments; use super::AbstractAttachments;
@@ -34,10 +37,9 @@ impl AbstractAttachments for MongoDb {
&self, &self,
id: &str, id: &str,
tag: &str, tag: &str,
parent_type: &str, used_for: FileUsedFor,
parent_id: &str, uploader_id: String,
) -> Result<File> { ) -> Result<File> {
let key = format!("{parent_type}_id");
let file = query!( let file = query!(
self, self,
find_one, find_one,
@@ -45,7 +47,7 @@ impl AbstractAttachments for MongoDb {
doc! { doc! {
"_id": id, "_id": id,
"tag": tag, "tag": tag,
&key: { "used_for": {
"$exists": false "$exists": false
} }
} }
@@ -59,7 +61,8 @@ impl AbstractAttachments for MongoDb {
}, },
doc! { doc! {
"$set": { "$set": {
key: parent_id "used_for": report_internal_error!(to_document(&used_for))?,
"uploader_id": uploader_id
} }
}, },
None, None,

View File

@@ -1,6 +1,7 @@
use revolt_result::Result; use revolt_result::Result;
use crate::File; use crate::File;
use crate::FileUsedFor;
use crate::ReferenceDb; use crate::ReferenceDb;
use super::AbstractAttachments; use super::AbstractAttachments;
@@ -37,19 +38,14 @@ impl AbstractAttachments for ReferenceDb {
&self, &self,
id: &str, id: &str,
tag: &str, tag: &str,
parent_type: &str, used_for: FileUsedFor,
parent_id: &str, uploader_id: String,
) -> Result<File> { ) -> Result<File> {
let mut files = self.files.lock().await; let mut files = self.files.lock().await;
if let Some(file) = files.get_mut(id) { if let Some(file) = files.get_mut(id) {
if file.tag == tag { if file.tag == tag {
match parent_type { file.uploader_id = Some(uploader_id);
"message" => file.message_id = Some(parent_id.to_owned()), file.used_for = Some(used_for);
"user" => file.user_id = Some(parent_id.to_owned()),
"object" => file.object_id = Some(parent_id.to_owned()),
"server" => file.server_id = Some(parent_id.to_owned()),
_ => unreachable!(),
}
Ok(file.clone()) Ok(file.clone())
} else { } else {

View File

@@ -370,10 +370,8 @@ impl Message {
} }
for attachment_id in data.attachments.as_deref().unwrap_or_default() { for attachment_id in data.attachments.as_deref().unwrap_or_default() {
attachments.push( attachments
db.find_and_use_attachment(attachment_id, "attachments", "message", &message_id) .push(File::use_attachment(db, attachment_id, &message_id, author.id()).await?);
.await?,
);
} }
if !attachments.is_empty() { if !attachments.is_empty() {
@@ -499,10 +497,7 @@ impl Message {
})?; })?;
let media = if let Some(id) = embed.media { let media = if let Some(id) = embed.media {
Some( Some(File::use_attachment(db, &id, &self.id, &self.author).await?)
db.find_and_use_attachment(&id, "attachments", "message", &self.id)
.await?,
)
} else { } else {
None None
}; };
@@ -661,7 +656,7 @@ impl Message {
) -> Result<()> { ) -> Result<()> {
let media: Option<v0::File> = if let Some(id) = embed.media { let media: Option<v0::File> = if let Some(id) = embed.media {
Some( Some(
db.find_and_use_attachment(&id, "attachments", "message", &self.id) File::use_attachment(db, &id, &self.id, &self.author)
.await? .await?
.into(), .into(),
) )

View File

@@ -20,6 +20,7 @@ use crate::Database;
/// Payload information, before assembly /// Payload information, before assembly
#[derive(Debug)] #[derive(Debug)]
#[allow(non_snake_case)]
pub struct ApnPayload { pub struct ApnPayload {
message: Message, message: Message,
url: String, url: String,
@@ -29,6 +30,7 @@ pub struct ApnPayload {
} }
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct Payload<'a> { struct Payload<'a> {
aps: APS<'a>, aps: APS<'a>,
#[serde(skip_serializing)] #[serde(skip_serializing)]

View File

@@ -11,7 +11,7 @@ use base64::{
use deadqueue::limited::Queue; use deadqueue::limited::Queue;
use fcm_v1::auth::{Authenticator, ServiceAccountKey}; use fcm_v1::auth::{Authenticator, ServiceAccountKey};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use revolt_config::config; use revolt_config::{config, report_internal_error};
use revolt_models::v0::PushNotification; use revolt_models::v0::PushNotification;
use revolt_presence::filter_online; use revolt_presence::filter_online;
use serde_json::json; use serde_json::json;
@@ -116,12 +116,11 @@ pub async fn worker(db: Database, authifier_db: AuthifierDatabase) {
if fcm_error.contains("404 (Not Found)") { if fcm_error.contains("404 (Not Found)") {
println!("Unregistering {:?}", session.id); println!("Unregistering {:?}", session.id);
if let Err(err) = db report_internal_error!(
.remove_push_subscription_by_session_id(&session.id) db.remove_push_subscription_by_session_id(&session.id)
.await .await
{ )
revolt_config::capture_error(&err); .ok();
}
} }
} }
} else { } else {

View File

@@ -108,6 +108,7 @@ impl From<crate::Webhook> for Webhook {
id: value.id, id: value.id,
name: value.name, name: value.name,
avatar: value.avatar.map(|file| file.into()), avatar: value.avatar.map(|file| file.into()),
creator_id: value.creator_id,
channel_id: value.channel_id, channel_id: value.channel_id,
token: value.token, token: value.token,
permissions: value.permissions, permissions: value.permissions,
@@ -121,6 +122,7 @@ impl From<crate::PartialWebhook> for PartialWebhook {
id: value.id, id: value.id,
name: value.name, name: value.name,
avatar: value.avatar.map(|file| file.into()), avatar: value.avatar.map(|file| file.into()),
creator_id: value.creator_id,
channel_id: value.channel_id, channel_id: value.channel_id,
token: value.token, token: value.token,
permissions: value.permissions, permissions: value.permissions,

View File

@@ -16,6 +16,9 @@ auto_derived_partial!(
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub avatar: Option<File>, pub avatar: Option<File>,
/// User that created this webhook
pub creator_id: String,
/// The channel this webhook belongs to /// The channel this webhook belongs to
pub channel_id: String, pub channel_id: String,

View File

@@ -124,7 +124,7 @@ pub async fn edit(
} }
if let Some(icon_id) = data.icon { if let Some(icon_id) = data.icon {
partial.icon = Some(File::use_icon(db, &icon_id, id).await?); partial.icon = Some(File::use_channel_icon(db, &icon_id, id, &user.id).await?);
*icon = partial.icon.clone(); *icon = partial.icon.clone();
} }

View File

@@ -1,6 +1,6 @@
use revolt_database::{ use revolt_database::{
util::{permissions::DatabasePermissionQuery, reference::Reference}, util::{permissions::DatabasePermissionQuery, reference::Reference},
Channel, Database, User, Webhook, Channel, Database, File, User, Webhook,
}; };
use revolt_models::v0; use revolt_models::v0;
use revolt_permissions::{ use revolt_permissions::{
@@ -43,10 +43,7 @@ pub async fn create_webhook(
let webhook_id = Ulid::new().to_string(); let webhook_id = Ulid::new().to_string();
let avatar = match &data.avatar { let avatar = match &data.avatar {
Some(id) => Some( Some(id) => Some(File::use_webhook_avatar(db, id, &webhook_id, &user.id).await?),
db.find_and_use_attachment(id, "avatars", "user", &webhook_id)
.await?,
),
None => None, None => None,
}; };
@@ -54,6 +51,7 @@ pub async fn create_webhook(
id: webhook_id, id: webhook_id,
name: data.name, name: data.name,
avatar, avatar,
creator_id: user.id,
channel_id: channel.id().to_string(), channel_id: channel.id().to_string(),
permissions: *DEFAULT_WEBHOOK_PERMISSIONS, permissions: *DEFAULT_WEBHOOK_PERMISSIONS,
token: Some(nanoid::nanoid!(64)), token: Some(nanoid::nanoid!(64)),

View File

@@ -55,7 +55,7 @@ pub async fn create_emoji(
}; };
// Find the relevant attachment // Find the relevant attachment
let attachment = File::use_emoji(db, &id, &id).await?; let attachment = File::use_emoji(db, &id, &id, &user.id).await?;
// Create the emoji object // Create the emoji object
let emoji = Emoji { let emoji = Emoji {

View File

@@ -142,7 +142,7 @@ pub async fn edit(
// 2. Apply new avatar // 2. Apply new avatar
if let Some(avatar) = avatar { if let Some(avatar) = avatar {
partial.avatar = Some(File::use_avatar(db, &avatar, &user.id).await?); partial.avatar = Some(File::use_user_avatar(db, &avatar, &user.id, &user.id).await?);
} }
member member

View File

@@ -138,13 +138,13 @@ pub async fn edit(
// 3. Apply new icon // 3. Apply new icon
if let Some(icon) = icon { if let Some(icon) = icon {
partial.icon = Some(File::use_server_icon(db, &icon, &server.id).await?); partial.icon = Some(File::use_server_icon(db, &icon, &server.id, &user.id).await?);
server.icon = partial.icon.clone(); server.icon = partial.icon.clone();
} }
// 4. Apply new banner // 4. Apply new banner
if let Some(banner) = banner { if let Some(banner) = banner {
partial.banner = Some(File::use_banner(db, &banner, &server.id).await?); partial.banner = Some(File::use_server_banner(db, &banner, &server.id, &user.id).await?);
server.banner = partial.banner.clone(); server.banner = partial.banner.clone();
} }

View File

@@ -89,7 +89,7 @@ pub async fn edit(
// 2. Apply new avatar // 2. Apply new avatar
if let Some(avatar) = data.avatar { if let Some(avatar) = data.avatar {
partial.avatar = Some(File::use_avatar(db, &avatar, &user.id).await?); partial.avatar = Some(File::use_user_avatar(db, &avatar, &user.id, &user.id).await?);
} }
// 3. Apply new status // 3. Apply new status
@@ -114,7 +114,8 @@ pub async fn edit(
} }
if let Some(background) = profile.background { if let Some(background) = profile.background {
new_profile.background = Some(File::use_background(db, &background, &user.id).await?); new_profile.background =
Some(File::use_background(db, &background, &user.id, &user.id).await?);
} }
partial.profile = Some(new_profile); partial.profile = Some(new_profile);

View File

@@ -1,6 +1,6 @@
use revolt_database::{ use revolt_database::{
util::{permissions::DatabasePermissionQuery, reference::Reference}, util::{permissions::DatabasePermissionQuery, reference::Reference},
Database, PartialWebhook, User, Database, File, PartialWebhook, User,
}; };
use revolt_models::v0::{DataEditWebhook, Webhook}; use revolt_models::v0::{DataEditWebhook, Webhook};
use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
@@ -52,10 +52,7 @@ pub async fn webhook_edit(
}; };
if let Some(avatar) = avatar { if let Some(avatar) = avatar {
let file = db let file = File::use_webhook_avatar(db, &avatar, &webhook.id, &webhook.creator_id).await?;
.find_and_use_attachment(&avatar, "avatars", "user", &webhook.id)
.await?;
partial.avatar = Some(file) partial.avatar = Some(file)
} }

View File

@@ -1,5 +1,5 @@
use revolt_database::util::reference::Reference; use revolt_database::util::reference::Reference;
use revolt_database::{Database, PartialWebhook}; use revolt_database::{Database, File, PartialWebhook};
use revolt_models::v0::{DataEditWebhook, Webhook}; use revolt_models::v0::{DataEditWebhook, Webhook};
use revolt_models::validator::Validate; use revolt_models::validator::Validate;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
@@ -34,7 +34,7 @@ pub async fn webhook_edit_token(
name, name,
avatar, avatar,
permissions, permissions,
remove remove,
} = data; } = data;
let mut partial = PartialWebhook { let mut partial = PartialWebhook {
@@ -44,10 +44,7 @@ pub async fn webhook_edit_token(
}; };
if let Some(avatar) = avatar { if let Some(avatar) = avatar {
let file = db let file = File::use_webhook_avatar(db, &avatar, &webhook.id, &webhook.creator_id).await?;
.find_and_use_attachment(&avatar, "avatars", "user", &webhook.id)
.await?;
partial.avatar = Some(file) partial.avatar = Some(file)
} }