forked from jmug/stoatchat
Feat: Push notification server (#387)
* feat: create base of push daemon Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> * Add outbound senders * Make web_push send to rabbit instead (temp stuff) * feat: stability and friend requests * make vapid fr stuff not suck * swap naming of queue * move pushd into daemons folder * fix cargo file for move into daemons folder * feat: probably working fcm push notifs * comment out fcm webpush stuff since the config keys dont exist * fix fcm, name queues according to their prod status and configure routing keys * add pushd to docker * mix: Remove old code, add stuff to pushd * fix: lockfile * feat: update rocket to 5.0.1 * fix: fix queues and ack bugs * Move rabbit messsage processing into ack queue * chore: update readme * chore: optimizations for ack database hits * pushd flowchart * misc: update flowchart * exit dependancy hell * add rocket_impl flag to authifier * make the tests file of delta actually compile * fix: don't silence every push message * fix: don't silence all messages * add debug logging for sending data to rabbit from message events * validate mentions at a server membership level * put back that import that was actually important * minor fix to lockfile * update delta authifier * feat: proper permissions for push notifications * add unit test for mention sanitization * remove local file dependancy on authifier * update ports to proper defaults * fixTM the node bindings * Theoretically configure docker releases for pushd Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> * declare exchange in pushd and delta * fix createbuckets script Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> * fix: reference db implementation Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> * fix: remove finally redundant code Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> * fix: changes Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> * fix: other changes Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> * fix: make channel name return result Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> --------- Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com>
This commit is contained in:
@@ -52,20 +52,21 @@ async-std = { version = "1.8.0", features = [
|
||||
lettre = "0.10.0-alpha.4"
|
||||
|
||||
# web
|
||||
rocket = { version = "0.5.0-rc.2", default-features = false, features = [
|
||||
"json",
|
||||
] }
|
||||
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "c17e8145baa4790319fdb6a473e465b960f55e7c" }
|
||||
rocket = { version = "0.5.1", default-features = false, features = ["json"] }
|
||||
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "072d90359b23e9b291df6b672c07c93de9c46011" }
|
||||
rocket_empty = { version = "0.1.1", features = ["schema"] }
|
||||
rocket_authifier = { version = "1.0.8" }
|
||||
rocket_authifier = { version = "1.0.9" }
|
||||
rocket_prometheus = "0.10.0-rc.3"
|
||||
|
||||
# spec generation
|
||||
schemars = "0.8.8"
|
||||
revolt_rocket_okapi = { version = "0.9.1", features = ["swagger"] }
|
||||
revolt_rocket_okapi = { version = "0.10.0", features = ["swagger"] }
|
||||
|
||||
# rabbit
|
||||
amqprs = { version = "1.7.0" }
|
||||
|
||||
# core
|
||||
authifier = "1.0.8"
|
||||
authifier = "1.0.9"
|
||||
revolt-config = { path = "../core/config" }
|
||||
revolt-database = { path = "../core/database", features = [
|
||||
"rocket-impl",
|
||||
|
||||
@@ -10,12 +10,17 @@ pub mod util;
|
||||
|
||||
use revolt_config::config;
|
||||
use revolt_database::events::client::EventV1;
|
||||
use revolt_database::AMQP;
|
||||
use rocket::{Build, Rocket};
|
||||
use rocket_cors::{AllowedOrigins, CorsOptions};
|
||||
use rocket_prometheus::PrometheusMetrics;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use amqprs::{
|
||||
channel::ExchangeDeclareArguments,
|
||||
connection::{Connection, OpenConnectionArguments},
|
||||
};
|
||||
use async_std::channel::unbounded;
|
||||
use authifier::AuthifierEvent;
|
||||
use rocket::data::ToByteUnit;
|
||||
@@ -32,7 +37,7 @@ pub async fn web() -> Rocket<Build> {
|
||||
db.migrate_database().await.unwrap();
|
||||
|
||||
// Setup Authifier event channel
|
||||
let (sender, receiver) = unbounded();
|
||||
let (_, receiver) = unbounded();
|
||||
|
||||
// Setup Authifier
|
||||
let authifier = db.clone().to_authifier().await;
|
||||
@@ -53,9 +58,6 @@ pub async fn web() -> Rocket<Build> {
|
||||
}
|
||||
});
|
||||
|
||||
// Launch background task workers
|
||||
revolt_database::tasks::start_workers(db.clone(), authifier.database.clone());
|
||||
|
||||
// Configure CORS
|
||||
let cors = CorsOptions {
|
||||
allowed_origins: AllowedOrigins::All,
|
||||
@@ -79,6 +81,31 @@ pub async fn web() -> Rocket<Build> {
|
||||
)
|
||||
.into();
|
||||
|
||||
// Configure Rabbit
|
||||
let connection = Connection::open(&OpenConnectionArguments::new(
|
||||
&config.rabbit.host,
|
||||
config.rabbit.port,
|
||||
&config.rabbit.username,
|
||||
&config.rabbit.password,
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
let channel = connection.open_channel(None).await.unwrap();
|
||||
|
||||
channel
|
||||
.exchange_declare(
|
||||
ExchangeDeclareArguments::new(&config.pushd.exchange, "direct")
|
||||
.durable(true)
|
||||
.finish(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to declare exchange");
|
||||
|
||||
let amqp = AMQP::new(connection, channel);
|
||||
|
||||
// Launch background task workers
|
||||
revolt_database::tasks::start_workers(db.clone(), amqp.clone());
|
||||
|
||||
// Configure Rocket
|
||||
let rocket = rocket::build();
|
||||
let prometheus = PrometheusMetrics::new();
|
||||
@@ -91,6 +118,7 @@ pub async fn web() -> Rocket<Build> {
|
||||
.mount("/swagger/", swagger)
|
||||
.manage(authifier)
|
||||
.manage(db)
|
||||
.manage(amqp)
|
||||
.manage(cors.clone())
|
||||
.attach(util::ratelimiter::RatelimitFairing)
|
||||
.attach(cors)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::util::permissions::DatabasePermissionQuery;
|
||||
use revolt_database::Member;
|
||||
use revolt_database::{util::reference::Reference, Database, User};
|
||||
use revolt_database::{Member, AMQP};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{
|
||||
calculate_channel_permissions, calculate_server_permissions, ChannelPermission,
|
||||
@@ -18,6 +18,7 @@ use rocket_empty::EmptyResponse;
|
||||
#[post("/<target>/invite", data = "<dest>")]
|
||||
pub async fn invite_bot(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
dest: Json<v0::InviteBotDestination>,
|
||||
@@ -55,7 +56,7 @@ pub async fn invite_bot(
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::InviteOthers)?;
|
||||
|
||||
channel
|
||||
.add_user_to_group(db, &bot_user, &user.id)
|
||||
.add_user_to_group(db, amqp, &bot_user, &user.id)
|
||||
.await
|
||||
.map(|_| EmptyResponse)
|
||||
}
|
||||
@@ -93,9 +94,12 @@ mod test {
|
||||
.client
|
||||
.post(format!("/bots/{}/invite", bot.id))
|
||||
.header(ContentType::JSON)
|
||||
.body(json!(v0::InviteBotDestination::Group {
|
||||
group: group.id().to_string()
|
||||
}).to_string())
|
||||
.body(
|
||||
json!(v0::InviteBotDestination::Group {
|
||||
group: group.id().to_string()
|
||||
})
|
||||
.to_string(),
|
||||
)
|
||||
.header(Header::new("x-session-token", session.token.to_string()))
|
||||
.dispatch()
|
||||
.await;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Channel, Database, PartialChannel, User,
|
||||
Channel, Database, PartialChannel, User, AMQP,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -15,6 +15,7 @@ use rocket_empty::EmptyResponse;
|
||||
#[delete("/<target>?<options..>")]
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
options: v0::OptionsChannelDelete,
|
||||
@@ -39,7 +40,13 @@ pub async fn delete(
|
||||
.await
|
||||
.map(|_| EmptyResponse),
|
||||
Channel::Group { .. } => channel
|
||||
.remove_user_from_group(db, &user, None, options.leave_silently.unwrap_or_default())
|
||||
.remove_user_from_group(
|
||||
db,
|
||||
amqp,
|
||||
&user,
|
||||
None,
|
||||
options.leave_silently.unwrap_or_default(),
|
||||
)
|
||||
.await
|
||||
.map(|_| EmptyResponse),
|
||||
Channel::TextChannel { .. } | Channel::VoiceChannel { .. } => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Channel, Database, File, PartialChannel, SystemMessage, User,
|
||||
Channel, Database, File, PartialChannel, SystemMessage, User, AMQP,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -15,6 +15,7 @@ use validator::Validate;
|
||||
#[patch("/<target>", data = "<data>")]
|
||||
pub async fn edit(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
data: Json<v0::DataEditChannel>,
|
||||
@@ -73,7 +74,15 @@ pub async fn edit(
|
||||
return Err(create_error!(InvalidOperation));
|
||||
}
|
||||
.into_message(channel.id().to_string())
|
||||
.send(db, user.as_author_for_system(), None, None, &channel, false)
|
||||
.send(
|
||||
db,
|
||||
Some(amqp),
|
||||
user.as_author_for_system(),
|
||||
None,
|
||||
None,
|
||||
&channel,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
@@ -151,7 +160,15 @@ pub async fn edit(
|
||||
by: user.id.clone(),
|
||||
}
|
||||
.into_message(channel.id().to_string())
|
||||
.send(db, user.as_author_for_system(), None, None, &channel, false)
|
||||
.send(
|
||||
db,
|
||||
Some(amqp),
|
||||
user.as_author_for_system(),
|
||||
None,
|
||||
None,
|
||||
&channel,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
@@ -161,7 +178,15 @@ pub async fn edit(
|
||||
by: user.id.clone(),
|
||||
}
|
||||
.into_message(channel.id().to_string())
|
||||
.send(db, user.as_author_for_system(), None, None, &channel, false)
|
||||
.send(
|
||||
db,
|
||||
Some(amqp),
|
||||
user.as_author_for_system(),
|
||||
None,
|
||||
None,
|
||||
&channel,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
@@ -171,7 +196,15 @@ pub async fn edit(
|
||||
by: user.id.clone(),
|
||||
}
|
||||
.into_message(channel.id().to_string())
|
||||
.send(db, user.as_author_for_system(), None, None, &channel, false)
|
||||
.send(
|
||||
db,
|
||||
Some(amqp),
|
||||
user.as_author_for_system(),
|
||||
None,
|
||||
None,
|
||||
&channel,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Channel, Database, User,
|
||||
Channel, Database, User, AMQP,
|
||||
};
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
@@ -15,6 +15,7 @@ use rocket_empty::EmptyResponse;
|
||||
#[put("/<group_id>/recipients/<member_id>")]
|
||||
pub async fn add_member(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
group_id: Reference,
|
||||
member_id: Reference,
|
||||
@@ -38,7 +39,7 @@ pub async fn add_member(
|
||||
}
|
||||
|
||||
channel
|
||||
.add_user_to_group(db, &member, &user.id)
|
||||
.add_user_to_group(db, amqp, &member, &user.id)
|
||||
.await
|
||||
.map(|_| EmptyResponse)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use revolt_database::{util::reference::Reference, Channel, Database, User};
|
||||
use revolt_database::{util::reference::Reference, Channel, Database, User, AMQP};
|
||||
use revolt_permissions::ChannelPermission;
|
||||
use revolt_result::{create_error, Result};
|
||||
|
||||
@@ -12,6 +12,7 @@ use rocket_empty::EmptyResponse;
|
||||
#[delete("/<target>/recipients/<member>")]
|
||||
pub async fn remove_member(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
member: Reference,
|
||||
@@ -42,7 +43,7 @@ pub async fn remove_member(
|
||||
}
|
||||
|
||||
channel
|
||||
.remove_user_from_group(db, &member, Some(&user.id), false)
|
||||
.remove_user_from_group(db, amqp, &member, Some(&user.id), false)
|
||||
.await
|
||||
.map(|_| EmptyResponse)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, Database, PartialMessage, SystemMessage, User
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, PartialMessage, SystemMessage, User, AMQP,
|
||||
};
|
||||
use revolt_models::v0::MessageAuthor;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -14,6 +15,7 @@ use rocket_empty::EmptyResponse;
|
||||
#[post("/<target>/messages/<msg>/pin")]
|
||||
pub async fn message_pin(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
msg: Reference,
|
||||
@@ -28,30 +30,38 @@ pub async fn message_pin(
|
||||
let mut message = msg.as_message_in_channel(db, channel.id()).await?;
|
||||
|
||||
if message.pinned.unwrap_or_default() {
|
||||
return Err(create_error!(AlreadyPinned))
|
||||
return Err(create_error!(AlreadyPinned));
|
||||
}
|
||||
|
||||
message.update(db, PartialMessage {
|
||||
pinned: Some(true),
|
||||
..Default::default()
|
||||
}, vec![]).await?;
|
||||
message
|
||||
.update(
|
||||
db,
|
||||
PartialMessage {
|
||||
pinned: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await?;
|
||||
|
||||
SystemMessage::MessagePinned {
|
||||
id: message.id.clone(),
|
||||
by: user.id.clone()
|
||||
by: user.id.clone(),
|
||||
}
|
||||
.into_message(channel.id().to_string())
|
||||
.send(
|
||||
db,
|
||||
Some(amqp),
|
||||
MessageAuthor::System {
|
||||
username: &user.username,
|
||||
avatar: user.avatar.as_ref().map(|file| file.id.as_ref())
|
||||
avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
|
||||
},
|
||||
None,
|
||||
None,
|
||||
&channel,
|
||||
false
|
||||
).await?;
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
@@ -59,7 +69,11 @@ pub async fn message_pin(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{rocket, util::test::TestHarness};
|
||||
use revolt_database::{events::client::EventV1, util::{idempotency::IdempotencyKey, reference::Reference}, Member, Message, Server};
|
||||
use revolt_database::{
|
||||
events::client::EventV1,
|
||||
util::{idempotency::IdempotencyKey, reference::Reference},
|
||||
Member, Message, Server,
|
||||
};
|
||||
use revolt_models::v0::{self, SystemMessage};
|
||||
use rocket::http::{Header, Status};
|
||||
|
||||
@@ -75,24 +89,29 @@ mod test {
|
||||
..Default::default()
|
||||
},
|
||||
&user,
|
||||
true
|
||||
).await.expect("Failed to create test server");
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create test server");
|
||||
|
||||
let (member, channels) = Member::create(&harness.db, &server, &user, Some(channels)).await.expect("Failed to create member");
|
||||
let (member, channels) = Member::create(&harness.db, &server, &user, Some(channels))
|
||||
.await
|
||||
.expect("Failed to create member");
|
||||
let channel = &channels[0];
|
||||
|
||||
let message = Message::create_from_api(
|
||||
&harness.db,
|
||||
None,
|
||||
channel.clone(),
|
||||
v0::DataMessageSend {
|
||||
content:Some("Test message".to_string()),
|
||||
content: Some("Test message".to_string()),
|
||||
nonce: None,
|
||||
attachments: None,
|
||||
replies: None,
|
||||
embeds: None,
|
||||
masquerade: None,
|
||||
interactions: None,
|
||||
flags: None
|
||||
flags: None,
|
||||
},
|
||||
v0::MessageAuthor::User(&user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(user.clone().into(&harness.db, Some(&user)).await),
|
||||
@@ -100,14 +119,18 @@ mod test {
|
||||
user.limits().await,
|
||||
IdempotencyKey::unchecked_from_string("0".to_string()),
|
||||
false,
|
||||
false
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create message");
|
||||
|
||||
let response = harness
|
||||
.client
|
||||
.post(format!("/channels/{}/messages/{}/pin", channel.id(), &message.id))
|
||||
.post(format!(
|
||||
"/channels/{}/messages/{}/pin",
|
||||
channel.id(),
|
||||
&message.id
|
||||
))
|
||||
.header(Header::new("x-session-token", session.token.to_string()))
|
||||
.dispatch()
|
||||
.await;
|
||||
@@ -115,34 +138,37 @@ mod test {
|
||||
assert_eq!(response.status(), Status::NoContent);
|
||||
drop(response);
|
||||
|
||||
harness.wait_for_event(channel.id(), |event| {
|
||||
match event {
|
||||
EventV1::Message(message) => {
|
||||
match &message.system {
|
||||
Some(SystemMessage::MessagePinned { by, .. }) => {
|
||||
assert_eq!(by, &user.id);
|
||||
harness
|
||||
.wait_for_event(channel.id(), |event| match event {
|
||||
EventV1::Message(message) => match &message.system {
|
||||
Some(SystemMessage::MessagePinned { by, .. }) => {
|
||||
assert_eq!(by, &user.id);
|
||||
|
||||
true
|
||||
},
|
||||
_ => false
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}).await;
|
||||
_ => false,
|
||||
})
|
||||
.await;
|
||||
|
||||
harness.wait_for_event(channel.id(), |event| {
|
||||
match event {
|
||||
EventV1::MessageUpdate { id, channel: channel_id, data, .. } => {
|
||||
harness
|
||||
.wait_for_event(channel.id(), |event| match event {
|
||||
EventV1::MessageUpdate {
|
||||
id,
|
||||
channel: channel_id,
|
||||
data,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(id, &message.id);
|
||||
assert_eq!(channel_id, channel.id());
|
||||
assert_eq!(data.pinned, Some(true));
|
||||
|
||||
true
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}).await;
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.await;
|
||||
|
||||
let updated_message = Reference::from_unchecked(message.id)
|
||||
.as_message(&harness.db)
|
||||
|
||||
@@ -3,7 +3,7 @@ use revolt_database::util::permissions::DatabasePermissionQuery;
|
||||
use revolt_database::{
|
||||
util::idempotency::IdempotencyKey, util::reference::Reference, Database, User,
|
||||
};
|
||||
use revolt_database::{Interactions, Message};
|
||||
use revolt_database::{Interactions, Message, AMQP};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::PermissionQuery;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -19,6 +19,7 @@ use validator::Validate;
|
||||
#[post("/<target>/messages", data = "<data>")]
|
||||
pub async fn message_send(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
data: Json<v0::DataMessageSend>,
|
||||
@@ -93,6 +94,7 @@ pub async fn message_send(
|
||||
Ok(Json(
|
||||
Message::create_from_api(
|
||||
db,
|
||||
Some(amqp),
|
||||
channel,
|
||||
data,
|
||||
v0::MessageAuthor::User(&author),
|
||||
@@ -107,3 +109,218 @@ pub async fn message_send(
|
||||
.into_model(Some(model_user), model_member),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{rocket, util::test::TestHarness};
|
||||
use revolt_database::{
|
||||
util::{idempotency::IdempotencyKey, reference::Reference},
|
||||
Channel, Member, Message, PartialChannel, PartialMember, Role, Server,
|
||||
};
|
||||
use revolt_models::v0::{self, DataCreateServerChannel};
|
||||
use revolt_permissions::{ChannelPermission, OverrideField};
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn message_mention_constraints() {
|
||||
let harness = TestHarness::new().await;
|
||||
let (_, _, user) = harness.new_user().await;
|
||||
let (_, _, second_user) = harness.new_user().await;
|
||||
|
||||
let (server, channels) = Server::create(
|
||||
&harness.db,
|
||||
v0::DataCreateServer {
|
||||
name: "Test Server".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
&user,
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create test server");
|
||||
|
||||
let server_mut: &mut Server = &mut server.clone();
|
||||
let mut locked_channel = Channel::create_server_channel(
|
||||
&harness.db,
|
||||
server_mut,
|
||||
DataCreateServerChannel {
|
||||
channel_type: v0::LegacyServerChannelType::Text,
|
||||
name: "Hidden Channel".to_string(),
|
||||
description: None,
|
||||
nsfw: Some(false),
|
||||
},
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to make new channel");
|
||||
|
||||
let role = Role {
|
||||
name: "Show Hidden Channel".to_string(),
|
||||
permissions: OverrideField { a: 0, d: 0 },
|
||||
colour: None,
|
||||
hoist: false,
|
||||
rank: 5,
|
||||
};
|
||||
|
||||
let role_id = role
|
||||
.create(&harness.db, &server.id)
|
||||
.await
|
||||
.expect("Failed to create the role");
|
||||
|
||||
let mut overrides = HashMap::new();
|
||||
overrides.insert(
|
||||
role_id.clone(),
|
||||
OverrideField {
|
||||
a: (ChannelPermission::ViewChannel) as i64,
|
||||
d: 0,
|
||||
},
|
||||
);
|
||||
|
||||
let partial = PartialChannel {
|
||||
name: None,
|
||||
owner: None,
|
||||
description: None,
|
||||
icon: None,
|
||||
nsfw: None,
|
||||
active: None,
|
||||
permissions: None,
|
||||
role_permissions: Some(overrides),
|
||||
default_permissions: Some(OverrideField {
|
||||
a: 0,
|
||||
d: ChannelPermission::ViewChannel as i64,
|
||||
}),
|
||||
last_message_id: None,
|
||||
};
|
||||
locked_channel
|
||||
.update(&harness.db, partial, vec![])
|
||||
.await
|
||||
.expect("Failed to update the channel permissions for special role");
|
||||
|
||||
Member::create(&harness.db, &server, &user, Some(channels.clone()))
|
||||
.await
|
||||
.expect("Failed to create member");
|
||||
let member = Reference::from_unchecked(user.id.clone())
|
||||
.as_member(&harness.db, &server.id)
|
||||
.await
|
||||
.expect("Failed to get member");
|
||||
|
||||
// Second user is not part of the server
|
||||
let message = Message::create_from_api(
|
||||
&harness.db,
|
||||
Some(&harness.amqp),
|
||||
locked_channel.clone(),
|
||||
v0::DataMessageSend {
|
||||
content: Some(format!("<@{}>", second_user.id)),
|
||||
nonce: None,
|
||||
attachments: None,
|
||||
replies: None,
|
||||
embeds: None,
|
||||
masquerade: None,
|
||||
interactions: None,
|
||||
flags: None,
|
||||
},
|
||||
v0::MessageAuthor::User(&user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(member.clone().into()),
|
||||
user.limits().await,
|
||||
IdempotencyKey::unchecked_from_string("0".to_string()),
|
||||
false,
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create message");
|
||||
|
||||
// The mention should not go through here
|
||||
assert!(
|
||||
message.mentions.is_none() || message.mentions.unwrap().is_empty(),
|
||||
"Mention failed to be scrubbed when the user is not part of the server"
|
||||
);
|
||||
|
||||
Member::create(&harness.db, &server, &second_user, Some(channels.clone()))
|
||||
.await
|
||||
.expect("Failed to create second member");
|
||||
let mut second_member = Reference::from_unchecked(second_user.id.clone())
|
||||
.as_member(&harness.db, &server.id)
|
||||
.await
|
||||
.expect("Failed to get second member");
|
||||
|
||||
// Second user cannot see the channel
|
||||
let message = Message::create_from_api(
|
||||
&harness.db,
|
||||
Some(&harness.amqp),
|
||||
locked_channel.clone(),
|
||||
v0::DataMessageSend {
|
||||
content: Some(format!("<@{}>", second_user.id)),
|
||||
nonce: None,
|
||||
attachments: None,
|
||||
replies: None,
|
||||
embeds: None,
|
||||
masquerade: None,
|
||||
interactions: None,
|
||||
flags: None,
|
||||
},
|
||||
v0::MessageAuthor::User(&user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(member.clone().into()),
|
||||
user.limits().await,
|
||||
IdempotencyKey::unchecked_from_string("1".to_string()),
|
||||
false,
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create message");
|
||||
|
||||
// The mention should not go through here
|
||||
assert!(
|
||||
message.mentions.is_none() || message.mentions.unwrap().is_empty(),
|
||||
"Mention failed to be scrubbed when the user cannot see the channel"
|
||||
);
|
||||
|
||||
let second_member_roles = vec![role_id.clone()];
|
||||
let partial = PartialMember {
|
||||
id: None,
|
||||
joined_at: None,
|
||||
nickname: None,
|
||||
avatar: None,
|
||||
timeout: None,
|
||||
roles: Some(second_member_roles),
|
||||
};
|
||||
second_member
|
||||
.update(&harness.db, partial, vec![])
|
||||
.await
|
||||
.expect("Failed to update the second user's roles");
|
||||
|
||||
// This time the mention SHOULD go through
|
||||
let message = Message::create_from_api(
|
||||
&harness.db,
|
||||
Some(&harness.amqp),
|
||||
locked_channel.clone(),
|
||||
v0::DataMessageSend {
|
||||
content: Some(format!("<@{}>", second_user.id)),
|
||||
nonce: None,
|
||||
attachments: None,
|
||||
replies: None,
|
||||
embeds: None,
|
||||
masquerade: None,
|
||||
interactions: None,
|
||||
flags: None,
|
||||
},
|
||||
v0::MessageAuthor::User(&user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(member.clone().into()),
|
||||
user.limits().await,
|
||||
IdempotencyKey::unchecked_from_string("2".to_string()),
|
||||
false,
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create message");
|
||||
|
||||
// The mention SHOULD go through here
|
||||
assert!(
|
||||
message.mentions.is_some() && !message.mentions.unwrap().is_empty(),
|
||||
"Mention was scrubbed when the user can see the channel"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, Database, FieldsMessage, PartialMessage, SystemMessage, User
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, FieldsMessage, PartialMessage, SystemMessage, User, AMQP,
|
||||
};
|
||||
use revolt_models::v0::MessageAuthor;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -14,6 +15,7 @@ use rocket_empty::EmptyResponse;
|
||||
#[delete("/<target>/messages/<msg>/pin")]
|
||||
pub async fn message_unpin(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
msg: Reference,
|
||||
@@ -28,27 +30,31 @@ pub async fn message_unpin(
|
||||
let mut message = msg.as_message_in_channel(db, channel.id()).await?;
|
||||
|
||||
if !message.pinned.unwrap_or_default() {
|
||||
return Err(create_error!(NotPinned))
|
||||
return Err(create_error!(NotPinned));
|
||||
}
|
||||
|
||||
message.update(db, PartialMessage::default(), vec![FieldsMessage::Pinned]).await?;
|
||||
message
|
||||
.update(db, PartialMessage::default(), vec![FieldsMessage::Pinned])
|
||||
.await?;
|
||||
|
||||
SystemMessage::MessageUnpinned {
|
||||
id: message.id.clone(),
|
||||
by: user.id.clone()
|
||||
by: user.id.clone(),
|
||||
}
|
||||
.into_message(channel.id().to_string())
|
||||
.send(
|
||||
db,
|
||||
Some(amqp),
|
||||
MessageAuthor::System {
|
||||
username: &user.username,
|
||||
avatar: user.avatar.as_ref().map(|file| file.id.as_ref())
|
||||
avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
|
||||
},
|
||||
None,
|
||||
None,
|
||||
&channel,
|
||||
false
|
||||
).await?;
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
@@ -56,7 +62,11 @@ pub async fn message_unpin(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{rocket, util::test::TestHarness};
|
||||
use revolt_database::{events::client::EventV1, util::{idempotency::IdempotencyKey, reference::Reference}, Member, Message, PartialMessage, Server};
|
||||
use revolt_database::{
|
||||
events::client::EventV1,
|
||||
util::{idempotency::IdempotencyKey, reference::Reference},
|
||||
Member, Message, PartialMessage, Server,
|
||||
};
|
||||
use revolt_models::v0::{self, FieldsMessage, SystemMessage};
|
||||
use rocket::http::{Header, Status};
|
||||
|
||||
@@ -72,26 +82,34 @@ mod test {
|
||||
..Default::default()
|
||||
},
|
||||
&user,
|
||||
true
|
||||
).await.expect("Failed to create test server");
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create test server");
|
||||
|
||||
let channel = &channels[0];
|
||||
|
||||
Member::create(&harness.db, &server, &user, Some(channels.clone())).await.expect("Failed to create member");
|
||||
let member = Reference::from_unchecked(user.id.clone()).as_member(&harness.db, &server.id).await.expect("Failed to get member");
|
||||
Member::create(&harness.db, &server, &user, Some(channels.clone()))
|
||||
.await
|
||||
.expect("Failed to create member");
|
||||
let member = Reference::from_unchecked(user.id.clone())
|
||||
.as_member(&harness.db, &server.id)
|
||||
.await
|
||||
.expect("Failed to get member");
|
||||
|
||||
let message = Message::create_from_api(
|
||||
&harness.db,
|
||||
None,
|
||||
channel.clone(),
|
||||
v0::DataMessageSend {
|
||||
content:Some("Test message".to_string()),
|
||||
content: Some("Test message".to_string()),
|
||||
nonce: None,
|
||||
attachments: None,
|
||||
replies: None,
|
||||
embeds: None,
|
||||
masquerade: None,
|
||||
interactions: None,
|
||||
flags: None
|
||||
flags: None,
|
||||
},
|
||||
v0::MessageAuthor::User(&user.clone().into(&harness.db, Some(&user)).await),
|
||||
Some(user.clone().into(&harness.db, Some(&user)).await),
|
||||
@@ -99,23 +117,31 @@ mod test {
|
||||
user.limits().await,
|
||||
IdempotencyKey::unchecked_from_string("0".to_string()),
|
||||
false,
|
||||
false
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create message");
|
||||
|
||||
harness.db.update_message(
|
||||
&message.id,
|
||||
&PartialMessage {
|
||||
pinned: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
vec![]
|
||||
).await.expect("Failed to update message");
|
||||
harness
|
||||
.db
|
||||
.update_message(
|
||||
&message.id,
|
||||
&PartialMessage {
|
||||
pinned: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
.expect("Failed to update message");
|
||||
|
||||
let response = harness
|
||||
.client
|
||||
.delete(format!("/channels/{}/messages/{}/pin", channel.id(), &message.id))
|
||||
.delete(format!(
|
||||
"/channels/{}/messages/{}/pin",
|
||||
channel.id(),
|
||||
&message.id
|
||||
))
|
||||
.header(Header::new("x-session-token", session.token.to_string()))
|
||||
.dispatch()
|
||||
.await;
|
||||
@@ -123,33 +149,31 @@ mod test {
|
||||
assert_eq!(response.status(), Status::NoContent);
|
||||
drop(response);
|
||||
|
||||
harness.wait_for_event(channel.id(), |event| {
|
||||
match event {
|
||||
EventV1::Message(message) => {
|
||||
match &message.system {
|
||||
Some(SystemMessage::MessageUnpinned { by, .. }) => {
|
||||
assert_eq!(by, &user.id);
|
||||
harness
|
||||
.wait_for_event(channel.id(), |event| match event {
|
||||
EventV1::Message(message) => match &message.system {
|
||||
Some(SystemMessage::MessageUnpinned { by, .. }) => {
|
||||
assert_eq!(by, &user.id);
|
||||
|
||||
true
|
||||
},
|
||||
_ => false
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}).await;
|
||||
_ => false,
|
||||
})
|
||||
.await;
|
||||
|
||||
harness.wait_for_event(channel.id(), |event| {
|
||||
match event {
|
||||
harness
|
||||
.wait_for_event(channel.id(), |event| match event {
|
||||
EventV1::MessageUpdate { id, clear, .. } => {
|
||||
assert_eq!(&message.id, id);
|
||||
assert_eq!(clear, &[FieldsMessage::Pinned]);
|
||||
|
||||
true
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}).await;
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.await;
|
||||
|
||||
let updated_message = Reference::from_unchecked(message.id)
|
||||
.as_message(&harness.db)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use revolt_database::{util::reference::Reference, Channel, Database, Invite, Member, User};
|
||||
use revolt_database::{util::reference::Reference, Channel, Database, Invite, Member, User, AMQP};
|
||||
use revolt_models::v0::{self, InviteJoinResponse};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
@@ -10,6 +10,7 @@ use rocket::{serde::json::Json, State};
|
||||
#[post("/<target>")]
|
||||
pub async fn join(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
target: Reference,
|
||||
) -> Result<Json<v0::InviteJoinResponse>> {
|
||||
@@ -34,7 +35,7 @@ pub async fn join(
|
||||
channel, creator, ..
|
||||
} => {
|
||||
let mut channel = db.fetch_channel(channel).await?;
|
||||
channel.add_user_to_group(db, &user, creator).await?;
|
||||
channel.add_user_to_group(db, amqp, &user, creator).await?;
|
||||
if let Channel::Group { recipients, .. } = &channel {
|
||||
Ok(Json(InviteJoinResponse::Group {
|
||||
users: User::fetch_many_ids_as_mutuals(db, &user, recipients).await?,
|
||||
|
||||
@@ -114,7 +114,7 @@ pub async fn root() -> Result<Json<RevoltConfig>> {
|
||||
},
|
||||
ws: config.hosts.events,
|
||||
app: config.hosts.app,
|
||||
vapid: config.api.vapid.public_key,
|
||||
vapid: config.pushd.vapid.public_key,
|
||||
build: BuildInformation {
|
||||
commit_sha: option_env!("VERGEN_GIT_SHA")
|
||||
.unwrap_or_else(|| "<failed to generate>")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use revolt_database::util::reference::Reference;
|
||||
use revolt_database::{Database, User};
|
||||
use revolt_database::{Database, User, AMQP};
|
||||
use revolt_models::v0;
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::serde::json::Json;
|
||||
@@ -12,6 +12,7 @@ use rocket::State;
|
||||
#[put("/<target>/friend")]
|
||||
pub async fn add(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
mut user: User,
|
||||
target: Reference,
|
||||
) -> Result<Json<v0::User>> {
|
||||
@@ -21,6 +22,6 @@ pub async fn add(
|
||||
return Err(create_error!(IsBot));
|
||||
}
|
||||
|
||||
user.add_friend(db, &mut target).await?;
|
||||
user.add_friend(db, amqp, &mut target).await?;
|
||||
Ok(Json(target.into(db, &user).await))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use revolt_database::util::reference::Reference;
|
||||
use revolt_database::{Database, User};
|
||||
// use revolt_database::util::reference::Reference;
|
||||
use revolt_database::{Database, User, AMQP};
|
||||
use revolt_models::v0;
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::serde::json::Json;
|
||||
@@ -12,6 +12,7 @@ use rocket::State;
|
||||
#[post("/friend", data = "<data>")]
|
||||
pub async fn send_friend_request(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
mut user: User,
|
||||
data: Json<v0::DataSendFriendRequest>,
|
||||
) -> Result<Json<v0::User>> {
|
||||
@@ -22,7 +23,7 @@ pub async fn send_friend_request(
|
||||
return Err(create_error!(IsBot));
|
||||
}
|
||||
|
||||
user.add_friend(db, &mut target).await?;
|
||||
user.add_friend(db, amqp, &mut target).await?;
|
||||
Ok(Json(target.into(db, &user).await))
|
||||
} else {
|
||||
Err(create_error!(InvalidProperty))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{
|
||||
util::{idempotency::IdempotencyKey, reference::Reference},
|
||||
Database, Message,
|
||||
Database, Message, AMQP,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{ChannelPermission, PermissionValue};
|
||||
@@ -17,6 +17,7 @@ use validator::Validate;
|
||||
#[post("/<webhook_id>/<token>", data = "<data>")]
|
||||
pub async fn webhook_execute(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
webhook_id: Reference,
|
||||
token: String,
|
||||
data: Json<v0::DataMessageSend>,
|
||||
@@ -56,6 +57,7 @@ pub async fn webhook_execute(
|
||||
Ok(Json(
|
||||
Message::create_from_api(
|
||||
db,
|
||||
Some(amqp),
|
||||
channel,
|
||||
data,
|
||||
v0::MessageAuthor::Webhook(&webhook.into()),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use revolt_database::{util::reference::Reference, Database, Message};
|
||||
use revolt_database::{util::reference::Reference, Database, Message, AMQP};
|
||||
use revolt_models::v0::{MessageAuthor, SendableEmbed, Webhook};
|
||||
use revolt_result::{create_error, Error, Result};
|
||||
use revolt_rocket_okapi::{
|
||||
@@ -635,7 +635,10 @@ impl<'r> FromRequest<'r> for EventHeader<'r> {
|
||||
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, create_error!(InvalidOperation)))
|
||||
return rocket::request::Outcome::Error((
|
||||
Status::BadRequest,
|
||||
create_error!(InvalidOperation),
|
||||
));
|
||||
};
|
||||
|
||||
rocket::request::Outcome::Success(Self(event))
|
||||
@@ -747,6 +750,7 @@ fn convert_event(data: &str, event_name: &str) -> Result<Event> {
|
||||
#[post("/<webhook_id>/<token>/github", data = "<data>")]
|
||||
pub async fn webhook_execute_github(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
webhook_id: Reference,
|
||||
token: String,
|
||||
event: EventHeader<'_>,
|
||||
@@ -784,7 +788,9 @@ pub async fn webhook_execute_github(
|
||||
r#ref,
|
||||
..
|
||||
}) => {
|
||||
let Some(branch) = r#ref.split('/').nth(2) else { return Ok(()) };
|
||||
let Some(branch) = r#ref.split('/').nth(2) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if forced {
|
||||
let description = format!(
|
||||
@@ -1074,6 +1080,7 @@ pub async fn webhook_execute_github(
|
||||
message
|
||||
.send(
|
||||
db,
|
||||
Some(amqp),
|
||||
MessageAuthor::Webhook(&webhook.into()),
|
||||
None,
|
||||
None,
|
||||
|
||||
@@ -235,7 +235,7 @@ impl<'r> FromRequest<'r> for Ratelimiter {
|
||||
|
||||
match ratelimiter {
|
||||
Ok(ratelimiter) => Outcome::Success(*ratelimiter),
|
||||
Err(ratelimiter) => Outcome::Failure((Status::TooManyRequests, *ratelimiter)),
|
||||
Err(ratelimiter) => Outcome::Error((Status::TooManyRequests, *ratelimiter)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,7 +264,7 @@ impl Fairing for RatelimitFairing {
|
||||
|
||||
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
|
||||
use rocket::outcome::Outcome;
|
||||
if let Outcome::Failure(_) = request.guard::<Ratelimiter>().await {
|
||||
if let Outcome::Error(_) = request.guard::<Ratelimiter>().await {
|
||||
info!(
|
||||
"User rate-limited on route {}! (IP = {:?})",
|
||||
request.uri(),
|
||||
@@ -278,7 +278,7 @@ impl Fairing for RatelimitFairing {
|
||||
|
||||
async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) {
|
||||
let guard = request.guard::<Ratelimiter>().await;
|
||||
let (Outcome::Success(ratelimiter) | Outcome::Failure((_, ratelimiter))) = guard else {
|
||||
let (Outcome::Success(ratelimiter) | Outcome::Error((_, ratelimiter))) = guard else {
|
||||
unreachable!()
|
||||
};
|
||||
let Ratelimiter {
|
||||
@@ -293,7 +293,7 @@ impl Fairing for RatelimitFairing {
|
||||
response.set_raw_header("X-RateLimit-Remaining", remaining.to_string());
|
||||
response.set_raw_header("X-RateLimit-Reset-After", reset.to_string());
|
||||
|
||||
if guard.is_failure() {
|
||||
if guard.is_error() {
|
||||
response.set_status(Status::TooManyRequests);
|
||||
}
|
||||
}
|
||||
@@ -313,7 +313,7 @@ impl<'r> FromRequest<'r> for RatelimitInformation {
|
||||
async fn from_request(request: &'r rocket::Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
let info = match request.guard::<Ratelimiter>().await {
|
||||
Outcome::Success(ratelimiter) => RatelimitInformation::Success(ratelimiter),
|
||||
Outcome::Failure((_, ratelimiter)) => RatelimitInformation::Failure {
|
||||
Outcome::Error((_, ratelimiter)) => RatelimitInformation::Failure {
|
||||
retry_after: ratelimiter.reset,
|
||||
},
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -5,7 +5,7 @@ use authifier::{
|
||||
use futures::StreamExt;
|
||||
use rand::Rng;
|
||||
use redis_kiss::redis::aio::PubSub;
|
||||
use revolt_database::{events::client::EventV1, Database, User};
|
||||
use revolt_database::{events::client::EventV1, Database, User, AMQP};
|
||||
use revolt_models::v0;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
@@ -13,12 +13,15 @@ pub struct TestHarness {
|
||||
pub client: Client,
|
||||
authifier: Authifier,
|
||||
pub db: Database,
|
||||
pub amqp: AMQP,
|
||||
sub: PubSub,
|
||||
event_buffer: Vec<(String, EventV1)>,
|
||||
}
|
||||
|
||||
impl TestHarness {
|
||||
pub async fn new() -> TestHarness {
|
||||
let config = revolt_config::config().await;
|
||||
|
||||
let client = Client::tracked(crate::web().await)
|
||||
.await
|
||||
.expect("valid rocket instance");
|
||||
@@ -41,10 +44,25 @@ impl TestHarness {
|
||||
.expect("`Authifier`")
|
||||
.clone();
|
||||
|
||||
let connection = amqprs::connection::Connection::open(
|
||||
&amqprs::connection::OpenConnectionArguments::new(
|
||||
&config.rabbit.host,
|
||||
config.rabbit.port,
|
||||
&config.rabbit.username,
|
||||
&config.rabbit.password,
|
||||
),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let channel = connection.open_channel(None).await.unwrap();
|
||||
|
||||
let amqp = AMQP::new(connection, channel);
|
||||
|
||||
TestHarness {
|
||||
client,
|
||||
authifier,
|
||||
db,
|
||||
amqp,
|
||||
sub,
|
||||
event_buffer: vec![],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user