use crate::{
agents::ForAgent,
endpoints::{Endpoint, HandleGetContext, HandlePostContext},
errors::AtomicResult,
urls, Resource, Storelike,
};
pub fn import_endpoint() -> Endpoint {
Endpoint {
path: "/import".to_string(),
params: [
urls::IMPORTER_OVERWRITE_OUTSIDE.to_string(),
urls::IMPORTER_PARENT.to_string(),
urls::IMPORTER_URL.to_string(),
].into(),
description: "Imports one or more Resources to some parent. POST your JSON-AD and add a `parent` query param to the URL. See https://docs.atomicdata.dev/create-json-ad.html".to_string(),
shortname: "path".to_string(),
handle: Some(handle_get),
handle_post: Some(handle_post),
}
}
pub fn handle_get(context: HandleGetContext) -> AtomicResult<Resource> {
import_endpoint().to_resource(context.store)
}
#[tracing::instrument]
pub fn handle_post(context: HandlePostContext) -> AtomicResult<Resource> {
let HandlePostContext {
store,
body,
for_agent,
subject,
} = context;
let mut url = None;
let mut json = None;
let mut parent_maybe = None;
let mut overwrite_outside = false;
for (k, v) in subject.query_pairs() {
match k.as_ref() {
"json" | urls::IMPORTER_URL => return Err("JSON must be POSTed in the body".into()),
"url" | urls::IMPORTER_JSON => url = Some(v.to_string()),
"parent" | urls::IMPORTER_PARENT => parent_maybe = Some(v.to_string()),
"overwrite-outside" | urls::IMPORTER_OVERWRITE_OUTSIDE => {
overwrite_outside = v == "true"
}
_ => {}
}
}
let parent = parent_maybe.ok_or("No parent specified for importer")?;
if !body.is_empty() {
json =
Some(String::from_utf8(body).map_err(|e| {
format!("Error while decoding body, expected a JSON string: {}", e)
})?);
}
if let Some(fetch_url) = url {
json = Some(
crate::client::fetch_body(&fetch_url, crate::parse::JSON_AD_MIME, None)
.map_err(|e| format!("Error while fetching {}: {}", fetch_url, e))?,
);
}
let parse_opts = crate::parse::ParseOpts {
for_agent: for_agent.clone(),
importer: Some(parent),
overwrite_outside,
signer: Some(store.get_default_agent()?),
save: crate::parse::SaveOpts::Commit,
};
if let Some(json_string) = json {
if for_agent == &ForAgent::Public {
return Err("No agent specified for importer".to_string().into());
}
store.import(&json_string, &parse_opts)?;
} else {
return Err(
"No JSON specified for importer. Pass a `url` query param, or post a JSON-AD body."
.to_string()
.into(),
);
}
import_endpoint().to_resource(context.store)
}