Skip to content
Open
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
867 changes: 442 additions & 425 deletions Cargo.lock

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,21 @@ authors = ["ndelvalle <nicolas.delvalle@gmail.com>"]
edition = "2018"

[dependencies]
config = "0.10.1"
config = "0.11.0"
log = "0.4.14"
pretty_env_logger = "0.4.0"
serde = { version = "1.0.124", features = ["derive"] }
serde_json = "1.0.64"
serde_derive = "1.0.116"
actix-web = "3.1.0"
actix-cors = "0.5.0"
actix-web = "4.0.0-beta.9"
actix-cors = "0.6.0-beta.2"
actix-web-httpauth = "0.6.0-beta.2"
wither = "0.9.0"
thiserror = "1.0.24"
chrono = { version = "0.4.19", features = ["serde"] }
futures-util = "0.3.13"
actix-files = "0.5.0"
actix-web-httpauth = "0.5.0"
# Do not update until actix web runs on tokio v1
reqwest = { version = "0.10.10", features = ["json"] }
reqwest = { version = "0.11.5", features = ["json"] }
jsonwebtoken = "7.2.0"
bcrypt = "0.9.0"
lettre = "0.9"
Expand All @@ -38,7 +37,7 @@ serde_qs = "0.8.3"
strum = { version = "0.20.0", features = ["derive"] }
serde_with = "1.7.0"
# Do not update until actix web runs on tokio v1
actix = "0.10.0"
actix = "0.12.0"
async-trait = "0.1.48"

[dev-dependencies.cargo-husky]
Expand Down
12 changes: 9 additions & 3 deletions api/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use actix_web::dev::HttpResponseBuilder;
use actix_web::error::BlockingError;
use actix_web::http::StatusCode;
use actix_web::HttpResponse;
use actix_web::HttpResponseBuilder;
use bcrypt::BcryptError;
use lettre_email::error::Error as LettreEmailError;
use reqwest::Error as ReqwestError;
use serde_json::json;
use serde_qs::Error as SerdeQsError;
use wither::bson;
use wither::mongodb::error::CommandError as MongoCommandError;
use wither::mongodb::error::Error as MongoError;
Expand Down Expand Up @@ -41,13 +43,13 @@ pub enum Error {
GoogleAuthentication {},

#[error("{0}")]
HashPassword(#[from] BlockingError<bcrypt::BcryptError>),
HashPassword(#[from] BcryptError),

#[error("Failed to parse URL")]
ParseURL(),

#[error("Failed to parse query string {0}")]
ParseQueryString(#[from] serde_qs::Error),
ParseQueryString(#[from] SerdeQsError),

#[error("RSS Integration error: {0}")]
RSSIntegration(String),
Expand All @@ -60,6 +62,9 @@ pub enum Error {

#[error("{0}")]
Reqwest(#[from] ReqwestError),

#[error("{0}")]
BlockingError(#[from] BlockingError),
}

impl Error {
Expand Down Expand Up @@ -94,6 +99,7 @@ impl Error {
Error::SendEmail(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5007),
Error::BuildEmail(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5008),
Error::SerializeMongoResponse(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5009),
Error::BlockingError(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5010),
}
}
}
Expand Down
14 changes: 8 additions & 6 deletions api/src/lib/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use actix_web::http::header::IntoHeaderValue;
use actix_web::{http, HttpResponse};
use itertools::Itertools;
use rand::Rng;
Expand All @@ -11,12 +10,15 @@ use crate::errors::Error;

type Response = actix_web::Result<HttpResponse>;

pub fn redirect_to<T: IntoHeaderValue>(url: T) -> Response {
// TODO: Validate that the given URL is a valid URL.
pub fn redirect_to<T>(url: T) -> Response
where
T: AsRef<str>,
{
Ok(
HttpResponse::Found()
.header(http::header::LOCATION, url)
.finish()
.into_body(),
.append_header((http::header::LOCATION, url.as_ref()))
.finish(),
)
}

Expand All @@ -41,8 +43,8 @@ pub fn to_object_id(id: String) -> Result<ObjectId, Error> {
pub fn parse_url(url: &str) -> Result<Url, Error> {
let mut url = url.to_owned();

// Removes the URL trailing slashes
while url.ends_with('/') {
// Removes the URL trailing slashes
url.pop();
}

Expand Down
13 changes: 6 additions & 7 deletions api/src/mailer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ use crate::settings::Settings;
#[derive(thiserror::Error, Debug)]
#[error("...")]
pub enum MailerError {
#[error("Failed to acquire mailer transport mutex")]
#[error("Failed to send email: Could not acquire transport mutex")]
LockTransport,

#[error("Failed to send email using SMTP transport {0}")]
#[error("Failed to send email: SMTP transport error {0}")]
Smtp(#[from] SmtpError),

#[error("Failed to send email actix_web::web::block operation was cancelled")]
Canceled,
#[error("Failed to send email: Blocking error {0}")]
BlockingError(#[from] BlockingError),
}

#[derive(Clone)]
Expand Down Expand Up @@ -51,14 +51,13 @@ impl Mailer {
.send(email.into())
.map_err(MailerError::Smtp)?;

Ok(())
Ok::<(), MailerError>(())
})
.await;

match sent {
Ok(_) => Ok(()),
Err(BlockingError::Canceled) => Err(Error::SendEmail(MailerError::Canceled)),
Err(BlockingError::Error(err)) => Err(Error::SendEmail(err)),
Err(err) => Err(Error::SendEmail(MailerError::BlockingError(err))),
}
}
}
2 changes: 1 addition & 1 deletion api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ async fn main() {

HttpServer::new(move || {
App::new()
.wrap(Cors::permissive())
.wrap(middleware::Compress::default())
.wrap(middleware::Logger::default())
.wrap(Cors::permissive())
.app_data(web::Data::new(settings.clone()))
.app_data(context.clone())
.configure(routes::user::create_router)
Expand Down
1 change: 1 addition & 0 deletions api/src/models/list/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ impl Model {
self.like.count(doc! { "list": list_id }).await
}

// TODO: Make this function reactive based on what we have on the database.
pub async fn update_last_activity_at(&self, list_id: &ObjectId) -> Result<(), Error> {
let update = doc! {
"$set": {
Expand Down
4 changes: 2 additions & 2 deletions api/src/models/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ impl User {
// }

pub async fn hash_password(password: String) -> Result<String, Error> {
let hash = to_future(move || bcrypt::hash(password, bcrypt::DEFAULT_COST));
let hash = to_future(move || bcrypt::hash(password, bcrypt::DEFAULT_COST)).await?;

match hash.await {
match hash {
Ok(hash) => Ok(hash),
Err(err) => Err(Error::HashPassword(err)),
}
Expand Down
6 changes: 3 additions & 3 deletions api/src/routes/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ async fn create_rss_integration(ctx: Ctx, body: RSSCreateBody, user_id: UserID)
"Failed to update last activity for list {}. Error {}",
&list_id, err
)
})?;
});

debug!("Returning integration and 200 status code");
let integration: PrivateIntegration = integration.into();
Expand Down Expand Up @@ -277,7 +277,7 @@ async fn create_subscription_integration(
"Failed to update last activity for list {}. Error {}",
&follower_list_id, err
)
})?;
});

debug!("Returning integration and 200 status code");
let integration: PrivateIntegration = integration.into();
Expand Down Expand Up @@ -320,7 +320,7 @@ async fn remove_integration(ctx: Ctx, id: ID, user_id: UserID) -> Response {
"Failed to update last activity for list {}. Error {}",
&integration.list, err
)
})?;
});

debug!("Integration removed, returning 204 status code");
let res = HttpResponse::NoContent().finish();
Expand Down
4 changes: 2 additions & 2 deletions api/src/routes/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ async fn update_list(ctx: web::Data<Context>, id: ID, body: web::Json<ListUpdate
id: list_id.clone(),
title: list.title.clone(),
})
.map_err(|err| error!("Failed to send message to subscription actor, {}", err))?;
.map_err(|err| error!("Failed to send message to subscription actor, {}", err));
}

let list = ctx.models.list.to_private_schema(&list).await?;
Expand Down Expand Up @@ -306,7 +306,7 @@ async fn remove_list(ctx: web::Data<Context>, id: ID, user: UserID) -> Response
id: list_id.clone(),
title: list.title.clone(),
})
.map_err(|err| error!("Failed to send message to subscription actor, {}", err))?;
.map_err(|err| error!("Failed to send message to subscription actor, {}", err));

debug!("List removed, returning 204 status code");
let res = HttpResponse::NoContent().finish();
Expand Down
8 changes: 4 additions & 4 deletions api/src/routes/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,15 +286,15 @@ async fn create_resource(ctx: Ctx, body: ResourceCreateBody, user_id: UserID) ->
.try_send(subscription::on_resource_created::ResourceCreated {
resource_id: resource_id.clone(),
})
.map_err(|err| error!("Failed to send message to subscription actor, {}", err))?;
.map_err(|err| error!("Failed to send message to subscription actor, {}", err));

ctx
.actors
.resource
.try_send(EnreachResourceMessage {
resource_id: resource_id.clone(),
})
.map_err(|err| error!("Failed to send message to resource actor, {}", err))?;
.map_err(|err| error!("Failed to send message to resource actor, {}", err));

ctx
.models
Expand All @@ -306,7 +306,7 @@ async fn create_resource(ctx: Ctx, body: ResourceCreateBody, user_id: UserID) ->
"Failed to update last activity for list {}. Error {}",
&resource.list, err
)
})?;
});

debug!("Returning created resource");
let resource: PrivateResource = resource.into();
Expand Down Expand Up @@ -389,7 +389,7 @@ async fn remove_resource(ctx: Ctx, id: ID, user_id: UserID) -> Response {
"Failed to update last activity for list {}. Error {}",
&resource.list, err
)
})?;
});

debug!("Resource removed, returning 204 status code");
let res = HttpResponse::NoContent().finish();
Expand Down
4 changes: 4 additions & 0 deletions config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,9 @@

"sendgrid": {
"token": ""
},

"traer": {
"token": ""
}
}