// zotapi - Rust wrapper for Sot API as implemented by Hubzilla // Copyright (C) 2018 Harald Eilertsen // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . use crate::{ client::{self, Client}, error::Error, }; use serde::Serialize; use std::collections::BTreeMap; /// Data type for values that an Item can hold. #[derive(Debug, Serialize)] #[serde(untagged)] pub enum ItemData<'a> { /// A single value, either textual or numeric. Value(&'a str), /// A list ov values. List(Vec<&'a str>), } impl<'a> From<&'a str> for ItemData<'a> { fn from(orig: &'a str) -> ItemData<'a> { ItemData::Value(orig) } } impl<'a> ToString for ItemData<'a> { fn to_string(&self) -> String { match &self { ItemData::Value(s) => s.to_string(), ItemData::List(v) => v.join(","), } } } impl<'a> ItemData<'a> { /// Push a new value into pub fn push(&mut self, value: &'a str) { match self { ItemData::Value(_) => std::panic!("Pushing to a simple value is not allowed."), ItemData::List(v) => v.push(value), }; } } #[test] fn convert_itemdata_list_to_a_string() { let l = ItemData::List(vec!["one", "two", "everything"]); assert_eq!(l.to_string(), "one,two,everything"); } #[test] fn convert_itemdata_list_with_one_member_to_a_string() { let l = ItemData::List(vec!["one"]); assert_eq!(l.to_string(), "one"); } /// A structure to help you create an item in a declarative way. /// /// Typical usage: /// /// ```no_run /// let client = zotapi::Client::new("https://myhub.com", "mychannel", "mypw"); /// let new_post = client.item() /// .title("A title") /// .body("The body of the post") /// .file("/my/photo.jpg") /// .create()?; /// # Ok::<(), zotapi::Error>(()) /// ``` #[derive(Debug)] pub struct ItemBuilder<'a> { client: &'a Client, data: BTreeMap<&'a str, ItemData<'a>>, files: Vec<&'a str>, } impl<'a> ItemBuilder<'a> { pub fn new(client: &'a Client) -> ItemBuilder<'a> { ItemBuilder { client: client, data: BTreeMap::new(), files: vec![], } } /// Add a title to the post pub fn title(&mut self, text: &'a str) -> &mut ItemBuilder<'a> { self.data.insert("title", ItemData::Value(text)); self } /// Add the body of the post pub fn body(&mut self, text: &'a str) -> &mut ItemBuilder<'a> { self.data.insert("body", ItemData::Value(text)); self } /// Add a file attachment to the post pub fn file(&mut self, fname: &'a str) -> &mut ItemBuilder<'a> { self.files.push(fname); self } /// Set groups allowed to access item pub fn group_allow(&mut self, group: &'a str) -> &mut ItemBuilder<'a> { let groups_allow = self .data .entry("groups_allow") .or_insert(ItemData::List(Vec::<&str>::new())); groups_allow.push(group); self } /// Create the item by poting it to the server pub fn create(&self) -> Result { dbg!(self); if self.files.is_empty() { self.client .post_data(client::ZOTAPI_ITEM_UPDATE_PATH, &self.data) } else { self.client .post_multipart(client::ZOTAPI_ITEM_UPDATE_PATH, &self.data, &self.files) } } } #[test] fn add_group_to_list_of_groups_allowed() { let client = Client::new("https://test.com", "test", "test1234"); let mut item = ItemBuilder::new(&client); item.group_allow("test"); match item.data.get("groups_allow") { Some(ItemData::List(v)) => assert_eq!(v.len(), 1), Some(ItemData::Value(s)) => assert!(false, format!("Expected a list, found value: {}", s)), None => assert!(false, "List not found!"), }; }