Add a way to send messages with attachments.
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
target
|
target
|
||||||
|
.mongo
|
||||||
.env
|
.env
|
||||||
21
src/database/entities/autumn.rs
Normal file
21
src/database/entities/autumn.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
enum Metadata {
|
||||||
|
File,
|
||||||
|
Image { width: isize, height: isize },
|
||||||
|
Video { width: isize, height: isize },
|
||||||
|
Audio,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct File {
|
||||||
|
#[serde(rename = "_id")]
|
||||||
|
pub id: String,
|
||||||
|
filename: String,
|
||||||
|
metadata: Metadata,
|
||||||
|
content_type: String,
|
||||||
|
|
||||||
|
message_id: Option<String>
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ pub struct Message {
|
|||||||
|
|
||||||
pub content: String,
|
pub content: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub attachment: Option<File>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub edited: Option<DateTime>,
|
pub edited: Option<DateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +33,7 @@ impl Message {
|
|||||||
author,
|
author,
|
||||||
|
|
||||||
content,
|
content,
|
||||||
|
attachment: None,
|
||||||
edited: None,
|
edited: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ mod channel;
|
|||||||
mod guild;
|
mod guild;
|
||||||
mod message;
|
mod message;
|
||||||
mod user;
|
mod user;
|
||||||
|
mod autumn;
|
||||||
|
|
||||||
pub use channel::*;
|
pub use channel::*;
|
||||||
pub use guild::*;
|
pub use guild::*;
|
||||||
pub use message::*;
|
pub use message::*;
|
||||||
pub use user::*;
|
pub use user::*;
|
||||||
|
pub use autumn::*;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::database::*;
|
use crate::database::*;
|
||||||
use crate::util::result::{Error, Result};
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
use mongodb::bson::doc;
|
use mongodb::{bson::{doc, from_document}, options::FindOneOptions};
|
||||||
use rocket_contrib::json::{Json, JsonValue};
|
use rocket_contrib::json::{Json, JsonValue};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
@@ -14,6 +14,8 @@ pub struct Data {
|
|||||||
// Maximum length of 36 allows both ULIDs and UUIDs.
|
// Maximum length of 36 allows both ULIDs and UUIDs.
|
||||||
#[validate(length(min = 1, max = 36))]
|
#[validate(length(min = 1, max = 36))]
|
||||||
nonce: String,
|
nonce: String,
|
||||||
|
#[validate(length(min = 1, max = 128))]
|
||||||
|
attachment: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/<target>/messages", data = "<message>")]
|
#[post("/<target>/messages", data = "<message>")]
|
||||||
@@ -37,7 +39,9 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<JsonVal
|
|||||||
doc! {
|
doc! {
|
||||||
"nonce": &message.nonce
|
"nonce": &message.nonce
|
||||||
},
|
},
|
||||||
None,
|
FindOneOptions::builder()
|
||||||
|
.projection(doc! { "_id": 1 })
|
||||||
|
.build()
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Error::DatabaseError {
|
.map_err(|_| Error::DatabaseError {
|
||||||
@@ -49,12 +53,56 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<JsonVal
|
|||||||
Err(Error::DuplicateNonce)?
|
Err(Error::DuplicateNonce)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let id = Ulid::new().to_string();
|
||||||
|
let attachments = get_collection("attachments");
|
||||||
|
let attachment = if let Some(attachment_id) = &message.attachment {
|
||||||
|
if let Some(doc) = attachments
|
||||||
|
.find_one(
|
||||||
|
doc! {
|
||||||
|
"_id": attachment_id,
|
||||||
|
"message_id": {
|
||||||
|
"$exists": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find_one",
|
||||||
|
with: "attachment",
|
||||||
|
})? {
|
||||||
|
let attachment = from_document::<File>(doc)
|
||||||
|
.map_err(|_| Error::DatabaseError { operation: "from_document", with: "attachment" })?;
|
||||||
|
|
||||||
|
attachments.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": &attachment.id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$set": {
|
||||||
|
"message_id": &id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError { operation: "update_one", with: "attachment" })?;
|
||||||
|
|
||||||
|
Some(attachment)
|
||||||
|
} else {
|
||||||
|
return Err(Error::UnknownAttachment)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let msg = Message {
|
let msg = Message {
|
||||||
id: Ulid::new().to_string(),
|
id,
|
||||||
channel: target.id().to_string(),
|
channel: target.id().to_string(),
|
||||||
author: user.id,
|
author: user.id,
|
||||||
|
|
||||||
content: message.content.clone(),
|
content: message.content.clone(),
|
||||||
|
attachment,
|
||||||
nonce: Some(message.nonce.clone()),
|
nonce: Some(message.nonce.clone()),
|
||||||
edited: None,
|
edited: None,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::util::variables::{
|
use crate::util::variables::{
|
||||||
DISABLE_REGISTRATION, EXTERNAL_WS_URL, HCAPTCHA_SITEKEY, INVITE_ONLY, USE_EMAIL, USE_HCAPTCHA,
|
DISABLE_REGISTRATION, EXTERNAL_WS_URL, HCAPTCHA_SITEKEY, INVITE_ONLY, USE_EMAIL, USE_HCAPTCHA, USE_AUTUMN, AUTUMN_URL
|
||||||
};
|
};
|
||||||
|
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
@@ -16,7 +16,11 @@ pub async fn root() -> JsonValue {
|
|||||||
"key": HCAPTCHA_SITEKEY.to_string()
|
"key": HCAPTCHA_SITEKEY.to_string()
|
||||||
},
|
},
|
||||||
"email": *USE_EMAIL,
|
"email": *USE_EMAIL,
|
||||||
"invite_only": *INVITE_ONLY
|
"invite_only": *INVITE_ONLY,
|
||||||
|
"autumn": {
|
||||||
|
"enabled": *USE_AUTUMN,
|
||||||
|
"url": *AUTUMN_URL
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"ws": *EXTERNAL_WS_URL,
|
"ws": *EXTERNAL_WS_URL,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ pub enum Error {
|
|||||||
// ? Channel related errors.
|
// ? Channel related errors.
|
||||||
#[snafu(display("This channel does not exist!"))]
|
#[snafu(display("This channel does not exist!"))]
|
||||||
UnknownChannel,
|
UnknownChannel,
|
||||||
|
#[snafu(display("Attachment does not exist!"))]
|
||||||
|
UnknownAttachment,
|
||||||
#[snafu(display("Cannot edit someone else's message."))]
|
#[snafu(display("Cannot edit someone else's message."))]
|
||||||
CannotEditMessage,
|
CannotEditMessage,
|
||||||
#[snafu(display("Cannot remove yourself from a group, use delete channel instead."))]
|
#[snafu(display("Cannot remove yourself from a group, use delete channel instead."))]
|
||||||
@@ -84,6 +86,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
Error::NotFriends => Status::Forbidden,
|
Error::NotFriends => Status::Forbidden,
|
||||||
|
|
||||||
Error::UnknownChannel => Status::NotFound,
|
Error::UnknownChannel => Status::NotFound,
|
||||||
|
Error::UnknownAttachment => Status::BadRequest,
|
||||||
Error::CannotEditMessage => Status::Forbidden,
|
Error::CannotEditMessage => Status::Forbidden,
|
||||||
Error::CannotRemoveYourself => Status::BadRequest,
|
Error::CannotRemoveYourself => Status::BadRequest,
|
||||||
Error::GroupTooLarge { .. } => Status::Forbidden,
|
Error::GroupTooLarge { .. } => Status::Forbidden,
|
||||||
|
|||||||
@@ -7,18 +7,20 @@ lazy_static! {
|
|||||||
// Application Settings
|
// Application Settings
|
||||||
pub static ref MONGO_URI: String =
|
pub static ref MONGO_URI: String =
|
||||||
env::var("REVOLT_MONGO_URI").expect("Missing REVOLT_MONGO_URI environment variable.");
|
env::var("REVOLT_MONGO_URI").expect("Missing REVOLT_MONGO_URI environment variable.");
|
||||||
|
pub static ref WS_HOST: String =
|
||||||
|
env::var("REVOLT_WS_HOST").unwrap_or_else(|_| "0.0.0.0:9000".to_string());
|
||||||
pub static ref PUBLIC_URL: String =
|
pub static ref PUBLIC_URL: String =
|
||||||
env::var("REVOLT_PUBLIC_URL").expect("Missing REVOLT_PUBLIC_URL environment variable.");
|
env::var("REVOLT_PUBLIC_URL").expect("Missing REVOLT_PUBLIC_URL environment variable.");
|
||||||
pub static ref APP_URL: String =
|
pub static ref APP_URL: String =
|
||||||
env::var("REVOLT_APP_URL").unwrap_or_else(|_| "https://app.revolt.chat".to_string());
|
env::var("REVOLT_APP_URL").unwrap_or_else(|_| "https://app.revolt.chat".to_string());
|
||||||
pub static ref EXTERNAL_WS_URL: String =
|
pub static ref EXTERNAL_WS_URL: String =
|
||||||
env::var("REVOLT_EXTERNAL_WS_URL").expect("Missing REVOLT_EXTERNAL_WS_URL environment variable.");
|
env::var("REVOLT_EXTERNAL_WS_URL").expect("Missing REVOLT_EXTERNAL_WS_URL environment variable.");
|
||||||
|
pub static ref AUTUMN_URL: String =
|
||||||
|
env::var("AUTUMN_PUBLIC_URL").unwrap_or_else(|_| "https://example.com".to_string());
|
||||||
pub static ref HCAPTCHA_KEY: String =
|
pub static ref HCAPTCHA_KEY: String =
|
||||||
env::var("REVOLT_HCAPTCHA_KEY").unwrap_or_else(|_| "0x0000000000000000000000000000000000000000".to_string());
|
env::var("REVOLT_HCAPTCHA_KEY").unwrap_or_else(|_| "0x0000000000000000000000000000000000000000".to_string());
|
||||||
pub static ref HCAPTCHA_SITEKEY: String =
|
pub static ref HCAPTCHA_SITEKEY: String =
|
||||||
env::var("REVOLT_HCAPTCHA_SITEKEY").unwrap_or_else(|_| "10000000-ffff-ffff-ffff-000000000001".to_string());
|
env::var("REVOLT_HCAPTCHA_SITEKEY").unwrap_or_else(|_| "10000000-ffff-ffff-ffff-000000000001".to_string());
|
||||||
pub static ref WS_HOST: String =
|
|
||||||
env::var("REVOLT_WS_HOST").unwrap_or_else(|_| "0.0.0.0:9000".to_string());
|
|
||||||
|
|
||||||
// Application Flags
|
// Application Flags
|
||||||
pub static ref DISABLE_REGISTRATION: bool = env::var("REVOLT_DISABLE_REGISTRATION").map_or(false, |v| v == "1");
|
pub static ref DISABLE_REGISTRATION: bool = env::var("REVOLT_DISABLE_REGISTRATION").map_or(false, |v| v == "1");
|
||||||
@@ -32,6 +34,7 @@ lazy_static! {
|
|||||||
);
|
);
|
||||||
pub static ref USE_HCAPTCHA: bool = env::var("REVOLT_HCAPTCHA_KEY").is_ok();
|
pub static ref USE_HCAPTCHA: bool = env::var("REVOLT_HCAPTCHA_KEY").is_ok();
|
||||||
pub static ref USE_PROMETHEUS: bool = env::var("REVOLT_ENABLE_PROMETHEUS").map_or(false, |v| v == "1");
|
pub static ref USE_PROMETHEUS: bool = env::var("REVOLT_ENABLE_PROMETHEUS").map_or(false, |v| v == "1");
|
||||||
|
pub static ref USE_AUTUMN: bool = env::var("AUTUMN_PUBLIC_URL").is_ok();
|
||||||
|
|
||||||
// SMTP Settings
|
// SMTP Settings
|
||||||
pub static ref SMTP_HOST: String =
|
pub static ref SMTP_HOST: String =
|
||||||
|
|||||||
Reference in New Issue
Block a user