Skip to content
Snippets Groups Projects
Verified Commit 20c82dde authored by insert's avatar insert
Browse files

Add all friend routes.

parent 92f20d7b
No related merge requests found
use rocket::Outcome; use rocket::Outcome;
use rocket::http::Status; use rocket::http::{ Status, RawStr };
use rocket::request::{self, Request, FromRequest}; use rocket::request::{ self, Request, FromRequest, FromParam };
use bson::{ bson, doc, ordered::OrderedDocument }; use bson::{ bson, doc, ordered::OrderedDocument };
use ulid::Ulid; use ulid::Ulid;
...@@ -45,4 +45,23 @@ impl<'a, 'r> FromRequest<'a, 'r> for User { ...@@ -45,4 +45,23 @@ impl<'a, 'r> FromRequest<'a, 'r> for User {
_ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)), _ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
} }
} }
} }
\ No newline at end of file
impl<'r> FromParam<'r> for User {
type Error = &'r RawStr;
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
let col = database::get_db().collection("users");
let result = col.find_one(doc! { "_id": param.to_string() }, None).unwrap();
if let Some(user) = result {
Ok(User(
Ulid::from_string(user.get_str("_id").unwrap()).unwrap(),
user.get_str("username").unwrap().to_string(),
user
))
} else {
Err(param)
}
}
}
use mongodb::{ Client, Database }; use mongodb::{ Client, Collection, Database };
use std::env; use std::env;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
...@@ -19,3 +19,7 @@ pub fn get_connection() -> &'static Client { ...@@ -19,3 +19,7 @@ pub fn get_connection() -> &'static Client {
pub fn get_db() -> Database { pub fn get_db() -> Database {
get_connection().database("revolt") get_connection().database("revolt")
} }
pub fn get_collection(collection: &str) -> Collection {
get_db().collection(collection)
}
...@@ -33,7 +33,7 @@ pub struct Create { ...@@ -33,7 +33,7 @@ pub struct Create {
/// (3) add user and send email verification /// (3) add user and send email verification
#[post("/create", data = "<info>")] #[post("/create", data = "<info>")]
pub fn create(info: Json<Create>) -> JsonValue { pub fn create(info: Json<Create>) -> JsonValue {
let col = database::get_db().collection("users"); let col = database::get_collection("users");
if info.username.len() < 2 || info.username.len() > 32 { if info.username.len() < 2 || info.username.len() > 32 {
return json!({ return json!({
...@@ -108,7 +108,7 @@ pub fn create(info: Json<Create>) -> JsonValue { ...@@ -108,7 +108,7 @@ pub fn create(info: Json<Create>) -> JsonValue {
/// (3) set account as verified /// (3) set account as verified
#[get("/verify/<code>")] #[get("/verify/<code>")]
pub fn verify_email(code: String) -> JsonValue { pub fn verify_email(code: String) -> JsonValue {
let col = database::get_db().collection("users"); let col = database::get_collection("users");
if let Some(u) = if let Some(u) =
col.find_one(doc! { "email_verification.code": code.clone() }, None).expect("Failed user lookup") { col.find_one(doc! { "email_verification.code": code.clone() }, None).expect("Failed user lookup") {
...@@ -166,8 +166,8 @@ pub struct Resend { ...@@ -166,8 +166,8 @@ pub struct Resend {
/// (2) check for rate limit /// (2) check for rate limit
/// (3) resend the email /// (3) resend the email
#[post("/resend", data = "<info>")] #[post("/resend", data = "<info>")]
pub fn resend_email(info: Json<Resend>) -> JsonValue { pub fn resend_email(info: Json<Resend>) -> JsonValue {
let col = database::get_db().collection("users"); let col = database::get_collection("users");
if let Some(u) = if let Some(u) =
col.find_one(doc! { "email_verification.target": info.email.clone() }, None).expect("Failed user lookup") { col.find_one(doc! { "email_verification.target": info.email.clone() }, None).expect("Failed user lookup") {
...@@ -239,7 +239,7 @@ pub struct Login { ...@@ -239,7 +239,7 @@ pub struct Login {
/// (3) return access token /// (3) return access token
#[post("/login", data = "<info>")] #[post("/login", data = "<info>")]
pub fn login(info: Json<Login>) -> JsonValue { pub fn login(info: Json<Login>) -> JsonValue {
let col = database::get_db().collection("users"); let col = database::get_collection("users");
if let Some(u) = if let Some(u) =
col.find_one(doc! { "email": info.email.clone() }, None).expect("Failed user lookup") { col.find_one(doc! { "email": info.email.clone() }, None).expect("Failed user lookup") {
......
...@@ -6,5 +6,5 @@ mod user; ...@@ -6,5 +6,5 @@ mod user;
pub fn mount(rocket: Rocket) -> Rocket { pub fn mount(rocket: Rocket) -> Rocket {
rocket rocket
.mount("/api/account", routes![ account::create, account::verify_email, account::resend_email, account::login ]) .mount("/api/account", routes![ account::create, account::verify_email, account::resend_email, account::login ])
.mount("/api/users", routes![ user::me, user::dms, user::lookup ]) .mount("/api/users", routes![ user::me, user::user, user::lookup, user::dms, user::dm, user::get_friends, user::get_friend, user::add_friend, user::remove_friend ])
} }
...@@ -22,8 +22,8 @@ pub fn me(user: User) -> JsonValue { ...@@ -22,8 +22,8 @@ pub fn me(user: User) -> JsonValue {
} }
/// retrieve another user's information /// retrieve another user's information
#[get("/<id>")] #[get("/<target>")]
pub fn user(user: User, id: String) -> JsonValue { pub fn user(user: User, target: User) -> JsonValue {
json!([]) json!([])
} }
...@@ -36,7 +36,7 @@ pub struct Query { ...@@ -36,7 +36,7 @@ pub struct Query {
/// 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>) -> JsonValue { pub fn lookup(_user: User, query: Json<Query>) -> JsonValue {
let col = database::get_db().collection("users"); let col = database::get_collection("users");
let users = col.find( let users = col.find(
doc! { "username": query.username.clone() }, doc! { "username": query.username.clone() },
...@@ -64,31 +64,245 @@ pub fn dms(user: User) -> JsonValue { ...@@ -64,31 +64,245 @@ pub fn dms(user: User) -> JsonValue {
} }
/// open a DM with a user /// open a DM with a user
#[get("/<id>/dm")] #[get("/<target>/dm")]
pub fn dm(user: User, id: String) -> JsonValue { pub fn dm(user: User, target: User) -> JsonValue {
json!([]) json!([])
} }
enum Relationship {
FRIEND = 0,
OUTGOING = 1,
INCOMING = 2,
BLOCKED = 3,
BLOCKED_OTHER = 4,
NONE = 5,
SELF = 6,
}
fn get_relationship(a: &User, b: &User) -> Relationship {
if a.0.to_string() == b.0.to_string() {
return Relationship::SELF
}
if let Ok(arr) = b.2.get_array("relations") {
let id = a.0.to_string();
for entry in arr {
let relation = entry.as_document().expect("Expected document in relations array.");
if relation.get_str("id").expect("DB[id]") == id {
match relation.get_i32("status").expect("DB[status]") {
0 => {
return Relationship::FRIEND
},
1 => {
return Relationship::INCOMING
},
2 => {
return Relationship::OUTGOING
},
3 => {
return Relationship::BLOCKED_OTHER
}
_ => {
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) -> JsonValue { pub fn get_friends(user: User) -> JsonValue {
json!([]) let mut results = Vec::new();
if let Ok(arr) = user.2.get_array("relations") {
for item in arr {
let doc = item.as_document().expect("Expected document in relations array.");
results.push(
json!({
"id": doc.get_str("id").expect("DB[id]"),
"status": doc.get_i32("status").expect("DB[status]")
})
)
}
}
json!(results)
} }
/// retrieve friend status with user /// retrieve friend status with user
#[get("/<id>/friend")] #[get("/<target>/friend")]
pub fn get_friend(user: User, id: String) -> JsonValue { pub fn get_friend(user: User, target: User) -> JsonValue {
json!([]) let relationship = get_relationship(&user, &target);
json!({
"id": target.0.to_string(),
"status": relationship as u8
})
} }
/// create or accept a friend request /// create or accept a friend request
#[put("/<id>/friend")] #[put("/<target>/friend")]
pub fn add_friend(user: User, id: String) -> JsonValue { pub fn add_friend(user: User, target: User) -> JsonValue {
json!([]) let col = database::get_collection("users");
let relationship = get_relationship(&user, &target);
let User ( id, _, _ ) = user;
let User ( tid, _, _ ) = target;
match relationship {
Relationship::FRIEND =>
json!({
"success": false,
"error": "Already friends."
}),
Relationship::OUTGOING =>
json!({
"success": false,
"error": "Already sent a friend request."
}),
Relationship::INCOMING => {
col.update_one(
doc! {
"_id": id.to_string(),
"relations.id": tid.to_string()
},
doc! {
"$set": {
"relations.$.status": Relationship::FRIEND as i32
}
},
None
).expect("Failed update query.");
col.update_one(
doc! {
"_id": tid.to_string(),
"relations.id": id.to_string()
},
doc! {
"$set": {
"relations.$.status": Relationship::FRIEND as i32
}
},
None
).expect("Failed update query.");
json!({
"success": true
})
},
Relationship::BLOCKED =>
json!({
"success": false,
"error": "You have blocked this person."
}),
Relationship::BLOCKED_OTHER =>
json!({
"success": false,
"error": "You have been blocked by this person."
}),
Relationship::NONE => {
col.update_one(
doc! {
"_id": id.to_string()
},
doc! {
"$push": {
"relations": {
"id": tid.to_string(),
"status": Relationship::OUTGOING as i32
}
}
},
None
).expect("Failed update query.");
col.update_one(
doc! {
"_id": tid.to_string()
},
doc! {
"$push": {
"relations": {
"id": id.to_string(),
"status": Relationship::INCOMING as i32
}
}
},
None
).expect("Failed update query.");
json!({
"success": true
})
},
Relationship::SELF =>
json!({
"success": false,
"error": "Cannot add yourself as a friend."
})
}
} }
/// remove a friend or deny a request /// remove a friend or deny a request
#[delete("/<id>/friend")] #[delete("/<target>/friend")]
pub fn remove_friend(user: User, id: String) -> JsonValue { pub fn remove_friend(user: User, target: User) -> JsonValue {
json!([]) let col = database::get_collection("users");
let relationship = get_relationship(&user, &target);
let User ( id, _, _ ) = user;
let User ( tid, _, _ ) = target;
match relationship {
Relationship::FRIEND |
Relationship::OUTGOING |
Relationship::INCOMING => {
col.update_one(
doc! {
"_id": id.to_string()
},
doc! {
"$pull": {
"relations": {
"id": tid.to_string()
}
}
},
None
).expect("Failed update query.");
col.update_one(
doc! {
"_id": tid.to_string()
},
doc! {
"$pull": {
"relations": {
"id": id.to_string()
}
}
},
None
).expect("Failed update query.");
json!({
"success": true
})
},
Relationship::BLOCKED |
Relationship::BLOCKED_OTHER |
Relationship::NONE |
Relationship::SELF =>
json!({
"success": false,
"error": "This has no effect."
})
}
} }
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment