guac 0.3.1

A library that provides toolkit for working with [Guac](https://guac.sh) from Rust.
Documentation
use chrono::Utc;
use graphql_client::reqwest::post_graphql;
use packageurl::PackageUrl;
use serde::{Deserialize, Serialize};

use crate::client::intrinsic::certify_bad::ingest::IngestCertifyBad;
use crate::client::intrinsic::certify_bad::query::QueryCertifyBad;
use crate::client::intrinsic::{
    IntrinsicGuacClient, MatchFlags, PackageSourceOrArtifact, PackageSourceOrArtifactInput, PackageSourceOrArtifactSpec,
};
use crate::client::{Error, Id};

mod ingest;
mod query;

type Time = chrono::DateTime<Utc>;

impl IntrinsicGuacClient {
    pub async fn ingest_certify_bad<MF: Into<MatchFlags>>(
        &self,
        subject: &PackageSourceOrArtifactInput,
        pkg_match_type: MF,
        certify_bad: &CertifyBadInputSpec,
    ) -> Result<Id, Error> {
        use self::ingest::ingest_certify_bad;

        let variables = ingest_certify_bad::Variables {
            subject: subject.into(),
            pkg_match_type: pkg_match_type.into().into(),
            certify_bad: certify_bad.into(),
        };

        let response_body = post_graphql::<IngestCertifyBad, _>(self.client(), self.url(), variables).await?;

        if let Some(errors) = response_body.errors {
            return Err(Error::GraphQL(errors));
        }

        let data = response_body.data.ok_or(Error::GraphQL(vec![]))?;

        Ok(data.ingest_certify_bad)
    }

    pub async fn certify_bad(&self, certify_bad_spec: &CertifyBadSpec) -> Result<Vec<CertifyBad>, Error> {
        use self::query::query_certify_bad;

        let variables = query_certify_bad::Variables {
            certify_bad_spec: certify_bad_spec.into(),
        };
        let response_body = post_graphql::<QueryCertifyBad, _>(self.client(), self.url(), variables).await?;

        if let Some(errors) = response_body.errors {
            return Err(Error::GraphQL(errors));
        }

        let data = response_body.data.ok_or(Error::GraphQL(vec![]))?;

        let mut certified = Vec::new();

        for entry in &data.certify_bad {
            certified.push(entry.into());
        }

        Ok(certified)
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CertifyBad {
    pub id: Id,
    pub subject: PackageSourceOrArtifact,
    pub justification: String,
    pub origin: String,
    pub collector: String,
    pub known_since: Option<Time>,
}

#[derive(Default, Debug, Clone)]
pub struct CertifyBadSpec {
    pub id: Option<Id>,
    pub subject: Option<PackageSourceOrArtifactSpec>,
    pub justification: Option<String>,
    pub origin: Option<String>,
    pub collector: Option<String>,
    pub known_since: Option<Time>,
}

impl From<&PackageUrl<'_>> for CertifyBadSpec {
    fn from(purl: &PackageUrl) -> Self {
        Self {
            subject: Some(PackageSourceOrArtifactSpec {
                package: Some(purl.clone().into()),
            }),
            ..Default::default()
        }
    }
}

#[derive(Debug, Clone)]
pub struct CertifyBadInputSpec {
    pub justification: String,
    pub origin: String,
    pub collector: String,
    pub known_since: Time,
}