From 5a0f01359795c24580b81cae966b9662b26a699e Mon Sep 17 00:00:00 2001 From: Cosmin Constantin Lazar Date: Thu, 28 Sep 2023 06:24:46 +0200 Subject: [PATCH 1/3] Support configuration via `FullySpecified` address --- Cargo.toml | 1 + src/lib.rs | 10 +-- src/main.rs | 4 +- src/mitaffald/mod.rs | 181 +++++++++++++++++++++++++------------- src/mitaffald/settings.rs | 29 ++++++ src/settings.rs | 30 +------ 6 files changed, 156 insertions(+), 99 deletions(-) create mode 100644 src/mitaffald/settings.rs diff --git a/Cargo.toml b/Cargo.toml index 1820933..da32bb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ easy-scraper = "0.2.0" reqwest = { version = "0.11.18", features = ["blocking"] } rumqttc = "0.22.0" serde = { version = "1.0.183", features = ["derive"] } +url = {version= "2.4.1", features = ["serde"]} [dev-dependencies] fluent-asserter = "0.1.9" diff --git a/src/lib.rs b/src/lib.rs index f792102..8f253a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,3 @@ -mod homeassistant; -mod mitaffald; -mod settings; - -pub use crate::mitaffald::*; -pub use homeassistant::*; -pub use settings::*; +pub mod homeassistant; +pub mod mitaffald; +pub mod settings; diff --git a/src/main.rs b/src/main.rs index 2da1308..c16d711 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,6 @@ -use ha_mitaffald::{get_containers, HASensor, Settings}; +use ha_mitaffald::homeassistant::HASensor; +use ha_mitaffald::mitaffald::get_containers; +use ha_mitaffald::settings::Settings; use rumqttc::Client; use std::collections::HashMap; diff --git a/src/mitaffald/mod.rs b/src/mitaffald/mod.rs index a621722..bad265c 100644 --- a/src/mitaffald/mod.rs +++ b/src/mitaffald/mod.rs @@ -1,7 +1,10 @@ -use crate::{settings::Address, AffaldVarmeConfig}; +pub mod settings; + use chrono::{Datelike, Local, NaiveDate}; use easy_scraper::Pattern; +use settings::{Address, AffaldVarmeConfig}; use std::collections::BTreeMap; +use url::Url; pub fn get_containers(config: AffaldVarmeConfig) -> Result, String> { let response = fetch_remote_response(config); @@ -32,17 +35,32 @@ fn fetch_remote_response( reqwest::blocking::get(remote_url) } -fn build_remote_url(config: AffaldVarmeConfig) -> String { - //todo: can we find a nicer way to compose a URL? +fn build_remote_url(config: AffaldVarmeConfig) -> Url { + let mut url_builder = config.base_url.clone(); + url_builder.set_path("Adresse/VisAdresseInfo"); + match config.address { Address::Id(x) => { - format!( - "{}/Adresse/VisAdresseInfo?address-selected-id={}", - config.base_url, x.id - ) + url_builder + .query_pairs_mut() + .append_pair("address-selected-id", x.id.as_str()); + } + Address::FullySpecified(x) => { + //The comma (URL encoded as `%2C`) after the street_name in the address-search query string is very important and prevents the website from finding the address if is missing. + //https://mitaffald.affaldvarme.dk/Adresse/VisAdresseInfo?address-search=Kongevejen%2C+8000+Aarhus+C&number-search=100&address-selected-postnr=8000 + + url_builder + .query_pairs_mut() + .append_pair( + "address-search", + format!("{}, {} {}", x.street_name, x.postal_code, x.city).as_str(), + ) + .append_pair("number-search", x.street_no.as_str()) + .append_pair("address-selected-postnr", x.postal_code.as_str()); } - Address::FullySpecified(_) => todo!(), } + + url_builder } fn extract_container_data(html: String) -> Vec { @@ -135,91 +153,73 @@ impl Container { #[cfg(test)] mod tests { - use crate::AddressId; - use super::*; + use crate::mitaffald::settings::{Address, AddressId, TraditionalAddress}; use chrono::{Datelike, Duration, Local}; use fluent_asserter::*; #[test] - fn can_calculate_next_date_future() { - let date_in_the_future = Local::now().date_naive() + Duration::days(1); - let input = build_container(date_in_the_future); - - let actual = input.get_next_empty(); - - assert_that!(actual).is_equal_to(date_in_the_future); - } - - #[test] - fn can_calculate_next_date_today() { - let today = Local::now().date_naive(); - let input = build_container(today); - - let actual = input.get_next_empty(); + fn can_extract_data_using_address_id() { + let mut remote = mockito::Server::new(); + let address_id = "123".to_string(); + let config = AffaldVarmeConfig { + address: Address::Id(AddressId { + id: address_id.clone(), + }), + base_url: Url::parse(remote.url().as_str()).unwrap(), + }; - assert_that!(actual).is_equal_to(today); - } + let remote = remote + .mock( + "GET", + format!("/Adresse/VisAdresseInfo?address-selected-id={}", address_id).as_str(), + ) + .with_status(200) + .with_body_from_file("src/mitaffald/sample_remote_response.html") + .create(); - #[test] - fn can_calculate_next_date_at_year_end() { - let today = Local::now().date_naive(); - let yesterday = today - chrono::Duration::days(1); + let actual = get_containers(config); + let expected = expected_cotainers_from_sample_reponse_file(); - let input = build_container(yesterday); + remote.assert(); - let actual = input.get_next_empty(); - let expected = - NaiveDate::from_ymd_opt(yesterday.year() + 1, yesterday.month(), yesterday.day()) - .unwrap(); + assert!(matches!(actual, Ok(_))); + assert_that!(actual.is_err()).is_equal_to(false); - assert_that!(actual).is_equal_to(expected); + assert_that!(actual.unwrap().as_slice()).is_equal_to(expected.as_slice()); } #[test] - fn can_extract_data() { + fn can_extract_data_using_traditional_address() { let mut remote = mockito::Server::new(); - let address_id = "123".to_string(); let config = AffaldVarmeConfig { - address: Address::Id(AddressId { - id: address_id.clone(), + address: Address::FullySpecified(TraditionalAddress { + street_name: "Kongevejen".to_string(), + street_no: "100".to_string(), + postal_code: "8000".to_string(), + city: "Aarhus C".to_string(), }), - base_url: remote.url(), + base_url: Url::parse(remote.url().as_str()).unwrap(), }; let remote = remote .mock( "GET", - format!("/Adresse/VisAdresseInfo?address-selected-id={}", address_id).as_str(), + "/Adresse/VisAdresseInfo?address-search=Kongevejen%2C+8000+Aarhus+C&number-search=100&address-selected-postnr=8000", ) .with_status(200) .with_body_from_file("src/mitaffald/sample_remote_response.html") .create(); let actual = get_containers(config); - let expected = vec![ - Container { - id: "11064295".to_owned(), - name: "Restaffald".to_owned(), - frequency: "1 gang på 2 uger".to_owned(), - next_empty: "04/08".to_owned(), - size: "240 L".to_owned(), - }, - Container { - id: "12019493".to_owned(), - name: "Genanvendeligt affald (Glas plast metal og papir pap)".to_owned(), - frequency: "1 gang på 4 uger".to_owned(), - next_empty: "03/08".to_owned(), - size: "240 L".to_owned(), - }, - ]; + let expected = expected_cotainers_from_sample_reponse_file(); remote.assert(); assert!(matches!(actual, Ok(_))); assert_that!(actual.is_err()).is_equal_to(false); - assert_that!(actual.unwrap()).is_equal_to(expected); + assert_that!(actual.unwrap().as_slice()).is_equal_to(expected.as_slice()); } #[test] @@ -227,7 +227,7 @@ mod tests { let mut remote = mockito::Server::new(); let config = AffaldVarmeConfig { address: Address::Id(AddressId { id: "123".into() }), - base_url: remote.url(), + base_url: Url::parse(remote.url().as_str()).unwrap(), }; let remote = remote @@ -245,7 +245,7 @@ mod tests { fn can_handle_no_responses() { let config = AffaldVarmeConfig { address: Address::Id(AddressId { id: "123".into() }), - base_url: "http://127.0.0.1:123123".to_string(), + base_url: Url::parse("http://127.0.0.1:12312").unwrap(), }; let actual = get_containers(config); @@ -253,6 +253,63 @@ mod tests { assert!(matches!(actual, Err(x) if x.contains("Error connecting"))); } + #[test] + fn can_calculate_next_date_future() { + let date_in_the_future = Local::now().date_naive() + Duration::days(1); + let input = build_container(date_in_the_future); + + let actual = input.get_next_empty(); + + assert_that!(actual).is_equal_to(date_in_the_future); + } + + #[test] + fn can_calculate_next_date_today() { + let today = Local::now().date_naive(); + let input = build_container(today); + + let actual = input.get_next_empty(); + + assert_that!(actual).is_equal_to(today); + } + + #[test] + fn can_calculate_next_date_at_year_end() { + let today = Local::now().date_naive(); + let yesterday = today - chrono::Duration::days(1); + + let input = build_container(yesterday); + + let actual = input.get_next_empty(); + let expected = + NaiveDate::from_ymd_opt(yesterday.year() + 1, yesterday.month(), yesterday.day()) + .unwrap(); + + assert_that!(actual).is_equal_to(expected); + } + + //todo: use this to test failure finding address + //https://mitaffald.affaldvarme.dk/Adresse/VisAdresseInfo?address-search=Kongevejen+8000+Aarhus+C&number-search=100&address-selected-postnr=8000 + //https://mitaffald.affaldvarme.dk/Adresse/VisAdresseInfo?address-search=Kongevejen%2C+8000+Aarhus+C&number-search=100&address-selected-postnr=8000 + fn expected_cotainers_from_sample_reponse_file() -> [Container; 2] { + [ + Container { + id: "11064295".to_owned(), + name: "Restaffald".to_owned(), + frequency: "1 gang på 2 uger".to_owned(), + next_empty: "04/08".to_owned(), + size: "240 L".to_owned(), + }, + Container { + id: "12019493".to_owned(), + name: "Genanvendeligt affald (Glas plast metal og papir pap)".to_owned(), + frequency: "1 gang på 4 uger".to_owned(), + next_empty: "03/08".to_owned(), + size: "240 L".to_owned(), + }, + ] + } + fn build_container(next_empty: NaiveDate) -> Container { Container { id: "11064295".to_owned(), diff --git a/src/mitaffald/settings.rs b/src/mitaffald/settings.rs new file mode 100644 index 0000000..ce0f20d --- /dev/null +++ b/src/mitaffald/settings.rs @@ -0,0 +1,29 @@ +use serde::Deserialize; +use url::Url; + +#[derive(Debug, Deserialize)] +#[allow(unused)] +pub struct AffaldVarmeConfig { + pub address: Address, + pub base_url: Url, +} + +#[derive(Deserialize, Debug)] +#[serde(untagged)] +pub enum Address { + Id(AddressId), + FullySpecified(TraditionalAddress), +} + +#[derive(Deserialize, Debug)] +pub struct TraditionalAddress { + pub street_name: String, + pub street_no: String, + pub postal_code: String, + pub city: String, +} + +#[derive(Deserialize, Debug)] +pub struct AddressId { + pub id: String, +} diff --git a/src/settings.rs b/src/settings.rs index e6eedd4..bb553e0 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,3 +1,4 @@ +use crate::mitaffald::settings::AffaldVarmeConfig; use config::{Config, ConfigError, File}; use serde::Deserialize; @@ -8,7 +9,6 @@ pub struct Settings { pub affaldvarme: AffaldVarmeConfig, } -//implement new for Settings impl Settings { pub fn new() -> Result { let settings = Config::builder() @@ -29,31 +29,3 @@ pub struct MQTTConfig { pub password: String, pub client_id: String, } - -#[derive(Debug, Deserialize)] -#[allow(unused)] -pub struct AffaldVarmeConfig { - pub address: Address, - pub base_url: String, -} - -//not really tested -#[derive(Deserialize, Debug)] -pub struct TraditionalAddress { - pub street_name: String, - pub street_no: String, - pub postal_code: String, - pub city: String, -} - -#[derive(Deserialize, Debug)] -pub struct AddressId { - pub id: String, -} - -#[derive(Deserialize, Debug)] -#[serde(untagged)] -pub enum Address { - Id(AddressId), - FullySpecified(TraditionalAddress), -} From 05bf629389fd6e4d2a09eda030a47437778a753a Mon Sep 17 00:00:00 2001 From: Cosmin Constantin Lazar Date: Mon, 2 Oct 2023 06:27:21 +0200 Subject: [PATCH 2/3] Add `soft` error detection --- Cargo.toml | 2 +- src/mitaffald/mod.rs | 121 +++++-- .../remote_responses/addressid_not_found.html | 308 ++++++++++++++++ .../container_information.html} | 0 .../traditionaladdress_not_found.html | 338 ++++++++++++++++++ 5 files changed, 746 insertions(+), 23 deletions(-) create mode 100644 src/mitaffald/remote_responses/addressid_not_found.html rename src/mitaffald/{sample_remote_response.html => remote_responses/container_information.html} (100%) create mode 100644 src/mitaffald/remote_responses/traditionaladdress_not_found.html diff --git a/Cargo.toml b/Cargo.toml index da32bb5..134a026 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ easy-scraper = "0.2.0" reqwest = { version = "0.11.18", features = ["blocking"] } rumqttc = "0.22.0" serde = { version = "1.0.183", features = ["derive"] } -url = {version= "2.4.1", features = ["serde"]} +url = { version = "2.4.1", features = ["serde"] } [dev-dependencies] fluent-asserter = "0.1.9" diff --git a/src/mitaffald/mod.rs b/src/mitaffald/mod.rs index bad265c..f8ca361 100644 --- a/src/mitaffald/mod.rs +++ b/src/mitaffald/mod.rs @@ -19,7 +19,7 @@ pub fn get_containers(config: AffaldVarmeConfig) -> Result, Strin } match response.text() { - Ok(text) => Ok(extract_container_data(text)), + Ok(text) => parse_response(text), Err(err_reading_text) => Err(format!( "Error reading response content: {:?}", err_reading_text @@ -63,7 +63,33 @@ fn build_remote_url(config: AffaldVarmeConfig) -> Url { url_builder } -fn extract_container_data(html: String) -> Vec { +fn parse_response(html: String) -> Result, String> { + match extract_error(html.as_str()) { + None => Ok(extract_container_data(html.as_str())), + Some(error_message) => Err(error_message), + } +} + +fn extract_error(html: &str) -> Option { + let pattern = Pattern::new( + r#" +
+ {{error}} +
+ "#, + ) + .unwrap(); + + let matches = pattern.matches(html); + + if matches.len() > 0 { + return Some(matches[0].get("error").unwrap().clone()); + } + + None +} + +fn extract_container_data(html: &str) -> Vec { let pattern = Pattern::new( r#"

@@ -87,7 +113,7 @@ fn extract_container_data(html: String) -> Vec { .unwrap(); pattern - .matches(&html) + .matches(html) .into_iter() //.map(from_destructive) .map(from_nondestructive) @@ -156,7 +182,7 @@ mod tests { use super::*; use crate::mitaffald::settings::{Address, AddressId, TraditionalAddress}; use chrono::{Datelike, Duration, Local}; - use fluent_asserter::*; + use fluent_asserter::{prelude::StrAssertions, *}; #[test] fn can_extract_data_using_address_id() { @@ -175,17 +201,14 @@ mod tests { format!("/Adresse/VisAdresseInfo?address-selected-id={}", address_id).as_str(), ) .with_status(200) - .with_body_from_file("src/mitaffald/sample_remote_response.html") + .with_body_from_file("src/mitaffald/remote_responses/container_information.html") .create(); let actual = get_containers(config); - let expected = expected_cotainers_from_sample_reponse_file(); + let expected = cotainers_from_container_information_file(); remote.assert(); - - assert!(matches!(actual, Ok(_))); - assert_that!(actual.is_err()).is_equal_to(false); - + assert_that!(actual.is_ok()).is_true(); assert_that!(actual.unwrap().as_slice()).is_equal_to(expected.as_slice()); } @@ -208,22 +231,77 @@ mod tests { "/Adresse/VisAdresseInfo?address-search=Kongevejen%2C+8000+Aarhus+C&number-search=100&address-selected-postnr=8000", ) .with_status(200) - .with_body_from_file("src/mitaffald/sample_remote_response.html") + .with_body_from_file("src/mitaffald/remote_responses/container_information.html") .create(); let actual = get_containers(config); - let expected = expected_cotainers_from_sample_reponse_file(); + let expected = cotainers_from_container_information_file(); remote.assert(); + assert_that!(actual.is_ok()).is_true(); + assert_that!(actual.unwrap().as_slice()).is_equal_to(expected.as_slice()); + } - assert!(matches!(actual, Ok(_))); - assert_that!(actual.is_err()).is_equal_to(false); + #[test] + fn using_traditional_address_can_detect_address_not_found() { + let mut remote = mockito::Server::new(); + let config = AffaldVarmeConfig { + address: Address::FullySpecified(TraditionalAddress { + street_name: "Kongevejen".to_string(), + street_no: "100".to_string(), + postal_code: "8000".to_string(), + city: "Aarhus C".to_string(), + }), + base_url: Url::parse(&remote.url()).unwrap(), + }; - assert_that!(actual.unwrap().as_slice()).is_equal_to(expected.as_slice()); + let remote = remote + .mock( + "GET", + "/Adresse/VisAdresseInfo?address-search=Kongevejen%2C+8000+Aarhus+C&number-search=100&address-selected-postnr=8000", + ) + .with_status(200) + .with_body_from_file("src/mitaffald/remote_responses/traditionaladdress_not_found.html") + .create(); + + let actual = get_containers(config); + + remote.assert(); + assert_that!(actual.is_err()).is_true(); + assert_that!(actual.unwrap_err()).is_equal_to(": fejl ved opslag på adressen. Kontakt venligst KundeService Affald på mail: kundeservicegenbrug@kredslob.dk eller telefonnummer 77 88 10 10.".to_string()); + } + + #[test] + fn using_addressid_can_detect_address_not_found() { + let mut remote = mockito::Server::new(); + let address_id = "123".to_string(); + let config = AffaldVarmeConfig { + address: Address::Id(AddressId { + id: address_id.clone(), + }), + base_url: Url::parse(&remote.url()).unwrap(), + }; + + println!("current dir: {:?}", std::env::current_dir()); + + let remote = remote + .mock( + "GET", + format!("/Adresse/VisAdresseInfo?address-selected-id={}", address_id).as_str(), + ) + .with_status(200) + .with_body_from_file("src/mitaffald/remote_responses/addressid_not_found.html") + .create(); + + let actual = get_containers(config); + + remote.assert(); + assert_that!(actual.is_err()).is_true(); + assert_that!(actual.unwrap_err()).is_equal_to("Søgningen gav intet resultat".to_string()); } #[test] - fn can_handle_error_responses() { + fn can_handle_server_error() { let mut remote = mockito::Server::new(); let config = AffaldVarmeConfig { address: Address::Id(AddressId { id: "123".into() }), @@ -238,7 +316,8 @@ mod tests { let actual = get_containers(config); remote.assert(); - assert!(matches!(actual, Err(msg) if msg.contains("Unexpected status code"))); + assert_that!(actual.is_err()).is_true(); + assert_that!(actual.unwrap_err()).contains("Unexpected status code"); } #[test] @@ -250,7 +329,8 @@ mod tests { let actual = get_containers(config); - assert!(matches!(actual, Err(x) if x.contains("Error connecting"))); + assert_that!(actual.is_err()).is_true(); + assert_that!(actual.unwrap_err()).contains("Error connecting"); } #[test] @@ -288,10 +368,7 @@ mod tests { assert_that!(actual).is_equal_to(expected); } - //todo: use this to test failure finding address - //https://mitaffald.affaldvarme.dk/Adresse/VisAdresseInfo?address-search=Kongevejen+8000+Aarhus+C&number-search=100&address-selected-postnr=8000 - //https://mitaffald.affaldvarme.dk/Adresse/VisAdresseInfo?address-search=Kongevejen%2C+8000+Aarhus+C&number-search=100&address-selected-postnr=8000 - fn expected_cotainers_from_sample_reponse_file() -> [Container; 2] { + fn cotainers_from_container_information_file() -> [Container; 2] { [ Container { id: "11064295".to_owned(), diff --git a/src/mitaffald/remote_responses/addressid_not_found.html b/src/mitaffald/remote_responses/addressid_not_found.html new file mode 100644 index 0000000..cf306e6 --- /dev/null +++ b/src/mitaffald/remote_responses/addressid_not_found.html @@ -0,0 +1,308 @@ + + + + + + + + + MitAffald – Din digitale selvbetjeningsløsning for affald + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+ + + +
+ + +
Søgningen gav intet resultat
+ + + +
+
+

Ekstra service til dit affald

+
+
+ +
+
+
+
    +
  • Bestille ekstra tømning af beholder
  • +
  • Få hentet ekstra restaffald i sække
  • +
  • Bestille vask af dine beholdere
  • +
  • Få repareret din beholder
  • +
+
+

Bestil nemt og hurtigt

+ +
+
+
+
+

Bestil storskraldsbilen

+
+
+ +
+
+
+
+

+ + Ret eller annuller bestilling + +

+
+ +  Find +
+
+
+
+
+
+ Få afhentet dit storskrald gratis ved + din hoveddør +
+
+

+ + Bestil storskraldsbilen + +

+ + +
+
+
+
+
+ + + +
+
+
+
+
+
-
+

Denne løsning er til privatkunder med egne affaldsbeholdere.

+
+

Se hvornår din beholder bliver tømt

+

+ Indtast dit vejnavn i det første felt. Vælg det korrekte vejnavn og postnummer. + Indtast dit husnummer i næste felt. +

+ + +
+ +
+
+
+
+
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/mitaffald/sample_remote_response.html b/src/mitaffald/remote_responses/container_information.html similarity index 100% rename from src/mitaffald/sample_remote_response.html rename to src/mitaffald/remote_responses/container_information.html diff --git a/src/mitaffald/remote_responses/traditionaladdress_not_found.html b/src/mitaffald/remote_responses/traditionaladdress_not_found.html new file mode 100644 index 0000000..c72fdab --- /dev/null +++ b/src/mitaffald/remote_responses/traditionaladdress_not_found.html @@ -0,0 +1,338 @@ + + + + + + + + MitAffald – Din digitale selvbetjeningsløsning for affald + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ +
+ +
+ 100, Kongevejen 8000 Aarhus C + : fejl ved opslag på adressen. Kontakt venligst KundeService Affald på mail: kundeservicegenbrug@kredslob.dk eller telefonnummer 77 88 10 10. +
+ +
+
+

Ekstra service til dit affald

+
+
+ +
+
+
+
    +
  • Bestille ekstra tømning af beholder
  • +
  • Få hentet ekstra restaffald i sække
  • +
  • Bestille vask af dine beholdere
  • +
  • Få repareret din beholder
  • +
+
+

+ Bestil nemt og hurtigt +

+ +
+
+
+
+

Bestil storskraldsbilen

+
+
+ +
+
+
+
+

+ + Ret eller annuller bestilling + +

+
+ +  Find +
+
+
+
+
+
+ Få afhentet dit storskrald gratis ved + din hoveddør +
+
+

+ + Bestil storskraldsbilen + +

+ +
+
+
+
+
+ + + +
+
+
+
+
+
+
-
+

Denne løsning er til privatkunder med egne affaldsbeholdere.

+
+

+ Se hvornår din beholder + bliver tømt + +

+

+ Indtast dit vejnavn i det første felt. Vælg det korrekte vejnavn og postnummer. + Indtast dit husnummer i næste felt. +

+ + +
+ +
+
+ + + +
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + From ab2c1bc6155ebc02647868dff76d9a484738ec67 Mon Sep 17 00:00:00 2001 From: Cosmin Constantin Lazar Date: Mon, 2 Oct 2023 06:35:50 +0200 Subject: [PATCH 3/3] Fix clippy --- src/mitaffald/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mitaffald/mod.rs b/src/mitaffald/mod.rs index f8ca361..6229dbe 100644 --- a/src/mitaffald/mod.rs +++ b/src/mitaffald/mod.rs @@ -82,7 +82,7 @@ fn extract_error(html: &str) -> Option { let matches = pattern.matches(html); - if matches.len() > 0 { + if !matches.is_empty() { return Some(matches[0].get("error").unwrap().clone()); }