tatuin-providers 0.6.1

Providers lib of the Tatuin project
Documentation
// SPDX-License-Identifier: MIT

mod client;
mod priority;
mod task;
use std::error::Error;

use async_trait::async_trait;

use client::Client;
pub use client::parse_calendar;
pub use task::{Task, TaskType, property_to_str};
use tatuin_core::{
    StringError, filter,
    project::Project as ProjectTrait,
    provider::{Capabilities, ProjectProviderTrait, ProviderTrait, TaskProviderTrait},
    task::Task as TaskTrait,
    task_patch::{PatchError, TaskPatch},
};

use crate::config::Config;

pub const PROVIDER_NAME: &str = "iCal";

pub struct Provider {
    cfg: Config,

    c: Client,
    tasks: Vec<Task>,
}

impl Provider {
    pub fn new(cfg: Config, url: &str) -> Result<Self, Box<dyn Error>> {
        let mut c = Client::new(url);
        c.set_cache_folder(&cfg.cache_path()?);
        Ok(Self {
            cfg,
            c,
            tasks: Vec::new(),
        })
    }
}

impl std::fmt::Debug for Provider {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Provider name={}", ProviderTrait::name(self))
    }
}

#[async_trait]
impl ProjectProviderTrait for Provider {
    async fn list(&mut self) -> Result<Vec<Box<dyn ProjectTrait>>, StringError> {
        Err(StringError::new("not implemented"))
    }
}

#[async_trait]
impl TaskProviderTrait for Provider {
    #[tracing::instrument(level = "info", target = "ical_tasks")]
    async fn list(
        &mut self,
        _project: Option<Box<dyn ProjectTrait>>,
        f: &filter::Filter,
    ) -> Result<Vec<Box<dyn TaskTrait>>, StringError> {
        if self.tasks.is_empty() {
            self.c.download_calendar().await?;
            self.tasks = self
                .c
                .parse_calendar()
                .await?
                .iter()
                .filter(|t| f.accept(*t))
                .map(|t| {
                    let mut task = t.clone();
                    task.set_provider(self.cfg.name().as_str());
                    task
                })
                .collect();
        }

        return Ok(self.tasks.iter().map(|t| t.clone_boxed()).collect());
    }

    async fn create(&mut self, _project_id: &str, _tp: &TaskPatch) -> Result<(), StringError> {
        panic!("Not implemented")
    }

    async fn update(&mut self, _patches: &[TaskPatch]) -> Vec<PatchError> {
        panic!("Not implemented")
    }
}

#[async_trait]
impl ProviderTrait for Provider {
    fn name(&self) -> String {
        self.cfg.name()
    }

    fn type_name(&self) -> String {
        PROVIDER_NAME.to_string()
    }

    async fn reload(&mut self) {
        self.tasks.clear();
    }

    fn capabilities(&self) -> Capabilities {
        Capabilities { create_task: false }
    }
}