- 01
 - 02
 - 03
 - 04
 - 05
 - 06
 - 07
 - 08
 - 09
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 - 56
 - 57
 - 58
 - 59
 - 60
 - 61
 - 62
 - 63
 - 64
 - 65
 - 66
 - 67
 - 68
 - 69
 - 70
 - 71
 - 72
 - 73
 - 74
 - 75
 - 76
 - 77
 - 78
 - 79
 - 80
 - 81
 - 82
 - 83
 - 84
 - 85
 - 86
 - 87
 - 88
 - 89
 - 90
 
                        fn do_get_summary(req: &HttpRequest<AppState>) -> SummaryFuture {
    let token = req.token().expect("ISE: token not verified during AuthMiddleware stage");
    let datetime = req.match_info()
        .get("timestamp")
        .and_then(|s| i64::from_str(s).ok())
        .map(|ts| NaiveDateTime::from_timestamp(ts, 0));
    let datetime = match datetime {
        Some(dt) => dt,
        None => return Box::new(future::result(Err(ServiceError::InvalidSetting {
            key: "timestamp".into(),
            hint: "local time in seconds since Unix Epoch".into()
        }.into())))
    };
    let db = req.state().db.clone();
    let settings = req.state().db
        .send(db::GetSettings(token.clone()))
        .map_err(failure::Error::from)
        // flatten error
        .and_then(|res| match res {
            Ok(settings) => Ok(settings),
            Err(err) => Err(err)
        });
    let fitbit = req.state().db
        .send(db::GetSettingsFitbit(token))
        .map_err(failure::Error::from)
        // Check if there is token and flatten error
        .and_then(|res| match res {
            Ok(fitbit) => {
                if fitbit.client_token.is_none() {
                    Err(ServiceError::TokenExpired.into())
                } else {
                    Ok(fitbit)
                }
            },
            Err(err) => Err(err)
        });
    let headmaster = req.state().headmaster.clone();
    let summary_and_token = settings.join(fitbit)
        .and_then(move |(settings, fitbit)| -> Box<dyn Future<Item = (Summary, FitbitToken), Error = failure::Error>> {
            // Deserialize token
            let token = fitbit.client_token.expect("ISE: token option is not cleared");
            let fitbit_token = match FitbitToken::from_json(&token) {
                Ok(token) => token,
                Err(err) => return Box::new(future::err(ServiceError::TokenExpired.into()))
            };
            let headmaster_config = master::HeadmasterConfig {
                minimum_active_time: settings.hourly_activity_goal,
                max_accounted_active_minutes: settings.hourly_activity_limit.unwrap_or(settings.hourly_activity_goal * 3),
                debt_limit: settings.hourly_debt_limit.unwrap_or(settings.hourly_activity_goal * 3),
                day_begins_at: settings.day_starts_at,
                day_ends_at: settings.day_ends_at,
                day_length: settings.day_length.unwrap_or((settings.day_ends_at.hour() - settings.day_starts_at.hour()) as i32),
                user_date_time: datetime,
            };
            let auth_data = FitbitAuthData {
                id: fitbit.client_id,
                secret: fitbit.client_secret,
                token: fitbit_token,
            };
            let future = headmaster.send(master::GetSummary::<FitbitActivityGrabber>::new(headmaster_config, auth_data))
                .map_err(failure::Error::from)
                // flatten error
                .and_then(|res| res);
            Box::new(future)
        });
    let summary = summary_and_token
        .and_then(move |(summary, fitbit_token)| {
            db.send(db::UpdateSettingsFitbit::new(
                token, db::models::UpdateFitbitCredentials {
                    client_token: Some(Some(fitbit_token.to_json())),
                    ..Default::default()
                }))
                .map_err(failure::Error::from)
                .and_then(|_| Ok(summary))
        });
    Box::new(summary)
}