Refractor to use UserRef.

This commit is contained in:
Paul Makles
2020-04-09 09:49:10 +01:00
parent b21a6f2231
commit 7af9a77df4
10 changed files with 496 additions and 138 deletions

View File

@@ -1,5 +1,7 @@
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 bson::{bson, doc, from_bson, Bson::UtcDatetime};
@@ -17,53 +19,65 @@ pub enum ChannelType {
GUILDCHANNEL = 2,
}
fn has_permission(user: &User, target: &Channel) -> bool {
match target.channel_type {
0..=1 => {
if let Some(arr) = &target.recipients {
for item in arr {
if item == &user.id {
return true;
}
}
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;
}
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
#[get("/<target>")]
pub fn channel(user: User, target: Channel) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
pub fn channel(user: UserRef, target: ChannelRef) -> Option<Response> {
with_permissions!(user, target);
Some(Response::Success(json!({
"id": target.id,
"type": target.channel_type,
"recipients": get_recipients(&target),
})))
match target.channel_type {
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(""),
})
))
} else {
None
}
},
_ => unreachable!()
}
}
/// delete channel
/// or leave group DM
/// or close DM conversation
#[delete("/<target>")]
pub fn delete(user: User, target: Channel) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> {
with_permissions!(user, target);
let col = database::get_collection("channels");
Some(match target.channel_type {
@@ -93,10 +107,8 @@ pub fn delete(user: User, target: Channel) -> Option<Response> {
/// fetch channel messages
#[get("/<target>/messages")]
pub fn messages(user: User, target: Channel) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
pub fn messages(user: UserRef, target: ChannelRef) -> Option<Response> {
with_permissions!(user, target);
let col = database::get_collection("messages");
let result = col.find(doc! { "channel": target.id }, None).unwrap();
@@ -124,10 +136,8 @@ pub struct SendMessage {
/// send a message to a channel
#[post("/<target>/messages", data = "<message>")]
pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
pub fn send_message(user: UserRef, target: ChannelRef, message: Json<SendMessage>) -> Option<Response> {
with_permissions!(user, target);
let content: String = message.content.chars().take(2000).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();
}
websocket::queue_message(
/*websocket::queue_message(
get_recipients(&target),
json!({
"type": "message",
@@ -177,7 +187,7 @@ pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) ->
},
})
.to_string(),
);
);*/
Response::Success(json!({ "id": id }))
} else {
@@ -190,10 +200,8 @@ pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) ->
/// get a message
#[get("/<target>/messages/<message>")]
pub fn get_message(user: User, target: Channel, message: Message) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
pub fn get_message(user: UserRef, target: ChannelRef, message: Message) -> Option<Response> {
with_permissions!(user, target);
let prev =
// ! CHECK IF USER HAS PERMISSION TO VIEW EDITS OF MESSAGES
@@ -228,14 +236,12 @@ pub struct EditMessage {
/// edit a message
#[patch("/<target>/messages/<message>", data = "<edit>")]
pub fn edit_message(
user: User,
target: Channel,
user: UserRef,
target: ChannelRef,
message: Message,
edit: Json<EditMessage>,
) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
with_permissions!(user, target);
Some(if message.author != user.id {
Response::Unauthorized(json!({ "error": "You did not send this message." }))
@@ -266,7 +272,7 @@ pub fn edit_message(
None,
) {
Ok(_) => {
websocket::queue_message(
/*websocket::queue_message(
get_recipients(&target),
json!({
"type": "message_update",
@@ -278,7 +284,7 @@ pub fn edit_message(
},
})
.to_string(),
);
);*/
Response::Result(super::Status::Ok)
}
@@ -291,10 +297,8 @@ pub fn edit_message(
/// delete a message
#[delete("/<target>/messages/<message>")]
pub fn delete_message(user: User, target: Channel, message: Message) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
pub fn delete_message(user: UserRef, target: ChannelRef, message: Message) -> Option<Response> {
with_permissions!(user, target);
Some(if message.author != user.id {
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) {
Ok(_) => {
websocket::queue_message(
/*websocket::queue_message(
get_recipients(&target),
json!({
"type": "message_delete",
@@ -313,7 +317,7 @@ pub fn delete_message(user: User, target: Channel, message: Message) -> Option<R
},
})
.to_string(),
);
);*/
Response::Result(super::Status::Ok)
}

View File

@@ -5,6 +5,7 @@ use crate::database::{
guild::{find_member_permissions, Guild},
user::User,
};
use crate::guards::auth::UserRef;
use bson::{bson, doc, from_bson, Bson};
use rocket_contrib::json::{Json, JsonValue};
@@ -15,7 +16,7 @@ use super::channel::ChannelType;
/// fetch your guilds
#[get("/@me")]
pub fn my_guilds(user: User) -> Response {
pub fn my_guilds(user: UserRef) -> Response {
let col = database::get_collection("guilds");
let guilds = col
.find(
@@ -46,7 +47,7 @@ pub fn my_guilds(user: User) -> Response {
/// fetch a guild
#[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 {
return None;
}
@@ -72,7 +73,7 @@ pub fn guild(user: User, target: Guild) -> Option<Response> {
.expect("Failed to unwrap channel.");
channels.push(json!({
"_id": channel.id,
"id": channel.id,
"last_message": channel.last_message,
"name": channel.name,
"description": channel.description,
@@ -102,8 +103,8 @@ pub struct CreateGuild {
/// create a new guild
#[post("/create", data = "<info>")]
pub fn create_guild(user: User, info: Json<CreateGuild>) -> Response {
if !user.email_verification.verified {
pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
if !user.email_verified {
return Response::Unauthorized(json!({ "error": "Email not verified!" }));
}

View File

@@ -1,27 +1,75 @@
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::guards::auth::UserRef;
use bson::{bson, doc, from_bson};
use mongodb::options::FindOptions;
use rocket_contrib::json::{Json, JsonValue};
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: User) -> JsonValue {
json!({
"id": user.id,
"username": user.username,
"email": user.email,
"verified": user.email_verification.verified,
})
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,
})
)
} else {
Response::InternalServerError(json!({ "error": "Failed to fetch information from database." }))
}
}
/// retrieve another user's information
#[get("/<target>")]
pub fn user(user: User, target: User) -> Response {
pub fn user(user: UserRef, target: UserRef) -> Response {
Response::Success(json!({
"id": target.id,
"username": target.username,
@@ -37,25 +85,30 @@ pub struct Query {
/// lookup a user on Revolt
/// currently only supports exact username searches
#[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 users = col
.find(
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");
let mut results = Vec::new();
for item in users {
let u: User =
from_bson(bson::Bson::Document(item.unwrap())).expect("Failed to unwrap user.");
results.push(json!({
"id": u.id,
"username": u.username,
"relationship": get_relationship(&user, &u) as u8
}));
if let Ok(doc) = item {
let id = doc.get_str("id").unwrap();
results.push(json!({
"id": id.clone(),
"username": doc.get_str("username").unwrap(),
"relationship": get_relationship_internal(&user.id, &id, &relationships) as u8
}));
}
}
Response::Success(json!(results))
@@ -63,7 +116,7 @@ pub fn lookup(user: User, query: Json<Query>) -> Response {
/// retrieve all of your DMs
#[get("/@me/dms")]
pub fn dms(user: User) -> Response {
pub fn dms(user: UserRef) -> Response {
let col = database::get_collection("channels");
let results = col
@@ -101,7 +154,7 @@ pub fn dms(user: User) -> Response {
/// open a DM with a user
#[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");
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
#[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();
if let Some(arr) = user.relations {
if let Some(arr) = relationships {
for item in arr {
results.push(json!({
"id": item.id,
@@ -179,7 +201,7 @@ pub fn get_friends(user: User) -> Response {
/// retrieve friend status with user
#[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);
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
#[put("/<target>/friend")]
pub fn add_friend(user: User, target: User) -> Response {
let col = database::get_collection("users");
pub fn add_friend(user: UserRef, target: UserRef) -> Response {
let relationship = get_relationship(&user, &target);
let col = database::get_collection("users");
match relationship {
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
#[delete("/<target>/friend")]
pub fn remove_friend(user: User, target: User) -> Response {
let col = database::get_collection("users");
pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
let relationship = get_relationship(&user, &target);
let col = database::get_collection("users");
match relationship {
Relationship::FRIEND | Relationship::OUTGOING | Relationship::INCOMING => {