Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/controllers/user/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
use crate::models::{NewUser, User};
use crate::schema::users;
use crate::tasks::spawn_blocking;
use crate::util::diesel::Conn;
use crate::util::errors::{bad_request, server_error, AppResult, BoxedAppError, ReadOnlyMode};
use crate::util::diesel::{is_read_only_error, Conn};
use crate::util::errors::{bad_request, server_error, AppResult};
use crate::views::EncodableMe;
use crates_io_github::GithubUser;

Expand Down Expand Up @@ -145,11 +145,10 @@
access_token,
)
.create_or_update(user.email.as_deref(), emails, conn)
.map_err(Into::into)
.or_else(|e: BoxedAppError| {
.or_else(|e| {
// If we're in read only mode, we can't update their details
// just look for an existing user
if e.is::<ReadOnlyMode>() {
if is_read_only_error(&e) {

Check warning on line 151 in src/controllers/user/session.rs

View check run for this annotation

Codecov / codecov/patch

src/controllers/user/session.rs#L151

Added line #L151 was not covered by tests
users::table
.filter(users::gh_id.eq(user.id))
.first(conn)
Expand All @@ -159,6 +158,7 @@
Err(e)
}
})
.map_err(Into::into)
}

/// Handles the `DELETE /api/private/session` route.
Expand Down
5 changes: 5 additions & 0 deletions src/util/diesel.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use diesel::connection::LoadConnection;
use diesel::pg::Pg;
use diesel::result::Error;

pub trait Conn: LoadConnection<Backend = Pg> {}

impl<T> Conn for T where T: LoadConnection<Backend = Pg> {}

pub fn is_read_only_error(error: &Error) -> bool {
matches!(error, Error::DatabaseError(_, info) if info.message().ends_with("read-only transaction"))
}

pub mod prelude {
//! Inline diesel prelude
pub use diesel::associations::{Associations, GroupedBy, Identifiable};
Expand Down
10 changes: 5 additions & 5 deletions src/util/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ use crate::middleware::log_request::ErrorField;
mod json;

use crate::email::EmailError;
use crate::util::diesel::is_read_only_error;
use crates_io_github::GitHubError;
pub use json::TOKEN_FORMAT_ERROR;
pub(crate) use json::{custom, InsecurelyGeneratedTokenRevoked, ReadOnlyMode, TooManyRequests};
pub(crate) use json::{custom, InsecurelyGeneratedTokenRevoked, TooManyRequests};

pub type BoxedAppError = Box<dyn AppError>;

Expand Down Expand Up @@ -145,10 +146,9 @@ impl From<DieselError> for BoxedAppError {
fn from(err: DieselError) -> BoxedAppError {
match err {
DieselError::NotFound => not_found(),
DieselError::DatabaseError(_, info)
if info.message().ends_with("read-only transaction") =>
{
Box::new(ReadOnlyMode)
e if is_read_only_error(&e) => {
let detail = "crates.io is currently in read-only mode for maintenance. Please try again later.";
custom(StatusCode::SERVICE_UNAVAILABLE, detail)
}
DieselError::DatabaseError(DatabaseErrorKind::ClosedConnection, _) => {
service_unavailable()
Expand Down
19 changes: 0 additions & 19 deletions src/util/errors/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,6 @@ fn json_error(detail: &str, status: StatusCode) -> Response {
(status, json).into_response()
}

// The following structs are empty and do not provide a custom message to the user

#[derive(Debug)]
pub(crate) struct ReadOnlyMode;

impl AppError for ReadOnlyMode {
fn response(&self) -> Response {
let detail = "crates.io is currently in read-only mode for maintenance. \
Please try again later.";
json_error(detail, StatusCode::SERVICE_UNAVAILABLE)
}
}

impl fmt::Display for ReadOnlyMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"Tried to write in read only mode".fmt(f)
}
}

// The following structs wrap owned data and provide a custom message to the user

pub fn custom(status: StatusCode, detail: impl Into<Cow<'static, str>>) -> BoxedAppError {
Expand Down