Refractor to use UserRef.
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
[development]
|
[development]
|
||||||
address = "192.168.0.10"
|
address = "192.168.0.10"
|
||||||
port = 5500
|
port = 5500
|
||||||
|
|
||||||
|
[production]
|
||||||
|
address = "192.168.0.10"
|
||||||
|
port = 5500
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use bson::{bson, doc};
|
use bson::{bson, doc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{get_collection, MemberPermissions};
|
use super::get_collection;
|
||||||
use mongodb::options::FindOneOptions;
|
use mongodb::options::FindOneOptions;
|
||||||
|
|
||||||
pub fn find_member_permissions<C: Into<Option<String>>>(
|
pub fn find_member_permissions<C: Into<Option<String>>>(
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ pub fn get_collection(collection: &str) -> Collection {
|
|||||||
get_db().collection(collection)
|
get_db().collection(collection)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod permissions;
|
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
pub mod guild;
|
pub mod guild;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
|
pub mod permissions;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
pub use permissions::*;
|
pub use permissions::*;
|
||||||
|
|||||||
@@ -9,6 +9,107 @@ bitfield! {
|
|||||||
pub get_send_messages, set_send_messages: 2;
|
pub get_send_messages, set_send_messages: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//struct PermissionCalculator {
|
use super::get_collection;
|
||||||
//channel: Option<>,
|
use crate::guards::channel::ChannelRef;
|
||||||
//}
|
use crate::guards::guild::GuildRef;
|
||||||
|
|
||||||
|
use bson::{bson, doc};
|
||||||
|
use mongodb::options::FindOneOptions;
|
||||||
|
|
||||||
|
pub struct PermissionCalculator {
|
||||||
|
pub user_id: String,
|
||||||
|
pub channel: Option<ChannelRef>,
|
||||||
|
pub guild: Option<GuildRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PermissionCalculator {
|
||||||
|
pub fn new(user_id: String) -> PermissionCalculator {
|
||||||
|
PermissionCalculator {
|
||||||
|
user_id,
|
||||||
|
channel: None,
|
||||||
|
guild: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn channel(self, channel: ChannelRef) -> PermissionCalculator {
|
||||||
|
PermissionCalculator {
|
||||||
|
channel: Some(channel),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn guild(self, guild: GuildRef) -> PermissionCalculator {
|
||||||
|
PermissionCalculator {
|
||||||
|
guild: Some(guild),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate(self) -> u8 {
|
||||||
|
let guild = if let Some(value) = self.guild {
|
||||||
|
Some(value)
|
||||||
|
} else if let Some(channel) = &self.channel {
|
||||||
|
match channel.channel_type {
|
||||||
|
0..=1 => None,
|
||||||
|
2 => {
|
||||||
|
if let Some(id) = &channel.guild {
|
||||||
|
GuildRef::from(id.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut permissions = 0;
|
||||||
|
if let Some(guild) = guild {
|
||||||
|
if let Some(_data) = guild.fetch_data_given(
|
||||||
|
doc! {
|
||||||
|
"members": {
|
||||||
|
"$elemMatch": {
|
||||||
|
"id": &self.user_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
doc! { }
|
||||||
|
) {
|
||||||
|
if guild.owner == self.user_id {
|
||||||
|
return u8::MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions = guild.default_permissions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(channel) = &self.channel {
|
||||||
|
match channel.channel_type {
|
||||||
|
0 => {
|
||||||
|
if let Some(arr) = &channel.recipients {
|
||||||
|
for item in arr {
|
||||||
|
if item == &self.user_id {
|
||||||
|
permissions = 49;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
1 => {
|
||||||
|
unreachable!()
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
// nothing implemented yet
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_permission(self) -> MemberPermissions<[u8; 1]> {
|
||||||
|
MemberPermissions([ self.calculate() ])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,51 @@
|
|||||||
use rocket::http::{RawStr, Status};
|
use rocket::http::{RawStr, Status};
|
||||||
use rocket::request::{self, FromParam, FromRequest, Request};
|
use rocket::request::{self, FromParam, FromRequest, Request};
|
||||||
use rocket::Outcome;
|
use rocket::Outcome;
|
||||||
|
use bson::{bson, doc, from_bson, Document};
|
||||||
use bson::{bson, doc, from_bson};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use mongodb::options::FindOneOptions;
|
||||||
|
|
||||||
use crate::database;
|
use crate::database;
|
||||||
use database::user::User;
|
use database::user::{User, UserRelationship};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct UserRef {
|
||||||
|
pub id: String,
|
||||||
|
pub username: String,
|
||||||
|
pub email_verified: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserRef {
|
||||||
|
pub fn fetch_data(&self, projection: Document) -> Option<Document> {
|
||||||
|
database::get_collection("users")
|
||||||
|
.find_one(
|
||||||
|
doc! { "_id": &self.id },
|
||||||
|
FindOneOptions::builder().projection(projection).build(),
|
||||||
|
)
|
||||||
|
.expect("Failed to fetch user from database.")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_relationships(&self) -> Option<Vec<UserRelationship>> {
|
||||||
|
let user = database::get_collection("users")
|
||||||
|
.find_one(
|
||||||
|
doc! { "_id": &self.id },
|
||||||
|
FindOneOptions::builder().projection(doc! { "relations": 1 }).build(),
|
||||||
|
)
|
||||||
|
.expect("Failed to fetch user relationships from database.")
|
||||||
|
.expect("Missing user document.");
|
||||||
|
|
||||||
|
if let Ok(arr) = user.get_array("relations") {
|
||||||
|
let mut relationships = vec![];
|
||||||
|
for item in arr {
|
||||||
|
relationships.push(from_bson(item.clone()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(relationships)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AuthError {
|
pub enum AuthError {
|
||||||
@@ -14,6 +54,45 @@ pub enum AuthError {
|
|||||||
Invalid,
|
Invalid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'r> FromRequest<'a, 'r> for UserRef {
|
||||||
|
type Error = AuthError;
|
||||||
|
|
||||||
|
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||||
|
let keys: Vec<_> = request.headers().get("x-auth-token").collect();
|
||||||
|
match keys.len() {
|
||||||
|
0 => Outcome::Failure((Status::Forbidden, AuthError::Missing)),
|
||||||
|
1 => {
|
||||||
|
let key = keys[0];
|
||||||
|
let result = database::get_collection("users")
|
||||||
|
.find_one(
|
||||||
|
doc! { "access_token": key },
|
||||||
|
FindOneOptions::builder()
|
||||||
|
.projection(doc! {
|
||||||
|
"_id": 1,
|
||||||
|
"username": 1,
|
||||||
|
"email_verification.verified": 1,
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(user) = result {
|
||||||
|
Outcome::Success(
|
||||||
|
UserRef {
|
||||||
|
id: user.get_str("_id").unwrap().to_string(),
|
||||||
|
username: user.get_str("username").unwrap().to_string(),
|
||||||
|
email_verified: user.get_document("email_verification").unwrap().get_bool("verified").unwrap(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Outcome::Failure((Status::Forbidden, AuthError::Invalid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'r> FromRequest<'a, 'r> for User {
|
impl<'a, 'r> FromRequest<'a, 'r> for User {
|
||||||
type Error = AuthError;
|
type Error = AuthError;
|
||||||
|
|
||||||
@@ -39,6 +118,38 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'r> FromParam<'r> for UserRef {
|
||||||
|
type Error = &'r RawStr;
|
||||||
|
|
||||||
|
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||||
|
let col = database::get_db().collection("users");
|
||||||
|
let result = database::get_collection("users")
|
||||||
|
.find_one(
|
||||||
|
doc! { "_id": param.to_string() },
|
||||||
|
FindOneOptions::builder()
|
||||||
|
.projection(doc! {
|
||||||
|
"_id": 1,
|
||||||
|
"username": 1,
|
||||||
|
"email_verification.verified": 1,
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(user) = result {
|
||||||
|
Ok(
|
||||||
|
UserRef {
|
||||||
|
id: user.get_str("_id").unwrap().to_string(),
|
||||||
|
username: user.get_str("username").unwrap().to_string(),
|
||||||
|
email_verified: user.get_document("email_verification").unwrap().get_bool("verified").unwrap(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(param)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'r> FromParam<'r> for User {
|
impl<'r> FromParam<'r> for User {
|
||||||
type Error = &'r RawStr;
|
type Error = &'r RawStr;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use bson::{bson, doc, from_bson};
|
use bson::{bson, doc, from_bson, Document};
|
||||||
|
use mongodb::options::FindOneOptions;
|
||||||
use rocket::http::RawStr;
|
use rocket::http::RawStr;
|
||||||
use rocket::request::FromParam;
|
use rocket::request::FromParam;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::database;
|
use crate::database;
|
||||||
|
|
||||||
@@ -24,6 +26,56 @@ impl<'r> FromParam<'r> for Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct ChannelRef {
|
||||||
|
#[serde(rename = "_id")]
|
||||||
|
pub id: String,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub channel_type: u8,
|
||||||
|
|
||||||
|
// information required for permission calculations
|
||||||
|
pub recipients: Option<Vec<String>>,
|
||||||
|
pub guild: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChannelRef {
|
||||||
|
pub fn fetch_data(&self, projection: Document) -> Option<Document> {
|
||||||
|
database::get_collection("channels")
|
||||||
|
.find_one(
|
||||||
|
doc! { "_id": &self.id },
|
||||||
|
FindOneOptions::builder().projection(projection).build(),
|
||||||
|
)
|
||||||
|
.expect("Failed to fetch channel from database.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> FromParam<'r> for ChannelRef {
|
||||||
|
type Error = &'r RawStr;
|
||||||
|
|
||||||
|
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||||
|
let id = param.to_string();
|
||||||
|
let result = database::get_collection("channels")
|
||||||
|
.find_one(
|
||||||
|
doc! { "_id": id },
|
||||||
|
FindOneOptions::builder()
|
||||||
|
.projection(doc! {
|
||||||
|
"_id": 1,
|
||||||
|
"type": 1,
|
||||||
|
"recipients": 1,
|
||||||
|
"guild": 1,
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(channel) = result {
|
||||||
|
Ok(from_bson(bson::Bson::Document(channel)).expect("Failed to deserialize channel."))
|
||||||
|
} else {
|
||||||
|
Err(param)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'r> FromParam<'r> for Message {
|
impl<'r> FromParam<'r> for Message {
|
||||||
type Error = &'r RawStr;
|
type Error = &'r RawStr;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,73 @@
|
|||||||
use bson::{bson, doc, from_bson};
|
use bson::{bson, doc, from_bson, Document};
|
||||||
|
use mongodb::options::FindOneOptions;
|
||||||
use rocket::http::RawStr;
|
use rocket::http::RawStr;
|
||||||
use rocket::request::FromParam;
|
use rocket::request::FromParam;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::database;
|
use crate::database;
|
||||||
|
use crate::database::guild::Guild;
|
||||||
|
|
||||||
use database::guild::Guild;
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct GuildRef {
|
||||||
|
#[serde(rename = "_id")]
|
||||||
|
pub id: String,
|
||||||
|
|
||||||
|
pub owner: String,
|
||||||
|
pub default_permissions: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GuildRef {
|
||||||
|
pub fn from(id: String) -> Option<GuildRef> {
|
||||||
|
match database::get_collection("guilds").find_one(
|
||||||
|
doc! { "_id": id },
|
||||||
|
FindOneOptions::builder()
|
||||||
|
.projection(doc! {
|
||||||
|
"owner": 1,
|
||||||
|
"default_permissions": 1
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
) {
|
||||||
|
Ok(result) => match result {
|
||||||
|
Some(doc) => {
|
||||||
|
Some(from_bson(bson::Bson::Document(doc)).expect("Failed to unwrap guild."))
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_data(&self, projection: Document) -> Option<Document> {
|
||||||
|
database::get_collection("guilds")
|
||||||
|
.find_one(
|
||||||
|
doc! { "_id": &self.id },
|
||||||
|
FindOneOptions::builder().projection(projection).build(),
|
||||||
|
)
|
||||||
|
.expect("Failed to fetch guild from database.")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_data_given(&self, mut filter: Document, projection: Document) -> Option<Document> {
|
||||||
|
filter.insert("_id", self.id.clone());
|
||||||
|
database::get_collection("guilds")
|
||||||
|
.find_one(
|
||||||
|
filter,
|
||||||
|
FindOneOptions::builder().projection(projection).build(),
|
||||||
|
)
|
||||||
|
.expect("Failed to fetch guild from database.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> FromParam<'r> for GuildRef {
|
||||||
|
type Error = &'r RawStr;
|
||||||
|
|
||||||
|
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||||
|
if let Some(guild) = GuildRef::from(param.to_string()) {
|
||||||
|
Ok(guild)
|
||||||
|
} else {
|
||||||
|
Err(param)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'r> FromParam<'r> for Guild {
|
impl<'r> FromParam<'r> for Guild {
|
||||||
type Error = &'r RawStr;
|
type Error = &'r RawStr;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use super::Response;
|
use super::Response;
|
||||||
use crate::database::{self, channel::Channel, message::Message, user::User};
|
use crate::database::{self, channel::Channel, message::Message, user::User, PermissionCalculator};
|
||||||
|
use crate::guards::channel::ChannelRef;
|
||||||
|
use crate::guards::auth::UserRef;
|
||||||
use crate::websocket;
|
use crate::websocket;
|
||||||
|
|
||||||
use bson::{bson, doc, from_bson, Bson::UtcDatetime};
|
use bson::{bson, doc, from_bson, Bson::UtcDatetime};
|
||||||
@@ -17,53 +19,65 @@ pub enum ChannelType {
|
|||||||
GUILDCHANNEL = 2,
|
GUILDCHANNEL = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_permission(user: &User, target: &Channel) -> bool {
|
macro_rules! with_permissions {
|
||||||
match target.channel_type {
|
($user: expr, $target: expr) => {
|
||||||
0..=1 => {
|
{
|
||||||
if let Some(arr) = &target.recipients {
|
let permissions = PermissionCalculator::new($user.id.clone())
|
||||||
for item in arr {
|
.channel($target.clone())
|
||||||
if item == &user.id {
|
.as_permission();
|
||||||
return true;
|
|
||||||
}
|
if !permissions.get_access() {
|
||||||
}
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
permissions
|
||||||
}
|
}
|
||||||
2 => false,
|
};
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_recipients(target: &Channel) -> Vec<String> {
|
|
||||||
match target.channel_type {
|
|
||||||
0..=1 => target.recipients.clone().unwrap(),
|
|
||||||
_ => vec![],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// fetch channel information
|
/// fetch channel information
|
||||||
#[get("/<target>")]
|
#[get("/<target>")]
|
||||||
pub fn channel(user: User, target: Channel) -> Option<Response> {
|
pub fn channel(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||||
if !has_permission(&user, &target) {
|
with_permissions!(user, target);
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Response::Success(json!({
|
match target.channel_type {
|
||||||
"id": target.id,
|
0..=1 => Some(Response::Success(
|
||||||
"type": target.channel_type,
|
json!({
|
||||||
"recipients": get_recipients(&target),
|
"id": target.id,
|
||||||
})))
|
"type": target.channel_type,
|
||||||
|
"recipients": target.recipients,
|
||||||
|
})
|
||||||
|
)),
|
||||||
|
2 => {
|
||||||
|
if let Some(info) = target.fetch_data(
|
||||||
|
doc! {
|
||||||
|
"name": 1,
|
||||||
|
"description": 1,
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Some(Response::Success(
|
||||||
|
json!({
|
||||||
|
"id": target.id,
|
||||||
|
"type": target.channel_type,
|
||||||
|
"guild": target.guild,
|
||||||
|
"name": info.get_str("name").unwrap(),
|
||||||
|
"description": info.get_str("description").unwrap_or(""),
|
||||||
|
})
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// delete channel
|
/// delete channel
|
||||||
/// or leave group DM
|
/// or leave group DM
|
||||||
/// or close DM conversation
|
/// or close DM conversation
|
||||||
#[delete("/<target>")]
|
#[delete("/<target>")]
|
||||||
pub fn delete(user: User, target: Channel) -> Option<Response> {
|
pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||||
if !has_permission(&user, &target) {
|
with_permissions!(user, target);
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let col = database::get_collection("channels");
|
let col = database::get_collection("channels");
|
||||||
Some(match target.channel_type {
|
Some(match target.channel_type {
|
||||||
@@ -93,10 +107,8 @@ pub fn delete(user: User, target: Channel) -> Option<Response> {
|
|||||||
|
|
||||||
/// fetch channel messages
|
/// fetch channel messages
|
||||||
#[get("/<target>/messages")]
|
#[get("/<target>/messages")]
|
||||||
pub fn messages(user: User, target: Channel) -> Option<Response> {
|
pub fn messages(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||||
if !has_permission(&user, &target) {
|
with_permissions!(user, target);
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let col = database::get_collection("messages");
|
let col = database::get_collection("messages");
|
||||||
let result = col.find(doc! { "channel": target.id }, None).unwrap();
|
let result = col.find(doc! { "channel": target.id }, None).unwrap();
|
||||||
@@ -124,10 +136,8 @@ pub struct SendMessage {
|
|||||||
|
|
||||||
/// send a message to a channel
|
/// send a message to a channel
|
||||||
#[post("/<target>/messages", data = "<message>")]
|
#[post("/<target>/messages", data = "<message>")]
|
||||||
pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) -> Option<Response> {
|
pub fn send_message(user: UserRef, target: ChannelRef, message: Json<SendMessage>) -> Option<Response> {
|
||||||
if !has_permission(&user, &target) {
|
with_permissions!(user, target);
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let content: String = message.content.chars().take(2000).collect();
|
let content: String = message.content.chars().take(2000).collect();
|
||||||
let nonce: String = message.nonce.chars().take(32).collect();
|
let nonce: String = message.nonce.chars().take(32).collect();
|
||||||
@@ -164,7 +174,7 @@ pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) ->
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
websocket::queue_message(
|
/*websocket::queue_message(
|
||||||
get_recipients(&target),
|
get_recipients(&target),
|
||||||
json!({
|
json!({
|
||||||
"type": "message",
|
"type": "message",
|
||||||
@@ -177,7 +187,7 @@ pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) ->
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);*/
|
||||||
|
|
||||||
Response::Success(json!({ "id": id }))
|
Response::Success(json!({ "id": id }))
|
||||||
} else {
|
} else {
|
||||||
@@ -190,10 +200,8 @@ pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) ->
|
|||||||
|
|
||||||
/// get a message
|
/// get a message
|
||||||
#[get("/<target>/messages/<message>")]
|
#[get("/<target>/messages/<message>")]
|
||||||
pub fn get_message(user: User, target: Channel, message: Message) -> Option<Response> {
|
pub fn get_message(user: UserRef, target: ChannelRef, message: Message) -> Option<Response> {
|
||||||
if !has_permission(&user, &target) {
|
with_permissions!(user, target);
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let prev =
|
let prev =
|
||||||
// ! CHECK IF USER HAS PERMISSION TO VIEW EDITS OF MESSAGES
|
// ! CHECK IF USER HAS PERMISSION TO VIEW EDITS OF MESSAGES
|
||||||
@@ -228,14 +236,12 @@ pub struct EditMessage {
|
|||||||
/// edit a message
|
/// edit a message
|
||||||
#[patch("/<target>/messages/<message>", data = "<edit>")]
|
#[patch("/<target>/messages/<message>", data = "<edit>")]
|
||||||
pub fn edit_message(
|
pub fn edit_message(
|
||||||
user: User,
|
user: UserRef,
|
||||||
target: Channel,
|
target: ChannelRef,
|
||||||
message: Message,
|
message: Message,
|
||||||
edit: Json<EditMessage>,
|
edit: Json<EditMessage>,
|
||||||
) -> Option<Response> {
|
) -> Option<Response> {
|
||||||
if !has_permission(&user, &target) {
|
with_permissions!(user, target);
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(if message.author != user.id {
|
Some(if message.author != user.id {
|
||||||
Response::Unauthorized(json!({ "error": "You did not send this message." }))
|
Response::Unauthorized(json!({ "error": "You did not send this message." }))
|
||||||
@@ -266,7 +272,7 @@ pub fn edit_message(
|
|||||||
None,
|
None,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
websocket::queue_message(
|
/*websocket::queue_message(
|
||||||
get_recipients(&target),
|
get_recipients(&target),
|
||||||
json!({
|
json!({
|
||||||
"type": "message_update",
|
"type": "message_update",
|
||||||
@@ -278,7 +284,7 @@ pub fn edit_message(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);*/
|
||||||
|
|
||||||
Response::Result(super::Status::Ok)
|
Response::Result(super::Status::Ok)
|
||||||
}
|
}
|
||||||
@@ -291,10 +297,8 @@ pub fn edit_message(
|
|||||||
|
|
||||||
/// delete a message
|
/// delete a message
|
||||||
#[delete("/<target>/messages/<message>")]
|
#[delete("/<target>/messages/<message>")]
|
||||||
pub fn delete_message(user: User, target: Channel, message: Message) -> Option<Response> {
|
pub fn delete_message(user: UserRef, target: ChannelRef, message: Message) -> Option<Response> {
|
||||||
if !has_permission(&user, &target) {
|
with_permissions!(user, target);
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(if message.author != user.id {
|
Some(if message.author != user.id {
|
||||||
Response::Unauthorized(json!({ "error": "You did not send this message." }))
|
Response::Unauthorized(json!({ "error": "You did not send this message." }))
|
||||||
@@ -303,7 +307,7 @@ pub fn delete_message(user: User, target: Channel, message: Message) -> Option<R
|
|||||||
|
|
||||||
match col.delete_one(doc! { "_id": message.id.clone() }, None) {
|
match col.delete_one(doc! { "_id": message.id.clone() }, None) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
websocket::queue_message(
|
/*websocket::queue_message(
|
||||||
get_recipients(&target),
|
get_recipients(&target),
|
||||||
json!({
|
json!({
|
||||||
"type": "message_delete",
|
"type": "message_delete",
|
||||||
@@ -313,7 +317,7 @@ pub fn delete_message(user: User, target: Channel, message: Message) -> Option<R
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);*/
|
||||||
|
|
||||||
Response::Result(super::Status::Ok)
|
Response::Result(super::Status::Ok)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::database::{
|
|||||||
guild::{find_member_permissions, Guild},
|
guild::{find_member_permissions, Guild},
|
||||||
user::User,
|
user::User,
|
||||||
};
|
};
|
||||||
|
use crate::guards::auth::UserRef;
|
||||||
|
|
||||||
use bson::{bson, doc, from_bson, Bson};
|
use bson::{bson, doc, from_bson, Bson};
|
||||||
use rocket_contrib::json::{Json, JsonValue};
|
use rocket_contrib::json::{Json, JsonValue};
|
||||||
@@ -15,7 +16,7 @@ use super::channel::ChannelType;
|
|||||||
|
|
||||||
/// fetch your guilds
|
/// fetch your guilds
|
||||||
#[get("/@me")]
|
#[get("/@me")]
|
||||||
pub fn my_guilds(user: User) -> Response {
|
pub fn my_guilds(user: UserRef) -> Response {
|
||||||
let col = database::get_collection("guilds");
|
let col = database::get_collection("guilds");
|
||||||
let guilds = col
|
let guilds = col
|
||||||
.find(
|
.find(
|
||||||
@@ -46,7 +47,7 @@ pub fn my_guilds(user: User) -> Response {
|
|||||||
|
|
||||||
/// fetch a guild
|
/// fetch a guild
|
||||||
#[get("/<target>")]
|
#[get("/<target>")]
|
||||||
pub fn guild(user: User, target: Guild) -> Option<Response> {
|
pub fn guild(user: UserRef, target: Guild) -> Option<Response> {
|
||||||
if find_member_permissions(user.id.clone(), target.id.clone(), None) == 0 {
|
if find_member_permissions(user.id.clone(), target.id.clone(), None) == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -72,7 +73,7 @@ pub fn guild(user: User, target: Guild) -> Option<Response> {
|
|||||||
.expect("Failed to unwrap channel.");
|
.expect("Failed to unwrap channel.");
|
||||||
|
|
||||||
channels.push(json!({
|
channels.push(json!({
|
||||||
"_id": channel.id,
|
"id": channel.id,
|
||||||
"last_message": channel.last_message,
|
"last_message": channel.last_message,
|
||||||
"name": channel.name,
|
"name": channel.name,
|
||||||
"description": channel.description,
|
"description": channel.description,
|
||||||
@@ -102,8 +103,8 @@ pub struct CreateGuild {
|
|||||||
|
|
||||||
/// create a new guild
|
/// create a new guild
|
||||||
#[post("/create", data = "<info>")]
|
#[post("/create", data = "<info>")]
|
||||||
pub fn create_guild(user: User, info: Json<CreateGuild>) -> Response {
|
pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
|
||||||
if !user.email_verification.verified {
|
if !user.email_verified {
|
||||||
return Response::Unauthorized(json!({ "error": "Email not verified!" }));
|
return Response::Unauthorized(json!({ "error": "Email not verified!" }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,75 @@
|
|||||||
use super::Response;
|
use super::Response;
|
||||||
use crate::database::{self, channel::Channel, user::User};
|
use crate::database::{self, channel::Channel, user::UserRelationship};
|
||||||
use crate::routes::channel;
|
use crate::routes::channel;
|
||||||
|
use crate::guards::auth::UserRef;
|
||||||
|
|
||||||
use bson::{bson, doc, from_bson};
|
use bson::{bson, doc, from_bson};
|
||||||
use mongodb::options::FindOptions;
|
use mongodb::options::FindOptions;
|
||||||
use rocket_contrib::json::{Json, JsonValue};
|
use rocket_contrib::json::Json;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
|
|
||||||
|
enum Relationship {
|
||||||
|
FRIEND = 0,
|
||||||
|
OUTGOING = 1,
|
||||||
|
INCOMING = 2,
|
||||||
|
BLOCKED = 3,
|
||||||
|
BLOCKEDOTHER = 4,
|
||||||
|
NONE = 5,
|
||||||
|
SELF = 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_relationship_internal(user_id: &str, target_id: &str, relationships: &Option<Vec<UserRelationship>>) -> Relationship {
|
||||||
|
if user_id == target_id {
|
||||||
|
return Relationship::SELF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = &relationships {
|
||||||
|
for entry in arr {
|
||||||
|
if entry.id == target_id {
|
||||||
|
match entry.status {
|
||||||
|
0 => return Relationship::FRIEND,
|
||||||
|
1 => return Relationship::OUTGOING,
|
||||||
|
2 => return Relationship::INCOMING,
|
||||||
|
3 => return Relationship::BLOCKED,
|
||||||
|
4 => return Relationship::BLOCKEDOTHER,
|
||||||
|
_ => return Relationship::NONE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Relationship::NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_relationship(a: &UserRef, b: &UserRef) -> Relationship {
|
||||||
|
if a.id == b.id {
|
||||||
|
return Relationship::SELF;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_relationship_internal(&a.id, &b.id, &a.fetch_relationships())
|
||||||
|
}
|
||||||
|
|
||||||
/// retrieve your user information
|
/// retrieve your user information
|
||||||
#[get("/@me")]
|
#[get("/@me")]
|
||||||
pub fn me(user: User) -> JsonValue {
|
pub fn me(user: UserRef) -> Response {
|
||||||
json!({
|
if let Some(info) = user.fetch_data(doc! { "email": 1 }) {
|
||||||
"id": user.id,
|
Response::Success(
|
||||||
"username": user.username,
|
json!({
|
||||||
"email": user.email,
|
"id": user.id,
|
||||||
"verified": user.email_verification.verified,
|
"username": user.username,
|
||||||
})
|
"email": info.get_str("email").unwrap(),
|
||||||
|
"verified": user.email_verified,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Response::InternalServerError(json!({ "error": "Failed to fetch information from database." }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// retrieve another user's information
|
/// retrieve another user's information
|
||||||
#[get("/<target>")]
|
#[get("/<target>")]
|
||||||
pub fn user(user: User, target: User) -> Response {
|
pub fn user(user: UserRef, target: UserRef) -> Response {
|
||||||
Response::Success(json!({
|
Response::Success(json!({
|
||||||
"id": target.id,
|
"id": target.id,
|
||||||
"username": target.username,
|
"username": target.username,
|
||||||
@@ -37,25 +85,30 @@ pub struct Query {
|
|||||||
/// lookup a user on Revolt
|
/// lookup a user on Revolt
|
||||||
/// currently only supports exact username searches
|
/// currently only supports exact username searches
|
||||||
#[post("/lookup", data = "<query>")]
|
#[post("/lookup", data = "<query>")]
|
||||||
pub fn lookup(user: User, query: Json<Query>) -> Response {
|
pub fn lookup(user: UserRef, query: Json<Query>) -> Response {
|
||||||
|
let relationships = user.fetch_relationships();
|
||||||
let col = database::get_collection("users");
|
let col = database::get_collection("users");
|
||||||
|
|
||||||
let users = col
|
let users = col
|
||||||
.find(
|
.find(
|
||||||
doc! { "username": query.username.clone() },
|
doc! { "username": query.username.clone() },
|
||||||
FindOptions::builder().limit(10).build(),
|
FindOptions::builder()
|
||||||
|
.projection(doc! { "_id": 1, "username": 1 })
|
||||||
|
.limit(10)
|
||||||
|
.build(),
|
||||||
)
|
)
|
||||||
.expect("Failed user lookup");
|
.expect("Failed user lookup");
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
for item in users {
|
for item in users {
|
||||||
let u: User =
|
if let Ok(doc) = item {
|
||||||
from_bson(bson::Bson::Document(item.unwrap())).expect("Failed to unwrap user.");
|
let id = doc.get_str("id").unwrap();
|
||||||
results.push(json!({
|
results.push(json!({
|
||||||
"id": u.id,
|
"id": id.clone(),
|
||||||
"username": u.username,
|
"username": doc.get_str("username").unwrap(),
|
||||||
"relationship": get_relationship(&user, &u) as u8
|
"relationship": get_relationship_internal(&user.id, &id, &relationships) as u8
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Response::Success(json!(results))
|
Response::Success(json!(results))
|
||||||
@@ -63,7 +116,7 @@ pub fn lookup(user: User, query: Json<Query>) -> Response {
|
|||||||
|
|
||||||
/// retrieve all of your DMs
|
/// retrieve all of your DMs
|
||||||
#[get("/@me/dms")]
|
#[get("/@me/dms")]
|
||||||
pub fn dms(user: User) -> Response {
|
pub fn dms(user: UserRef) -> Response {
|
||||||
let col = database::get_collection("channels");
|
let col = database::get_collection("channels");
|
||||||
|
|
||||||
let results = col
|
let results = col
|
||||||
@@ -101,7 +154,7 @@ pub fn dms(user: User) -> Response {
|
|||||||
|
|
||||||
/// open a DM with a user
|
/// open a DM with a user
|
||||||
#[get("/<target>/dm")]
|
#[get("/<target>/dm")]
|
||||||
pub fn dm(user: User, target: User) -> Response {
|
pub fn dm(user: UserRef, target: UserRef) -> Response {
|
||||||
let col = database::get_collection("channels");
|
let col = database::get_collection("channels");
|
||||||
|
|
||||||
match col.find_one(
|
match col.find_one(
|
||||||
@@ -128,44 +181,13 @@ pub fn dm(user: User, target: User) -> Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Relationship {
|
|
||||||
FRIEND = 0,
|
|
||||||
OUTGOING = 1,
|
|
||||||
INCOMING = 2,
|
|
||||||
BLOCKED = 3,
|
|
||||||
BLOCKEDOTHER = 4,
|
|
||||||
NONE = 5,
|
|
||||||
SELF = 6,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_relationship(a: &User, b: &User) -> Relationship {
|
|
||||||
if a.id == b.id {
|
|
||||||
return Relationship::SELF;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(arr) = &b.relations {
|
|
||||||
for entry in arr {
|
|
||||||
if entry.id == a.id {
|
|
||||||
match entry.status {
|
|
||||||
0 => return Relationship::FRIEND,
|
|
||||||
1 => return Relationship::INCOMING,
|
|
||||||
2 => return Relationship::OUTGOING,
|
|
||||||
3 => return Relationship::BLOCKEDOTHER,
|
|
||||||
4 => return Relationship::BLOCKED,
|
|
||||||
_ => return Relationship::NONE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Relationship::NONE
|
|
||||||
}
|
|
||||||
|
|
||||||
/// retrieve all of your friends
|
/// retrieve all of your friends
|
||||||
#[get("/@me/friend")]
|
#[get("/@me/friend")]
|
||||||
pub fn get_friends(user: User) -> Response {
|
pub fn get_friends(user: UserRef) -> Response {
|
||||||
|
let relationships = user.fetch_relationships();
|
||||||
|
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
if let Some(arr) = user.relations {
|
if let Some(arr) = relationships {
|
||||||
for item in arr {
|
for item in arr {
|
||||||
results.push(json!({
|
results.push(json!({
|
||||||
"id": item.id,
|
"id": item.id,
|
||||||
@@ -179,7 +201,7 @@ pub fn get_friends(user: User) -> Response {
|
|||||||
|
|
||||||
/// retrieve friend status with user
|
/// retrieve friend status with user
|
||||||
#[get("/<target>/friend")]
|
#[get("/<target>/friend")]
|
||||||
pub fn get_friend(user: User, target: User) -> Response {
|
pub fn get_friend(user: UserRef, target: UserRef) -> Response {
|
||||||
let relationship = get_relationship(&user, &target);
|
let relationship = get_relationship(&user, &target);
|
||||||
|
|
||||||
Response::Success(json!({ "status": relationship as u8 }))
|
Response::Success(json!({ "status": relationship as u8 }))
|
||||||
@@ -187,9 +209,9 @@ pub fn get_friend(user: User, target: User) -> Response {
|
|||||||
|
|
||||||
/// create or accept a friend request
|
/// create or accept a friend request
|
||||||
#[put("/<target>/friend")]
|
#[put("/<target>/friend")]
|
||||||
pub fn add_friend(user: User, target: User) -> Response {
|
pub fn add_friend(user: UserRef, target: UserRef) -> Response {
|
||||||
let col = database::get_collection("users");
|
|
||||||
let relationship = get_relationship(&user, &target);
|
let relationship = get_relationship(&user, &target);
|
||||||
|
let col = database::get_collection("users");
|
||||||
|
|
||||||
match relationship {
|
match relationship {
|
||||||
Relationship::FRIEND => Response::BadRequest(json!({ "error": "Already friends." })),
|
Relationship::FRIEND => Response::BadRequest(json!({ "error": "Already friends." })),
|
||||||
@@ -300,9 +322,9 @@ pub fn add_friend(user: User, target: User) -> Response {
|
|||||||
|
|
||||||
/// remove a friend or deny a request
|
/// remove a friend or deny a request
|
||||||
#[delete("/<target>/friend")]
|
#[delete("/<target>/friend")]
|
||||||
pub fn remove_friend(user: User, target: User) -> Response {
|
pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
|
||||||
let col = database::get_collection("users");
|
|
||||||
let relationship = get_relationship(&user, &target);
|
let relationship = get_relationship(&user, &target);
|
||||||
|
let col = database::get_collection("users");
|
||||||
|
|
||||||
match relationship {
|
match relationship {
|
||||||
Relationship::FRIEND | Relationship::OUTGOING | Relationship::INCOMING => {
|
Relationship::FRIEND | Relationship::OUTGOING | Relationship::INCOMING => {
|
||||||
|
|||||||
Reference in New Issue
Block a user