<commit_before>#![feature(proc_macro)]
#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate hyper;
extern crate chrono;

extern crate rocket;

use std::env;
use hyper::Client;
use hyper::header::Connection;
use std::vec::Vec;
use std::ops::Deref;
use chrono::UTC;
use serde::{Deserialize, Deserializer};
use std::str::FromStr;
use rocket::Outcome;

header! { (XToken, "x-token") => [String] }

static DEBITOOR_TOKEN: &'static str = "DEBITOOR_TOKEN";

// This single-element tuple struct is called a newtype struct.
#[derive(Debug)]
struct Date(chrono::Date<UTC>);

impl Deserialize for Date {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        struct Visitor;

        impl ::serde::de::Visitor for Visitor {
            type Value = Date;

            fn visit_str<E>(&mut self, value: &str) -> Result<Date, E>
                where E: ::serde::de::Error,
            {
                Ok(Date(chrono::Date::from_utc(chrono::naive::date::NaiveDate::from_str(value).unwrap(), UTC)))
            }
        }

        // Deserialize the enum from a string.
        deserializer.deserialize_str(Visitor)
    }
}

// Enable `Deref` coercion.
impl Deref for Date {
    type Target = chrono::Date<UTC>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[derive(Deserialize, Debug)]
struct Expense {
    date: String,
    lines: Vec<Line>,
}

#[derive(Deserialize, Debug)]
struct Line {
    #[serde(rename = "categoryType")]
    category_type: Option<String>,
    description: String,
    #[serde(rename = "assetDepreciation")]
    #[serde(default = "Vec::new")]
    asset_depreciation: Vec<AssetDepreciation>,
}

#[derive(Deserialize, Debug)]
struct AssetDepreciation {
    #[serde(rename = "depreciationCost")]
    depreciation_cost: f64,
    #[serde(rename = "depreciationDate")]
    depreciation_date: Date,
    #[serde(rename = "bookValue")]
    book_value: f64,
}

#[derive(Deserialize, Debug)]
struct AccessToken {
    access_token: String
}

impl<'a, 'r> rocket::request::FromRequest<'a, 'r> for AccessToken {
    type Error = ();

    fn from_request(request: &'a rocket::request::Request<'r>) -> rocket::request::Outcome<Self, Self::Error> {
        let token = request.cookies().find(DEBITOOR_TOKEN).map(|c| c.value.to_owned());

        println!("Header: {:?}", request.headers());

        match token {
            None => {
                Outcome::Forward(())
            }
            Some(token) => {
                Outcome::Success(AccessToken {
                    access_token: token
                })
            }
        }
    }
}

#[derive(FromForm)]
struct CodeWrapper<'r> {
    code: &'r str
}

#[get("/?<code>", rank = 1)]
fn check_code(cookies: &rocket::http::Cookies, code: CodeWrapper) -> rocket::response::Redirect {
    let client_secret = env::var("CLIENT_SECRET").unwrap();

    println!("got code {:?}", code.code);

    let client = Client::new();

    let body = format!("code={}&client_secret={}&redirect_uri=http://localhost:8080/", code.code, client_secret);

    println!("body {}", body);

    let res = client.
        post("https://app.debitoor.com/login/oauth2/access_token").
        //if we keep the connection open the parsing will wait for a minute in between for a timeout
        //don't know why this is, so just disable keep alive for now
        body(body.as_bytes()).<commit_msg>extract base url from request<commit_after>#![feature(proc_macro)]
#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate hyper;
extern crate chrono;

extern crate rocket;

use std::env;
use hyper::Client;
use hyper::header::Connection;
use std::vec::Vec;
use std::ops::Deref;
use chrono::UTC;
use serde::{Deserialize, Deserializer};
use std::str::FromStr;
use rocket::Outcome;

header! { (XToken, "x-token") => [String] }

static DEBITOOR_TOKEN: &'static str = "DEBITOOR_TOKEN";

// This single-element tuple struct is called a newtype struct.
#[derive(Debug)]
struct Date(chrono::Date<UTC>);

impl Deserialize for Date {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        struct Visitor;

        impl ::serde::de::Visitor for Visitor {
            type Value = Date;

            fn visit_str<E>(&mut self, value: &str) -> Result<Date, E>
                where E: ::serde::de::Error,
            {
                Ok(Date(chrono::Date::from_utc(chrono::naive::date::NaiveDate::from_str(value).unwrap(), UTC)))
            }
        }

        // Deserialize the enum from a string.
        deserializer.deserialize_str(Visitor)
    }
}

// Enable `Deref` coercion.
impl Deref for Date {
    type Target = chrono::Date<UTC>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[derive(Deserialize, Debug)]
struct Expense {
    date: String,
    lines: Vec<Line>,
}

#[derive(Deserialize, Debug)]
struct Line {
    #[serde(rename = "categoryType")]
    category_type: Option<String>,
    description: String,
    #[serde(rename = "assetDepreciation")]
    #[serde(default = "Vec::new")]
    asset_depreciation: Vec<AssetDepreciation>,
}

#[derive(Deserialize, Debug)]
struct AssetDepreciation {
    #[serde(rename = "depreciationCost")]
    depreciation_cost: f64,
    #[serde(rename = "depreciationDate")]
    depreciation_date: Date,
    #[serde(rename = "bookValue")]
    book_value: f64,
}

#[derive(Deserialize, Debug)]
struct AccessToken {
    access_token: String
}

impl<'a, 'r> rocket::request::FromRequest<'a, 'r> for AccessToken {
    type Error = ();

    fn from_request(request: &'a rocket::request::Request<'r>) -> rocket::request::Outcome<Self, Self::Error> {
        let token = request.cookies().find(DEBITOOR_TOKEN).map(|c| c.value.to_owned());

        match token {
            None => {
                Outcome::Forward(())
            }
            Some(token) => {
                Outcome::Success(AccessToken {
                    access_token: token
                })
            }
        }
    }
}

#[derive(Deserialize, Debug)]
struct BaseURL {
    base_url: String
}

impl<'a, 'r> rocket::request::FromRequest<'a, 'r> for BaseURL {
    type Error = ();

    fn from_request(request: &'a rocket::request::Request<'r>) -> rocket::request::Outcome<Self, Self::Error> {
        println!("Header: {:?}", request.headers());

        let schema = request.headers().get_one("X-Forwarded-Proto").unwrap_or("http");
        let host = request.headers().get_one("Host").unwrap();

        Outcome::Success(BaseURL {
            base_url: format!("{}://{}", schema, host)
        })
    }
}

#[derive(FromForm)]
struct CodeWrapper<'r> {
    code: &'r str
}

#[get("/?<code>", rank = 1)]
fn check_code(cookies: &rocket::http::Cookies, code: CodeWrapper, base_url: BaseURL) -> rocket::response::Redirect {
    let client_secret = env::var("CLIENT_SECRET").unwrap();

    println!("got code {:?}", code.code);

    let client = Client::new();

    let body = format!("code={}&client_secret={}&redirect_uri={}", code.code, client_secret, base_url.base_url);

    println!("body {}", body);

    let res = client.
        post("https://app.debitoor.com/login/oauth2/access_token").
        //if we keep the connection open the parsing will wait for a minute in between for a timeout
        //don't know why this is, so just disable keep alive for now
        body(body.as_bytes()).
{'fraction_non_alphanumeric': 0.1600418410041841, 'fraction_numerical': 0.0023535564853556486, 'mean_word_length': 3.237673130193906, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 54, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '167493', 'n_tokens_mistral': 2507, 'n_tokens_neox': 2506, 'n_words': 555}