Compare commits

..

No commits in common. "a64096fa87d646788c9838bedd8cfaa7c42f0d38" and "2e6aed97efadcbca2c4bf3f2c6555f8fe220b7d6" have entirely different histories.

10 changed files with 42 additions and 90 deletions

View File

@ -1,6 +1,6 @@
--- ---
name: "🐛 Bug report" name: "Bug report"
about: "For reporting bugs" about: "This template is for reporting a bug"
title: "" title: ""
labels: labels:
- "type::bug" - "type::bug"

View File

@ -1,5 +1,5 @@
--- ---
name: "🗣 Design discussion" name: "Design discussion"
about: "For discussion about the design of features in the application, when there are several possibilities for implementation" about: "For discussion about the design of features in the application, when there are several possibilities for implementation"
title: "" title: ""
labels: labels:

View File

@ -1,6 +1,6 @@
--- ---
name: "💡 Feature request" name: "Feature request"
about: "For requesting a new feature, with an implementation plan" about: "This template is for requesting a new feature"
title: "" title: ""
labels: labels:
- "type::enhancement" - "type::enhancement"
@ -11,4 +11,4 @@ labels:
*describe what you would like to be able to do, or what solution you would like* *describe what you would like to be able to do, or what solution you would like*
*(optional) additional context, comments *(optional) additional context, comments or implementation propositions*

View File

@ -1,5 +1,5 @@
--- ---
name: "Ask a question" name: "Ask a question"
about: "If you have a question about the usage of the libraries or the tool" about: "If you have a question about the usage of the libraries or the tool"
title: "" title: ""
labels: labels:

View File

@ -1,5 +1,5 @@
--- ---
name: "🚧 Refactor" name: "Refactor"
about: "For refactoring propositions" about: "For refactoring propositions"
title: "" title: ""
labels: labels:

View File

@ -46,18 +46,18 @@ impl Builder {
user: &impl AsRef<str>, user: &impl AsRef<str>,
password: &impl AsRef<str>, password: &impl AsRef<str>,
) -> &mut Self { ) -> &mut Self {
self.user = user.as_ref().into(); self.user = String::from(user.as_ref());
self.password = password.as_ref().into(); self.password = String::from(password.as_ref());
self self
} }
pub(crate) fn homeserver(&mut self, homeserver: &impl AsRef<str>) -> &mut Self { pub(crate) fn homeserver(&mut self, homeserver: &impl AsRef<str>) -> &mut Self {
self.homeserver = homeserver.as_ref().into(); self.homeserver = String::from(homeserver.as_ref());
self self
} }
pub(crate) fn room(&mut self, room: &impl AsRef<str>) -> &mut Self { pub(crate) fn room(&mut self, room: &impl AsRef<str>) -> &mut Self {
self.room = room.as_ref().into(); self.room = String::from(room.as_ref());
self self
} }
} }

View File

@ -1,7 +1,8 @@
use std::convert::TryInto; use std::convert::TryInto;
use std::env; use std::env;
use log::{error, info}; use anyhow::Result;
use log::info;
use matrix_sdk::{ use matrix_sdk::{
self, async_trait, self, async_trait,
events::{ events::{
@ -12,7 +13,7 @@ use matrix_sdk::{
Client, ClientConfig, EventHandler, SyncSettings, Client, ClientConfig, EventHandler, SyncSettings,
}; };
use crieur_retrieve::{article_location::Error, article_location::Result, ArticleLocation, Url}; use crieur_retrieve::{ArticleLocation, Url};
pub(crate) struct Html {} pub(crate) struct Html {}
@ -47,39 +48,8 @@ where
//TODO: replace occurences ok() by async and logging block when async block is stable //TODO: replace occurences ok() by async and logging block when async block is stable
let article_html = match article_html(url).await { let article_html = match article_html(url).await {
Ok(url) => url, Ok(url) => url,
Err(Error::MalformedUrl) => {
room.send(text_message("Error: Given url is malformed"), None)
.await
.ok();
return;
}
Err(Error::UnknownNewspaper) => {
room.send(
text_message("Error: Given url is do not correspond to a known newspaper"),
None,
)
.await
.ok();
return;
}
Err(Error::Misconfiguration(key)) => {
error!(
"Error in configuration : {} key is missing or malformed",
&key
);
room.send(
text_message("Error: configuration error, please contact your admin"),
None,
)
.await
.ok();
return;
}
Err(_) => { Err(_) => {
room.send( room.send(text_message("Can't download the file"), None)
text_message("Unknown error =/, can't download the file"),
None,
)
.await .await
.ok(); .ok();
return; return;

View File

@ -2,42 +2,17 @@ use std::boxed::Box;
use std::convert::TryInto; use std::convert::TryInto;
use std::env; use std::env;
use anyhow::anyhow; use anyhow::{anyhow, Result};
use log::info; use log::info;
use url::{Host, Url}; use url::{Host, Url};
use crate::newspaper::Newspaper; use crate::newspaper::Newspaper;
use crate::newspapers::mediapart::{self, Mediapart}; use crate::newspapers::mediapart::{self, Mediapart};
/// Enumerate all errors that can be encountered when using ArticleLocation
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// The url was not set. Therefore, the article location can't be deduced
#[error("No url set")]
NoUrl,
/// The given URL isn't an accepted Url
#[error("Malformed URL")]
MalformedUrl,
/// The given url doesn't correspond to a newspaper.
#[error("The given url doesn't link to a known newspaper")]
UnknownNewspaper,
/// Error in configuration : used for missing or malformed configuration
#[error("Error in configuration (configuration key {0} malformed or missing)")]
Misconfiguration(String),
/// Other errors
#[error(transparent)]
Other(#[from] anyhow::Error),
}
type Newspapers = Vec<Box<dyn Newspaper>>; type Newspapers = Vec<Box<dyn Newspaper>>;
pub type Result<T, E = Error> = core::result::Result<T, E>;
fn default_newpapers() -> Result<Newspapers> { fn default_newpapers() -> Result<Newspapers> {
let config_key = "MEDIAPART_COOKIE".to_string(); let mpruiid = env::var("MEDIAPART_COOKIE")?.into();
let mpruiid = env::var(&config_key)
.map_err(|_| Error::Misconfiguration(config_key))?
.into();
let mediapart = Mediapart::builder() let mediapart = Mediapart::builder()
.login(mediapart::Login::MPRUUID(mpruiid)) .login(mediapart::Login::MPRUUID(mpruiid))
.build()?; .build()?;
@ -61,12 +36,13 @@ impl Builder {
/// # Errors /// # Errors
/// ///
/// An error is returned if the could not be converted into an url /// An error is returned if the could not be converted into an url
// TODO: move this to a defined error, remove anyhow !
pub fn url<U, E>(mut self, url: U) -> Result<Self> pub fn url<U, E>(mut self, url: U) -> Result<Self>
where where
U: TryInto<Url, Error = E> + Send, U: TryInto<Url, Error = E> + Send,
E: std::error::Error + Sync + Send + 'static, E: std::error::Error + Sync + Send + 'static,
{ {
let url = url.try_into().map_err(|_| Error::MalformedUrl)?; let url = url.try_into()?;
self.url = Some(url); self.url = Some(url);
Ok(self) Ok(self)
} }
@ -84,13 +60,18 @@ impl Builder {
} }
/// Adds several newspapers to the list of accepted newspapers /// Adds several newspapers to the list of accepted newspapers
pub fn newspapers(mut self, newspapers: Newspapers) -> Self { //fn newspapers(&mut self, newspapers: Newspapers) -> Result<&mut Self> {
match &mut self.newspapers { // let newspapers = match &self.newspapers {
Some(current_newspapers) => current_newspapers.extend(newspapers), // Some(current_newspapers) => newspapers
None => self.newspapers = Some(newspapers.into_iter().collect::<Vec<_>>()), // .iter()
}; // .chain(current_newspapers.iter())
self // .map(|s| *(s.clone()))
} // .collect::<Newspapers>(),
// None => newspapers.into_iter().collect::<Vec<_>>(),
// };
// self.newspapers = Some(newspapers);
// Ok(self)
//}
/// Builds the ArticleLocation by looking which newspaper /// Builds the ArticleLocation by looking which newspaper
/// ///
@ -101,16 +82,19 @@ impl Builder {
/// - no newpspaper is given /// - no newpspaper is given
/// - the url is not set /// - the url is not set
/// - the given url has no host /// - the given url has no host
// TODO: move this to a defined error, remove anyhow !
pub fn build(self) -> Result<ArticleLocation> { pub fn build(self) -> Result<ArticleLocation> {
let url = Clone::clone(self.url.as_ref().ok_or(Error::NoUrl)?); let url = Clone::clone(self.url.as_ref().ok_or(anyhow!(
let host = url.host_str().ok_or(Error::MalformedUrl)?; "No url set. You can set it with the url() function"
let host = Host::parse(host).map_err(|_| Error::MalformedUrl)?; ))?);
let host = url.host_str().ok_or(anyhow!("Given url has no host"))?;
let host = Host::parse(host)?;
let newspaper = self let newspaper = self
.newspapers .newspapers
.unwrap_or(default_newpapers()?) .unwrap_or(default_newpapers()?)
.into_iter() .into_iter()
.find(|c| c.metadata().hosts.contains(&host)) .find(|c| c.metadata().hosts.contains(&host))
.ok_or(Error::UnknownNewspaper)?; .ok_or(anyhow!("Newspaper couldn't be found"))?;
Ok(ArticleLocation { newspaper, url }) Ok(ArticleLocation { newspaper, url })
} }
} }
@ -127,7 +111,6 @@ impl ArticleLocation {
pub async fn retrieve_html(&self) -> Result<String> { pub async fn retrieve_html(&self) -> Result<String> {
info!("It will download from {}", self.url); info!("It will download from {}", self.url);
// TODO: modify when retrieve_html returns a specific Error type self.newspaper.retrieve_html(&self.url).await
Ok(self.newspaper.retrieve_html(&self.url).await?)
} }
} }

View File

@ -10,7 +10,7 @@ pub mod newspaper;
// TODO: move to another crate // TODO: move to another crate
pub mod newspapers; pub mod newspapers;
pub mod article_location; mod article_location;
pub use article_location::ArticleLocation; pub use article_location::ArticleLocation;
mod consts; mod consts;

View File

@ -4,7 +4,6 @@ use dotenv::dotenv;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
env_logger::init();
dotenv().ok(); dotenv().ok();
run().await?; run().await?;
Ok(()) Ok(())