From 8cb697dfcdabc86d5da72d2070da5fc8dfe990b3 Mon Sep 17 00:00:00 2001 From: Paul Makles <paulmakles@gmail.com> Date: Mon, 10 Aug 2020 21:11:01 +0200 Subject: [PATCH] Add user cache, no more "guard refs". --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/database/permissions.rs | 14 ++- src/database/user.rs | 104 +++++++++++++++++++++- src/guards/auth.rs | 167 ------------------------------------ src/guards/mod.rs | 1 - src/main.rs | 5 +- src/routes/channel.rs | 26 +++--- src/routes/guild.rs | 35 ++++---- src/routes/root.rs | 2 +- src/routes/user.rs | 54 +++++------- 11 files changed, 165 insertions(+), 247 deletions(-) delete mode 100644 src/guards/auth.rs delete mode 100644 src/guards/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 91babf3..9e8c5de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1885,7 +1885,7 @@ dependencies = [ [[package]] name = "revolt" -version = "0.2.5" +version = "0.2.6" dependencies = [ "bcrypt", "bitfield", diff --git a/Cargo.toml b/Cargo.toml index 13e8c78..fa70586 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "revolt" -version = "0.2.5" +version = "0.2.6" authors = ["Paul Makles <paulmakles@gmail.com>"] edition = "2018" diff --git a/src/database/permissions.rs b/src/database/permissions.rs index 37d35f7..19bdb89 100644 --- a/src/database/permissions.rs +++ b/src/database/permissions.rs @@ -1,8 +1,7 @@ use super::mutual::has_mutual_connection; use crate::database::channel::Channel; use crate::database::guild::{fetch_guild, fetch_member, Guild, Member, MemberKey}; -use crate::database::user::UserRelationship; -use crate::guards::auth::UserRef; +use crate::database::user::{User, UserRelationship}; use num_enum::TryFromPrimitive; @@ -77,23 +76,23 @@ pub fn get_relationship_internal( Relationship::NONE } -pub fn get_relationship(a: &UserRef, b: &UserRef) -> Relationship { +pub fn get_relationship(a: &User, b: &User) -> Relationship { if a.id == b.id { return Relationship::SELF; } - get_relationship_internal(&a.id, &b.id, &a.fetch_relationships()) + get_relationship_internal(&a.id, &b.id, &a.relations) } pub struct PermissionCalculator { - pub user: UserRef, + pub user: User, pub channel: Option<Channel>, pub guild: Option<Guild>, pub member: Option<Member>, } impl PermissionCalculator { - pub fn new(user: UserRef) -> PermissionCalculator { + pub fn new(user: User) -> PermissionCalculator { PermissionCalculator { user, channel: None, @@ -174,9 +173,8 @@ impl PermissionCalculator { } if let Some(other) = other_user { - let relationships = self.user.fetch_relationships(); let relationship = - get_relationship_internal(&self.user.id, &other, &relationships); + get_relationship_internal(&self.user.id, &other, &self.user.relations); if relationship == Relationship::Friend { permissions = 1024 + 128 + 32 + 16 + 1; diff --git a/src/database/user.rs b/src/database/user.rs index 990fc5f..96e82f9 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -1,4 +1,11 @@ -use mongodb::bson::DateTime; +use super::get_collection; + +use lru::LruCache; +use mongodb::bson::{doc, from_bson, Bson, DateTime}; +use rocket::http::{RawStr, Status}; +use rocket::request::{self, FromParam, FromRequest, Request}; +use rocket::Outcome; +use std::sync::{Arc, Mutex}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] @@ -28,3 +35,98 @@ pub struct User { pub email_verification: UserEmailVerification, pub relations: Option<Vec<UserRelationship>>, } + +lazy_static! { + static ref CACHE: Arc<Mutex<LruCache<String, User>>> = + Arc::new(Mutex::new(LruCache::new(4_000_000))); +} + +pub fn fetch_user(id: &str) -> Result<Option<User>, String> { + { + if let Ok(mut cache) = CACHE.lock() { + let existing = cache.get(&id.to_string()); + + if let Some(user) = existing { + return Ok(Some((*user).clone())); + } + } else { + return Err("Failed to lock cache.".to_string()); + } + } + + let col = get_collection("users"); + if let Ok(result) = col.find_one(doc! { "_id": id }, None) { + if let Some(doc) = result { + if let Ok(user) = from_bson(Bson::Document(doc)) as Result<User, _> { + let mut cache = CACHE.lock().unwrap(); + cache.put(id.to_string(), user.clone()); + + Ok(Some(user)) + } else { + Err("Failed to deserialize user!".to_string()) + } + } else { + Ok(None) + } + } else { + Err("Failed to fetch user from database.".to_string()) + } +} + +#[derive(Debug)] +pub enum AuthError { + Failed, + Missing, + Invalid, +} + +impl<'a, 'r> FromRequest<'a, 'r> for User { + type Error = AuthError; + + fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { + let u = request.headers().get("x-user").next(); + let t = request.headers().get("x-auth-token").next(); + + if let Some(uid) = u { + if let Some(token) = t { + if let Ok(result) = fetch_user(uid) { + if let Some(user) = result { + if let Some(access_token) = &user.access_token { + if access_token == token { + Outcome::Success(user) + } else { + Outcome::Failure((Status::Forbidden, AuthError::Invalid)) + } + } else { + Outcome::Failure((Status::Forbidden, AuthError::Invalid)) + } + } else { + Outcome::Failure((Status::Forbidden, AuthError::Invalid)) + } + } else { + Outcome::Failure((Status::Forbidden, AuthError::Failed)) + } + } else { + Outcome::Failure((Status::Forbidden, AuthError::Missing)) + } + } else { + Outcome::Failure((Status::Forbidden, AuthError::Missing)) + } + } +} + +impl<'r> FromParam<'r> for User { + type Error = &'r RawStr; + + fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> { + if let Ok(result) = fetch_user(¶m.to_string()) { + if let Some(user) = result { + Ok(user) + } else { + Err(param) + } + } else { + Err(param) + } + } +} diff --git a/src/guards/auth.rs b/src/guards/auth.rs deleted file mode 100644 index 35e9e7a..0000000 --- a/src/guards/auth.rs +++ /dev/null @@ -1,167 +0,0 @@ -use mongodb::bson::{doc, from_bson, Bson, Document}; -use mongodb::options::FindOneOptions; -use rocket::http::{RawStr, Status}; -use rocket::request::{self, FromParam, FromRequest, Request}; -use rocket::Outcome; -use serde::{Deserialize, Serialize}; - -use crate::database; -use database::user::{User, UserRelationship}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct UserRef { - pub id: String, - pub username: String, - pub display_name: String, - pub email_verified: bool, -} - -impl UserRef { - pub fn from(id: String) -> Option<UserRef> { - match database::get_collection("users").find_one( - doc! { "_id": id }, - FindOneOptions::builder() - .projection(doc! { - "_id": 1, - "username": 1, - "display_name": 1, - "email_verification.verified": 1, - }) - .build(), - ) { - Ok(result) => match result { - Some(doc) => Some(UserRef { - id: doc.get_str("_id").unwrap().to_string(), - username: doc.get_str("username").unwrap().to_string(), - display_name: doc.get_str("display_name").unwrap().to_string(), - email_verified: doc - .get_document("email_verification") - .unwrap() - .get_bool("verified") - .unwrap(), - }), - None => None, - }, - Err(_) => None, - } - } - - 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)] -pub enum AuthError { - BadCount, - Missing, - 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, - "display_name": 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(), - display_name: user.get_str("display_name").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 { - 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 col = database::get_collection("users"); - let result = col.find_one(doc! { "access_token": key }, None).unwrap(); - - if let Some(user) = result { - Outcome::Success( - from_bson(Bson::Document(user)).expect("Failed to unwrap user."), - ) - } else { - Outcome::Failure((Status::Forbidden, AuthError::Invalid)) - } - } - _ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)), - } - } -} - -impl<'r> FromParam<'r> for UserRef { - type Error = &'r RawStr; - - fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> { - if let Some(user) = UserRef::from(param.to_string()) { - Ok(user) - } else { - Err(param) - } - } -} diff --git a/src/guards/mod.rs b/src/guards/mod.rs deleted file mode 100644 index 0e4a05d..0000000 --- a/src/guards/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod auth; diff --git a/src/main.rs b/src/main.rs index 0acea35..b220a02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,11 +9,10 @@ extern crate bitfield; #[macro_use] extern crate lazy_static; -pub mod database; -pub mod email; -pub mod guards; pub mod notifications; +pub mod database; pub mod routes; +pub mod email; pub mod util; use dotenv; diff --git a/src/routes/channel.rs b/src/routes/channel.rs index 5a0a721..5d79050 100644 --- a/src/routes/channel.rs +++ b/src/routes/channel.rs @@ -1,9 +1,8 @@ use super::Response; use crate::database::{ self, channel::Channel, get_relationship, get_relationship_internal, message::Message, - Permission, PermissionCalculator, Relationship, + Permission, PermissionCalculator, Relationship, user::User }; -use crate::guards::auth::UserRef; use crate::notifications::{ self, events::{groups::*, guilds::ChannelDelete, message::*, Notification}, @@ -53,7 +52,7 @@ pub struct CreateGroup { /// create a new group #[post("/create", data = "<info>")] -pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response { +pub fn create_group(user: User, info: Json<CreateGroup>) -> Response { let name: String = info.name.chars().take(32).collect(); let nonce: String = info.nonce.chars().take(32).collect(); @@ -90,13 +89,12 @@ pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response { return Response::BadRequest(json!({ "error": "Specified non-existant user(s)." })); } - let relationships = user.fetch_relationships(); for item in set { if item == user.id { continue; } - if get_relationship_internal(&user.id, &item, &relationships) != Relationship::Friend { + if get_relationship_internal(&user.id, &item, &user.relations) != Relationship::Friend { return Response::BadRequest(json!({ "error": "Not friends with user(s)." })); } } @@ -129,7 +127,7 @@ pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response { /// fetch channel information #[get("/<target>")] -pub fn channel(user: UserRef, target: Channel) -> Option<Response> { +pub fn channel(user: User, target: Channel) -> Option<Response> { with_permissions!(user, target); match target.channel_type { @@ -180,7 +178,7 @@ pub fn channel(user: UserRef, target: Channel) -> Option<Response> { /// [groups] add user to channel #[put("/<target>/recipients/<member>")] -pub fn add_member(user: UserRef, target: Channel, member: UserRef) -> Option<Response> { +pub fn add_member(user: User, target: Channel, member: User) -> Option<Response> { if target.channel_type != 1 { return Some(Response::BadRequest(json!({ "error": "Not a group DM." }))); } @@ -254,7 +252,7 @@ pub fn add_member(user: UserRef, target: Channel, member: UserRef) -> Option<Res /// [groups] remove user from channel #[delete("/<target>/recipients/<member>")] -pub fn remove_member(user: UserRef, target: Channel, member: UserRef) -> Option<Response> { +pub fn remove_member(user: User, target: Channel, member: User) -> Option<Response> { if target.channel_type != 1 { return Some(Response::BadRequest(json!({ "error": "Not a group DM." }))); } @@ -326,7 +324,7 @@ pub fn remove_member(user: UserRef, target: Channel, member: UserRef) -> Option< /// or leave group DM /// or close DM conversation #[delete("/<target>")] -pub fn delete(user: UserRef, target: Channel) -> Option<Response> { +pub fn delete(user: User, target: Channel) -> Option<Response> { let permissions = with_permissions!(user, target); if !permissions.get_manage_channels() { @@ -488,7 +486,7 @@ pub struct MessageFetchOptions { /// fetch channel messages #[get("/<target>/messages?<options..>")] pub fn messages( - user: UserRef, + user: User, target: Channel, options: Form<MessageFetchOptions>, ) -> Option<Response> { @@ -552,7 +550,7 @@ pub struct SendMessage { /// send a message to a channel #[post("/<target>/messages", data = "<message>")] pub fn send_message( - user: UserRef, + user: User, target: Channel, message: Json<SendMessage>, ) -> Option<Response> { @@ -608,7 +606,7 @@ pub fn send_message( /// get a message #[get("/<target>/messages/<message>")] -pub fn get_message(user: UserRef, target: Channel, message: Message) -> Option<Response> { +pub fn get_message(user: User, target: Channel, message: Message) -> Option<Response> { let permissions = with_permissions!(user, target); if !permissions.get_read_messages() { @@ -641,7 +639,7 @@ pub struct EditMessage { /// edit a message #[patch("/<target>/messages/<message>", data = "<edit>")] pub fn edit_message( - user: UserRef, + user: User, target: Channel, message: Message, edit: Json<EditMessage>, @@ -699,7 +697,7 @@ pub fn edit_message( /// delete a message #[delete("/<target>/messages/<message>")] -pub fn delete_message(user: UserRef, target: Channel, message: Message) -> Option<Response> { +pub fn delete_message(user: User, target: Channel, message: Message) -> Option<Response> { let permissions = with_permissions!(user, target); if !permissions.get_manage_messages() { diff --git a/src/routes/guild.rs b/src/routes/guild.rs index 7726943..cf91b3c 100644 --- a/src/routes/guild.rs +++ b/src/routes/guild.rs @@ -2,9 +2,8 @@ use super::channel::ChannelType; use super::Response; use crate::database::guild::{fetch_member as get_member, get_invite, Guild, MemberKey}; use crate::database::{ - self, channel::fetch_channel, channel::Channel, Permission, PermissionCalculator, + self, channel::fetch_channel, channel::Channel, Permission, PermissionCalculator, user::User }; -use crate::guards::auth::UserRef; use crate::notifications::{ self, events::{guilds::*, Notification}, @@ -35,7 +34,7 @@ macro_rules! with_permissions { /// fetch your guilds #[get("/@me")] -pub fn my_guilds(user: UserRef) -> Response { +pub fn my_guilds(user: User) -> Response { if let Ok(result) = database::get_collection("members").find( doc! { "_id.user": &user.id @@ -93,7 +92,7 @@ pub fn my_guilds(user: UserRef) -> Response { /// fetch a guild #[get("/<target>")] -pub fn guild(user: UserRef, target: Guild) -> Option<Response> { +pub fn guild(user: User, target: Guild) -> Option<Response> { with_permissions!(user, target); let col = database::get_collection("channels"); @@ -134,7 +133,7 @@ pub fn guild(user: UserRef, target: Guild) -> Option<Response> { /// delete or leave a guild #[delete("/<target>")] -pub fn remove_guild(user: UserRef, target: Guild) -> Option<Response> { +pub fn remove_guild(user: User, target: Guild) -> Option<Response> { with_permissions!(user, target); if user.id == target.owner { @@ -265,7 +264,7 @@ pub struct CreateChannel { /// create a new channel #[post("/<target>/channels", data = "<info>")] -pub fn create_channel(user: UserRef, target: Guild, info: Json<CreateChannel>) -> Option<Response> { +pub fn create_channel(user: User, target: Guild, info: Json<CreateChannel>) -> Option<Response> { let (permissions, _) = with_permissions!(user, target); if !permissions.get_manage_channels() { @@ -338,7 +337,7 @@ pub struct InviteOptions { /// create a new invite #[post("/<target>/channels/<channel>/invite", data = "<_options>")] pub fn create_invite( - user: UserRef, + user: User, target: Guild, channel: Channel, _options: Json<InviteOptions>, @@ -376,7 +375,7 @@ pub fn create_invite( /// remove an invite #[delete("/<target>/invites/<code>")] -pub fn remove_invite(user: UserRef, target: Guild, code: String) -> Option<Response> { +pub fn remove_invite(user: User, target: Guild, code: String) -> Option<Response> { let (permissions, _) = with_permissions!(user, target); if let Some((guild_id, _, invite)) = get_invite(&code, None) { @@ -417,7 +416,7 @@ pub fn remove_invite(user: UserRef, target: Guild, code: String) -> Option<Respo /// fetch all guild invites #[get("/<target>/invites")] -pub fn fetch_invites(user: UserRef, target: Guild) -> Option<Response> { +pub fn fetch_invites(user: User, target: Guild) -> Option<Response> { let (permissions, _) = with_permissions!(user, target); if !permissions.get_manage_server() { @@ -429,7 +428,7 @@ pub fn fetch_invites(user: UserRef, target: Guild) -> Option<Response> { /// view an invite before joining #[get("/join/<code>", rank = 1)] -pub fn fetch_invite(user: UserRef, code: String) -> Response { +pub fn fetch_invite(user: User, code: String) -> Response { if let Some((guild_id, name, invite)) = get_invite(&code, user.id) { match fetch_channel(&invite.channel) { Ok(result) => { @@ -457,7 +456,7 @@ pub fn fetch_invite(user: UserRef, code: String) -> Response { /// join a guild using an invite #[post("/join/<code>", rank = 1)] -pub fn use_invite(user: UserRef, code: String) -> Response { +pub fn use_invite(user: User, code: String) -> Response { if let Some((guild_id, _, invite)) = get_invite(&code, Some(user.id.clone())) { if let Ok(result) = database::get_collection("members").find_one( doc! { @@ -521,8 +520,8 @@ pub struct CreateGuild { /// create a new guild #[post("/create", data = "<info>")] -pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response { - if !user.email_verified { +pub fn create_guild(user: User, info: Json<CreateGuild>) -> Response { + if !user.email_verification.verified { return Response::Unauthorized(json!({ "error": "Email not verified!" })); } @@ -611,7 +610,7 @@ pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response { /// fetch a guild's member #[get("/<target>/members")] -pub fn fetch_members(user: UserRef, target: Guild) -> Option<Response> { +pub fn fetch_members(user: User, target: Guild) -> Option<Response> { with_permissions!(user, target); if let Ok(result) = @@ -638,7 +637,7 @@ pub fn fetch_members(user: UserRef, target: Guild) -> Option<Response> { /// fetch a guild member #[get("/<target>/members/<other>")] -pub fn fetch_member(user: UserRef, target: Guild, other: String) -> Option<Response> { +pub fn fetch_member(user: User, target: Guild, other: String) -> Option<Response> { with_permissions!(user, target); if let Ok(result) = get_member(MemberKey(target.id, user.id)) { @@ -661,7 +660,7 @@ pub fn fetch_member(user: UserRef, target: Guild, other: String) -> Option<Respo /// kick a guild member #[delete("/<target>/members/<other>")] -pub fn kick_member(user: UserRef, target: Guild, other: String) -> Option<Response> { +pub fn kick_member(user: User, target: Guild, other: String) -> Option<Response> { let (permissions, _) = with_permissions!(user, target); if user.id == other { @@ -720,7 +719,7 @@ pub struct BanOptions { /// ban a guild member #[put("/<target>/members/<other>/ban?<options..>")] pub fn ban_member( - user: UserRef, + user: User, target: Guild, other: String, options: Form<BanOptions>, @@ -804,7 +803,7 @@ pub fn ban_member( /// unban a guild member #[delete("/<target>/members/<other>/ban")] -pub fn unban_member(user: UserRef, target: Guild, other: String) -> Option<Response> { +pub fn unban_member(user: User, target: Guild, other: String) -> Option<Response> { let (permissions, _) = with_permissions!(user, target); if user.id == other { diff --git a/src/routes/root.rs b/src/routes/root.rs index 3381b4d..2f2f03c 100644 --- a/src/routes/root.rs +++ b/src/routes/root.rs @@ -6,7 +6,7 @@ use mongodb::bson::doc; #[get("/")] pub fn root() -> Response { Response::Success(json!({ - "revolt": "0.2.5" + "revolt": "0.2.6" })) } diff --git a/src/routes/user.rs b/src/routes/user.rs index c9a3663..2c4cdb6 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -1,6 +1,5 @@ use super::Response; -use crate::database::{self, get_relationship, get_relationship_internal, mutual, Relationship}; -use crate::guards::auth::UserRef; +use crate::database::{self, get_relationship, get_relationship_internal, mutual, Relationship, user::User}; use crate::notifications::{ self, events::{users::*, Notification}, @@ -15,25 +14,19 @@ use ulid::Ulid; /// 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, - "display_name": user.display_name, - "email": info.get_str("email").unwrap(), - "verified": user.email_verified, - })) - } else { - Response::InternalServerError( - json!({ "error": "Failed to fetch information from database." }), - ) - } +pub fn me(user: User) -> Response { + Response::Success(json!({ + "id": user.id, + "username": user.username, + "display_name": user.display_name, + "email": user.email, + "verified": user.email_verification.verified, + })) } /// retrieve another user's information #[get("/<target>")] -pub fn user(user: UserRef, target: UserRef) -> Response { +pub fn user(user: User, target: User) -> Response { Response::Success(json!({ "id": target.id, "username": target.username, @@ -54,8 +47,7 @@ pub struct UserQuery { /// find a user by their username #[post("/query", data = "<query>")] -pub fn query(user: UserRef, query: Json<UserQuery>) -> Response { - let relationships = user.fetch_relationships(); +pub fn query(user: User, query: Json<UserQuery>) -> Response { let col = database::get_collection("users"); if let Ok(result) = col.find_one( @@ -70,7 +62,7 @@ pub fn query(user: UserRef, query: Json<UserQuery>) -> Response { "id": id, "username": doc.get_str("username").unwrap(), "display_name": doc.get_str("display_name").unwrap(), - "relationship": get_relationship_internal(&user.id, &id, &relationships) as i32 + "relationship": get_relationship_internal(&user.id, &id, &user.relations) as i32 })) } else { Response::NotFound(json!({ @@ -90,7 +82,7 @@ pub struct LookupQuery { /// lookup a user on Revolt /// currently only supports exact username searches #[post("/lookup", data = "<query>")] -pub fn lookup(user: UserRef, query: Json<LookupQuery>) -> Response { +pub fn lookup(user: User, query: Json<LookupQuery>) -> Response { let relationships = user.fetch_relationships(); let col = database::get_collection("users"); @@ -121,7 +113,7 @@ pub fn lookup(user: UserRef, query: Json<LookupQuery>) -> Response { /// retrieve all of your DMs #[get("/@me/dms")] -pub fn dms(user: UserRef) -> Response { +pub fn dms(user: User) -> Response { let col = database::get_collection("channels"); if let Ok(results) = col.find( @@ -178,7 +170,7 @@ pub fn dms(user: UserRef) -> Response { /// open a DM with a user #[get("/<target>/dm")] -pub fn dm(user: UserRef, target: UserRef) -> Response { +pub fn dm(user: User, target: User) -> Response { let col = database::get_collection("channels"); if let Ok(result) = col.find_one( @@ -211,11 +203,9 @@ pub fn dm(user: UserRef, target: UserRef) -> Response { /// retrieve all of your friends #[get("/@me/friend")] -pub fn get_friends(user: UserRef) -> Response { - let relationships = user.fetch_relationships(); - +pub fn get_friends(user: User) -> Response { let mut results = Vec::new(); - if let Some(arr) = relationships { + if let Some(arr) = user.relations { for item in arr { results.push(json!({ "id": item.id, @@ -229,13 +219,13 @@ pub fn get_friends(user: UserRef) -> Response { /// retrieve friend status with user #[get("/<target>/friend")] -pub fn get_friend(user: UserRef, target: UserRef) -> Response { +pub fn get_friend(user: User, target: User) -> Response { Response::Success(json!({ "status": get_relationship(&user, &target) as i32 })) } /// create or accept a friend request #[put("/<target>/friend")] -pub fn add_friend(user: UserRef, target: UserRef) -> Response { +pub fn add_friend(user: User, target: User) -> Response { let col = database::get_collection("users"); match get_relationship(&user, &target) { @@ -383,7 +373,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response { /// remove a friend or deny a request #[delete("/<target>/friend")] -pub fn remove_friend(user: UserRef, target: UserRef) -> Response { +pub fn remove_friend(user: User, target: User) -> Response { let col = database::get_collection("users"); match get_relationship(&user, &target) { @@ -459,7 +449,7 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response { /// block a user #[put("/<target>/block")] -pub fn block_user(user: UserRef, target: UserRef) -> Response { +pub fn block_user(user: User, target: User) -> Response { let col = database::get_collection("users"); match get_relationship(&user, &target) { @@ -631,7 +621,7 @@ pub fn block_user(user: UserRef, target: UserRef) -> Response { /// unblock a user #[delete("/<target>/block")] -pub fn unblock_user(user: UserRef, target: UserRef) -> Response { +pub fn unblock_user(user: User, target: User) -> Response { let col = database::get_collection("users"); match get_relationship(&user, &target) { -- GitLab