spotify_cli/cli/commands/
pin.rs

1use super::init_pin_store;
2use crate::io::output::{ErrorKind, Response};
3use crate::storage::pins::{Pin, ResourceType};
4
5pub async fn pin_add(
6    resource_type: &str,
7    url_or_id: &str,
8    alias: &str,
9    tags: Option<&str>,
10) -> Response {
11    let rtype: ResourceType = match resource_type.parse() {
12        Ok(t) => t,
13        Err(e) => return Response::err(400, &e, ErrorKind::Validation),
14    };
15
16    let id = Pin::extract_id(url_or_id);
17    let tag_list: Vec<String> = tags
18        .map(|t| t.split(',').map(|s| s.trim().to_string()).collect())
19        .unwrap_or_default();
20
21    let pin = Pin::new(rtype, id.clone(), alias.to_string(), tag_list.clone());
22
23    let mut store = match init_pin_store() {
24        Ok(s) => s,
25        Err(e) => return e,
26    };
27
28    match store.add(pin) {
29        Ok(_) => Response::success_with_payload(
30            201,
31            "Pin added",
32            serde_json::json!({
33                "type": resource_type,
34                "id": id,
35                "alias": alias,
36                "tags": tag_list,
37                "uri": format!("spotify:{}:{}", resource_type, id)
38            }),
39        ),
40        Err(e) => {
41            Response::err_with_details(400, "Failed to add pin", ErrorKind::Storage, e.to_string())
42        }
43    }
44}
45
46pub async fn pin_remove(alias_or_id: &str) -> Response {
47    let mut store = match init_pin_store() {
48        Ok(s) => s,
49        Err(e) => return e,
50    };
51
52    match store.remove(alias_or_id) {
53        Ok(removed) => Response::success_with_payload(
54            200,
55            "Pin removed",
56            serde_json::json!({
57                "type": removed.resource_type.as_str(),
58                "id": removed.id,
59                "alias": removed.alias
60            }),
61        ),
62        Err(e) => Response::err_with_details(
63            404,
64            "Failed to remove pin",
65            ErrorKind::NotFound,
66            e.to_string(),
67        ),
68    }
69}
70
71pub async fn pin_list(filter_type: Option<&str>) -> Response {
72    let store = match init_pin_store() {
73        Ok(s) => s,
74        Err(e) => return e,
75    };
76
77    let rtype: Option<ResourceType> = match filter_type {
78        Some(t) => match t.parse() {
79            Ok(rt) => Some(rt),
80            Err(e) => return Response::err(400, &e, ErrorKind::Validation),
81        },
82        None => None,
83    };
84
85    let pins: Vec<serde_json::Value> = store
86        .list(rtype)
87        .iter()
88        .map(|p| {
89            serde_json::json!({
90                "type": p.resource_type.as_str(),
91                "id": p.id,
92                "alias": p.alias,
93                "tags": p.tags,
94                "uri": p.uri()
95            })
96        })
97        .collect();
98
99    Response::success_with_payload(
100        200,
101        format!("{} pin(s)", pins.len()),
102        serde_json::json!({ "pins": pins }),
103    )
104}