Better error handling for all routes.

This commit is contained in:
Paul Makles
2020-04-07 17:54:18 +01:00
parent ca0b8411d5
commit da95f6247d
6 changed files with 226 additions and 259 deletions

View File

@@ -205,7 +205,7 @@ pub fn resend_email(info: Json<Resend>) -> Response {
).expect("Failed to update user!");
match email::send_verification_email(info.email.to_string(), code) {
true => Response::Ok(None),
true => Response::Result(super::Status::Ok),
false => Response::InternalServerError(
json!({ "success": false, "error": "Failed to send email! Likely an issue with the backend API." }),
),
@@ -279,16 +279,12 @@ pub fn token(info: Json<Token>) -> Response {
.find_one(doc! { "access_token": info.token.clone() }, None)
.expect("Failed user lookup")
{
Response::Success(
json!({
"id": u.get_str("_id").unwrap(),
})
)
Response::Success(json!({
"id": u.get_str("_id").unwrap(),
}))
} else {
Response::Unauthorized(
json!({
"error": "Invalid token!",
})
)
Response::Unauthorized(json!({
"error": "Invalid token!",
}))
}
}

View File

@@ -1,3 +1,4 @@
use super::Response;
use crate::database::{self, channel::Channel, message::Message, user::User};
use crate::websocket;
@@ -43,24 +44,23 @@ fn get_recipients(target: &Channel) -> Vec<String> {
/// fetch channel information
#[get("/<target>")]
pub fn channel(user: User, target: Channel) -> Option<JsonValue> {
pub fn channel(user: User, target: Channel) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
Some(json!({
"id": target.id,
"type": target.channel_type,
"recipients": get_recipients(&target),
}
))
Some(Response::Success(json!({
"id": target.id,
"type": target.channel_type,
"recipients": get_recipients(&target),
})))
}
/// delete channel
/// or leave group DM
/// or close DM conversation
#[delete("/<target>")]
pub fn delete(user: User, target: Channel) -> Option<JsonValue> {
pub fn delete(user: User, target: Channel) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
@@ -75,33 +75,25 @@ pub fn delete(user: User, target: Channel) -> Option<JsonValue> {
)
.expect("Failed to update channel.");
json!({
"success": true
})
Response::Result(super::Status::Ok)
}
1 => {
// ? TODO: group dm
json!({
"success": true
})
Response::Result(super::Status::Ok)
}
2 => {
// ? TODO: guild
json!({
"success": true
})
Response::Result(super::Status::Ok)
}
_ => json!({
"success": false
}),
_ => Response::InternalServerError(json!({ "error": "Unknown error has occurred." })),
})
}
/// fetch channel messages
#[get("/<target>/messages")]
pub fn messages(user: User, target: Channel) -> Option<JsonValue> {
pub fn messages(user: User, target: Channel) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
@@ -121,7 +113,7 @@ pub fn messages(user: User, target: Channel) -> Option<JsonValue> {
}));
}
Some(json!(messages))
Some(Response::Success(json!(messages)))
}
#[derive(Serialize, Deserialize)]
@@ -132,7 +124,7 @@ 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<JsonValue> {
pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
@@ -142,10 +134,9 @@ pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) ->
let col = database::get_collection("messages");
if let Some(_) = col.find_one(doc! { "nonce": nonce.clone() }, None).unwrap() {
return Some(json!({
"success": false,
"error": "Message already sent!"
}));
return Some(Response::BadRequest(
json!({ "error": "Message already sent!" }),
));
}
let id = Ulid::new().to_string();
@@ -188,22 +179,18 @@ pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) ->
.to_string(),
);
json!({
"success": true,
"id": id
})
Response::Success(json!({ "id": id }))
} else {
json!({
"success": false,
Response::InternalServerError(json!({
"error": "Failed database query."
})
}))
},
)
}
/// get a message
#[get("/<target>/messages/<message>")]
pub fn get_message(user: User, target: Channel, message: Message) -> Option<JsonValue> {
pub fn get_message(user: User, target: Channel, message: Message) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
@@ -224,13 +211,13 @@ pub fn get_message(user: User, target: Channel, message: Message) -> Option<Json
None
};
Some(json!({
Some(Response::Success(json!({
"id": message.id,
"author": message.author,
"content": message.content,
"edited": if let Some(t) = message.edited { Some(t.timestamp()) } else { None },
"previous_content": prev,
}))
})))
}
#[derive(Serialize, Deserialize)]
@@ -245,16 +232,13 @@ pub fn edit_message(
target: Channel,
message: Message,
edit: Json<EditMessage>,
) -> Option<JsonValue> {
) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
Some(if message.author != user.id {
json!({
"success": false,
"error": "You did not send this message."
})
Response::Unauthorized(json!({ "error": "You did not send this message." }))
} else {
let col = database::get_collection("messages");
@@ -296,30 +280,24 @@ pub fn edit_message(
.to_string(),
);
json!({
"success": true
})
Response::Result(super::Status::Ok)
}
Err(_) => {
Response::InternalServerError(json!({ "error": "Failed to update message." }))
}
Err(_) => json!({
"success": false,
"error": "Failed to update message."
}),
}
})
}
/// delete a message
#[delete("/<target>/messages/<message>")]
pub fn delete_message(user: User, target: Channel, message: Message) -> Option<JsonValue> {
pub fn delete_message(user: User, target: Channel, message: Message) -> Option<Response> {
if !has_permission(&user, &target) {
return None;
}
Some(if message.author != user.id {
json!({
"success": false,
"error": "You did not send this message."
})
Response::Unauthorized(json!({ "error": "You did not send this message." }))
} else {
let col = database::get_collection("messages");
@@ -337,14 +315,11 @@ pub fn delete_message(user: User, target: Channel, message: Message) -> Option<J
.to_string(),
);
json!({
"success": true
})
Response::Result(super::Status::Ok)
}
Err(_) => {
Response::InternalServerError(json!({ "error": "Failed to delete message." }))
}
Err(_) => json!({
"success": false,
"error": "Failed to delete message."
}),
}
})
}

View File

@@ -1,3 +1,4 @@
use super::Response;
use crate::database::{
self,
channel::Channel,
@@ -14,7 +15,7 @@ use super::channel::ChannelType;
/// fetch your guilds
#[get("/@me")]
pub fn my_guilds(user: User) -> JsonValue {
pub fn my_guilds(user: User) -> Response {
let col = database::get_collection("guilds");
let guilds = col
.find(
@@ -40,12 +41,12 @@ pub fn my_guilds(user: User) -> JsonValue {
}));
}
json!(parsed)
Response::Success(json!(parsed))
}
/// fetch a guild
#[get("/<target>")]
pub fn guild(user: User, target: Guild) -> Option<JsonValue> {
pub fn guild(user: User, target: Guild) -> Option<Response> {
if find_member_permissions(user.id.clone(), target.id.clone(), None) == 0 {
return None;
}
@@ -78,18 +79,17 @@ pub fn guild(user: User, target: Guild) -> Option<JsonValue> {
}));
}
Some(json!({
Some(Response::Success(json!({
"id": target.id,
"name": target.name,
"description": target.description,
"owner": target.owner,
"channels": channels,
}))
})))
}
Err(_) => Some(json!({
"success": false,
"error": "Failed to fetch channels."
})),
Err(_) => Some(Response::InternalServerError(
json!({ "error": "Failed to fetch channels." }),
)),
}
}
@@ -102,12 +102,9 @@ pub struct CreateGuild {
/// create a new guild
#[post("/create", data = "<info>")]
pub fn create_guild(user: User, info: Json<CreateGuild>) -> JsonValue {
pub fn create_guild(user: User, info: Json<CreateGuild>) -> Response {
if !user.email_verification.verified {
return json!({
"success": false,
"error": "Email not verified!",
});
return Response::Unauthorized(json!({ "error": "Email not verified!" }));
}
let name: String = info.name.chars().take(32).collect();
@@ -123,10 +120,7 @@ pub fn create_guild(user: User, info: Json<CreateGuild>) -> JsonValue {
let channels = database::get_collection("channels");
let col = database::get_collection("guilds");
if let Some(_) = col.find_one(doc! { "nonce": nonce.clone() }, None).unwrap() {
return json!({
"success": false,
"error": "Guild already created!"
});
return Response::BadRequest(json!({ "error": "Guild already created!" }));
}
let id = Ulid::new().to_string();
@@ -140,10 +134,9 @@ pub fn create_guild(user: User, info: Json<CreateGuild>) -> JsonValue {
},
None,
) {
return json!({
"success": false,
"error": "Failed to create guild channel."
});
return Response::InternalServerError(
json!({ "error": "Failed to create guild channel." }),
);
}
if col
@@ -169,18 +162,12 @@ pub fn create_guild(user: User, info: Json<CreateGuild>) -> JsonValue {
)
.is_ok()
{
json!({
"success": true,
"id": id,
})
Response::Success(json!({ "id": id }))
} else {
channels
.delete_one(doc! { "_id": channel_id }, None)
.expect("Failed to delete the channel we just made.");
json!({
"success": false,
"error": "Failed to create guild."
})
Response::InternalServerError(json!({ "error": "Failed to create guild." }))
}
}

View File

@@ -1,4 +1,4 @@
use rocket::http::Status;
pub use rocket::http::Status;
pub use rocket::response::Redirect;
use rocket::Rocket;
use rocket_contrib::json::JsonValue;
@@ -12,7 +12,7 @@ pub mod user;
#[derive(Responder)]
pub enum Response {
#[response()]
Ok(Option<JsonValue>),
Result(Status),
#[response()]
Success(JsonValue),
#[response()]
@@ -35,8 +35,6 @@ pub enum Response {
TooManyRequests(JsonValue),
#[response(status = 500)]
InternalServerError(JsonValue),
#[response()]
Error(Status),
}
pub fn mount(rocket: Rocket) -> Rocket {

View File

@@ -1,10 +1,11 @@
use super::Response;
use bson::doc;
use rocket_contrib::json::JsonValue;
/// root
#[get("/")]
pub fn root() -> JsonValue {
json!({
pub fn root() -> Response {
Response::Success(json!({
"revolt": "0.0.1"
})
}))
}

View File

@@ -1,3 +1,4 @@
use super::Response;
use crate::database::{self, channel::Channel, user::User};
use crate::routes::channel;
@@ -20,12 +21,12 @@ pub fn me(user: User) -> JsonValue {
/// retrieve another user's information
#[get("/<target>")]
pub fn user(user: User, target: User) -> JsonValue {
json!({
pub fn user(user: User, target: User) -> Response {
Response::Success(json!({
"id": target.id,
"username": target.username,
"relationship": get_relationship(&user, &target) as u8
})
}))
}
#[derive(Serialize, Deserialize)]
@@ -36,7 +37,7 @@ 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>) -> JsonValue {
pub fn lookup(user: User, query: Json<Query>) -> Response {
let col = database::get_collection("users");
let users = col
@@ -57,12 +58,12 @@ pub fn lookup(user: User, query: Json<Query>) -> JsonValue {
}));
}
json!(results)
Response::Success(json!(results))
}
/// retrieve all of your DMs
#[get("/@me/dms")]
pub fn dms(user: User) -> JsonValue {
pub fn dms(user: User) -> Response {
let col = database::get_collection("channels");
let results = col
@@ -95,23 +96,20 @@ pub fn dms(user: User) -> JsonValue {
}));
}
json!(channels)
Response::Success(json!(channels))
}
/// open a DM with a user
#[get("/<target>/dm")]
pub fn dm(user: User, target: User) -> JsonValue {
pub fn dm(user: User, target: User) -> Response {
let col = database::get_collection("channels");
match col.find_one(
doc! { "type": channel::ChannelType::DM as i32, "recipients": { "$all": [ user.id.clone(), target.id.clone() ] } },
None
).expect("Failed channel lookup") {
Some(channel) =>
json!({
"success": true,
"id": channel.get_str("_id").unwrap()
}),
Some(channel) =>
Response::Success( json!({ "id": channel.get_str("_id").unwrap() })),
None => {
let id = Ulid::new();
@@ -125,10 +123,7 @@ pub fn dm(user: User, target: User) -> JsonValue {
None
).expect("Failed insert query.");
json!({
"success": true,
"id": id.to_string()
})
Response::Success(json!({ "id": id.to_string() }))
}
}
}
@@ -168,7 +163,7 @@ fn get_relationship(a: &User, b: &User) -> Relationship {
/// retrieve all of your friends
#[get("/@me/friend")]
pub fn get_friends(user: User) -> JsonValue {
pub fn get_friends(user: User) -> Response {
let mut results = Vec::new();
if let Some(arr) = user.relations {
for item in arr {
@@ -179,170 +174,185 @@ pub fn get_friends(user: User) -> JsonValue {
}
}
json!(results)
Response::Success(json!(results))
}
/// retrieve friend status with user
#[get("/<target>/friend")]
pub fn get_friend(user: User, target: User) -> JsonValue {
pub fn get_friend(user: User, target: User) -> Response {
let relationship = get_relationship(&user, &target);
json!({
"id": target.id,
"status": relationship as u8
})
Response::Success(json!({ "status": relationship as u8 }))
}
/// create or accept a friend request
#[put("/<target>/friend")]
pub fn add_friend(user: User, target: User) -> JsonValue {
pub fn add_friend(user: User, target: User) -> Response {
let col = database::get_collection("users");
let relationship = get_relationship(&user, &target);
match relationship {
Relationship::FRIEND => json!({
"success": false,
"error": "Already friends."
}),
Relationship::OUTGOING => json!({
"success": false,
"error": "Already sent a friend request."
}),
Relationship::FRIEND => Response::BadRequest(json!({ "error": "Already friends." })),
Relationship::OUTGOING => {
Response::BadRequest(json!({ "error": "Already sent a friend request." }))
}
Relationship::INCOMING => {
col.update_one(
doc! {
"_id": user.id.clone(),
"relations.id": target.id.clone()
},
doc! {
"$set": {
"relations.$.status": Relationship::FRIEND as i32
}
},
None,
)
.expect("Failed update query.");
col.update_one(
doc! {
"_id": target.id,
"relations.id": user.id
},
doc! {
"$set": {
"relations.$.status": Relationship::FRIEND as i32
}
},
None,
)
.expect("Failed update query.");
json!({
"success": true,
"status": Relationship::FRIEND as u8,
})
if col
.update_one(
doc! {
"_id": user.id.clone(),
"relations.id": target.id.clone()
},
doc! {
"$set": {
"relations.$.status": Relationship::FRIEND as i32
}
},
None,
)
.is_ok()
{
if col
.update_one(
doc! {
"_id": target.id,
"relations.id": user.id
},
doc! {
"$set": {
"relations.$.status": Relationship::FRIEND as i32
}
},
None,
)
.is_ok()
{
Response::Success(json!({ "status": Relationship::FRIEND as u8 }))
} else {
Response::InternalServerError(
json!({ "error": "Failed to commit! Try re-adding them as a friend." }),
)
}
} else {
Response::InternalServerError(
json!({ "error": "Failed to commit to database, try again." }),
)
}
}
Relationship::BLOCKED => {
Response::BadRequest(json!({ "error": "You have blocked this person." }))
}
Relationship::BLOCKEDOTHER => {
Response::Conflict(json!({ "error": "You have been blocked by this person." }))
}
Relationship::BLOCKED => json!({
"success": false,
"error": "You have blocked this person."
}),
Relationship::BLOCKEDOTHER => json!({
"success": false,
"error": "You have been blocked by this person."
}),
Relationship::NONE => {
col.update_one(
doc! {
"_id": user.id.clone()
},
doc! {
"$push": {
"relations": {
"id": target.id.clone(),
"status": Relationship::OUTGOING as i32
if col
.update_one(
doc! {
"_id": user.id.clone()
},
doc! {
"$push": {
"relations": {
"id": target.id.clone(),
"status": Relationship::OUTGOING as i32
}
}
}
},
None,
)
.expect("Failed update query.");
col.update_one(
doc! {
"_id": target.id
},
doc! {
"$push": {
"relations": {
"id": user.id,
"status": Relationship::INCOMING as i32
}
}
},
None,
)
.expect("Failed update query.");
json!({
"success": true,
"status": Relationship::OUTGOING as u8,
})
},
None,
)
.is_ok()
{
if col
.update_one(
doc! {
"_id": target.id
},
doc! {
"$push": {
"relations": {
"id": user.id,
"status": Relationship::INCOMING as i32
}
}
},
None,
)
.is_ok()
{
Response::Success(json!({ "status": Relationship::OUTGOING as u8 }))
} else {
Response::InternalServerError(
json!({ "error": "Failed to commit! Try re-adding them as a friend." }),
)
}
} else {
Response::InternalServerError(
json!({ "error": "Failed to commit to database, try again." }),
)
}
}
Relationship::SELF => {
Response::BadRequest(json!({ "error": "You're already friends with yourself, no? c:" }))
}
Relationship::SELF => json!({
"success": false,
"error": "Cannot add yourself as a friend."
}),
}
}
/// remove a friend or deny a request
#[delete("/<target>/friend")]
pub fn remove_friend(user: User, target: User) -> JsonValue {
pub fn remove_friend(user: User, target: User) -> Response {
let col = database::get_collection("users");
let relationship = get_relationship(&user, &target);
match relationship {
Relationship::FRIEND | Relationship::OUTGOING | Relationship::INCOMING => {
col.update_one(
doc! {
"_id": user.id.clone()
},
doc! {
"$pull": {
"relations": {
"id": target.id.clone()
if col
.update_one(
doc! {
"_id": user.id.clone()
},
doc! {
"$pull": {
"relations": {
"id": target.id.clone()
}
}
}
},
None,
)
.expect("Failed update query.");
col.update_one(
doc! {
"_id": target.id
},
doc! {
"$pull": {
"relations": {
"id": user.id
}
}
},
None,
)
.expect("Failed update query.");
json!({
"success": true
})
},
None,
)
.is_ok()
{
if col
.update_one(
doc! {
"_id": target.id
},
doc! {
"$pull": {
"relations": {
"id": user.id
}
}
},
None,
)
.is_ok()
{
Response::Result(super::Status::Ok)
} else {
Response::InternalServerError(
json!({ "error": "Failed to commit! Target remains in same state." }),
)
}
} else {
Response::InternalServerError(
json!({ "error": "Failed to commit to database, try again." }),
)
}
}
Relationship::BLOCKED
| Relationship::BLOCKEDOTHER
| Relationship::NONE
| Relationship::SELF => json!({
"success": false,
"error": "This has no effect."
}),
| Relationship::SELF => Response::BadRequest(json!({ "error": "This has no effect." })),
}
}