mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 05:26:59 +00:00
Implement channel permissions.
This commit is contained in:
@@ -8,7 +8,7 @@ pub fn find_member_permissions<C: Into<Option<String>>>(
|
||||
id: String,
|
||||
guild: String,
|
||||
channel: C,
|
||||
) -> u8 {
|
||||
) -> u32 {
|
||||
let col = get_collection("guilds");
|
||||
|
||||
match col.find_one(
|
||||
@@ -31,10 +31,10 @@ pub fn find_member_permissions<C: Into<Option<String>>>(
|
||||
Ok(result) => {
|
||||
if let Some(doc) = result {
|
||||
if doc.get_str("owner").unwrap() == id {
|
||||
return u8::MAX;
|
||||
return u32::MAX;
|
||||
}
|
||||
|
||||
doc.get_i32("default_permissions").unwrap() as u8
|
||||
doc.get_i32("default_permissions").unwrap() as u32
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ pub fn get_collection(collection: &str) -> Collection {
|
||||
pub mod channel;
|
||||
pub mod guild;
|
||||
pub mod message;
|
||||
pub mod mutual;
|
||||
pub mod permissions;
|
||||
pub mod user;
|
||||
|
||||
|
||||
35
src/database/mutual.rs
Normal file
35
src/database/mutual.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use super::get_collection;
|
||||
|
||||
use bson::{bson, doc};
|
||||
use mongodb::options::FindOneOptions;
|
||||
|
||||
/*pub struct MutualGuild {
|
||||
|
||||
}
|
||||
|
||||
pub fn find_mutual_guilds(user_id: String, target_id: String) -> Vec<> {
|
||||
|
||||
}*/
|
||||
|
||||
pub fn has_mutual_connection(user_id: String, target_id: String) -> bool {
|
||||
let col = get_collection("guilds");
|
||||
if let Ok(result) = col.find_one(
|
||||
doc! {
|
||||
"$and": [
|
||||
{ "members": { "$elemMatch": { "id": user_id } } },
|
||||
{ "members": { "$elemMatch": { "id": target_id } } },
|
||||
]
|
||||
},
|
||||
FindOneOptions::builder()
|
||||
.projection(doc! { "_id": 1 })
|
||||
.build(),
|
||||
) {
|
||||
if result.is_some() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,99 @@
|
||||
bitfield! {
|
||||
pub struct MemberPermissions(MSB0 [u8]);
|
||||
u8;
|
||||
pub get_access, set_access: 7;
|
||||
pub get_create_invite, set_create_invite: 6;
|
||||
pub get_kick_members, set_kick_members: 5;
|
||||
pub get_ban_members, set_ban_members: 4;
|
||||
pub get_read_messages, set_read_messages: 3;
|
||||
pub get_send_messages, set_send_messages: 2;
|
||||
}
|
||||
|
||||
use super::get_collection;
|
||||
use super::mutual::has_mutual_connection;
|
||||
use crate::database::user::UserRelationship;
|
||||
use crate::guards::auth::UserRef;
|
||||
use crate::guards::channel::ChannelRef;
|
||||
use crate::guards::guild::GuildRef;
|
||||
|
||||
use bson::{bson, doc};
|
||||
use mongodb::options::FindOneOptions;
|
||||
use num_enum::TryFromPrimitive;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Relationship {
|
||||
FRIEND = 0,
|
||||
OUTGOING = 1,
|
||||
INCOMING = 2,
|
||||
BLOCKED = 3,
|
||||
BLOCKEDOTHER = 4,
|
||||
NONE = 5,
|
||||
SELF = 6,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
pub enum Permission {
|
||||
ACCESS = 1,
|
||||
CREATE_INVITE = 2,
|
||||
KICK_MEMBERS = 4,
|
||||
BAN_MEMBERS = 8,
|
||||
READ_MESSAGES = 16,
|
||||
SEND_MESSAGES = 32,
|
||||
MANAGE_MESSAGES = 64,
|
||||
MANAGE_CHANNELS = 128,
|
||||
MANAGE_SERVER = 256,
|
||||
MANAGE_ROLES = 512,
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
pub struct MemberPermissions(MSB0 [u32]);
|
||||
u8;
|
||||
pub get_access, set_access: 31;
|
||||
pub get_create_invite, set_create_invite: 30;
|
||||
pub get_kick_members, set_kick_members: 29;
|
||||
pub get_ban_members, set_ban_members: 28;
|
||||
pub get_read_messages, set_read_messages: 27;
|
||||
pub get_send_messages, set_send_messages: 26;
|
||||
pub get_manage_messages, set_manage_messages: 25;
|
||||
pub get_manage_channels, set_manage_channels: 24;
|
||||
pub get_manage_server, set_manage_server: 23;
|
||||
pub get_manage_roles, set_manage_roles: 22;
|
||||
}
|
||||
|
||||
pub 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
|
||||
}
|
||||
|
||||
pub 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())
|
||||
}
|
||||
|
||||
pub struct PermissionCalculator {
|
||||
pub user_id: String,
|
||||
pub user: UserRef,
|
||||
pub channel: Option<ChannelRef>,
|
||||
pub guild: Option<GuildRef>,
|
||||
}
|
||||
|
||||
impl PermissionCalculator {
|
||||
pub fn new(user_id: String) -> PermissionCalculator {
|
||||
pub fn new(user: UserRef) -> PermissionCalculator {
|
||||
PermissionCalculator {
|
||||
user_id,
|
||||
user,
|
||||
channel: None,
|
||||
guild: None,
|
||||
}
|
||||
@@ -45,7 +113,7 @@ impl PermissionCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate(self) -> u8 {
|
||||
pub fn calculate(self) -> u32 {
|
||||
let guild = if let Some(value) = self.guild {
|
||||
Some(value)
|
||||
} else if let Some(channel) = &self.channel {
|
||||
@@ -70,14 +138,14 @@ impl PermissionCalculator {
|
||||
doc! {
|
||||
"members": {
|
||||
"$elemMatch": {
|
||||
"id": &self.user_id,
|
||||
"id": &self.user.id,
|
||||
}
|
||||
}
|
||||
},
|
||||
doc! { }
|
||||
doc! {},
|
||||
) {
|
||||
if guild.owner == self.user_id {
|
||||
return u8::MAX;
|
||||
if guild.owner == self.user.id {
|
||||
return u32::MAX;
|
||||
}
|
||||
|
||||
permissions = guild.default_permissions;
|
||||
@@ -87,29 +155,42 @@ impl PermissionCalculator {
|
||||
if let Some(channel) = &self.channel {
|
||||
match channel.channel_type {
|
||||
0 => {
|
||||
// ? check user is part of the channel
|
||||
if let Some(arr) = &channel.recipients {
|
||||
let mut other_user = "";
|
||||
for item in arr {
|
||||
if item == &self.user_id {
|
||||
if item == &self.user.id {
|
||||
permissions = 49;
|
||||
break;
|
||||
} else {
|
||||
other_user = item;
|
||||
}
|
||||
}
|
||||
|
||||
let relationships = self.user.fetch_relationships();
|
||||
let relationship =
|
||||
get_relationship_internal(&self.user.id, &other_user, &relationships);
|
||||
|
||||
if relationship == Relationship::BLOCKED
|
||||
|| relationship == Relationship::BLOCKEDOTHER
|
||||
{
|
||||
permissions = 1;
|
||||
} else if has_mutual_connection(self.user.id, other_user.to_string()) {
|
||||
permissions = 49;
|
||||
}
|
||||
}
|
||||
},
|
||||
1 => {
|
||||
unreachable!()
|
||||
},
|
||||
}
|
||||
1 => unreachable!(),
|
||||
2 => {
|
||||
// nothing implemented yet
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
permissions as u8
|
||||
permissions as u32
|
||||
}
|
||||
|
||||
pub fn as_permission(self) -> MemberPermissions<[u8; 1]> {
|
||||
MemberPermissions([ self.calculate() ])
|
||||
pub fn as_permission(self) -> MemberPermissions<[u32; 1]> {
|
||||
MemberPermissions([self.calculate()])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use bson::{bson, doc, from_bson, Document};
|
||||
use mongodb::options::FindOneOptions;
|
||||
use rocket::http::{RawStr, Status};
|
||||
use rocket::request::{self, FromParam, FromRequest, Request};
|
||||
use rocket::Outcome;
|
||||
use bson::{bson, doc, from_bson, Document};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use mongodb::options::FindOneOptions;
|
||||
|
||||
use crate::database;
|
||||
use database::user::{User, UserRelationship};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct UserRef {
|
||||
pub id: String,
|
||||
pub username: String,
|
||||
@@ -29,11 +29,13 @@ impl UserRef {
|
||||
let user = database::get_collection("users")
|
||||
.find_one(
|
||||
doc! { "_id": &self.id },
|
||||
FindOneOptions::builder().projection(doc! { "relations": 1 }).build(),
|
||||
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 {
|
||||
@@ -77,13 +79,15 @@ impl<'a, 'r> FromRequest<'a, 'r> for UserRef {
|
||||
.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(),
|
||||
}
|
||||
)
|
||||
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))
|
||||
}
|
||||
@@ -124,26 +128,28 @@ impl<'r> FromParam<'r> for UserRef {
|
||||
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();
|
||||
.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(),
|
||||
}
|
||||
)
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use super::Response;
|
||||
use crate::database::{self, channel::Channel, message::Message, user::User, PermissionCalculator};
|
||||
use crate::guards::channel::ChannelRef;
|
||||
use crate::database::{self, message::Message, Permission, PermissionCalculator};
|
||||
use crate::guards::auth::UserRef;
|
||||
use crate::websocket;
|
||||
use crate::guards::channel::ChannelRef;
|
||||
|
||||
use bson::{bson, doc, from_bson, Bson::UtcDatetime};
|
||||
use chrono::prelude::*;
|
||||
@@ -20,19 +19,17 @@ pub enum ChannelType {
|
||||
}
|
||||
|
||||
macro_rules! with_permissions {
|
||||
($user: expr, $target: expr) => {
|
||||
{
|
||||
let permissions = PermissionCalculator::new($user.id.clone())
|
||||
.channel($target.clone())
|
||||
.as_permission();
|
||||
|
||||
if !permissions.get_access() {
|
||||
return None;
|
||||
}
|
||||
($user: expr, $target: expr) => {{
|
||||
let permissions = PermissionCalculator::new($user.clone())
|
||||
.channel($target.clone())
|
||||
.as_permission();
|
||||
|
||||
permissions
|
||||
if !permissions.get_access() {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
permissions
|
||||
}};
|
||||
}
|
||||
|
||||
/// fetch channel information
|
||||
@@ -41,34 +38,28 @@ pub fn channel(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||
with_permissions!(user, target);
|
||||
|
||||
match target.channel_type {
|
||||
0..=1 => Some(Response::Success(
|
||||
json!({
|
||||
"id": target.id,
|
||||
"type": target.channel_type,
|
||||
"recipients": target.recipients,
|
||||
})
|
||||
)),
|
||||
0..=1 => Some(Response::Success(json!({
|
||||
"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(""),
|
||||
})
|
||||
))
|
||||
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!()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,38 +68,49 @@ pub fn channel(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||
/// or close DM conversation
|
||||
#[delete("/<target>")]
|
||||
pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||
with_permissions!(user, target);
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_manage_channels() {
|
||||
return Some(Response::LackingPermission(Permission::MANAGE_CHANNELS));
|
||||
}
|
||||
|
||||
let col = database::get_collection("channels");
|
||||
Some(match target.channel_type {
|
||||
match target.channel_type {
|
||||
0 => {
|
||||
col.update_one(
|
||||
if col.update_one(
|
||||
doc! { "_id": target.id },
|
||||
doc! { "$set": { "active": false } },
|
||||
None,
|
||||
)
|
||||
.expect("Failed to update channel.");
|
||||
|
||||
Response::Result(super::Status::Ok)
|
||||
).is_ok() {
|
||||
Some(Response::Result(super::Status::Ok))
|
||||
} else {
|
||||
Some(Response::InternalServerError(json!({ "error": "Failed to close channel." })))
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
// ? TODO: group dm
|
||||
|
||||
Response::Result(super::Status::Ok)
|
||||
Some(Response::Result(super::Status::Ok))
|
||||
}
|
||||
2 => {
|
||||
// ? TODO: guild
|
||||
|
||||
Response::Result(super::Status::Ok)
|
||||
Some(Response::Result(super::Status::Ok))
|
||||
}
|
||||
_ => Response::InternalServerError(json!({ "error": "Unknown error has occurred." })),
|
||||
})
|
||||
_ => Some(Response::InternalServerError(
|
||||
json!({ "error": "Unknown error has occurred." }),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// fetch channel messages
|
||||
#[get("/<target>/messages")]
|
||||
pub fn messages(user: UserRef, target: ChannelRef) -> Option<Response> {
|
||||
with_permissions!(user, target);
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_read_messages() {
|
||||
return Some(Response::LackingPermission(Permission::READ_MESSAGES));
|
||||
}
|
||||
|
||||
let col = database::get_collection("messages");
|
||||
let result = col.find(doc! { "channel": target.id }, None).unwrap();
|
||||
@@ -136,8 +138,16 @@ pub struct SendMessage {
|
||||
|
||||
/// send a message to a channel
|
||||
#[post("/<target>/messages", data = "<message>")]
|
||||
pub fn send_message(user: UserRef, target: ChannelRef, message: Json<SendMessage>) -> Option<Response> {
|
||||
with_permissions!(user, target);
|
||||
pub fn send_message(
|
||||
user: UserRef,
|
||||
target: ChannelRef,
|
||||
message: Json<SendMessage>,
|
||||
) -> Option<Response> {
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_send_messages() {
|
||||
return Some(Response::LackingPermission(Permission::SEND_MESSAGES));
|
||||
}
|
||||
|
||||
let content: String = message.content.chars().take(2000).collect();
|
||||
let nonce: String = message.nonce.chars().take(32).collect();
|
||||
@@ -201,7 +211,11 @@ pub fn send_message(user: UserRef, target: ChannelRef, message: Json<SendMessage
|
||||
/// get a message
|
||||
#[get("/<target>/messages/<message>")]
|
||||
pub fn get_message(user: UserRef, target: ChannelRef, message: Message) -> Option<Response> {
|
||||
with_permissions!(user, target);
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
if !permissions.get_read_messages() {
|
||||
return Some(Response::LackingPermission(Permission::READ_MESSAGES));
|
||||
}
|
||||
|
||||
let prev =
|
||||
// ! CHECK IF USER HAS PERMISSION TO VIEW EDITS OF MESSAGES
|
||||
@@ -243,87 +257,90 @@ pub fn edit_message(
|
||||
) -> Option<Response> {
|
||||
with_permissions!(user, target);
|
||||
|
||||
Some(if message.author != user.id {
|
||||
Response::Unauthorized(json!({ "error": "You did not send this message." }))
|
||||
if message.author != user.id {
|
||||
return Some(Response::Unauthorized(
|
||||
json!({ "error": "You did not send this message." }),
|
||||
));
|
||||
}
|
||||
|
||||
let col = database::get_collection("messages");
|
||||
let time = if let Some(edited) = message.edited {
|
||||
edited.0
|
||||
} else {
|
||||
let col = database::get_collection("messages");
|
||||
Ulid::from_string(&message.id).unwrap().datetime()
|
||||
};
|
||||
|
||||
let time = if let Some(edited) = message.edited {
|
||||
edited.0
|
||||
} else {
|
||||
Ulid::from_string(&message.id).unwrap().datetime()
|
||||
};
|
||||
|
||||
let edited = Utc::now();
|
||||
match col.update_one(
|
||||
doc! { "_id": message.id.clone() },
|
||||
doc! {
|
||||
"$set": {
|
||||
"content": edit.content.clone(),
|
||||
"edited": UtcDatetime(edited.clone())
|
||||
},
|
||||
"$push": {
|
||||
"previous_content": {
|
||||
"content": message.content,
|
||||
"time": time,
|
||||
}
|
||||
},
|
||||
let edited = Utc::now();
|
||||
match col.update_one(
|
||||
doc! { "_id": message.id.clone() },
|
||||
doc! {
|
||||
"$set": {
|
||||
"content": edit.content.clone(),
|
||||
"edited": UtcDatetime(edited.clone())
|
||||
},
|
||||
None,
|
||||
) {
|
||||
Ok(_) => {
|
||||
/*websocket::queue_message(
|
||||
get_recipients(&target),
|
||||
json!({
|
||||
"type": "message_update",
|
||||
"data": {
|
||||
"id": message.id,
|
||||
"channel": target.id,
|
||||
"content": edit.content.clone(),
|
||||
"edited": edited.timestamp()
|
||||
},
|
||||
})
|
||||
.to_string(),
|
||||
);*/
|
||||
"$push": {
|
||||
"previous_content": {
|
||||
"content": message.content,
|
||||
"time": time,
|
||||
}
|
||||
},
|
||||
},
|
||||
None,
|
||||
) {
|
||||
Ok(_) => {
|
||||
/*websocket::queue_message(
|
||||
get_recipients(&target),
|
||||
json!({
|
||||
"type": "message_update",
|
||||
"data": {
|
||||
"id": message.id,
|
||||
"channel": target.id,
|
||||
"content": edit.content.clone(),
|
||||
"edited": edited.timestamp()
|
||||
},
|
||||
})
|
||||
.to_string(),
|
||||
);*/
|
||||
|
||||
Response::Result(super::Status::Ok)
|
||||
}
|
||||
Err(_) => {
|
||||
Response::InternalServerError(json!({ "error": "Failed to update message." }))
|
||||
}
|
||||
Some(Response::Result(super::Status::Ok))
|
||||
}
|
||||
})
|
||||
Err(_) => Some(Response::InternalServerError(
|
||||
json!({ "error": "Failed to update message." }),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// delete a message
|
||||
#[delete("/<target>/messages/<message>")]
|
||||
pub fn delete_message(user: UserRef, target: ChannelRef, message: Message) -> Option<Response> {
|
||||
with_permissions!(user, target);
|
||||
let permissions = with_permissions!(user, target);
|
||||
|
||||
Some(if message.author != user.id {
|
||||
Response::Unauthorized(json!({ "error": "You did not send this message." }))
|
||||
} else {
|
||||
let col = database::get_collection("messages");
|
||||
|
||||
match col.delete_one(doc! { "_id": message.id.clone() }, None) {
|
||||
Ok(_) => {
|
||||
/*websocket::queue_message(
|
||||
get_recipients(&target),
|
||||
json!({
|
||||
"type": "message_delete",
|
||||
"data": {
|
||||
"id": message.id,
|
||||
"channel": target.id
|
||||
},
|
||||
})
|
||||
.to_string(),
|
||||
);*/
|
||||
|
||||
Response::Result(super::Status::Ok)
|
||||
}
|
||||
Err(_) => {
|
||||
Response::InternalServerError(json!({ "error": "Failed to delete message." }))
|
||||
}
|
||||
if !permissions.get_manage_messages() {
|
||||
if message.author != user.id {
|
||||
return Some(Response::LackingPermission(Permission::MANAGE_MESSAGES));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let col = database::get_collection("messages");
|
||||
|
||||
match col.delete_one(doc! { "_id": message.id.clone() }, None) {
|
||||
Ok(_) => {
|
||||
/*websocket::queue_message(
|
||||
get_recipients(&target),
|
||||
json!({
|
||||
"type": "message_delete",
|
||||
"data": {
|
||||
"id": message.id,
|
||||
"channel": target.id
|
||||
},
|
||||
})
|
||||
.to_string(),
|
||||
);*/
|
||||
|
||||
Some(Response::Result(super::Status::Ok))
|
||||
}
|
||||
Err(_) => Some(Response::InternalServerError(
|
||||
json!({ "error": "Failed to delete message." }),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ pub use rocket::response::Redirect;
|
||||
use rocket::Rocket;
|
||||
use rocket_contrib::json::JsonValue;
|
||||
|
||||
use crate::database::Permission;
|
||||
|
||||
pub mod account;
|
||||
pub mod channel;
|
||||
pub mod guild;
|
||||
@@ -21,6 +23,8 @@ pub enum Response {
|
||||
BadRequest(JsonValue),
|
||||
#[response(status = 401)]
|
||||
Unauthorized(JsonValue),
|
||||
#[response(status = 401)]
|
||||
LackingPermission(Permission),
|
||||
#[response(status = 404)]
|
||||
NotFound(JsonValue),
|
||||
#[response(status = 406)]
|
||||
@@ -37,6 +41,22 @@ pub enum Response {
|
||||
InternalServerError(JsonValue),
|
||||
}
|
||||
|
||||
use rocket::http::ContentType;
|
||||
use rocket::request::Request;
|
||||
use std::io::Cursor;
|
||||
|
||||
impl<'a> rocket::response::Responder<'a> for Permission {
|
||||
fn respond_to(self, _: &Request) -> rocket::response::Result<'a> {
|
||||
rocket::response::Response::build()
|
||||
.header(ContentType::JSON)
|
||||
.sized_body(Cursor::new(format!(
|
||||
"{{\"error\":\"Lacking {:?} permission.\"}}",
|
||||
self
|
||||
)))
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mount(rocket: Rocket) -> Rocket {
|
||||
rocket
|
||||
.mount("/api", routes![root::root])
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::Response;
|
||||
use crate::database::{self, channel::Channel, user::UserRelationship};
|
||||
use crate::routes::channel;
|
||||
use crate::database::{self, channel::Channel};
|
||||
use crate::database::{get_relationship, get_relationship_internal, Relationship};
|
||||
use crate::guards::auth::UserRef;
|
||||
use crate::routes::channel;
|
||||
|
||||
use bson::{bson, doc, from_bson};
|
||||
use mongodb::options::FindOptions;
|
||||
@@ -9,61 +10,20 @@ use rocket_contrib::json::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
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
|
||||
#[get("/@me")]
|
||||
pub fn me(user: UserRef) -> Response {
|
||||
if let Some(info) = user.fetch_data(doc! { "email": 1 }) {
|
||||
Response::Success(
|
||||
json!({
|
||||
"id": user.id,
|
||||
"username": user.username,
|
||||
"email": info.get_str("email").unwrap(),
|
||||
"verified": user.email_verified,
|
||||
})
|
||||
)
|
||||
Response::Success(json!({
|
||||
"id": user.id,
|
||||
"username": user.username,
|
||||
"email": info.get_str("email").unwrap(),
|
||||
"verified": user.email_verified,
|
||||
}))
|
||||
} else {
|
||||
Response::InternalServerError(json!({ "error": "Failed to fetch information from database." }))
|
||||
Response::InternalServerError(
|
||||
json!({ "error": "Failed to fetch information from database." }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user