Skip to content

Commit 02ff7fc

Browse files
committed
Fix HTTP status codes for 2 non-cargo user endpoints
1 parent 4f3bfdf commit 02ff7fc

File tree

5 files changed

+77
-20
lines changed

5 files changed

+77
-20
lines changed

src/controllers.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
mod cargo_prelude {
2+
pub use super::prelude::*;
3+
pub use crate::util::cargo_err;
4+
}
5+
6+
mod frontend_prelude {
7+
pub use super::prelude::*;
8+
pub use crate::util::errors::{bad_request, server_error};
9+
}
10+
111
mod prelude {
212
pub use super::helpers::ok_true;
313
pub use diesel::prelude::*;
@@ -6,7 +16,7 @@ mod prelude {
616
pub use conduit_router::RequestParams;
717

818
pub use crate::db::RequestTransaction;
9-
pub use crate::util::{cargo_err, AppResult};
19+
pub use crate::util::{cargo_err, AppResult}; // TODO: Remove cargo_err from here
1020

1121
pub use crate::middleware::app::RequestApp;
1222
pub use crate::middleware::current_user::RequestUser;

src/controllers/user/me.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use std::collections::HashMap;
22

3-
use crate::controllers::prelude::*;
3+
use crate::controllers::frontend_prelude::*;
44

55
use crate::controllers::helpers::*;
66
use crate::email;
7-
use crate::util::bad_request;
87
use crate::util::errors::AppError;
98

109
use crate::models::user::{UserNoEmailType, ALL_COLUMNS};
@@ -122,7 +121,7 @@ pub fn update_user(req: &mut dyn Request) -> AppResult<Response> {
122121

123122
// need to check if current user matches user to be updated
124123
if &user.id.to_string() != name {
125-
return Err(cargo_err("current user does not match requested user"));
124+
return Err(bad_request("current user does not match requested user"));
126125
}
127126

128127
#[derive(Deserialize)]
@@ -136,17 +135,17 @@ pub fn update_user(req: &mut dyn Request) -> AppResult<Response> {
136135
}
137136

138137
let user_update: UserUpdate =
139-
serde_json::from_str(&body).map_err(|_| cargo_err("invalid json request"))?;
138+
serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;
140139

141140
if user_update.user.email.is_none() {
142-
return Err(cargo_err("empty email rejected"));
141+
return Err(bad_request("empty email rejected"));
143142
}
144143

145144
let user_email = user_update.user.email.unwrap();
146145
let user_email = user_email.trim();
147146

148147
if user_email == "" {
149-
return Err(cargo_err("empty email rejected"));
148+
return Err(bad_request("empty email rejected"));
150149
}
151150

152151
conn.transaction::<_, Box<dyn AppError>, _>(|| {
@@ -166,7 +165,7 @@ pub fn update_user(req: &mut dyn Request) -> AppResult<Response> {
166165
.set(&new_email)
167166
.returning(emails::token)
168167
.get_result::<String>(&*conn)
169-
.map_err(|_| cargo_err("Error in creating token"))?;
168+
.map_err(|_| server_error("Error in creating token"))?;
170169

171170
crate::email::send_user_confirm_email(user_email, &user.gh_login, &token);
172171

@@ -213,7 +212,7 @@ pub fn regenerate_token_and_send(req: &mut dyn Request) -> AppResult<Response> {
213212

214213
// need to check if current user matches user to be updated
215214
if &user.id != name {
216-
return Err(cargo_err("current user does not match requested user"));
215+
return Err(bad_request("current user does not match requested user"));
217216
}
218217

219218
conn.transaction(|| {
@@ -223,7 +222,7 @@ pub fn regenerate_token_and_send(req: &mut dyn Request) -> AppResult<Response> {
223222
.map_err(|_| bad_request("Email could not be found"))?;
224223

225224
email::try_send_user_confirm_email(&email.email, &user.gh_login, &email.token)
226-
.map_err(|_| bad_request("Error in sending email"))
225+
.map_err(|_| server_error("Error in sending email"))
227226
})?;
228227

229228
#[derive(Serialize)]

src/tests/user.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ fn test_empty_email_not_added() {
466466

467467
let json = user
468468
.update_email_more_control(model.id, Some(""))
469-
.bad_with_status(200);
469+
.bad_with_status(400);
470470
assert!(
471471
json.errors[0].detail.contains("empty email rejected"),
472472
"{:?}",
@@ -475,7 +475,7 @@ fn test_empty_email_not_added() {
475475

476476
let json = user
477477
.update_email_more_control(model.id, None)
478-
.bad_with_status(200);
478+
.bad_with_status(400);
479479

480480
assert!(
481481
json.errors[0].detail.contains("empty email rejected"),
@@ -501,7 +501,7 @@ fn test_other_users_cannot_change_my_email() {
501501
another_user_model.id,
502502
503503
)
504-
.bad_with_status(200);
504+
.bad_with_status(400);
505505
assert!(
506506
json.errors[0]
507507
.detail

src/util/errors.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@ use diesel::result::Error as DieselError;
88

99
use crate::util::json_response;
1010

11+
mod http;
12+
13+
/// Returns an error with status 200 and the provided description as JSON
14+
///
15+
/// This is for backwards compatibility with cargo endpoints. For all other
16+
/// endpoints, use helpers like `bad_request` or `server_error` which set a
17+
/// correct status code.
18+
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
19+
Box::new(ConcreteAppError {
20+
description: error.to_string(),
21+
cargo_err: true,
22+
})
23+
}
24+
25+
// The following are intended to be used for errors being sent back to the Ember
26+
// frontend, not to cargo as cargo does not handle non-200 response codes well
27+
// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
28+
// non-200 response codes for its stores to work properly.
29+
30+
/// Returns an error with status 500 and the provided description as JSON
31+
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
32+
Box::new(http::ServerError(error.to_string()))
33+
}
34+
1135
#[derive(Serialize)]
1236
struct StringError {
1337
detail: String,
@@ -305,13 +329,6 @@ pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
305329
})
306330
}
307331

308-
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
309-
Box::new(ConcreteAppError {
310-
description: error.to_string(),
311-
cargo_err: true,
312-
})
313-
}
314-
315332
/// This is intended to be used for errors being sent back to the Ember
316333
/// frontend, not to cargo as cargo does not handle non-200 response codes well
317334
/// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires

src/util/errors/http.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use std::fmt;
2+
3+
use conduit::Response;
4+
5+
use super::{AppError, Bad, StringError};
6+
use crate::util::json_response;
7+
8+
#[derive(Debug)]
9+
pub(super) struct ServerError(pub(super) String);
10+
11+
impl AppError for ServerError {
12+
fn description(&self) -> &str {
13+
self.0.as_ref()
14+
}
15+
16+
fn response(&self) -> Option<Response> {
17+
let mut response = json_response(&Bad {
18+
errors: vec![StringError {
19+
detail: self.0.clone(),
20+
}],
21+
});
22+
response.status = (500, "Internal Server Error");
23+
Some(response)
24+
}
25+
}
26+
27+
impl fmt::Display for ServerError {
28+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29+
self.0.fmt(f)
30+
}
31+
}

0 commit comments

Comments
 (0)