devto-cli 0.3.1

A CLI tool to manage dev.to articles
use http::StatusCode;

use anyhow::{bail, Result};
use convert_case::{Case, Casing};
use isahc::{prelude::*, Request};
use serde::Deserialize;
use serde_json::json;

pub(crate) fn create_draft(title: &String, devto_token: String) -> Result<u32> {
    let data = json!({
        "article": {
            "title": title.to_case(Case::Title),
            "body_markdown": "",
            "published": false,
            "tags": []
        }
    })
    .to_string();

    let mut response = Request::post("https://dev.to/api/articles")
        .header("Content-Type", "application/json")
        .header("api-key", devto_token)
        .body(data.as_str())?
        .send()?;

    if response.status() != StatusCode::CREATED {
        bail!("Could not create an article: {}", response.text()?);
    }

    #[derive(Deserialize)]
    struct Response {
        id: u32,
    }
    Ok(response.json::<Response>()?.id)
}

#[derive(Deserialize, Debug, Clone)]
pub(crate) struct DevToUser {
    pub(crate) username: String,
}

#[derive(Deserialize, Debug, Clone)]
pub(crate) struct Article {
    id: u32,
    pub(crate) slug: String,
    pub(crate) user: DevToUser,
}

pub(crate) fn get_matched_article(article_id: u32, devto_token: String) -> Result<Article> {
    let mut response = Request::get("https://dev.to/api/articles/me/unpublished")
        .header("api-key", devto_token)
        .body(())?
        .send()?;

    if response.status() != StatusCode::OK {
        bail!("Could not retrieve article info: {}", response.text()?);
    }

    let articles = response.json::<Vec<Article>>()?;
    let matched = articles.iter().find(|&x| x.id == article_id);
    if matched.is_none() {
        bail!("Could not find the article with id: {article_id}");
    }

    Ok(matched.unwrap().clone())
}

pub(crate) fn update_article(id: u32, content: String, devto_token: String) -> Result<Article> {
    let data = json!({
        "article": {
            "body_markdown": content,
        }
    })
    .to_string();

    let mut response = Request::put(format!("https://dev.to/api/articles/{id}"))
        .header("Content-Type", "application/json")
        .header("api-key", devto_token)
        .body(data.as_str())?
        .send()?;

    if response.status() != StatusCode::OK {
        bail!("Could not update article info: {}", response.text()?);
    }

    Ok(response.json::<Article>()?)
}