forked from jmug/stoatchat
Add all friend routes.
This commit is contained in:
25
src/auth.rs
25
src/auth.rs
@@ -1,6 +1,6 @@
|
|||||||
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 {
|
|||||||
_ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
|
_ => Outcome::Failure((Status::BadRequest, AuthError::BadCount)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// (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 {
|
|||||||
/// (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 {
|
|||||||
/// (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 {
|
|||||||
/// (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;
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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 {
|
|||||||
/// 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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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."
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user