forked from jmug/stoatchat
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2864ac025 | ||
|
|
4eb76fd154 | ||
|
|
3c7852271a | ||
|
|
dadad271b4 | ||
|
|
db6047f2d3 | ||
|
|
5baf85a8e9 | ||
|
|
10cac358a9 | ||
|
|
64d2707366 | ||
|
|
78cfbf9d21 |
No files matched your search
Generated
+1
-1
@@ -2473,7 +2473,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt"
|
name = "revolt"
|
||||||
version = "0.3.3-alpha.6"
|
version = "0.3.3-alpha.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"async-tungstenite",
|
"async-tungstenite",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt"
|
name = "revolt"
|
||||||
version = "0.3.3-alpha.6"
|
version = "0.3.3-alpha.7"
|
||||||
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ use mongodb::{
|
|||||||
use rocket_contrib::json::JsonValue;
|
use rocket_contrib::json::JsonValue;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
use web_push::{ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder};
|
use web_push::{
|
||||||
|
ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
@@ -171,7 +173,8 @@ impl Message {
|
|||||||
for subscription in subscriptions {
|
for subscription in subscriptions {
|
||||||
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
|
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
|
||||||
let sig_builder =
|
let sig_builder =
|
||||||
VapidSignatureBuilder::from_pem(std::io::Cursor::new(&key), &subscription).unwrap();
|
VapidSignatureBuilder::from_pem(std::io::Cursor::new(&key), &subscription)
|
||||||
|
.unwrap();
|
||||||
let signature = sig_builder.build().unwrap();
|
let signature = sig_builder.build().unwrap();
|
||||||
builder.set_vapid_signature(signature);
|
builder.set_vapid_signature(signature);
|
||||||
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
|
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
|
||||||
@@ -198,6 +201,26 @@ impl Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(&self) -> Result<()> {
|
pub async fn delete(&self) -> Result<()> {
|
||||||
|
if let Some(attachment) = &self.attachment {
|
||||||
|
get_collection("attachments")
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": &attachment.id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$set": {
|
||||||
|
"deleted": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "update_one",
|
||||||
|
with: "attachment",
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
get_collection("messages")
|
get_collection("messages")
|
||||||
.delete_one(
|
.delete_one(
|
||||||
doc! {
|
doc! {
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
use mongodb::bson::doc;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use mongodb::options::{Collation, FindOneOptions};
|
||||||
|
|
||||||
use crate::{database::permissions::user::UserPermissions, notifications::websocket::is_online};
|
use crate::database::*;
|
||||||
|
use crate::util::result::{Error, Result};
|
||||||
|
use crate::notifications::websocket::is_online;
|
||||||
|
use crate::database::permissions::user::UserPermissions;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
pub enum RelationshipStatus {
|
pub enum RelationshipStatus {
|
||||||
@@ -62,4 +67,32 @@ impl User {
|
|||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Utility function for checking claimed usernames.
|
||||||
|
pub async fn is_username_taken(username: &str) -> Result<bool> {
|
||||||
|
if username == "revolt" && username == "admin" {
|
||||||
|
return Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if get_collection("users")
|
||||||
|
.find_one(
|
||||||
|
doc! {
|
||||||
|
"username": username
|
||||||
|
},
|
||||||
|
FindOneOptions::builder()
|
||||||
|
.collation(Collation::builder().locale("en").strength(2).build())
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "find_one",
|
||||||
|
with: "user",
|
||||||
|
})?
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,12 @@ pub enum WebSocketError {
|
|||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum ServerboundNotification {
|
pub enum ServerboundNotification {
|
||||||
Authenticate(Session),
|
Authenticate(Session),
|
||||||
|
BeginTyping {
|
||||||
|
channel: String
|
||||||
|
},
|
||||||
|
EndTyping {
|
||||||
|
channel: String
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@@ -63,6 +69,14 @@ pub enum ClientboundNotification {
|
|||||||
ChannelDelete {
|
ChannelDelete {
|
||||||
id: String,
|
id: String,
|
||||||
},
|
},
|
||||||
|
ChannelStartTyping {
|
||||||
|
id: String,
|
||||||
|
user: String
|
||||||
|
},
|
||||||
|
ChannelStopTyping {
|
||||||
|
id: String,
|
||||||
|
user: String
|
||||||
|
},
|
||||||
|
|
||||||
UserRelationship {
|
UserRelationship {
|
||||||
id: String,
|
id: String,
|
||||||
|
|||||||
@@ -71,8 +71,6 @@ async fn accept(stream: TcpStream) {
|
|||||||
let fwd = rx.map(Ok).forward(write);
|
let fwd = rx.map(Ok).forward(write);
|
||||||
let incoming = read.try_for_each(async move |msg| {
|
let incoming = read.try_for_each(async move |msg| {
|
||||||
let mutex = mutex_generator();
|
let mutex = mutex_generator();
|
||||||
//dbg!(&mutex.lock().unwrap());
|
|
||||||
|
|
||||||
if let Message::Text(text) = msg {
|
if let Message::Text(text) = msg {
|
||||||
if let Ok(notification) = serde_json::from_str::<ServerboundNotification>(&text) {
|
if let Ok(notification) = serde_json::from_str::<ServerboundNotification>(&text) {
|
||||||
match notification {
|
match notification {
|
||||||
@@ -161,6 +159,54 @@ async fn accept(stream: TcpStream) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ! TEMP: verify user part of channel
|
||||||
|
// ! Could just run permission check here.
|
||||||
|
ServerboundNotification::BeginTyping { channel } => {
|
||||||
|
if mutex.lock().unwrap().is_some() {
|
||||||
|
let user = {
|
||||||
|
let mutex = mutex.lock().unwrap();
|
||||||
|
let session = mutex.as_ref().unwrap();
|
||||||
|
session.user_id.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientboundNotification::ChannelStartTyping {
|
||||||
|
id: channel.clone(),
|
||||||
|
user
|
||||||
|
}
|
||||||
|
.publish(channel)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
} else {
|
||||||
|
send(ClientboundNotification::Error(
|
||||||
|
WebSocketError::AlreadyAuthenticated,
|
||||||
|
));
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ServerboundNotification::EndTyping { channel } => {
|
||||||
|
if mutex.lock().unwrap().is_some() {
|
||||||
|
let user = {
|
||||||
|
let mutex = mutex.lock().unwrap();
|
||||||
|
let session = mutex.as_ref().unwrap();
|
||||||
|
session.user_id.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
ClientboundNotification::ChannelStopTyping {
|
||||||
|
id: channel.clone(),
|
||||||
|
user
|
||||||
|
}
|
||||||
|
.publish(channel)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
} else {
|
||||||
|
send(ClientboundNotification::Error(
|
||||||
|
WebSocketError::AlreadyAuthenticated,
|
||||||
|
));
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub async fn req(user: User, target: Ref) -> Result<()> {
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
match &target {
|
match &target {
|
||||||
@@ -102,7 +102,8 @@ pub async fn req(user: User, target: Ref) -> Result<()> {
|
|||||||
Message::create(
|
Message::create(
|
||||||
"00000000000000000000000000".to_string(),
|
"00000000000000000000000000".to_string(),
|
||||||
id.clone(),
|
id.clone(),
|
||||||
format!("<@{}> left the group.", user.id),
|
// ! FIXME: make a schema for this
|
||||||
|
format!("{{\"type\":\"user_left\",\"id\":\"{}\"}}", user.id),
|
||||||
)
|
)
|
||||||
.publish(&target)
|
.publish(&target)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(json!(target))
|
Ok(json!(target))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub async fn req(user: User, target: Ref, member: Ref) -> Result<()> {
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Channel::Group { id, recipients, .. } = &channel {
|
if let Channel::Group { id, recipients, .. } = &channel {
|
||||||
@@ -59,7 +59,8 @@ pub async fn req(user: User, target: Ref, member: Ref) -> Result<()> {
|
|||||||
Message::create(
|
Message::create(
|
||||||
"00000000000000000000000000".to_string(),
|
"00000000000000000000000000".to_string(),
|
||||||
id.clone(),
|
id.clone(),
|
||||||
format!("<@{}> added <@{}> to the group.", user.id, member.id),
|
// ! FIXME: make a schema for this
|
||||||
|
format!("{{\"type\":\"user_added\",\"id\":\"{}\",\"by\":\"{}\"}}", member.id, user.id),
|
||||||
)
|
)
|
||||||
.publish(&channel)
|
.publish(&channel)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub async fn req(user: User, target: Ref, member: Ref) -> Result<()> {
|
|||||||
{
|
{
|
||||||
if &user.id != owner {
|
if &user.id != owner {
|
||||||
// figure out if we want to use perm system here
|
// figure out if we want to use perm system here
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
if recipients.iter().find(|x| *x == &member.id).is_none() {
|
if recipients.iter().find(|x| *x == &member.id).is_none() {
|
||||||
@@ -56,7 +56,8 @@ pub async fn req(user: User, target: Ref, member: Ref) -> Result<()> {
|
|||||||
Message::create(
|
Message::create(
|
||||||
"00000000000000000000000000".to_string(),
|
"00000000000000000000000000".to_string(),
|
||||||
id.clone(),
|
id.clone(),
|
||||||
format!("<@{}> removed <@{}> from the group.", user.id, member.id),
|
// ! FIXME: make a schema for this
|
||||||
|
format!("{{\"type\":\"user_remove\",\"id\":\"{}\",\"by\":\"{}\"}}", member.id, user.id),
|
||||||
)
|
)
|
||||||
.publish(&channel)
|
.publish(&channel)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub async fn req(user: User, target: Ref, msg: Ref) -> Result<()> {
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = msg.fetch_message(&channel).await?;
|
let message = msg.fetch_message(&channel).await?;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pub async fn req(user: User, target: Ref, msg: Ref, edit: Json<Data>) -> Result<
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = msg.fetch_message(&channel).await?;
|
let message = msg.fetch_message(&channel).await?;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub async fn req(user: User, target: Ref, msg: Ref) -> Result<JsonValue> {
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
let message = msg.fetch_message(&channel).await?;
|
let message = msg.fetch_message(&channel).await?;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ pub async fn req(user: User, target: Ref, options: Form<Options>) -> Result<Json
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut query = doc! { "channel": target.id() };
|
let mut query = doc! { "channel": target.id() };
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub struct Options {
|
|||||||
#[post("/<target>/messages/stale", data = "<data>")]
|
#[post("/<target>/messages/stale", data = "<data>")]
|
||||||
pub async fn req(user: User, target: Ref, data: Json<Options>) -> Result<JsonValue> {
|
pub async fn req(user: User, target: Ref, data: Json<Options>) -> Result<JsonValue> {
|
||||||
if data.ids.len() > 150 {
|
if data.ids.len() > 150 {
|
||||||
return Err(Error::LabelMe);
|
return Err(Error::TooManyIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
let target = target.fetch_channel().await?;
|
let target = target.fetch_channel().await?;
|
||||||
@@ -24,7 +24,7 @@ pub async fn req(user: User, target: Ref, data: Json<Options>) -> Result<JsonVal
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_view() {
|
if !perm.get_view() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cursor = get_collection("messages")
|
let mut cursor = get_collection("messages")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use validator::Validate;
|
|||||||
|
|
||||||
#[derive(Validate, Serialize, Deserialize)]
|
#[derive(Validate, Serialize, Deserialize)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
#[validate(length(min = 1, max = 2000))]
|
#[validate(length(min = 0, max = 2000))]
|
||||||
content: String,
|
content: String,
|
||||||
// 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))]
|
||||||
@@ -26,6 +26,10 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<JsonVal
|
|||||||
message
|
message
|
||||||
.validate()
|
.validate()
|
||||||
.map_err(|error| Error::FailedValidation { error })?;
|
.map_err(|error| Error::FailedValidation { error })?;
|
||||||
|
|
||||||
|
if message.content.len() == 0 && message.attachment.is_none() {
|
||||||
|
return Err(Error::EmptyMessage);
|
||||||
|
}
|
||||||
|
|
||||||
let target = target.fetch_channel().await?;
|
let target = target.fetch_channel().await?;
|
||||||
|
|
||||||
@@ -34,7 +38,7 @@ pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<JsonVal
|
|||||||
.for_channel()
|
.for_channel()
|
||||||
.await?;
|
.await?;
|
||||||
if !perm.get_send_message() {
|
if !perm.get_send_message() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_collection("messages")
|
if get_collection("messages")
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::database::*;
|
|||||||
use crate::util::result::{Error, Result};
|
use crate::util::result::{Error, Result};
|
||||||
|
|
||||||
use mongodb::bson::doc;
|
use mongodb::bson::doc;
|
||||||
use mongodb::options::{Collation, FindOneOptions};
|
|
||||||
use rauth::auth::Session;
|
use rauth::auth::Session;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rocket_contrib::json::Json;
|
use rocket_contrib::json::Json;
|
||||||
@@ -10,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref RE_USERNAME: Regex = Regex::new(r"^[a-zA-Z0-9_]+$").unwrap();
|
static ref RE_USERNAME: Regex = Regex::new(r"^[a-zA-Z0-9_.]+$").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Validate, Serialize, Deserialize)]
|
#[derive(Validate, Serialize, Deserialize)]
|
||||||
@@ -28,31 +27,11 @@ pub async fn req(session: Session, user: Option<User>, data: Json<Data>) -> Resu
|
|||||||
data.validate()
|
data.validate()
|
||||||
.map_err(|error| Error::FailedValidation { error })?;
|
.map_err(|error| Error::FailedValidation { error })?;
|
||||||
|
|
||||||
if data.username == "revolt" {
|
if User::is_username_taken(&data.username).await? {
|
||||||
Err(Error::UsernameTaken)?
|
return Err(Error::UsernameTaken)
|
||||||
}
|
}
|
||||||
|
|
||||||
let col = get_collection("users");
|
get_collection("users").insert_one(
|
||||||
if col
|
|
||||||
.find_one(
|
|
||||||
doc! {
|
|
||||||
"username": &data.username
|
|
||||||
},
|
|
||||||
FindOneOptions::builder()
|
|
||||||
.collation(Collation::builder().locale("en").strength(2).build())
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|_| Error::DatabaseError {
|
|
||||||
operation: "find_one",
|
|
||||||
with: "user",
|
|
||||||
})?
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
Err(Error::UsernameTaken)?
|
|
||||||
}
|
|
||||||
|
|
||||||
col.insert_one(
|
|
||||||
doc! {
|
doc! {
|
||||||
"_id": session.user_id,
|
"_id": session.user_id,
|
||||||
"username": &data.username
|
"username": &data.username
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub struct Subscription {
|
|||||||
#[post("/subscribe", data = "<data>")]
|
#[post("/subscribe", data = "<data>")]
|
||||||
pub async fn req(session: Session, data: Json<Subscription>) -> Result<()> {
|
pub async fn req(session: Session, data: Json<Subscription>) -> Result<()> {
|
||||||
let data = data.into_inner();
|
let data = data.into_inner();
|
||||||
let col = get_collection("accounts")
|
get_collection("accounts")
|
||||||
.update_one(
|
.update_one(
|
||||||
doc! {
|
doc! {
|
||||||
"_id": session.user_id,
|
"_id": session.user_id,
|
||||||
@@ -24,13 +24,14 @@ pub async fn req(session: Session, data: Json<Subscription>) -> Result<()> {
|
|||||||
},
|
},
|
||||||
doc! {
|
doc! {
|
||||||
"$set": {
|
"$set": {
|
||||||
"sessions.$.subscription": to_document(&data).unwrap()
|
"sessions.$.subscription": to_document(&data)
|
||||||
|
.map_err(|_| Error::DatabaseError { operation: "to_document", with: "subscription" })?
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.map_err(|_| Error::DatabaseError { operation: "update_one", with: "account" })?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ use rauth::auth::Session;
|
|||||||
|
|
||||||
#[post("/unsubscribe")]
|
#[post("/unsubscribe")]
|
||||||
pub async fn req(session: Session) -> Result<()> {
|
pub async fn req(session: Session) -> Result<()> {
|
||||||
let col = get_collection("accounts")
|
get_collection("accounts")
|
||||||
.update_one(
|
.update_one(
|
||||||
doc! {
|
doc! {
|
||||||
"_id": session.user_id,
|
"_id": session.user_id,
|
||||||
@@ -20,7 +20,10 @@ pub async fn req(session: Session) -> Result<()> {
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.map_err(|_| Error::DatabaseError {
|
||||||
|
operation: "to_document",
|
||||||
|
with: "subscription",
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
+1
-1
@@ -9,7 +9,7 @@ use rocket_contrib::json::JsonValue;
|
|||||||
#[get("/")]
|
#[get("/")]
|
||||||
pub async fn root() -> JsonValue {
|
pub async fn root() -> JsonValue {
|
||||||
json!({
|
json!({
|
||||||
"revolt": "0.3.3-alpha.6",
|
"revolt": "0.3.3-alpha.7",
|
||||||
"features": {
|
"features": {
|
||||||
"registration": !*DISABLE_REGISTRATION,
|
"registration": !*DISABLE_REGISTRATION,
|
||||||
"captcha": {
|
"captcha": {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !perm.get_access() {
|
if !perm.get_access() {
|
||||||
Err(Error::LabelMe)?
|
Err(Error::MissingPermission)?
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(json!(target.from(&user).with(perm)))
|
Ok(json!(target.from(&user).with(perm)))
|
||||||
|
|||||||
@@ -8,15 +8,12 @@ use rocket_contrib::json::JsonValue;
|
|||||||
|
|
||||||
#[get("/<target>/mutual")]
|
#[get("/<target>/mutual")]
|
||||||
pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
||||||
let channels = get_collection("channels")
|
let users = get_collection("users")
|
||||||
.find(
|
.find(
|
||||||
doc! {
|
doc! {
|
||||||
"$or": [
|
|
||||||
{ "type": "Group" },
|
|
||||||
],
|
|
||||||
"$and": [
|
"$and": [
|
||||||
{ "recipients": &user.id },
|
{ "relations._id": &user.id, "relations.status": "Friend" },
|
||||||
{ "recipients": &target.id }
|
{ "relations._id": &target.id, "relations.status": "Friend" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
FindOptions::builder().projection(doc! { "_id": 1 }).build(),
|
FindOptions::builder().projection(doc! { "_id": 1 }).build(),
|
||||||
@@ -24,7 +21,7 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
|||||||
.await
|
.await
|
||||||
.map_err(|_| Error::DatabaseError {
|
.map_err(|_| Error::DatabaseError {
|
||||||
operation: "find",
|
operation: "find",
|
||||||
with: "channels",
|
with: "users",
|
||||||
})?
|
})?
|
||||||
.filter_map(async move |s| s.ok())
|
.filter_map(async move |s| s.ok())
|
||||||
.collect::<Vec<Document>>()
|
.collect::<Vec<Document>>()
|
||||||
@@ -33,5 +30,5 @@ pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
|
|||||||
.filter_map(|x| x.get_str("_id").ok().map(|x| x.to_string()))
|
.filter_map(|x| x.get_str("_id").ok().map(|x| x.to_string()))
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
Ok(json!({ "channels": channels }))
|
Ok(json!({ "users": users }))
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,8 @@ pub enum Error {
|
|||||||
UnknownAttachment,
|
UnknownAttachment,
|
||||||
#[snafu(display("Cannot edit someone else's message."))]
|
#[snafu(display("Cannot edit someone else's message."))]
|
||||||
CannotEditMessage,
|
CannotEditMessage,
|
||||||
|
#[snafu(display("Cannot send empty message."))]
|
||||||
|
EmptyMessage,
|
||||||
#[snafu(display("Cannot remove yourself from a group, use delete channel instead."))]
|
#[snafu(display("Cannot remove yourself from a group, use delete channel instead."))]
|
||||||
CannotRemoveYourself,
|
CannotRemoveYourself,
|
||||||
#[snafu(display("Group size is too large."))]
|
#[snafu(display("Group size is too large."))]
|
||||||
@@ -50,6 +52,8 @@ pub enum Error {
|
|||||||
NotInGroup,
|
NotInGroup,
|
||||||
|
|
||||||
// ? General errors.
|
// ? General errors.
|
||||||
|
#[snafu(display("Trying to fetch too much data."))]
|
||||||
|
TooManyIds,
|
||||||
#[snafu(display("Failed to validate fields."))]
|
#[snafu(display("Failed to validate fields."))]
|
||||||
FailedValidation { error: ValidationErrors },
|
FailedValidation { error: ValidationErrors },
|
||||||
#[snafu(display("Encountered a database error."))]
|
#[snafu(display("Encountered a database error."))]
|
||||||
@@ -59,6 +63,8 @@ pub enum Error {
|
|||||||
},
|
},
|
||||||
#[snafu(display("Internal server error."))]
|
#[snafu(display("Internal server error."))]
|
||||||
InternalError,
|
InternalError,
|
||||||
|
#[snafu(display("Missing permission."))]
|
||||||
|
MissingPermission,
|
||||||
#[snafu(display("Operation cannot be performed on this object."))]
|
#[snafu(display("Operation cannot be performed on this object."))]
|
||||||
InvalidOperation,
|
InvalidOperation,
|
||||||
#[snafu(display("Already created an object with this nonce."))]
|
#[snafu(display("Already created an object with this nonce."))]
|
||||||
@@ -88,6 +94,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
Error::UnknownChannel => Status::NotFound,
|
Error::UnknownChannel => Status::NotFound,
|
||||||
Error::UnknownAttachment => Status::BadRequest,
|
Error::UnknownAttachment => Status::BadRequest,
|
||||||
Error::CannotEditMessage => Status::Forbidden,
|
Error::CannotEditMessage => Status::Forbidden,
|
||||||
|
Error::EmptyMessage => Status::UnprocessableEntity,
|
||||||
Error::CannotRemoveYourself => Status::BadRequest,
|
Error::CannotRemoveYourself => Status::BadRequest,
|
||||||
Error::GroupTooLarge { .. } => Status::Forbidden,
|
Error::GroupTooLarge { .. } => Status::Forbidden,
|
||||||
Error::AlreadyInGroup => Status::Conflict,
|
Error::AlreadyInGroup => Status::Conflict,
|
||||||
@@ -96,7 +103,9 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
Error::FailedValidation { .. } => Status::UnprocessableEntity,
|
||||||
Error::DatabaseError { .. } => Status::InternalServerError,
|
Error::DatabaseError { .. } => Status::InternalServerError,
|
||||||
Error::InternalError => Status::InternalServerError,
|
Error::InternalError => Status::InternalServerError,
|
||||||
|
Error::MissingPermission => Status::Forbidden,
|
||||||
Error::InvalidOperation => Status::BadRequest,
|
Error::InvalidOperation => Status::BadRequest,
|
||||||
|
Error::TooManyIds => Status::BadRequest,
|
||||||
Error::DuplicateNonce => Status::Conflict,
|
Error::DuplicateNonce => Status::Conflict,
|
||||||
Error::NoEffect => Status::Ok,
|
Error::NoEffect => Status::Ok,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -52,8 +52,6 @@ lazy_static! {
|
|||||||
// Application Logic Settings
|
// Application Logic Settings
|
||||||
pub static ref MAX_GROUP_SIZE: usize =
|
pub static ref MAX_GROUP_SIZE: usize =
|
||||||
env::var("REVOLT_MAX_GROUP_SIZE").unwrap_or_else(|_| "50".to_string()).parse().unwrap();
|
env::var("REVOLT_MAX_GROUP_SIZE").unwrap_or_else(|_| "50".to_string()).parse().unwrap();
|
||||||
pub static ref PUSH_LIMIT: usize =
|
|
||||||
env::var("REVOLT_PUSH_LIMIT").unwrap_or_else(|_| "50".to_string()).parse().unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preflight_checks() {
|
pub fn preflight_checks() {
|
||||||
|
|||||||
Reference in new issue
Block a user