// Interface for Standard Notes (Actions) use crate::router::Router; use crate::utils::{self, Error, MyResult}; use serde::{Serialize, Serializer}; use std::vec::Vec; use web_sys::*; pub fn build_routes(router: &mut Router) { router.add_route("/actions", &get_actions); } macro_rules! verify_secret { ($url:expr, $params:ident, $config:ident) => { let $config = utils::get_config(); let $params = UrlSearchParams::new_with_str(&$url.search()) .map_err(|_| Error::BadRequest("Failed to parse query string".into()))?; if !$params.has("secret") { return Err(Error::BadRequest("Secret needed".into())); } else if $params.get("secret").unwrap() != $config.secret { return Err(Error::Unauthorized("Secret mismatch".into())); } }; } async fn get_actions(_req: Request, url: Url) -> MyResult { verify_secret!(url, params, config); let origin = url.origin(); let mut actions = vec![]; actions.push(Action { label: "Publish".into(), url: format!("{}/post?secret={}", origin, config.secret.clone()), verb: Verb::Post, context: Context::Item, content_types: vec![ContentType::Note], access_type: Some(AccessType::Decrypted) }); let info = ActionsExtension { identifier: config.plugin_identifier.clone(), name: config.title.clone(), description: format!("Standard Notes plugin for {}", config.title.clone()), url: format!("{}/actions?secret={}", origin, config.secret.clone()), content_type: ContentType::Extension, supported_types: vec![ContentType::Note], actions }; Ok(Response::new_with_opt_str_and_init( Some(&serde_json::to_string(&info) .map_err(|_| Error::InternalError())?), ResponseInit::new() .status(200) .headers({ let headers = Headers::new().unwrap(); headers.set("Content-Type", "application/json").unwrap(); cors!(headers); headers }.as_ref()) ).unwrap()) } pub enum Verb { Show, Post, Render } impl Serialize for Verb { fn serialize(&self, serializer: S) -> Result where S: Serializer { serializer.serialize_str(match *self { Verb::Show => "show", Verb::Post => "post", Verb::Render => "render" }) } } pub enum Context { Item } impl Serialize for Context { fn serialize(&self, serializer: S) -> Result where S: Serializer { serializer.serialize_str(match *self { Context::Item => "Item" }) } } pub enum ContentType { Note, Extension } impl Serialize for ContentType { fn serialize(&self, serializer: S) -> Result where S: Serializer { serializer.serialize_str(match *self { ContentType::Note => "Note", ContentType::Extension => "Extension" }) } } pub enum AccessType { Decrypted, Encrypted } impl Serialize for AccessType { fn serialize(&self, serializer: S) -> Result where S: Serializer { serializer.serialize_str(match *self { AccessType::Decrypted => "decrypted", AccessType::Encrypted => "encrypted" }) } } #[derive(Serialize)] pub struct Action { label: String, url: String, verb: Verb, context: Context, content_types: Vec, access_type: Option } #[derive(Serialize)] pub struct ActionsExtension { identifier: String, name: String, description: String, url: String, content_type: ContentType, supported_types: Vec, actions: Vec }