feat: implement channel invites, perms, group create, members fetch

chore: when you accidentally run fmt
This commit is contained in:
Paul Makles
2022-02-04 21:50:30 +00:00
parent b58755dbeb
commit 88f811761b
59 changed files with 536 additions and 195 deletions

1
Cargo.lock generated
View File

@@ -2948,6 +2948,7 @@ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
"mongodb 2.1.0", "mongodb 2.1.0",
"nanoid",
"num_enum", "num_enum",
"ops", "ops",
"optional_struct", "optional_struct",

View File

@@ -30,8 +30,8 @@ use rauth::{
logic::Auth, logic::Auth,
}; };
use revolt_quark::DatabaseInfo; use revolt_quark::DatabaseInfo;
use std::str::FromStr;
use rocket_cors::AllowedOrigins; use rocket_cors::AllowedOrigins;
use std::str::FromStr;
/*use util::variables::{ /*use util::variables::{
APP_URL, HCAPTCHA_KEY, INVITE_ONLY, SMTP_FROM, SMTP_HOST, SMTP_PASSWORD, SMTP_USERNAME, APP_URL, HCAPTCHA_KEY, INVITE_ONLY, SMTP_FROM, SMTP_HOST, SMTP_PASSWORD, SMTP_USERNAME,
USE_EMAIL, USE_HCAPTCHA, USE_EMAIL, USE_HCAPTCHA,

View File

@@ -1,7 +1,7 @@
use revolt_quark::Result;
use rauth::util::EmptyResponse; use rauth::util::EmptyResponse;
use revolt_quark::Result;
#[delete("/<target>")] #[delete("/<target>")]
pub async fn delete_bot(/*user: UserRef, target: Ref*/ target: String) -> Result<EmptyResponse> { pub async fn delete_bot(/*user: UserRef, target: Ref*/ target: String,) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,6 +1,6 @@
use crate::util::regex::RE_USERNAME; use crate::util::regex::RE_USERNAME;
use revolt_quark::{Result, models::bot::FieldsBot, EmptyResponse}; use revolt_quark::{models::bot::FieldsBot, EmptyResponse, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::serde::json::Json; use rocket::serde::json::Json;
@@ -19,6 +19,9 @@ pub struct Data {
} }
#[patch("/<target>", data = "<data>")] #[patch("/<target>", data = "<data>")]
pub async fn edit_bot(/*user: UserRef, target: Ref,*/ target: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn edit_bot(
/*user: UserRef, target: Ref,*/ target: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -5,22 +5,25 @@ use serde::Deserialize;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct ServerId { pub struct ServerId {
server: String server: String,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct GroupId { pub struct GroupId {
group: String group: String,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum Destination { pub enum Destination {
Server(ServerId), Server(ServerId),
Group(GroupId) Group(GroupId),
} }
#[post("/<target>/invite", data = "<dest>")] #[post("/<target>/invite", data = "<dest>")]
pub async fn invite_bot(/*user: UserRef, target: Ref,*/ target: String, dest: Json<Destination>) -> Result<EmptyResponse> { pub async fn invite_bot(
/*user: UserRef, target: Ref,*/ target: String,
dest: Json<Destination>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,12 +1,12 @@
use rocket::Route; use rocket::Route;
mod create; mod create;
mod invite; mod delete;
mod fetch_public; mod edit;
mod fetch; mod fetch;
mod fetch_owned; mod fetch_owned;
mod edit; mod fetch_public;
mod delete; mod invite;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![ routes![

View File

@@ -1,6 +1,9 @@
use revolt_quark::{EmptyResponse, Result}; use revolt_quark::{EmptyResponse, Result};
#[put("/<target>/ack/<message>")] #[put("/<target>/ack/<message>")]
pub async fn req(/*user: UserRef, target: Ref, message: Ref*/ target: String, message: String) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref, message: Ref*/ target: String,
message: String,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,4 +1,7 @@
use revolt_quark::{Error, EmptyResponse, Result, models::{User, Channel, channel::PartialChannel}, Ref, Db, perms, ChannelPermission}; use revolt_quark::{
models::{channel::PartialChannel, Channel, User},
perms, ChannelPermission, Db, EmptyResponse, Error, Ref, Result,
};
use mongodb::bson::doc; use mongodb::bson::doc;
@@ -8,16 +11,21 @@ pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
let perm = perms(&user).channel(&channel).calc_channel(db).await; let perm = perms(&user).channel(&channel).calc_channel(db).await;
if !perm.get_view() { if !perm.get_view() {
return Err(Error::NotFound) return Err(Error::NotFound);
} }
match channel { match channel {
Channel::SavedMessages { .. } => Err(Error::NoEffect), Channel::SavedMessages { .. } => Err(Error::NoEffect),
Channel::DirectMessage { id, .. } => { Channel::DirectMessage { id, .. } => {
db.update_channel(&id, &PartialChannel { db.update_channel(
active: Some(false), &id,
..Default::default() &PartialChannel {
}, vec![]).await?; active: Some(false),
..Default::default()
},
vec![],
)
.await?;
Ok(EmptyResponse) Ok(EmptyResponse)
} }
@@ -29,10 +37,15 @@ pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
} => { } => {
if user.id == owner { if user.id == owner {
if let Some(new_owner) = recipients.iter().find(|x| *x != &user.id) { if let Some(new_owner) = recipients.iter().find(|x| *x != &user.id) {
db.update_channel(&id, &PartialChannel { db.update_channel(
owner: Some(new_owner.into()), &id,
..Default::default() &PartialChannel {
}, vec![]).await?; owner: Some(new_owner.into()),
..Default::default()
},
vec![],
)
.await?;
} else { } else {
db.delete_channel(&id).await?; db.delete_channel(&id).await?;
return Ok(EmptyResponse); return Ok(EmptyResponse);
@@ -54,13 +67,14 @@ pub async fn req(db: &Db, user: User, target: Ref) -> Result<EmptyResponse> {
Ok(EmptyResponse) Ok(EmptyResponse)
} }
Channel::TextChannel { id, .. } | Channel::TextChannel { id, .. } | Channel::VoiceChannel { id, .. } => {
Channel::VoiceChannel { id, .. } => {
if perm.get_manage_channel() { if perm.get_manage_channel() {
db.delete_channel(&id).await?; db.delete_channel(&id).await?;
Ok(EmptyResponse) Ok(EmptyResponse)
} else { } else {
Err(Error::MissingPermission { permission: ChannelPermission::ManageChannel as i32 }) Err(Error::MissingPermission {
permission: ChannelPermission::ManageChannel as i32,
})
} }
} }
} }

View File

@@ -1,4 +1,10 @@
use revolt_quark::{Error, Result, models::{channel::{FieldsChannel, PartialChannel, Channel}, User, File}, Ref, Database, perms, ChannelPermission}; use revolt_quark::{
models::{
channel::{Channel, FieldsChannel, PartialChannel},
File, User,
},
perms, ChannelPermission, Database, Error, Ref, Result,
};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
@@ -22,24 +28,63 @@ pub struct Data {
} }
#[patch("/<target>", data = "<data>")] #[patch("/<target>", data = "<data>")]
pub async fn req(db: &State<Database>, user: User, target: Ref, data: Json<Data>) -> Result<Json<Channel>> { pub async fn req(
db: &State<Database>,
user: User,
target: Ref,
data: Json<Data>,
) -> Result<Json<Channel>> {
let data = data.into_inner(); let data = data.into_inner();
data.validate().map_err(|error| Error::FailedValidation { error })?; data.validate()
.map_err(|error| Error::FailedValidation { error })?;
let mut channel = target.as_channel(db).await?; let mut channel = target.as_channel(db).await?;
if !perms(&user).channel(&channel).calc_channel(db).await.get_manage_channel() { if !perms(&user)
return Err(Error::MissingPermission { permission: ChannelPermission::ManageChannel as i32 }) .channel(&channel)
.calc_channel(db)
.await
.get_manage_channel()
{
return Err(Error::MissingPermission {
permission: ChannelPermission::ManageChannel as i32,
});
} }
if data.name.is_none() && data.description.is_none() && data.icon.is_none() && data.nsfw.is_none() && data.remove.is_none() { if data.name.is_none()
return Ok(Json(channel)) && data.description.is_none()
&& data.icon.is_none()
&& data.nsfw.is_none()
&& data.remove.is_none()
{
return Ok(Json(channel));
} }
let mut partial: PartialChannel = Default::default(); let mut partial: PartialChannel = Default::default();
match &mut channel { match &mut channel {
Channel::Group { id, name, description, icon, nsfw, .. } Channel::Group {
| Channel::TextChannel { id, name, description, icon, nsfw, .. } id,
| Channel::VoiceChannel { id, name, description, icon, nsfw, .. } => { name,
description,
icon,
nsfw,
..
}
| Channel::TextChannel {
id,
name,
description,
icon,
nsfw,
..
}
| Channel::VoiceChannel {
id,
name,
description,
icon,
nsfw,
..
} => {
if let Some(fields) = &data.remove { if let Some(fields) = &data.remove {
if fields.contains(&FieldsChannel::Icon) { if fields.contains(&FieldsChannel::Icon) {
if let Some(icon) = &icon { if let Some(icon) = &icon {
@@ -51,10 +96,10 @@ pub async fn req(db: &State<Database>, user: User, target: Ref, data: Json<Data>
match field { match field {
FieldsChannel::Description => { FieldsChannel::Description => {
description.take(); description.take();
}, }
FieldsChannel::Icon => { FieldsChannel::Icon => {
icon.take(); icon.take();
}, }
_ => {} _ => {}
} }
} }
@@ -80,9 +125,10 @@ pub async fn req(db: &State<Database>, user: User, target: Ref, data: Json<Data>
partial.nsfw = Some(new_nsfw); partial.nsfw = Some(new_nsfw);
} }
db.update_channel(id, &partial, data.remove.unwrap_or_default()).await?; db.update_channel(id, &partial, data.remove.unwrap_or_default())
}, .await?;
_ => return Err(Error::InvalidOperation) }
_ => return Err(Error::InvalidOperation),
}; };
Ok(Json(channel)) Ok(Json(channel))

View File

@@ -1,4 +1,7 @@
use revolt_quark::{Error, Result, models::{User, Channel}, Ref, Database, perms, ChannelPermission}; use revolt_quark::{
models::{Channel, User},
perms, ChannelPermission, Database, Error, Ref, Result,
};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
@@ -6,9 +9,16 @@ use rocket::{serde::json::Json, State};
pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<Channel>> { pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<Channel>> {
let target = target.as_channel(db).await?; let target = target.as_channel(db).await?;
if perms(&user).channel(&target).calc_channel(db).await.get_view() { if perms(&user)
.channel(&target)
.calc_channel(db)
.await
.get_view()
{
Ok(Json(target)) Ok(Json(target))
} else { } else {
Err(Error::MissingPermission { permission: ChannelPermission::View as i32 }) Err(Error::MissingPermission {
permission: ChannelPermission::View as i32,
})
} }
} }

View File

@@ -3,6 +3,9 @@ use revolt_quark::{EmptyResponse, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
#[put("/<target>/recipients/<member>")] #[put("/<target>/recipients/<member>")]
pub async fn req(/*user: UserRef, target: Ref, member: Ref*/ target: String, member: String) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref, member: Ref*/ target: String,
member: String,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,8 +1,15 @@
use revolt_quark::Result; use std::{collections::HashSet, iter::FromIterator};
use revolt_quark::{
get_relationship,
models::{user::RelationshipStatus, Channel, User},
Db, Error, Result,
};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::serde::json::{Json, Value}; use rocket::serde::json::Json;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ulid::Ulid;
use validator::Validate; use validator::Validate;
#[derive(Validate, Serialize, Deserialize)] #[derive(Validate, Serialize, Deserialize)]
@@ -13,10 +20,48 @@ pub struct Data {
description: Option<String>, description: Option<String>,
users: Vec<String>, users: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
nsfw: Option<bool> nsfw: Option<bool>,
} }
#[post("/create", data = "<info>")] #[post("/create", data = "<info>")]
pub async fn req(/*_idempotency: IdempotencyKey, user: User,*/ info: Json<Data>) -> Result<Value> { pub async fn req(db: &Db, user: User, info: Json<Data>) -> Result<Json<Channel>> {
todo!(); let info = info.into_inner();
info.validate()
.map_err(|error| Error::FailedValidation { error })?;
let mut set: HashSet<String> = HashSet::from_iter(info.users.into_iter());
set.insert(user.id.clone());
// ! FIXME: un hard code this
if set.len() > 50 {
return Err(Error::GroupTooLarge { max: 50 });
}
for target in &set {
match get_relationship(&user, target) {
RelationshipStatus::Friend | RelationshipStatus::User => {}
_ => {
return Err(Error::NotFriends);
}
}
}
let group = Channel::Group {
id: Ulid::new().to_string(),
name: info.name,
owner: user.id,
description: info.description,
recipients: set.into_iter().collect::<Vec<String>>(),
icon: None,
last_message_id: None,
permissions: None,
nsfw: info.nsfw.unwrap_or(false),
};
db.insert_channel(&group).await?;
Ok(Json(group))
} }

View File

@@ -3,6 +3,9 @@ use revolt_quark::{EmptyResponse, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
#[delete("/<target>/recipients/<member>")] #[delete("/<target>/recipients/<member>")]
pub async fn req(/*user: UserRef, target: Ref, member: Ref*/ target: String, member: String) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref, member: Ref*/ target: String,
member: String,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,17 +1,25 @@
use revolt_quark::Result; use revolt_quark::{
models::{Invite, User},
perms, ChannelPermission, Db, Error, Ref, Result,
};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::serde::json::Value; use rocket::serde::json::Json;
lazy_static! {
static ref ALPHABET: [char; 54] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z'
];
}
#[post("/<target>/invites")] #[post("/<target>/invites")]
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> { pub async fn req(db: &Db, user: User, target: Ref) -> Result<Json<Invite>> {
todo!() let channel = target.as_channel(db).await?;
if !perms(&user)
.channel(&channel)
.calc_channel(db)
.await
.get_invite_others()
{
return Err(Error::MissingPermission {
permission: ChannelPermission::InviteOthers as i32,
});
}
Invite::create(db, &user, &channel).await.map(Json)
} }

View File

@@ -1,8 +1,31 @@
use revolt_quark::Result; use revolt_quark::{
models::{Channel, User},
perms, Db, Error, Ref, Result,
};
use rocket::serde::json::Value; use rocket::serde::json::Json;
#[get("/<target>/members")] #[get("/<target>/members")]
pub async fn req(/*user: UserRef, target: Ref*/ target: String) -> Result<Value> { pub async fn req(db: &Db, user: User, target: Ref) -> Result<Json<Vec<User>>> {
todo!() let channel = target.as_channel(db).await?;
if !perms(&user)
.channel(&channel)
.calc_channel(db)
.await
.get_view()
{
return Err(Error::NotFound);
}
if let Channel::Group { recipients, .. } = channel {
Ok(Json(
db.fetch_users(&recipients)
.await?
.into_iter()
.map(|x| x.with_relationship(&user))
.collect::<Vec<User>>(),
))
} else {
Err(Error::InvalidOperation)
}
} }

View File

@@ -3,6 +3,9 @@ use revolt_quark::{EmptyResponse, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
#[delete("/<target>/messages/<msg>")] #[delete("/<target>/messages/<msg>")]
pub async fn req(/*user: UserRef, target: Ref, msg: Ref*/ target: String, msg: String) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref, msg: Ref*/ target: String,
msg: String,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,7 +1,7 @@
use revolt_quark::{EmptyResponse, Result}; use revolt_quark::{EmptyResponse, Result};
use chrono::Utc; use chrono::Utc;
use mongodb::bson::{Bson, Document, doc, to_document}; use mongodb::bson::{doc, to_document, Bson, Document};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use validator::Validate; use validator::Validate;
@@ -15,6 +15,10 @@ pub struct Data {
} }
#[patch("/<target>/messages/<msg>", data = "<edit>")] #[patch("/<target>/messages/<msg>", data = "<edit>")]
pub async fn req(/*user: UserRef, target: Ref, msg: Ref,*/ target: String, msg: String, edit: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref, msg: Ref,*/ target: String,
msg: String,
edit: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -3,6 +3,9 @@ use revolt_quark::Result;
use rocket::serde::json::Value; use rocket::serde::json::Value;
#[get("/<target>/messages/<msg>")] #[get("/<target>/messages/<msg>")]
pub async fn req(/*user: UserRef, target: Ref, msg: Ref*/ target: String, msg: String) -> Result<Value> { pub async fn req(
/*user: UserRef, target: Ref, msg: Ref*/ target: String,
msg: String,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -2,7 +2,7 @@ use std::collections::HashSet;
use revolt_quark::{Error, Result}; use revolt_quark::{Error, Result};
use futures::{StreamExt, try_join}; use futures::{try_join, StreamExt};
use mongodb::{ use mongodb::{
bson::{doc, from_document}, bson::{doc, from_document},
options::FindOptions, options::FindOptions,
@@ -35,6 +35,9 @@ pub struct Options {
} }
#[get("/<target>/messages?<options..>")] #[get("/<target>/messages?<options..>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, options: Options) -> Result<Value> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
options: Options,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -11,6 +11,9 @@ pub struct Options {
} }
#[post("/<target>/messages/stale", data = "<data>")] #[post("/<target>/messages/stale", data = "<data>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, data: Json<Options>) -> Result<Value> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
data: Json<Options>,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -39,6 +39,9 @@ pub struct Options {
} }
#[post("/<target>/search", data = "<options>")] #[post("/<target>/search", data = "<options>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, options: Json<Options>) -> Result<Value> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
options: Json<Options>,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -1,4 +1,4 @@
use revolt_quark::{Result, models::message::Masquerade}; use revolt_quark::{models::message::Masquerade, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use regex::Regex; use regex::Regex;
@@ -9,7 +9,7 @@ use validator::Validate;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Reply { pub struct Reply {
id: String, id: String,
mention: bool mention: bool,
} }
#[derive(Validate, Serialize, Deserialize, Clone, Debug)] #[derive(Validate, Serialize, Deserialize, Clone, Debug)]
@@ -21,7 +21,7 @@ pub struct SendableEmbed {
#[validate(length(min = 1, max = 2000))] #[validate(length(min = 1, max = 2000))]
description: Option<String>, description: Option<String>,
media: Option<String>, media: Option<String>,
colour: Option<String>, colour: Option<String>,
} }
#[derive(Validate, Serialize, Deserialize)] #[derive(Validate, Serialize, Deserialize)]
pub struct Data { pub struct Data {
@@ -34,7 +34,7 @@ pub struct Data {
//#[validate] //#[validate]
masquerade: Option<Masquerade>, masquerade: Option<Masquerade>,
#[validate(length(min = 1, max = 10))] #[validate(length(min = 1, max = 10))]
embeds: Option<Vec<SendableEmbed>> embeds: Option<Vec<SendableEmbed>>,
} }
lazy_static! { lazy_static! {
@@ -43,6 +43,10 @@ lazy_static! {
} }
#[post("/<target>/messages", data = "<message>")] #[post("/<target>/messages", data = "<message>")]
pub async fn message_send(/*user: UserRef, _r: Ratelimiter, mut idempotency: IdempotencyKey, target: Ref,*/ target: String, message: Json<Data>) -> /*Result<RatelimitResponse<Value>>*/ Result<Value> { pub async fn message_send(
/*user: UserRef, _r: Ratelimiter, mut idempotency: IdempotencyKey, target: Ref,*/
target: String,
message: Json<Data>,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -4,21 +4,21 @@ mod channel_ack;
mod channel_delete; mod channel_delete;
mod channel_edit; mod channel_edit;
mod channel_fetch; mod channel_fetch;
mod members_fetch;
mod group_add_member; mod group_add_member;
mod group_create; mod group_create;
mod group_remove_member; mod group_remove_member;
mod invite_create; mod invite_create;
mod voice_join; mod members_fetch;
mod message_delete; mod message_delete;
mod message_edit; mod message_edit;
mod message_fetch; mod message_fetch;
mod message_query; mod message_query;
mod message_search;
mod message_query_stale; mod message_query_stale;
mod message_search;
mod message_send; mod message_send;
mod permissions_set; mod permissions_set;
mod permissions_set_default; mod permissions_set_default;
mod voice_join;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![ routes![

View File

@@ -1,16 +1,44 @@
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use validator::Contains;
use revolt_quark::{EmptyResponse, Result}; use revolt_quark::{
models::{Channel, User},
perms, ChannelPermission, Db, EmptyResponse, Error, Ref, Result,
};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Data { pub struct Data {
permissions: u32 permissions: u32,
} }
#[put("/<target>/permissions/<role>", data = "<data>", rank = 2)] #[put("/<target>/permissions/<role>", data = "<data>", rank = 2)]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, role: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
todo!() db: &Db,
user: User,
target: Ref,
role: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
let channel = target.as_channel(db).await?;
if !perms(&user)
.channel(&channel)
.calc_channel(db)
.await
.get_manage_channel()
{
return Err(Error::MissingPermission {
permission: ChannelPermission::ManageChannel as i32,
});
}
match channel {
Channel::TextChannel { id, .. } | Channel::VoiceChannel { id, .. } => {
db.set_channel_role_permission(&id, &role, data.permissions)
.await?;
}
_ => return Err(Error::InvalidOperation),
}
Ok(EmptyResponse)
} }

View File

@@ -1,15 +1,56 @@
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use revolt_quark::{EmptyResponse, Result}; use revolt_quark::{
models::{channel::PartialChannel, Channel, User},
perms, ChannelPermission, Db, EmptyResponse, Error, Ref, Result,
};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Data { pub struct Data {
permissions: u32 permissions: u32,
} }
#[put("/<target>/permissions/default", data = "<data>", rank = 1)] #[put("/<target>/permissions/default", data = "<data>", rank = 1)]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(db: &Db, user: User, target: Ref, data: Json<Data>) -> Result<EmptyResponse> {
todo!() let channel = target.as_channel(db).await?;
if !perms(&user)
.channel(&channel)
.calc_channel(db)
.await
.get_manage_channel()
{
return Err(Error::MissingPermission {
permission: ChannelPermission::ManageChannel as i32,
});
}
match channel {
Channel::Group { id, .. } => {
db.update_channel(
&id,
&PartialChannel {
permissions: Some(data.permissions as i32),
..Default::default()
},
vec![],
)
.await?;
}
Channel::TextChannel { id, .. } | Channel::VoiceChannel { id, .. } => {
db.update_channel(
&id,
&PartialChannel {
default_permissions: Some(data.permissions as i32),
..Default::default()
},
vec![],
)
.await?;
}
_ => return Err(Error::InvalidOperation),
}
Ok(EmptyResponse)
} }

View File

@@ -1,5 +1,5 @@
use revolt_quark::Result;
use revolt_quark::models::File; use revolt_quark::models::File;
use revolt_quark::Result;
use rocket::serde::json::Value; use rocket::serde::json::Value;
use serde::Serialize; use serde::Serialize;

View File

@@ -1,5 +1,5 @@
use revolt_quark::{EmptyResponse, Error, Result, models::User, Database};
use crate::util::regex::RE_USERNAME; use crate::util::regex::RE_USERNAME;
use revolt_quark::{models::User, Database, EmptyResponse, Error, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use rauth::entities::Session; use rauth::entities::Session;
@@ -14,9 +14,14 @@ pub struct Data {
} }
#[post("/complete", data = "<data>")] #[post("/complete", data = "<data>")]
pub async fn req(db: &State<Database>, session: Session, user: Option<User>, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
db: &State<Database>,
session: Session,
user: Option<User>,
data: Json<Data>,
) -> Result<EmptyResponse> {
if user.is_some() { if user.is_some() {
return Err(Error::AlreadyOnboarded) return Err(Error::AlreadyOnboarded);
} }
let data = data.into_inner(); let data = data.into_inner();
@@ -33,7 +38,5 @@ pub async fn req(db: &State<Database>, session: Session, user: Option<User>, dat
..Default::default() ..Default::default()
}; };
db.insert_user(&user) db.insert_user(&user).await.map(|_| EmptyResponse)
.await
.map(|_| EmptyResponse)
} }

View File

@@ -5,6 +5,7 @@ use rauth::entities::{Model, Session, WebPushSubscription};
use rocket::serde::json::Json; use rocket::serde::json::Json;
#[post("/subscribe"/*, data = "<data>"*/)] #[post("/subscribe"/*, data = "<data>"*/)]
pub async fn req(/*mut session: Session, data: Json<WebPushSubscription>*/) -> Result<EmptyResponse> { pub async fn req(/*mut session: Session, data: Json<WebPushSubscription>*/) -> Result<EmptyResponse>
{
todo!() todo!()
} }

View File

@@ -12,6 +12,10 @@ pub struct Data {
} }
#[put("/<server>/bans/<target>", data = "<data>")] #[put("/<server>/bans/<target>", data = "<data>")]
pub async fn req(/*user: UserRef, server: Ref, target: Ref,*/ server: String, target: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, server: Ref, target: Ref,*/ server: String,
target: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,17 +1,17 @@
use revolt_quark::{Error, Result};
use revolt_quark::models::File; use revolt_quark::models::File;
use revolt_quark::{Error, Result};
use futures::StreamExt; use futures::StreamExt;
use mongodb::options::FindOptions;
use serde::{Serialize, Deserialize};
use rocket::serde::json::Value;
use mongodb::bson::{doc, from_document}; use mongodb::bson::{doc, from_document};
use mongodb::options::FindOptions;
use rocket::serde::json::Value;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct BannedUser { struct BannedUser {
_id: String, _id: String,
username: String, username: String,
avatar: Option<File> avatar: Option<File>,
} }
#[get("/<target>/bans")] #[get("/<target>/bans")]

View File

@@ -3,6 +3,9 @@ use revolt_quark::{EmptyResponse, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
#[delete("/<server>/bans/<target>")] #[delete("/<server>/bans/<target>")]
pub async fn req(/*user: UserRef, server: Ref, target: Ref*/ server: String, target: String) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, server: Ref, target: Ref*/ server: String,
target: String,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -11,7 +11,7 @@ use validator::Validate;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
enum ChannelType { enum ChannelType {
Text, Text,
Voice Voice,
} }
impl Default for ChannelType { impl Default for ChannelType {
@@ -33,6 +33,9 @@ pub struct Data {
} }
#[post("/<target>/channels", data = "<info>")] #[post("/<target>/channels", data = "<info>")]
pub async fn req(/*_idempotency: IdempotencyKey, user: User, target: Ref,*/ target: String, info: Json<Data>) -> Result<Value> { pub async fn req(
/*_idempotency: IdempotencyKey, user: User, target: Ref,*/ target: String,
info: Json<Data>,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -1,4 +1,4 @@
use revolt_quark::{EmptyResponse, Result, models::server_member::FieldsMember}; use revolt_quark::{models::server_member::FieldsMember, EmptyResponse, Result};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -14,6 +14,10 @@ pub struct Data {
} }
#[patch("/<server>/members/<target>", data = "<data>")] #[patch("/<server>/members/<target>", data = "<data>")]
pub async fn req(/*user: UserRef, server: Ref,*/ server: String, target: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, server: Ref,*/ server: String,
target: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -4,6 +4,9 @@ use mongodb::bson::doc;
use rocket::serde::json::Value; use rocket::serde::json::Value;
#[get("/<target>/members/<member>")] #[get("/<target>/members/<member>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, member: String) -> Result<Value> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
member: String,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -3,6 +3,9 @@ use revolt_quark::{EmptyResponse, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
#[delete("/<target>/members/<member>")] #[delete("/<target>/members/<member>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, member: String) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
member: String,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,10 +1,10 @@
use rocket::Route; use rocket::Route;
mod server_ack;
mod server_create; mod server_create;
mod server_delete; mod server_delete;
mod server_edit; mod server_edit;
mod server_fetch; mod server_fetch;
mod server_ack;
mod channel_create; mod channel_create;
@@ -19,11 +19,11 @@ mod ban_remove;
mod invites_fetch; mod invites_fetch;
mod roles_create;
mod roles_edit;
mod roles_delete;
mod permissions_set; mod permissions_set;
mod permissions_set_default; mod permissions_set_default;
mod roles_create;
mod roles_delete;
mod roles_edit;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![ routes![

View File

@@ -1,21 +1,25 @@
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use revolt_quark::{EmptyResponse, Result}; use revolt_quark::{EmptyResponse, Result};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Values { pub struct Values {
server: u32, server: u32,
channel: u32 channel: u32,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Data { pub struct Data {
permissions: Values permissions: Values,
} }
#[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)] #[put("/<target>/permissions/<role_id>", data = "<data>", rank = 2)]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, role_id: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
role_id: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,21 +1,24 @@
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
use revolt_quark::{EmptyResponse, Result}; use revolt_quark::{EmptyResponse, Result};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Values { pub struct Values {
server: u32, server: u32,
channel: u32 channel: u32,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Data { pub struct Data {
permissions: Values permissions: Values,
} }
#[put("/<target>/permissions/default", data = "<data>", rank = 1)] #[put("/<target>/permissions/default", data = "<data>", rank = 1)]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,18 +1,21 @@
use revolt_quark::{Error, Result}; use revolt_quark::{Error, Result};
use ulid::Ulid;
use mongodb::bson::doc; use mongodb::bson::doc;
use validator::Validate;
use serde::{Serialize, Deserialize};
use rocket::serde::json::{Json, Value}; use rocket::serde::json::{Json, Value};
use serde::{Deserialize, Serialize};
use ulid::Ulid;
use validator::Validate;
#[derive(Validate, Serialize, Deserialize)] #[derive(Validate, Serialize, Deserialize)]
pub struct Data { pub struct Data {
#[validate(length(min = 1, max = 32))] #[validate(length(min = 1, max = 32))]
name: String name: String,
} }
#[post("/<target>/roles", data = "<data>")] #[post("/<target>/roles", data = "<data>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, data: Json<Data>) -> Result<Value> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
data: Json<Data>,
) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -1,6 +1,9 @@
use revolt_quark::{EmptyResponse, Result}; use revolt_quark::{EmptyResponse, Result};
#[delete("/<target>/roles/<role_id>")] #[delete("/<target>/roles/<role_id>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, role_id: String) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
role_id: String,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -17,6 +17,10 @@ pub struct Data {
} }
#[patch("/<target>/roles/<role_id>", data = "<data>")] #[patch("/<target>/roles/<role_id>", data = "<data>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, role_id: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
role_id: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -15,10 +15,10 @@ pub struct Data {
#[validate(length(min = 0, max = 1024))] #[validate(length(min = 0, max = 1024))]
description: Option<String>, description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
nsfw: Option<bool> nsfw: Option<bool>,
} }
#[post("/create", data = "<info>")] #[post("/create", data = "<info>")]
pub async fn req(/*_idempotency: IdempotencyKey, user: User,*/ info: Json<Data>) -> Result<Value> { pub async fn req(/*_idempotency: IdempotencyKey, user: User,*/ info: Json<Data>,) -> Result<Value> {
todo!() todo!()
} }

View File

@@ -1,4 +1,7 @@
use revolt_quark::{EmptyResponse, Result, models::server::{FieldsServer, SystemMessageChannels, Category}}; use revolt_quark::{
models::server::{Category, FieldsServer, SystemMessageChannels},
EmptyResponse, Result,
};
use rocket::serde::json::Json; use rocket::serde::json::Json;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -20,6 +23,9 @@ pub struct Data {
} }
#[patch("/<target>", data = "<data>")] #[patch("/<target>", data = "<data>")]
pub async fn req(/*user: UserRef, target: Ref,*/ target: String, data: Json<Data>) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef, target: Ref,*/ target: String,
data: Json<Data>,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -16,6 +16,9 @@ pub struct Options {
} }
#[post("/settings/set?<options..>", data = "<data>")] #[post("/settings/set?<options..>", data = "<data>")]
pub async fn req(/*user: UserRef,*/ data: Json<Data>, options: Options) -> Result<EmptyResponse> { pub async fn req(
/*user: UserRef,*/ data: Json<Data>,
options: Options,
) -> Result<EmptyResponse> {
todo!() todo!()
} }

View File

@@ -1,9 +1,9 @@
use revolt_quark::models::User; use revolt_quark::models::User;
use revolt_quark::{Result, Database}; use revolt_quark::{Database, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::State;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State;
#[put("/<username>/friend")] #[put("/<username>/friend")]
pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> { pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> {

View File

@@ -1,9 +1,9 @@
use revolt_quark::models::User; use revolt_quark::models::User;
use revolt_quark::{Result, Database}; use revolt_quark::{Database, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::State;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State;
#[put("/<username>/block")] #[put("/<username>/block")]
pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> { pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> {

View File

@@ -1,7 +1,7 @@
use revolt_quark::{Error, EmptyResponse, Result, models::User, Database};
use crate::util::regex::RE_USERNAME; use crate::util::regex::RE_USERNAME;
use mongodb::bson::doc; use mongodb::bson::doc;
use rauth::entities::Account; use rauth::entities::Account;
use revolt_quark::{models::User, Database, EmptyResponse, Error, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use validator::Validate; use validator::Validate;
@@ -22,6 +22,10 @@ pub async fn req(
data: Json<Data>, data: Json<Data>,
) -> Result<EmptyResponse> { ) -> Result<EmptyResponse> {
let data = data.into_inner(); let data = data.into_inner();
account.verify_password(&data.password).map_err(|_| Error::InvalidCredentials)?; account
user.update_username(db, data.username).await.map(|_| EmptyResponse) .verify_password(&data.password)
.map_err(|_| Error::InvalidCredentials)?;
user.update_username(db, data.username)
.await
.map(|_| EmptyResponse)
} }

View File

@@ -1,13 +1,13 @@
//! Edit currently authenticated user. //! Edit currently authenticated user.
use revolt_quark::models::user::{FieldsUser, PartialUser, User};
use revolt_quark::models::File; use revolt_quark::models::File;
use revolt_quark::{Error, Result, Database}; use revolt_quark::{Database, Error, Result};
use revolt_quark::models::user::{FieldsUser, User, PartialUser};
use mongodb::bson::doc; use mongodb::bson::doc;
use revolt_quark::models::user::UserStatus; use revolt_quark::models::user::UserStatus;
use rocket::State;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use validator::Validate; use validator::Validate;
@@ -36,10 +36,15 @@ pub struct Data {
#[patch("/@me", data = "<data>")] #[patch("/@me", data = "<data>")]
pub async fn req(db: &State<Database>, mut user: User, data: Json<Data>) -> Result<Json<User>> { pub async fn req(db: &State<Database>, mut user: User, data: Json<Data>) -> Result<Json<User>> {
let data = data.into_inner(); let data = data.into_inner();
data.validate().map_err(|error| Error::FailedValidation { error })?; data.validate()
.map_err(|error| Error::FailedValidation { error })?;
if data.status.is_none() && data.profile.is_none() && data.avatar.is_none() && data.remove.is_none() { if data.status.is_none()
return Ok(Json(user)) && data.profile.is_none()
&& data.avatar.is_none()
&& data.remove.is_none()
{
return Ok(Json(user));
} }
if let Some(fields) = &data.remove { if let Some(fields) = &data.remove {
@@ -97,6 +102,7 @@ pub async fn req(db: &State<Database>, mut user: User, data: Json<Data>) -> Resu
user.profile = partial.profile.clone(); user.profile = partial.profile.clone();
} }
db.update_user(&user.id, &partial, data.remove.unwrap_or_default()).await?; db.update_user(&user.id, &partial, data.remove.unwrap_or_default())
.await?;
Ok(Json(user.foreign())) Ok(Json(user.foreign()))
} }

View File

@@ -2,7 +2,10 @@
//! //!
//! This includes group DMs and "active" 1:1 DMs. //! This includes group DMs and "active" 1:1 DMs.
use revolt_quark::{Result, models::{Channel, User}, Database}; use revolt_quark::{
models::{Channel, User},
Database, Result,
};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};

View File

@@ -3,7 +3,10 @@
//! Will fail if the authenticated user does not //! Will fail if the authenticated user does not
//! have permission to access the other user's profile. //! have permission to access the other user's profile.
use revolt_quark::{Ref, Result, Error, models::{User, user::UserProfile}, perms, Database}; use revolt_quark::{
models::{user::UserProfile, User},
perms, Database, Error, Ref, Result,
};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
@@ -11,7 +14,12 @@ use rocket::{serde::json::Json, State};
pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<UserProfile>> { pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<UserProfile>> {
let target = target.as_user(db).await?; let target = target.as_user(db).await?;
if perms(&user).user(&target).calc_user(db).await.get_view_profile() { if perms(&user)
.user(&target)
.calc_user(db)
.await
.get_view_profile()
{
Ok(Json(target.profile.unwrap_or_default())) Ok(Json(target.profile.unwrap_or_default()))
} else { } else {
Err(Error::NotFound) Err(Error::NotFound)

View File

@@ -1,7 +1,7 @@
//! Fetch the currently authenticated session's user account //! Fetch the currently authenticated session's user account
use revolt_quark::Result;
use revolt_quark::models::User; use revolt_quark::models::User;
use revolt_quark::Result;
use rocket::serde::json::Json; use rocket::serde::json::Json;

View File

@@ -3,7 +3,7 @@
//! Will fail if the authenticated user does not //! Will fail if the authenticated user does not
//! have permission to access the other user. //! have permission to access the other user.
use revolt_quark::{Ref, Result, Error, models::User, perms, Database}; use revolt_quark::{models::User, perms, Database, Error, Ref, Result};
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};

View File

@@ -2,16 +2,21 @@
//! authenticated user and the target user //! authenticated user and the target user
use revolt_quark::models::User; use revolt_quark::models::User;
use revolt_quark::{Error, Result, perms, Database, Ref}; use revolt_quark::{perms, Database, Error, Ref, Result};
use rocket::State;
use rocket::serde::json::Value; use rocket::serde::json::Value;
use rocket::State;
#[get("/<target>/mutual")] #[get("/<target>/mutual")]
pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Value> { pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Value> {
let target = target.as_user(db).await?; let target = target.as_user(db).await?;
if perms(&user).user(&target).calc_user(db).await.get_view_profile() { if perms(&user)
.user(&target)
.calc_user(db)
.await
.get_view_profile()
{
Ok(json!({ Ok(json!({
"users": db.fetch_mutual_user_ids(&user.id, &target.id).await?, "users": db.fetch_mutual_user_ids(&user.id, &target.id).await?,
"servers": db.fetch_mutual_server_ids(&user.id, &target.id).await? "servers": db.fetch_mutual_server_ids(&user.id, &target.id).await?

View File

@@ -1,6 +1,6 @@
use rocket::{Request, Response};
use rocket::response::{self, Responder};
use rocket::fs::NamedFile; use rocket::fs::NamedFile;
use rocket::response::{self, Responder};
use rocket::{Request, Response};
use std::path::Path; use std::path::Path;
pub struct CachedFile(NamedFile); pub struct CachedFile(NamedFile);
@@ -19,22 +19,28 @@ impl<'r> Responder<'r, 'static> for CachedFile {
pub async fn req(target: String) -> Option<CachedFile> { pub async fn req(target: String) -> Option<CachedFile> {
match target.chars().nth(25).unwrap() { match target.chars().nth(25).unwrap() {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => {
NamedFile::open(Path::new("assets/user_red.png")).await.ok().map(CachedFile) NamedFile::open(Path::new("assets/user_red.png"))
.await
.ok()
.map(CachedFile)
} }
'8' | '9' | 'A' | 'C' | 'B' | 'D' | 'E' | 'F' => { '8' | '9' | 'A' | 'C' | 'B' | 'D' | 'E' | 'F' => {
NamedFile::open(Path::new("assets/user_green.png")) NamedFile::open(Path::new("assets/user_green.png"))
.await .await
.ok().map(CachedFile) .ok()
.map(CachedFile)
} }
'G' | 'H' | 'J' | 'K' | 'M' | 'N' | 'P' | 'Q' => { 'G' | 'H' | 'J' | 'K' | 'M' | 'N' | 'P' | 'Q' => {
NamedFile::open(Path::new("assets/user_blue.png")) NamedFile::open(Path::new("assets/user_blue.png"))
.await .await
.ok().map(CachedFile) .ok()
.map(CachedFile)
} }
'R' | 'S' | 'T' | 'V' | 'W' | 'X' | 'Y' | 'Z' => { 'R' | 'S' | 'T' | 'V' | 'W' | 'X' | 'Y' | 'Z' => {
NamedFile::open(Path::new("assets/user_yellow.png")) NamedFile::open(Path::new("assets/user_yellow.png"))
.await .await
.ok().map(CachedFile) .ok()
.map(CachedFile)
} }
_ => unreachable!(), _ => unreachable!(),
} }

View File

@@ -6,13 +6,13 @@ mod change_username;
mod edit_user; mod edit_user;
mod fetch_dms; mod fetch_dms;
mod fetch_profile; mod fetch_profile;
mod fetch_self;
mod fetch_user; mod fetch_user;
mod find_mutual; mod find_mutual;
mod get_default_avatar; mod get_default_avatar;
mod open_dm; mod open_dm;
mod remove_friend; mod remove_friend;
mod unblock_user; mod unblock_user;
mod fetch_self;
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![ routes![

View File

@@ -1,9 +1,12 @@
//! Open a direct message with another user //! Open a direct message with another user
use revolt_quark::{Error, Result, Ref, models::{User, Channel}, Database, perms, UserPermission}; use revolt_quark::{
models::{Channel, User},
perms, Database, Error, Ref, Result, UserPermission,
};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::{State, serde::json::Json}; use rocket::{serde::json::Json, State};
use ulid::Ulid; use ulid::Ulid;
#[get("/<target>/dm")] #[get("/<target>/dm")]
@@ -12,14 +15,16 @@ pub async fn req(db: &State<Database>, user: User, target: Ref) -> Result<Json<C
if let Ok(channel) = db.find_direct_message_channel(&user.id, &target.id).await { if let Ok(channel) = db.find_direct_message_channel(&user.id, &target.id).await {
Ok(Json(channel)) Ok(Json(channel))
} else if perms(&user).user(&target).calc_user(db).await.get_send_message() { } else if perms(&user)
.user(&target)
.calc_user(db)
.await
.get_send_message()
{
let new_channel = Channel::DirectMessage { let new_channel = Channel::DirectMessage {
id: Ulid::new().to_string(), id: Ulid::new().to_string(),
active: false, active: false,
recipients: vec! [ recipients: vec![user.id.clone(), target.id.clone()],
user.id.clone(),
target.id.clone()
],
last_message_id: None, last_message_id: None,
}; };

View File

@@ -1,9 +1,9 @@
use revolt_quark::models::User; use revolt_quark::models::User;
use revolt_quark::{Result, Database}; use revolt_quark::{Database, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::State;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State;
#[delete("/<username>/friend")] #[delete("/<username>/friend")]
pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> { pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> {

View File

@@ -1,9 +1,9 @@
use revolt_quark::models::User; use revolt_quark::models::User;
use revolt_quark::{Result, Database}; use revolt_quark::{Database, Result};
use mongodb::bson::doc; use mongodb::bson::doc;
use rocket::State;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State;
#[delete("/<username>/block")] #[delete("/<username>/block")]
pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> { pub async fn req(db: &State<Database>, user: User, username: String) -> Result<Json<User>> {