news-flash 3.0.1

Base library for a modern feed reader
Documentation
use super::config::AccountConfig;
use super::feedly_secrets::FeedlySecrets;
use super::{Feedly, FeedlyApi};
use crate::feed_api::{ApiMetadata, FeedApi, FeedApiError, FeedApiResult, Portal};
use crate::models::{
    ApiSecret, LoginGUI, OAuthLoginGUI, PluginID, PluginIcon, PluginInfo, ServiceLicense, ServicePrice, ServiceType, Url, VectorIcon,
};
use rust_embed::RustEmbed;
use std::path::Path;
use std::str;
use std::sync::Arc;
use tokio::sync::RwLock;

#[derive(RustEmbed)]
#[folder = "src/feed_api_implementations/feedly/icons"]
struct FeedlyResources;

pub struct FeedlyMetadata;

impl FeedlyMetadata {
    pub fn get_id() -> PluginID {
        PluginID::new("feedly")
    }
}

impl ApiMetadata for FeedlyMetadata {
    fn id(&self) -> PluginID {
        Self::get_id()
    }

    fn info(&self) -> FeedApiResult<PluginInfo> {
        let icon_data = FeedlyResources::get("feed-service-feedly.svg").ok_or(FeedApiError::Resource)?;
        let icon = VectorIcon {
            data: icon_data.data.to_vec(),
            width: 48,
            height: 48,
        };
        let icon = PluginIcon::Vector(icon);

        let symbolic_icon_data = FeedlyResources::get("feed-service-feedly-symbolic.svg").ok_or(FeedApiError::Resource)?;
        let symbolic_icon = VectorIcon {
            data: symbolic_icon_data.data.to_vec(),
            width: 48,
            height: 48,
        };
        let symbolic_icon = PluginIcon::Vector(symbolic_icon);

        let secrets = FeedlySecrets::new();
        let login_url = Url::new(FeedlyApi::login_url(&secrets.id(), &secrets.secret())?);
        let login_fn = move |_: Option<&ApiSecret>| Some(login_url.clone());
        let redirect_url = FeedlyApi::redirect_uri()?;

        let login_gui = LoginGUI::OAuth(Box::new(OAuthLoginGUI {
            login_website: Box::new(login_fn),
            catch_redirect: Some(String::from(redirect_url.as_str())),
            custom_api_secret: true,
            custom_api_secret_url: None,
            embeded_api_secret: false,
            create_secret_url: None,
        }));

        Ok(PluginInfo {
            id: self.id(),
            name: String::from("feedly"),
            icon: Some(icon),
            icon_symbolic: Some(symbolic_icon),
            website: Url::parse("http://feedly.com/").ok(),
            service_type: ServiceType::Remote { self_hosted: false },
            license_type: ServiceLicense::GenericProprietary,
            service_price: ServicePrice::PaidPremimum,
            login_gui,
        })
    }

    fn get_instance(&self, config_dir: &Path, portal: Box<dyn Portal>, _user_api_secret: Option<ApiSecret>) -> FeedApiResult<Box<dyn FeedApi>> {
        let account_config = AccountConfig::load(config_dir)?;
        let secret_struct = FeedlySecrets::new();

        let mut api: Option<FeedlyApi> = None;
        let mut logged_in: bool = false;
        if let Some(access_token) = account_config.get_access_token()
            && let Some(refresh_token) = account_config.get_refresh_token()
            && let Some(token_expires) = account_config.get_token_expires()
        {
            let token_expires = FeedlyApi::parse_expiration_date(&token_expires)?;
            api = Some(FeedlyApi::new(
                secret_struct.id(),
                secret_struct.secret(),
                access_token,
                refresh_token,
                token_expires,
            )?);

            // FIXME: find more accurate way of figuring out if login is still valid
            logged_in = true;
        }

        let feedly = Feedly {
            api,
            portal: Arc::new(portal),
            logged_in,
            config: Arc::new(RwLock::new(account_config)),
        };
        let feedly = Box::new(feedly);

        Ok(feedly)
    }
}