Skip to content

Commit

Permalink
#288 #489 Register Endpoint and true URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
joepio committed Mar 30, 2023
1 parent 165c054 commit 6e2fadf
Show file tree
Hide file tree
Showing 19 changed files with 210 additions and 89 deletions.
29 changes: 14 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ bincode = {version = "1", optional = true}
directories = {version = ">= 2, < 5", optional = true}
html2md = {version = "0.2.13", optional = true}
kuchiki = {version = "0.8.1", optional = true}
lazy_static = "1"
lol_html = {version = "0.3.1", optional = true}
rand = {version = "0.8"}
regex = "1"
Expand Down
2 changes: 1 addition & 1 deletion lib/src/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ pub fn create_collection_resource_for_class(

// Let the Collections collection be the top level item
let parent = if class.subject == urls::COLLECTION {
drive
drive.to_string()
} else {
format!("{}/collections", drive)
};
Expand Down
2 changes: 1 addition & 1 deletion lib/src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl Commit {
let default_parent = store.get_self_url().ok_or("There is no self_url set, and no parent in the Commit. The commit can not be applied.")?;
resource_old.set_propval(
urls::PARENT.into(),
Value::AtomicUrl(default_parent),
Value::AtomicUrl(default_parent.to_string()),
store,
)?;
}
Expand Down
23 changes: 13 additions & 10 deletions lib/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use std::{
sync::{Arc, Mutex},
};

use tracing::{info, instrument};
use tracing::instrument;
use url::Url;

use crate::{
agents::ForAgent,
Expand Down Expand Up @@ -76,7 +77,7 @@ pub struct Db {
/// A list of all the Collections currently being used. Is used to update `query_index`.
watched_queries: sled::Tree,
/// The address where the db will be hosted, e.g. http://localhost/
server_url: String,
server_url: Url,
/// Endpoints are checked whenever a resource is requested. They calculate (some properties of) the resource and return it.
endpoints: Vec<Endpoint>,
/// Function called whenever a Commit is applied.
Expand Down Expand Up @@ -193,14 +194,15 @@ impl Db {
}

fn map_sled_item_to_resource(
&self,
item: Result<(sled::IVec, sled::IVec), sled::Error>,
self_url: String,
include_external: bool,
) -> Option<Resource> {
let (subject, resource_bin) = item.expect(DB_CORRUPT_MSG);
let subject: String = String::from_utf8_lossy(&subject).to_string();

if !include_external && !subject.starts_with(&self_url) {
if !include_external && self.is_external_subject(&subject).ok()? {
return None;
}

Expand Down Expand Up @@ -308,14 +310,14 @@ impl Storelike for Db {
Ok(())
}

fn get_server_url(&self) -> &str {
fn get_server_url(&self) -> &Url {
&self.server_url
}

// Since the DB is often also the server, this should make sense.
// Some edge cases might appear later on (e.g. a slave DB that only stores copies?)
fn get_self_url(&self) -> Option<String> {
Some(self.get_server_url().into())
fn get_self_url(&self) -> Option<&Url> {
// Since the DB is often also the server, this should make sense.
// Some edge cases might appear later on (e.g. a slave DB that only stores copies?)
Some(self.get_server_url())
}

fn get_default_agent(&self) -> AtomicResult<crate::agents::Agent> {
Expand Down Expand Up @@ -479,7 +481,7 @@ impl Storelike for Db {
// Maybe make this optional?
q_filter.watch(self)?;

info!(filter = ?q_filter, "Building query index");
tracing::info!(filter = ?q_filter, "Building query index");

let atoms: IndexIterator = match (&q.property, q.value.as_ref()) {
(Some(prop), val) => find_in_prop_val_sub_index(self, prop, val),
Expand Down Expand Up @@ -523,7 +525,7 @@ impl Storelike for Db {
.expect("No self URL set, is required in DB");

let result = self.resources.into_iter().filter_map(move |item| {
Db::map_sled_item_to_resource(item, self_url.clone(), include_external)
Db::map_sled_item_to_resource(self, item, self_url.to_string(), include_external)
});

Box::new(result)
Expand Down Expand Up @@ -577,6 +579,7 @@ impl Storelike for Db {

fn populate(&self) -> AtomicResult<()> {
crate::populate::populate_all(self)
crate::populate::create_drive(self, None, &default_agent.subject, true)
}

#[instrument(skip(self))]
Expand Down
6 changes: 1 addition & 5 deletions lib/src/db/query_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ pub fn query_indexed(store: &Db, q: &Query) -> AtomicResult<QueryResult> {
let mut resources = Vec::new();
let mut count = 0;

let self_url = store
.get_self_url()
.ok_or("No self_url set, required for Queries")?;

let limit = if let Some(limit) = q.limit {
limit
} else {
Expand All @@ -119,7 +115,7 @@ pub fn query_indexed(store: &Db, q: &Query) -> AtomicResult<QueryResult> {
let (k, _v) = kv.map_err(|_e| "Unable to parse query_cached")?;
let (_q_filter, _val, subject) = parse_collection_members_key(&k)?;
// If no external resources should be included, skip this one if it's an external resource
if !q.include_external && !subject.starts_with(&self_url) {
if !q.include_external && store.is_external_subject(subject)? {
continue;
}

Expand Down
1 change: 1 addition & 0 deletions lib/src/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub fn default_endpoints() -> Vec<Endpoint> {
plugins::path::path_endpoint(),
plugins::search::search_endpoint(),
plugins::files::upload_endpoint(),
plugins::register::register_endpoint(),
#[cfg(feature = "html")]
plugins::bookmark::bookmark_endpoint(),
plugins::importer::import_endpoint(),
Expand Down
1 change: 1 addition & 0 deletions lib/src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ pub mod invite;
pub mod bookmark;
pub mod files;
pub mod path;
pub mod register;
pub mod search;
pub mod versioning;
72 changes: 72 additions & 0 deletions lib/src/plugins/register.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//! Creates a new Drive and optionally also an Agent.

use crate::{agents::Agent, endpoints::Endpoint, errors::AtomicResult, urls, Resource, Storelike};

pub fn register_endpoint() -> Endpoint {
Endpoint {
path: "/register".to_string(),
params: [
urls::INVITE_PUBKEY.to_string(),
urls::NAME.to_string(),
].into(),
description: "Allows new users to easily, in one request, make both an Agent and a Drive. This drive will be created at the subdomain of `name`.".to_string(),
shortname: "register".to_string(),
handle: Some(construct_register_redirect),
}
}

#[tracing::instrument(skip(store))]
pub fn construct_register_redirect(
url: url::Url,
store: &impl Storelike,
for_agent: Option<&str>,
) -> AtomicResult<Resource> {
let requested_subject = url.to_string();
let mut pub_key = None;
let mut name_option = None;
for (k, v) in url.query_pairs() {
match k.as_ref() {
"public-key" | urls::INVITE_PUBKEY => pub_key = Some(v.to_string()),
"name" | urls::NAME => name_option = Some(v.to_string()),
_ => {}
}
}
if pub_key.is_none() && name_option.is_none() {
return register_endpoint().to_resource(store);
}

let name = if let Some(n) = name_option {
n
} else {
return Err("No name provided".into());
};

let mut new_agent = None;

let drive_creator_agent: String = if let Some(key) = pub_key {
let new = Agent::new_from_public_key(store, &key)?.subject;
new_agent = Some(new.clone());
new
} else if let Some(agent) = for_agent {
agent.to_string()
} else {
return Err("No `public-key` provided".into());
};

// Create the new Drive
let drive = crate::populate::create_drive(store, Some(&name), &drive_creator_agent, false)?;

// Construct the Redirect Resource, which might provide the Client with a Subject for his Agent.
let mut redirect = Resource::new_instance(urls::REDIRECT, store)?;
redirect.set_propval_string(urls::DESTINATION.into(), drive.get_subject(), store)?;
if let Some(agent) = new_agent {
redirect.set_propval(
urls::REDIRECT_AGENT.into(),
crate::Value::AtomicUrl(agent),
store,
)?;
}
// The front-end requires the @id to be the same as requested
redirect.set_subject(requested_subject);
Ok(redirect)
}
Loading

0 comments on commit 6e2fadf

Please sign in to comment.