use crate::limits::VALIDATION_LIMITS;
use crate::traits::{HasIdPath, HasPath, HashId, TimestampId, Validatable};
use crate::*;
use serde_wasm_bindgen::{from_value, to_value};
use std::str::FromStr;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct Meta {
id: String,
path: String,
url: String,
}
#[wasm_bindgen]
impl Meta {
#[wasm_bindgen(getter)]
pub fn id(&self) -> String {
self.id.clone()
}
#[wasm_bindgen(getter)]
pub fn path(&self) -> String {
self.path.clone()
}
#[wasm_bindgen(getter)]
pub fn url(&self) -> String {
self.url.clone()
}
}
impl Meta {
pub fn from_object(object_id: Option<&str>, pubky_id: PubkyId, path: String) -> Self {
let id = match object_id {
Some(id) => id.to_string(),
None => "".to_string(),
};
Self {
id,
url: format!("{}{}{}", PROTOCOL, pubky_id, path),
path,
}
}
}
#[wasm_bindgen]
pub struct PubkySpecsBuilder {
#[wasm_bindgen(skip)]
pubky_id: PubkyId,
}
macro_rules! result_struct {
($struct_name:ident, $field_name:ident, $field_type:ty) => {
#[wasm_bindgen]
pub struct $struct_name {
$field_name: $field_type,
meta: Meta,
}
#[wasm_bindgen]
impl $struct_name {
#[wasm_bindgen(getter)]
pub fn $field_name(&self) -> $field_type {
self.$field_name.clone()
}
#[wasm_bindgen(getter)]
pub fn meta(&self) -> Meta {
self.meta.clone()
}
}
};
}
result_struct!(UserResult, user, PubkyAppUser);
result_struct!(FileResult, file, PubkyAppFile);
result_struct!(FollowResult, follow, PubkyAppFollow);
result_struct!(PostResult, post, PubkyAppPost);
result_struct!(FeedResult, feed, PubkyAppFeed);
result_struct!(TagResult, tag, PubkyAppTag);
result_struct!(BookmarkResult, bookmark, PubkyAppBookmark);
result_struct!(MuteResult, mute, PubkyAppMute);
result_struct!(LastReadResult, last_read, PubkyAppLastRead);
result_struct!(BlobResult, blob, PubkyAppBlob);
#[wasm_bindgen]
impl PubkySpecsBuilder {
#[wasm_bindgen(constructor)]
pub fn new(pubky_id: String) -> Result<Self, String> {
let pubky_id = PubkyId::try_from(&pubky_id)?;
Ok(Self { pubky_id })
}
#[wasm_bindgen(getter, js_name = validationLimits)]
pub fn validation_limits(&self) -> Result<JsValue, String> {
to_value(&VALIDATION_LIMITS).map_err(|e| e.to_string())
}
#[wasm_bindgen(js_name = createUser)]
pub fn create_user(
&self,
name: String,
bio: Option<String>,
image: Option<String>,
links: JsValue, status: Option<String>,
) -> Result<UserResult, String> {
let links_vec: Option<Vec<PubkyAppUserLink>> = if links.is_null() || links.is_undefined() {
None
} else {
from_value(links).map_err(|e| e.to_string())?
};
let user = PubkyAppUser::new(name, bio, image, links_vec, status);
user.validate(None)?;
let path = PubkyAppUser::create_path();
let meta = Meta::from_object(None, self.pubky_id.clone(), path);
Ok(UserResult { user, meta })
}
#[wasm_bindgen(js_name = createFeed)]
pub fn create_feed(
&self,
tags: JsValue,
reach: String,
layout: String,
sort: String,
content: Option<String>,
name: String,
) -> Result<FeedResult, String> {
let tags_vec: Option<Vec<String>> = if tags.is_null() || tags.is_undefined() {
None
} else {
from_value(tags).map_err(|e| e.to_string())?
};
let reach = PubkyAppFeedReach::from_str(&reach)?;
let layout = PubkyAppFeedLayout::from_str(&layout)?;
let sort = PubkyAppFeedSort::from_str(&sort)?;
let content = match content {
Some(val) => Some(PubkyAppPostKind::from_str(&val)?),
None => None,
};
let feed = PubkyAppFeed::new(tags_vec, reach, layout, sort, content, name);
let feed_id = feed.create_id();
feed.validate(Some(&feed_id))?;
let path = PubkyAppFeed::create_path(&feed_id);
let meta = Meta::from_object(Some(&feed_id), self.pubky_id.clone(), path);
Ok(FeedResult { feed, meta })
}
#[wasm_bindgen(js_name = createFile)]
pub fn create_file(
&self,
name: String,
src: String,
content_type: String,
size: usize,
) -> Result<FileResult, String> {
let file = PubkyAppFile::new(name, src, content_type, size);
let file_id = file.create_id();
file.validate(Some(&file_id))?;
let path = PubkyAppFile::create_path(&file_id);
let meta = Meta::from_object(Some(&file_id), self.pubky_id.clone(), path);
Ok(FileResult { file, meta })
}
#[wasm_bindgen(js_name = createPost)]
pub fn create_post(
&self,
content: String,
kind: PubkyAppPostKind,
parent: Option<String>,
embed: Option<PubkyAppPostEmbed>,
attachments: Option<Vec<String>>,
) -> Result<PostResult, String> {
let post = PubkyAppPost::new(content, kind, parent, embed, attachments);
let post_id = post.create_id();
post.validate(Some(&post_id))?;
let path = PubkyAppPost::create_path(&post_id);
let meta = Meta::from_object(Some(&post_id), self.pubky_id.clone(), path);
Ok(PostResult { post, meta })
}
#[wasm_bindgen(js_name = editPost)]
pub fn edit_post(
&self,
original_post: PubkyAppPost,
post_id: String,
new_content: String,
) -> Result<PostResult, String> {
let mut post = original_post;
post.content = new_content;
post = post.sanitize();
post.validate(Some(&post_id))?;
let path = PubkyAppPost::create_path(&post_id);
let meta = Meta::from_object(Some(&post_id), self.pubky_id.clone(), path);
Ok(PostResult { post, meta })
}
#[wasm_bindgen(js_name = createTag)]
pub fn create_tag(&self, uri: String, label: String) -> Result<TagResult, String> {
let tag = PubkyAppTag::new(uri, label);
let tag_id = tag.create_id();
tag.validate(Some(&tag_id))?;
let path = PubkyAppTag::create_path(&tag_id);
let meta = Meta::from_object(Some(&tag_id), self.pubky_id.clone(), path);
Ok(TagResult { tag, meta })
}
#[wasm_bindgen(js_name = createBookmark)]
pub fn create_bookmark(&self, uri: String) -> Result<BookmarkResult, String> {
let bookmark = PubkyAppBookmark::new(uri);
let bookmark_id = bookmark.create_id();
bookmark.validate(Some(&bookmark_id))?;
let path = PubkyAppBookmark::create_path(&bookmark_id);
let meta = Meta::from_object(Some(&bookmark_id), self.pubky_id.clone(), path);
Ok(BookmarkResult { bookmark, meta })
}
#[wasm_bindgen(js_name = createFollow)]
pub fn create_follow(&self, followee_id: String) -> Result<FollowResult, String> {
let follow = PubkyAppFollow::new();
follow.validate(Some(&followee_id))?;
let path = PubkyAppFollow::create_path(&followee_id);
let meta = Meta::from_object(Some(&followee_id), self.pubky_id.clone(), path);
Ok(FollowResult { follow, meta })
}
#[wasm_bindgen(js_name = createMute)]
pub fn create_mute(&self, mutee_id: String) -> Result<MuteResult, String> {
let mute = PubkyAppMute::new();
mute.validate(Some(&mutee_id))?;
let path = PubkyAppMute::create_path(&mutee_id);
let meta = Meta::from_object(Some(&mutee_id), self.pubky_id.clone(), path);
Ok(MuteResult { mute, meta })
}
#[wasm_bindgen(js_name = createLastRead)]
pub fn create_last_read(&self) -> Result<LastReadResult, String> {
let last_read = PubkyAppLastRead::new();
last_read.validate(None)?;
let path = PubkyAppLastRead::create_path();
let meta = Meta::from_object(None, self.pubky_id.clone(), path);
Ok(LastReadResult { last_read, meta })
}
#[wasm_bindgen(js_name = createBlob)]
pub fn create_blob(&self, blob_data: JsValue) -> Result<BlobResult, String> {
let data_vec: Vec<u8> = from_value(blob_data).map_err(|e| e.to_string())?;
let blob = PubkyAppBlob(data_vec);
let id = blob.create_id();
blob.validate(Some(&id))?;
let path = PubkyAppBlob::create_path(&id);
let meta = Meta::from_object(Some(&id), self.pubky_id.clone(), path);
Ok(BlobResult { blob, meta })
}
}
#[wasm_bindgen]
pub struct ParsedUriResult {
#[wasm_bindgen(skip)]
user_id: String,
#[wasm_bindgen(skip)]
resource: String,
#[wasm_bindgen(skip)]
resource_id: Option<String>,
}
#[wasm_bindgen]
impl ParsedUriResult {
#[wasm_bindgen(getter)]
pub fn user_id(&self) -> String {
self.user_id.clone()
}
#[wasm_bindgen(getter)]
pub fn resource(&self) -> String {
self.resource.clone()
}
#[wasm_bindgen(getter)]
pub fn resource_id(&self) -> Option<String> {
self.resource_id.clone()
}
}
#[wasm_bindgen(js_name = getValidMimeTypes)]
pub fn get_valid_mime_types() -> Vec<JsValue> {
VALID_MIME_TYPES
.iter()
.map(|s| JsValue::from_str(s))
.collect()
}
#[wasm_bindgen]
pub fn parse_uri(uri: &str) -> Result<ParsedUriResult, String> {
let parsed = ParsedUri::try_from(uri)?;
Ok(ParsedUriResult {
user_id: parsed.user_id.to_string(),
resource: parsed.resource.to_string(),
resource_id: parsed.resource.id(),
})
}