From 646696a49ed8c07ffd2b10e489ad1e1f47196ae9 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 14 Nov 2024 03:50:59 +0100 Subject: [PATCH 01/53] `webfinger`: Create crate by cloning `inbox` --- Cargo.toml | 2 +- acrate-webfinger/Cargo.toml | 12 ++++++++++++ acrate-webfinger/src/config.rs | 3 +++ acrate-webfinger/src/main.rs | 31 +++++++++++++++++++++++++++++++ acrate-webfinger/src/route.rs | 8 ++++++++ 5 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 acrate-webfinger/Cargo.toml create mode 100644 acrate-webfinger/src/config.rs create mode 100644 acrate-webfinger/src/main.rs create mode 100644 acrate-webfinger/src/route.rs diff --git a/Cargo.toml b/Cargo.toml index aecded5..357abb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] resolver = "2" -members = ["acrate-core", "acrate-hostmeta", "acrate-inbox", "acrate-nodeinfo"] +members = ["acrate-core", "acrate-hostmeta", "acrate-inbox", "acrate-nodeinfo", "acrate-webfinger"] diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml new file mode 100644 index 0000000..4640b18 --- /dev/null +++ b/acrate-webfinger/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "acrate-webfinger" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.93" +axum = "0.7.7" +log = "0.4.22" +micronfig = "0.3.0" +pretty_env_logger = "0.5.0" +tokio = { version = "1.41.1", features = ["macros", "net", "rt-multi-thread"] } diff --git a/acrate-webfinger/src/config.rs b/acrate-webfinger/src/config.rs new file mode 100644 index 0000000..63babb0 --- /dev/null +++ b/acrate-webfinger/src/config.rs @@ -0,0 +1,3 @@ +micronfig::config!( + ACRATE_INBOX_BIND_ADDRESS: String, +); diff --git a/acrate-webfinger/src/main.rs b/acrate-webfinger/src/main.rs new file mode 100644 index 0000000..8958b4c --- /dev/null +++ b/acrate-webfinger/src/main.rs @@ -0,0 +1,31 @@ +use anyhow::Context; + +mod config; +mod route; + + +#[tokio::main] +async fn main() -> anyhow::Result { + pretty_env_logger::init(); + log::debug!("Logging initialized!"); + + log::trace!("Creating Axum router..."); + let app = axum::Router::new() + .route("/inbox", axum::routing::post(route::inbox_handler)); + log::trace!("Axum router created successfully!"); + + log::trace!("Creating Tokio listener..."); + let bind_address = config::ACRATE_INBOX_BIND_ADDRESS(); + let listener = tokio::net::TcpListener::bind(bind_address) + .await + .context("failed to bind listener to address")?; + log::trace!("Tokio listener bound to: {bind_address}"); + + log::debug!("Starting server..."); + axum::serve(listener, app) + .await + .context("server exited with error")?; + + log::error!("Server exited with no error, panicking."); + panic!("server exited with no error"); +} diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs new file mode 100644 index 0000000..ca9ec6b --- /dev/null +++ b/acrate-webfinger/src/route.rs @@ -0,0 +1,8 @@ +#[allow(unreachable_code)] +pub async fn inbox_handler() { + todo!("pre-validation hook"); + todo!("validate signature"); + todo!("post-validation hook"); + todo!("database storage"); + todo!("post-storage hook"); +} From 8145ce57cc82a05be7ef6a7453f7137e84af7c67 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 14 Nov 2024 04:02:40 +0100 Subject: [PATCH 02/53] `webfinger`: Parse query string with `serde` and `axum_extra` --- .idea/acrate.iml | 1 + acrate-webfinger/Cargo.toml | 2 ++ acrate-webfinger/src/main.rs | 2 +- acrate-webfinger/src/route.rs | 22 +++++++++++++++------- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.idea/acrate.iml b/.idea/acrate.iml index 983a32b..32d223d 100644 --- a/.idea/acrate.iml +++ b/.idea/acrate.iml @@ -9,6 +9,7 @@ + diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml index 4640b18..5c74e51 100644 --- a/acrate-webfinger/Cargo.toml +++ b/acrate-webfinger/Cargo.toml @@ -6,7 +6,9 @@ edition = "2021" [dependencies] anyhow = "1.0.93" axum = "0.7.7" +axum-extra = { version = "0.9.4", features = ["query"] } log = "0.4.22" micronfig = "0.3.0" pretty_env_logger = "0.5.0" +serde = { version = "1.0.215", features = ["derive"] } tokio = { version = "1.41.1", features = ["macros", "net", "rt-multi-thread"] } diff --git a/acrate-webfinger/src/main.rs b/acrate-webfinger/src/main.rs index 8958b4c..cc8ad4d 100644 --- a/acrate-webfinger/src/main.rs +++ b/acrate-webfinger/src/main.rs @@ -11,7 +11,7 @@ async fn main() -> anyhow::Result { log::trace!("Creating Axum router..."); let app = axum::Router::new() - .route("/inbox", axum::routing::post(route::inbox_handler)); + .route("/.well-known/webfinger", axum::routing::get(route::webfinger_handler)); log::trace!("Axum router created successfully!"); log::trace!("Creating Tokio listener..."); diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index ca9ec6b..82a7986 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -1,8 +1,16 @@ -#[allow(unreachable_code)] -pub async fn inbox_handler() { - todo!("pre-validation hook"); - todo!("validate signature"); - todo!("post-validation hook"); - todo!("database storage"); - todo!("post-storage hook"); +use axum_extra::extract::Query; +use serde::Deserialize; + +#[derive(Debug, Clone, Deserialize)] +pub struct WebfingerQuery { + pub resource: String, + + #[serde(default)] + pub rel: Vec, +} + +pub async fn webfinger_handler( + Query(WebfingerQuery {resource, rel}): Query +) { + todo!() } From 025311e1009403877db9b74e82495aa8fb95d3fe Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 14 Nov 2024 04:16:12 +0100 Subject: [PATCH 03/53] `webfinger`: Properly handle requests --- acrate-webfinger/Cargo.toml | 2 +- acrate-webfinger/src/config.rs | 2 +- acrate-webfinger/src/main.rs | 2 +- acrate-webfinger/src/route.rs | 10 ++++++++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml index 5c74e51..34b5b6e 100644 --- a/acrate-webfinger/Cargo.toml +++ b/acrate-webfinger/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] anyhow = "1.0.93" -axum = "0.7.7" +axum = { version = "0.7.7", features = ["macros"] } axum-extra = { version = "0.9.4", features = ["query"] } log = "0.4.22" micronfig = "0.3.0" diff --git a/acrate-webfinger/src/config.rs b/acrate-webfinger/src/config.rs index 63babb0..535a5c4 100644 --- a/acrate-webfinger/src/config.rs +++ b/acrate-webfinger/src/config.rs @@ -1,3 +1,3 @@ micronfig::config!( - ACRATE_INBOX_BIND_ADDRESS: String, + ACRATE_WEBFINGER_BIND_ADDRESS: String, ); diff --git a/acrate-webfinger/src/main.rs b/acrate-webfinger/src/main.rs index cc8ad4d..de425ea 100644 --- a/acrate-webfinger/src/main.rs +++ b/acrate-webfinger/src/main.rs @@ -15,7 +15,7 @@ async fn main() -> anyhow::Result { log::trace!("Axum router created successfully!"); log::trace!("Creating Tokio listener..."); - let bind_address = config::ACRATE_INBOX_BIND_ADDRESS(); + let bind_address = config::ACRATE_WEBFINGER_BIND_ADDRESS(); let listener = tokio::net::TcpListener::bind(bind_address) .await .context("failed to bind listener to address")?; diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index 82a7986..47aac61 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -1,3 +1,4 @@ +use axum::http::StatusCode; use axum_extra::extract::Query; use serde::Deserialize; @@ -9,8 +10,13 @@ pub struct WebfingerQuery { pub rel: Vec, } +#[axum::debug_handler] pub async fn webfinger_handler( Query(WebfingerQuery {resource, rel}): Query -) { - todo!() +) -> StatusCode { + log::info!("Handling a WebFinger request!"); + log::debug!("Resource is: {resource:#?}"); + log::debug!("Rel is: {rel:#?}"); + + StatusCode::NO_CONTENT } From 2d3421e2c37e4639f9cab3bf6f379d683df7c844 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 14 Nov 2024 06:23:38 +0100 Subject: [PATCH 04/53] `core`: Create migration for metadata tables --- .idea/dataSources.xml | 12 +++++ .idea/sqldialects.xml | 6 +++ .../down.sql | 8 ++++ .../up.sql | 47 +++++++++++++++++++ acrate-core/src/schema.rs | 46 ++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/sqldialects.xml create mode 100644 acrate-core/migrations/2024-11-14-031744_Add webfinger table/down.sql create mode 100644 acrate-core/migrations/2024-11-14-031744_Add webfinger table/up.sql create mode 100644 acrate-core/src/schema.rs diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..6cfc387 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql:///acrate + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..610ed0f --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/acrate-core/migrations/2024-11-14-031744_Add webfinger table/down.sql b/acrate-core/migrations/2024-11-14-031744_Add webfinger table/down.sql new file mode 100644 index 0000000..af9bea0 --- /dev/null +++ b/acrate-core/migrations/2024-11-14-031744_Add webfinger table/down.sql @@ -0,0 +1,8 @@ +DROP FUNCTION get_meta_property; +DROP FUNCTION get_meta_link; +DROP FUNCTION get_meta_aliases; + +DROP TABLE meta_property; +DROP TABLE meta_link_property; +DROP TABLE meta_link; +DROP TABLE meta_alias; diff --git a/acrate-core/migrations/2024-11-14-031744_Add webfinger table/up.sql b/acrate-core/migrations/2024-11-14-031744_Add webfinger table/up.sql new file mode 100644 index 0000000..664d409 --- /dev/null +++ b/acrate-core/migrations/2024-11-14-031744_Add webfinger table/up.sql @@ -0,0 +1,47 @@ +CREATE TABLE meta_alias ( + id UUID DEFAULT gen_random_uuid(), + pattern BPCHAR NOT NULL, + alias BPCHAR NOT NULL, + + CONSTRAINT unique_aliases UNIQUE (alias), + PRIMARY KEY (id) +); + +CREATE TABLE meta_link ( + id UUID DEFAULT gen_random_uuid(), + pattern BPCHAR NOT NULL, + rel BPCHAR NOT NULL, + type BPCHAR, + href BPCHAR, + + PRIMARY KEY (id) +); + +CREATE TABLE meta_link_property ( + id UUID DEFAULT gen_random_uuid(), + link UUID REFERENCES meta_link (id), + rel BPCHAR NOT NULL, + value BPCHAR, + + PRIMARY KEY (id) +); + +CREATE TABLE meta_property ( + id UUID DEFAULT gen_random_uuid(), + pattern BPCHAR NOT NULL, + value BPCHAR, + + PRIMARY KEY (id) +); + +CREATE FUNCTION get_meta_aliases(BPCHAR) RETURNS SETOF meta_alias AS $$ + SELECT * FROM meta_alias WHERE meta_alias.pattern ILIKE $1; +$$ LANGUAGE SQL; + +CREATE FUNCTION get_meta_link(BPCHAR) RETURNS SETOF meta_link AS $$ + SELECT * FROM meta_link WHERE meta_link.pattern ILIKE $1; +$$ LANGUAGE SQL; + +CREATE FUNCTION get_meta_property(BPCHAR) RETURNS SETOF meta_property AS $$ + SELECT * FROM meta_property WHERE meta_property.pattern ILIKE $1; +$$ LANGUAGE SQL; diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs new file mode 100644 index 0000000..913e83e --- /dev/null +++ b/acrate-core/src/schema.rs @@ -0,0 +1,46 @@ +// @generated automatically by Diesel CLI. + +diesel::table! { + meta_alias (id) { + id -> Uuid, + pattern -> Bpchar, + alias -> Bpchar, + } +} + +diesel::table! { + meta_link (id) { + id -> Uuid, + pattern -> Bpchar, + rel -> Bpchar, + #[sql_name = "type"] + type_ -> Nullable, + href -> Nullable, + } +} + +diesel::table! { + meta_link_property (id) { + id -> Uuid, + link -> Nullable, + rel -> Bpchar, + value -> Nullable, + } +} + +diesel::table! { + meta_property (id) { + id -> Uuid, + pattern -> Bpchar, + value -> Nullable, + } +} + +diesel::joinable!(meta_link_property -> meta_link (link)); + +diesel::allow_tables_to_appear_in_same_query!( + meta_alias, + meta_link, + meta_link_property, + meta_property, +); From 03aab44ba407a204f8faf8e10462bb6cfdfdbe5a Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 01:37:26 +0100 Subject: [PATCH 05/53] `core`: Rename migration --- .../down.sql | 0 .../up.sql | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename acrate-core/migrations/{2024-11-14-031744_Add webfinger table => 2024-11-14-031744_meta}/down.sql (100%) rename acrate-core/migrations/{2024-11-14-031744_Add webfinger table => 2024-11-14-031744_meta}/up.sql (100%) diff --git a/acrate-core/migrations/2024-11-14-031744_Add webfinger table/down.sql b/acrate-core/migrations/2024-11-14-031744_meta/down.sql similarity index 100% rename from acrate-core/migrations/2024-11-14-031744_Add webfinger table/down.sql rename to acrate-core/migrations/2024-11-14-031744_meta/down.sql diff --git a/acrate-core/migrations/2024-11-14-031744_Add webfinger table/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql similarity index 100% rename from acrate-core/migrations/2024-11-14-031744_Add webfinger table/up.sql rename to acrate-core/migrations/2024-11-14-031744_meta/up.sql From ad2383c56b23e56fc4bfc4ff303c96a6a8454e8f Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 01:48:01 +0100 Subject: [PATCH 06/53] `core`: Add `postgres` feature to `diesel` --- .idea/sqldialects.xml | 2 +- acrate-core/Cargo.toml | 2 +- acrate-core/src/lib.rs | 2 ++ acrate-core/src/meta.rs | 0 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 acrate-core/src/meta.rs diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml index 610ed0f..4495f93 100644 --- a/.idea/sqldialects.xml +++ b/.idea/sqldialects.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/acrate-core/Cargo.toml b/acrate-core/Cargo.toml index 6823787..2b8a3ed 100644 --- a/acrate-core/Cargo.toml +++ b/acrate-core/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -diesel = "2.2.4" +diesel = { version = "2.2.4", features = ["postgres"] } diesel_migrations = "2.2.0" acrate-hostmeta = { path = "../acrate-hostmeta" } acrate-nodeinfo = { path = "../acrate-nodeinfo" } diff --git a/acrate-core/src/lib.rs b/acrate-core/src/lib.rs index dae5ee7..bca0f47 100644 --- a/acrate-core/src/lib.rs +++ b/acrate-core/src/lib.rs @@ -1,4 +1,6 @@ //! Core crate of the `acrate` project. +mod meta; + pub use acrate_nodeinfo as nodeinfo; pub use acrate_hostmeta as hostmeta; diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs new file mode 100644 index 0000000..e69de29 From c09edc9b088fc70908545d9e8b8f61afe9ad4e5a Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 01:49:26 +0100 Subject: [PATCH 07/53] `core`: Attach `core::schema` --- acrate-core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/acrate-core/src/lib.rs b/acrate-core/src/lib.rs index bca0f47..0011441 100644 --- a/acrate-core/src/lib.rs +++ b/acrate-core/src/lib.rs @@ -1,5 +1,6 @@ //! Core crate of the `acrate` project. +mod schema; mod meta; pub use acrate_nodeinfo as nodeinfo; From 34e1eff85594214007bfae0a531d5c72cd9358e0 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 01:51:30 +0100 Subject: [PATCH 08/53] `core`: Add `uuid` feature to `diesel` --- acrate-core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acrate-core/Cargo.toml b/acrate-core/Cargo.toml index 2b8a3ed..f46d521 100644 --- a/acrate-core/Cargo.toml +++ b/acrate-core/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -diesel = { version = "2.2.4", features = ["postgres"] } +diesel = { version = "2.2.4", features = ["postgres", "uuid"] } diesel_migrations = "2.2.0" acrate-hostmeta = { path = "../acrate-hostmeta" } acrate-nodeinfo = { path = "../acrate-nodeinfo" } From c9afa95fd6035abe561e91a412013b875cd2293b Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 01:57:13 +0100 Subject: [PATCH 09/53] `core`: Remove dependency on workspace (This will be the database crate) --- acrate-core/Cargo.toml | 3 +-- acrate-core/src/lib.rs | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/acrate-core/Cargo.toml b/acrate-core/Cargo.toml index f46d521..6e6c7ac 100644 --- a/acrate-core/Cargo.toml +++ b/acrate-core/Cargo.toml @@ -6,8 +6,7 @@ edition = "2021" [dependencies] diesel = { version = "2.2.4", features = ["postgres", "uuid"] } diesel_migrations = "2.2.0" -acrate-hostmeta = { path = "../acrate-hostmeta" } -acrate-nodeinfo = { path = "../acrate-nodeinfo" } +uuid = "1.11.0" [lints.clippy] tabs-in-doc-comments = "allow" diff --git a/acrate-core/src/lib.rs b/acrate-core/src/lib.rs index 0011441..e25af41 100644 --- a/acrate-core/src/lib.rs +++ b/acrate-core/src/lib.rs @@ -2,6 +2,3 @@ mod schema; mod meta; - -pub use acrate_nodeinfo as nodeinfo; -pub use acrate_hostmeta as hostmeta; From 956bd17ad08aa85bb8e487203ef30380a8e61f7b Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 01:57:32 +0100 Subject: [PATCH 10/53] `core`: Make `core::meta` public --- acrate-core/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acrate-core/src/lib.rs b/acrate-core/src/lib.rs index e25af41..9df93e2 100644 --- a/acrate-core/src/lib.rs +++ b/acrate-core/src/lib.rs @@ -1,4 +1,5 @@ //! Core crate of the `acrate` project. mod schema; -mod meta; + +pub mod meta; From e65c85616d9174ea5993b84a244dfa010ed7495e Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:04:15 +0100 Subject: [PATCH 11/53] `core`: Use plural in table names --- .../migrations/2024-11-14-031744_meta/down.sql | 12 ++++++------ .../migrations/2024-11-14-031744_meta/up.sql | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/down.sql b/acrate-core/migrations/2024-11-14-031744_meta/down.sql index af9bea0..93c97ae 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/down.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/down.sql @@ -1,8 +1,8 @@ -DROP FUNCTION get_meta_property; -DROP FUNCTION get_meta_link; +DROP FUNCTION get_meta_properties; +DROP FUNCTION get_meta_links; DROP FUNCTION get_meta_aliases; -DROP TABLE meta_property; -DROP TABLE meta_link_property; -DROP TABLE meta_link; -DROP TABLE meta_alias; +DROP TABLE meta_properties; +DROP TABLE meta_link_properties; +DROP TABLE meta_links; +DROP TABLE meta_aliases; diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 664d409..cb663db 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -1,4 +1,4 @@ -CREATE TABLE meta_alias ( +CREATE TABLE meta_aliases ( id UUID DEFAULT gen_random_uuid(), pattern BPCHAR NOT NULL, alias BPCHAR NOT NULL, @@ -7,7 +7,7 @@ CREATE TABLE meta_alias ( PRIMARY KEY (id) ); -CREATE TABLE meta_link ( +CREATE TABLE meta_links ( id UUID DEFAULT gen_random_uuid(), pattern BPCHAR NOT NULL, rel BPCHAR NOT NULL, @@ -17,7 +17,7 @@ CREATE TABLE meta_link ( PRIMARY KEY (id) ); -CREATE TABLE meta_link_property ( +CREATE TABLE meta_link_properties ( id UUID DEFAULT gen_random_uuid(), link UUID REFERENCES meta_link (id), rel BPCHAR NOT NULL, @@ -26,7 +26,7 @@ CREATE TABLE meta_link_property ( PRIMARY KEY (id) ); -CREATE TABLE meta_property ( +CREATE TABLE meta_properties ( id UUID DEFAULT gen_random_uuid(), pattern BPCHAR NOT NULL, value BPCHAR, @@ -35,13 +35,13 @@ CREATE TABLE meta_property ( ); CREATE FUNCTION get_meta_aliases(BPCHAR) RETURNS SETOF meta_alias AS $$ - SELECT * FROM meta_alias WHERE meta_alias.pattern ILIKE $1; + SELECT * FROM meta_aliases WHERE meta_aliases.pattern ILIKE $1; $$ LANGUAGE SQL; -CREATE FUNCTION get_meta_link(BPCHAR) RETURNS SETOF meta_link AS $$ - SELECT * FROM meta_link WHERE meta_link.pattern ILIKE $1; +CREATE FUNCTION get_meta_links(BPCHAR) RETURNS SETOF meta_link AS $$ + SELECT * FROM meta_links WHERE meta_links.pattern ILIKE $1; $$ LANGUAGE SQL; CREATE FUNCTION get_meta_property(BPCHAR) RETURNS SETOF meta_property AS $$ - SELECT * FROM meta_property WHERE meta_property.pattern ILIKE $1; + SELECT * FROM meta_properties WHERE meta_properties.pattern ILIKE $1; $$ LANGUAGE SQL; From c27af2cf53719c46f2789352896583c21a7c0256 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:05:49 +0100 Subject: [PATCH 12/53] `core`: Use plural in table names --- .../migrations/2024-11-14-031744_meta/up.sql | 8 ++--- acrate-core/src/schema.rs | 34 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index cb663db..12a9fdf 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -19,7 +19,7 @@ CREATE TABLE meta_links ( CREATE TABLE meta_link_properties ( id UUID DEFAULT gen_random_uuid(), - link UUID REFERENCES meta_link (id), + link UUID REFERENCES meta_links (id), rel BPCHAR NOT NULL, value BPCHAR, @@ -34,14 +34,14 @@ CREATE TABLE meta_properties ( PRIMARY KEY (id) ); -CREATE FUNCTION get_meta_aliases(BPCHAR) RETURNS SETOF meta_alias AS $$ +CREATE FUNCTION get_meta_aliases(BPCHAR) RETURNS SETOF meta_aliases AS $$ SELECT * FROM meta_aliases WHERE meta_aliases.pattern ILIKE $1; $$ LANGUAGE SQL; -CREATE FUNCTION get_meta_links(BPCHAR) RETURNS SETOF meta_link AS $$ +CREATE FUNCTION get_meta_links(BPCHAR) RETURNS SETOF meta_links AS $$ SELECT * FROM meta_links WHERE meta_links.pattern ILIKE $1; $$ LANGUAGE SQL; -CREATE FUNCTION get_meta_property(BPCHAR) RETURNS SETOF meta_property AS $$ +CREATE FUNCTION get_meta_properties(BPCHAR) RETURNS SETOF meta_properties AS $$ SELECT * FROM meta_properties WHERE meta_properties.pattern ILIKE $1; $$ LANGUAGE SQL; diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index 913e83e..9f8c994 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -1,7 +1,7 @@ // @generated automatically by Diesel CLI. diesel::table! { - meta_alias (id) { + meta_aliases (id) { id -> Uuid, pattern -> Bpchar, alias -> Bpchar, @@ -9,7 +9,16 @@ diesel::table! { } diesel::table! { - meta_link (id) { + meta_link_properties (id) { + id -> Uuid, + link -> Nullable, + rel -> Bpchar, + value -> Nullable, + } +} + +diesel::table! { + meta_links (id) { id -> Uuid, pattern -> Bpchar, rel -> Bpchar, @@ -20,27 +29,18 @@ diesel::table! { } diesel::table! { - meta_link_property (id) { - id -> Uuid, - link -> Nullable, - rel -> Bpchar, - value -> Nullable, - } -} - -diesel::table! { - meta_property (id) { + meta_properties (id) { id -> Uuid, pattern -> Bpchar, value -> Nullable, } } -diesel::joinable!(meta_link_property -> meta_link (link)); +diesel::joinable!(meta_link_properties -> meta_links (link)); diesel::allow_tables_to_appear_in_same_query!( - meta_alias, - meta_link, - meta_link_property, - meta_property, + meta_aliases, + meta_link_properties, + meta_links, + meta_properties, ); From 84f7002338486760d9a7e1ea97201009fe03da74 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:12:26 +0100 Subject: [PATCH 13/53] `core`: Make `link` not null --- acrate-core/migrations/2024-11-14-031744_meta/up.sql | 2 +- acrate-core/src/schema.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 12a9fdf..5eded6d 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -19,7 +19,7 @@ CREATE TABLE meta_links ( CREATE TABLE meta_link_properties ( id UUID DEFAULT gen_random_uuid(), - link UUID REFERENCES meta_links (id), + link UUID REFERENCES meta_links (id) NOT NULL, rel BPCHAR NOT NULL, value BPCHAR, diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index 9f8c994..f64b5f6 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -11,7 +11,7 @@ diesel::table! { diesel::table! { meta_link_properties (id) { id -> Uuid, - link -> Nullable, + link -> Uuid, rel -> Bpchar, value -> Nullable, } From 2ca4bb3662f3c9d1117736b371afe20626073e2f Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:14:04 +0100 Subject: [PATCH 14/53] `core`: Rename `link` to `meta_link_id` --- acrate-core/migrations/2024-11-14-031744_meta/up.sql | 2 +- acrate-core/src/schema.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 5eded6d..757b530 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -19,7 +19,7 @@ CREATE TABLE meta_links ( CREATE TABLE meta_link_properties ( id UUID DEFAULT gen_random_uuid(), - link UUID REFERENCES meta_links (id) NOT NULL, + meta_link_id UUID REFERENCES meta_links (id) NOT NULL, rel BPCHAR NOT NULL, value BPCHAR, diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index f64b5f6..a11635a 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -11,7 +11,7 @@ diesel::table! { diesel::table! { meta_link_properties (id) { id -> Uuid, - link -> Uuid, + meta_link_id -> Uuid, rel -> Bpchar, value -> Nullable, } @@ -36,7 +36,7 @@ diesel::table! { } } -diesel::joinable!(meta_link_properties -> meta_links (link)); +diesel::joinable!(meta_link_properties -> meta_links (meta_link_id)); diesel::allow_tables_to_appear_in_same_query!( meta_aliases, From 21842d9f80336ef3dc26525e861948d60b921f66 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:16:16 +0100 Subject: [PATCH 15/53] `core`: Add base `core::meta` structs --- acrate-core/src/meta.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index e69de29..aadf736 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -0,0 +1,41 @@ +use diesel::{Associations, Identifiable, Insertable, Queryable, QueryableByName, Selectable}; +use uuid::Uuid; + +use super::schema; + + +#[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] +#[diesel(table_name = schema::meta_aliases)] +pub struct MetaAlias { + pub id: Uuid, + pub pattern: String, + pub alias: String, +} + +#[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] +#[diesel(table_name = schema::meta_links)] +pub struct MetaLink { + pub id: Uuid, + pub pattern: String, + pub rel: String, + pub type_: Option, + pub href: Option, +} + +#[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable, Associations)] +#[diesel(belongs_to(MetaLink))] +#[diesel(table_name = schema::meta_link_properties)] +pub struct MetaLinkProperty { + pub id: Uuid, + pub meta_link_id: Uuid, + pub rel: String, + pub value: Option, +} + +#[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] +#[diesel(table_name = schema::meta_properties)] +pub struct MetaProperty { + pub id: Uuid, + pub pattern: String, + pub value: Option, +} From 5a3d9139336e0a587318c09f62e51f03b2ad8f15 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:34:53 +0100 Subject: [PATCH 16/53] `core`: Don't define database functions, implement them in Rust --- .../migrations/2024-11-14-031744_meta/down.sql | 4 ---- acrate-core/migrations/2024-11-14-031744_meta/up.sql | 12 ------------ 2 files changed, 16 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/down.sql b/acrate-core/migrations/2024-11-14-031744_meta/down.sql index 93c97ae..d56725b 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/down.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/down.sql @@ -1,7 +1,3 @@ -DROP FUNCTION get_meta_properties; -DROP FUNCTION get_meta_links; -DROP FUNCTION get_meta_aliases; - DROP TABLE meta_properties; DROP TABLE meta_link_properties; DROP TABLE meta_links; diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 757b530..41771cb 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -33,15 +33,3 @@ CREATE TABLE meta_properties ( PRIMARY KEY (id) ); - -CREATE FUNCTION get_meta_aliases(BPCHAR) RETURNS SETOF meta_aliases AS $$ - SELECT * FROM meta_aliases WHERE meta_aliases.pattern ILIKE $1; -$$ LANGUAGE SQL; - -CREATE FUNCTION get_meta_links(BPCHAR) RETURNS SETOF meta_links AS $$ - SELECT * FROM meta_links WHERE meta_links.pattern ILIKE $1; -$$ LANGUAGE SQL; - -CREATE FUNCTION get_meta_properties(BPCHAR) RETURNS SETOF meta_properties AS $$ - SELECT * FROM meta_properties WHERE meta_properties.pattern ILIKE $1; -$$ LANGUAGE SQL; From b5d907bd07620e7d39997f7831149a7cc8cbda65 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:35:17 +0100 Subject: [PATCH 17/53] `core`: Use `r#type` instead of `type_` --- acrate-core/src/schema.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index a11635a..51159fd 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -22,8 +22,7 @@ diesel::table! { id -> Uuid, pattern -> Bpchar, rel -> Bpchar, - #[sql_name = "type"] - type_ -> Nullable, + r#type -> Nullable, href -> Nullable, } } From 6ebf2ddd6dd9b6712281bb84c49041d5c683bdbc Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:40:58 +0100 Subject: [PATCH 18/53] `core`: Use `diesel_async` dep --- acrate-core/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acrate-core/Cargo.toml b/acrate-core/Cargo.toml index 6e6c7ac..1f94d4f 100644 --- a/acrate-core/Cargo.toml +++ b/acrate-core/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] -diesel = { version = "2.2.4", features = ["postgres", "uuid"] } +diesel = { version = "2.2.4", features = ["uuid"] } +diesel-async = { version = "0.5.1", features = ["postgres"] } diesel_migrations = "2.2.0" uuid = "1.11.0" From 18b361978505acab68a705b44759336db391bf13 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 02:57:39 +0100 Subject: [PATCH 19/53] `core`: Apparently you still need the `postgres` feature on `diesel` --- acrate-core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acrate-core/Cargo.toml b/acrate-core/Cargo.toml index 1f94d4f..d5b738a 100644 --- a/acrate-core/Cargo.toml +++ b/acrate-core/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -diesel = { version = "2.2.4", features = ["uuid"] } +diesel = { version = "2.2.4", features = ["postgres", "uuid"] } diesel-async = { version = "0.5.1", features = ["postgres"] } diesel_migrations = "2.2.0" uuid = "1.11.0" From c235467b060c3848404805217e7ec98e8b74ee24 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 03:16:06 +0100 Subject: [PATCH 20/53] `core`: Add queryable `meta` structs --- acrate-core/src/meta.rs | 64 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index aadf736..a365579 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -1,6 +1,6 @@ -use diesel::{Associations, Identifiable, Insertable, Queryable, QueryableByName, Selectable}; +use diesel::{Associations, Identifiable, Insertable, QueryResult, Queryable, QueryableByName, Selectable}; +use diesel_async::AsyncPgConnection; use uuid::Uuid; - use super::schema; @@ -18,7 +18,7 @@ pub struct MetaLink { pub id: Uuid, pub pattern: String, pub rel: String, - pub type_: Option, + pub r#type: Option, pub href: Option, } @@ -39,3 +39,61 @@ pub struct MetaProperty { pub pattern: String, pub value: Option, } + + +impl MetaAlias { + pub async fn query_matching(conn: &mut AsyncPgConnection, subject: &str) -> QueryResult> { + use diesel::prelude::*; + use diesel_async::RunQueryDsl; + use schema::meta_aliases::dsl::*; + + let subject_matches_pattern = subject.into_sql::().ilike(pattern); + + meta_aliases + .filter(subject_matches_pattern) + .select(Self::as_select()) + .load(conn) + .await + } +} + +impl MetaLink { + pub async fn query_matching(conn: &mut AsyncPgConnection, subject: &str) -> QueryResult> { + use diesel::prelude::*; + use diesel_async::RunQueryDsl; + use schema::meta_links::dsl::*; + + let subject_matches_pattern = subject.into_sql::().ilike(pattern); + + meta_links + .filter(subject_matches_pattern) + .select(Self::as_select()) + .load(conn) + .await + } + + pub async fn query_properties(&self, conn: &mut AsyncPgConnection) -> QueryResult> { + use diesel::prelude::*; + use diesel_async::RunQueryDsl; + + MetaLinkProperty::belonging_to(self) + .load(conn) + .await + } +} + +impl MetaProperty { + pub async fn query_matching(conn: &mut AsyncPgConnection, subject: &str) -> QueryResult> { + use diesel::prelude::*; + use diesel_async::RunQueryDsl; + use schema::meta_properties::dsl::*; + + let subject_matches_pattern = subject.into_sql::().ilike(pattern); + + meta_properties + .filter(subject_matches_pattern) + .select(Self::as_select()) + .load(conn) + .await + } +} From 3e2a7fd11045f4b3111e3963cba4bf8b8346094a Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 04:59:13 +0100 Subject: [PATCH 21/53] `core`: Expose `diesel` and `diesel_async` --- acrate-core/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acrate-core/src/lib.rs b/acrate-core/src/lib.rs index 9df93e2..d340197 100644 --- a/acrate-core/src/lib.rs +++ b/acrate-core/src/lib.rs @@ -3,3 +3,6 @@ mod schema; pub mod meta; + +pub use diesel; +pub use diesel_async; From 153dc7d50f2a7d799fc8c1c391949b085009d374 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 05:18:52 +0100 Subject: [PATCH 22/53] `core`: Cascade table DROPs --- acrate-core/migrations/2024-11-14-031744_meta/down.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/down.sql b/acrate-core/migrations/2024-11-14-031744_meta/down.sql index d56725b..b942998 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/down.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/down.sql @@ -1,4 +1,4 @@ -DROP TABLE meta_properties; -DROP TABLE meta_link_properties; -DROP TABLE meta_links; -DROP TABLE meta_aliases; +DROP TABLE meta_properties CASCADE; +DROP TABLE meta_link_properties CASCADE; +DROP TABLE meta_links CASCADE; +DROP TABLE meta_aliases CASCADE; From 69392bf7e582fc5f0f5c67d3670f7a628bf053f9 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 05:19:25 +0100 Subject: [PATCH 23/53] `core`: DROP tables only IF EXISTS --- acrate-core/migrations/2024-11-14-031744_meta/down.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/down.sql b/acrate-core/migrations/2024-11-14-031744_meta/down.sql index b942998..9b62cb9 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/down.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/down.sql @@ -1,4 +1,4 @@ -DROP TABLE meta_properties CASCADE; -DROP TABLE meta_link_properties CASCADE; -DROP TABLE meta_links CASCADE; -DROP TABLE meta_aliases CASCADE; +DROP TABLE IF EXISTS meta_properties CASCADE; +DROP TABLE IF EXISTS meta_link_properties CASCADE; +DROP TABLE IF EXISTS meta_links CASCADE; +DROP TABLE IF EXISTS meta_aliases CASCADE; From 3906d03653fd87826f4fd3190e4671d4a258f87e Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 05:19:50 +0100 Subject: [PATCH 24/53] `core`: Add document field to meta tables --- acrate-core/migrations/2024-11-14-031744_meta/up.sql | 3 +++ acrate-core/src/schema.rs | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 41771cb..222b04d 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -1,5 +1,6 @@ CREATE TABLE meta_aliases ( id UUID DEFAULT gen_random_uuid(), + document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, alias BPCHAR NOT NULL, @@ -9,6 +10,7 @@ CREATE TABLE meta_aliases ( CREATE TABLE meta_links ( id UUID DEFAULT gen_random_uuid(), + document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, rel BPCHAR NOT NULL, type BPCHAR, @@ -28,6 +30,7 @@ CREATE TABLE meta_link_properties ( CREATE TABLE meta_properties ( id UUID DEFAULT gen_random_uuid(), + document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, value BPCHAR, diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index 51159fd..4be615f 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -3,6 +3,7 @@ diesel::table! { meta_aliases (id) { id -> Uuid, + document -> Bpchar, pattern -> Bpchar, alias -> Bpchar, } @@ -20,9 +21,11 @@ diesel::table! { diesel::table! { meta_links (id) { id -> Uuid, + document -> Bpchar, pattern -> Bpchar, rel -> Bpchar, - r#type -> Nullable, + #[sql_name = "type"] + type_ -> Nullable, href -> Nullable, } } @@ -30,6 +33,7 @@ diesel::table! { diesel::table! { meta_properties (id) { id -> Uuid, + document -> Bpchar, pattern -> Bpchar, value -> Nullable, } From b7924c8776d5f35029d8c033701779a2100d5ffb Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 05:20:46 +0100 Subject: [PATCH 25/53] `core`: Fix r#type in schema --- acrate-core/src/schema.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index 4be615f..5cd7157 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -24,8 +24,7 @@ diesel::table! { document -> Bpchar, pattern -> Bpchar, rel -> Bpchar, - #[sql_name = "type"] - type_ -> Nullable, + r#type -> Nullable, href -> Nullable, } } From d0aa551ef4dcfa8546f41e4929b11fea1d910c36 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 05:21:05 +0100 Subject: [PATCH 26/53] `core`: Add document to the meta types --- acrate-core/src/meta.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index a365579..82da189 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -8,6 +8,7 @@ use super::schema; #[diesel(table_name = schema::meta_aliases)] pub struct MetaAlias { pub id: Uuid, + pub document: String, pub pattern: String, pub alias: String, } @@ -16,6 +17,7 @@ pub struct MetaAlias { #[diesel(table_name = schema::meta_links)] pub struct MetaLink { pub id: Uuid, + pub document: String, pub pattern: String, pub rel: String, pub r#type: Option, @@ -36,6 +38,7 @@ pub struct MetaLinkProperty { #[diesel(table_name = schema::meta_properties)] pub struct MetaProperty { pub id: Uuid, + pub document: String, pub pattern: String, pub value: Option, } From 94203cdc7bc660f892d21b82f42db20db2682c11 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 05:23:06 +0100 Subject: [PATCH 27/53] `core`: Filter meta queries on document --- acrate-core/src/meta.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index 82da189..7ff7aa9 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -45,14 +45,16 @@ pub struct MetaProperty { impl MetaAlias { - pub async fn query_matching(conn: &mut AsyncPgConnection, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_aliases::dsl::*; + let document_is_equal = document.eq(doc); let subject_matches_pattern = subject.into_sql::().ilike(pattern); meta_aliases + .filter(document_is_equal) .filter(subject_matches_pattern) .select(Self::as_select()) .load(conn) @@ -61,14 +63,16 @@ impl MetaAlias { } impl MetaLink { - pub async fn query_matching(conn: &mut AsyncPgConnection, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_links::dsl::*; + let document_is_equal = document.eq(doc); let subject_matches_pattern = subject.into_sql::().ilike(pattern); meta_links + .filter(document_is_equal) .filter(subject_matches_pattern) .select(Self::as_select()) .load(conn) @@ -86,14 +90,16 @@ impl MetaLink { } impl MetaProperty { - pub async fn query_matching(conn: &mut AsyncPgConnection, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_properties::dsl::*; + let document_is_equal = document.eq(doc); let subject_matches_pattern = subject.into_sql::().ilike(pattern); meta_properties + .filter(document_is_equal) .filter(subject_matches_pattern) .select(Self::as_select()) .load(conn) From affb063508d45d9f530557fee3a17565f1e62c60 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 05:23:21 +0100 Subject: [PATCH 28/53] `webfinger`: Add `acrate-core` dependency --- acrate-webfinger/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml index 34b5b6e..fa9296b 100644 --- a/acrate-webfinger/Cargo.toml +++ b/acrate-webfinger/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +acrate-core = { path = "../acrate-core" } anyhow = "1.0.93" axum = { version = "0.7.7", features = ["macros"] } axum-extra = { version = "0.9.4", features = ["query"] } From 6315c22ad6f3d775f837198197ae9e4af5629f9b Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 06:30:42 +0100 Subject: [PATCH 29/53] `core`: Add missing `rel` attribute to meta_properties --- acrate-core/migrations/2024-11-14-031744_meta/up.sql | 1 + acrate-core/src/meta.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 222b04d..1b7f236 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -32,6 +32,7 @@ CREATE TABLE meta_properties ( id UUID DEFAULT gen_random_uuid(), document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, + rel BPCHAR NOT NULL, value BPCHAR, PRIMARY KEY (id) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index 7ff7aa9..699cf4e 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -40,6 +40,7 @@ pub struct MetaProperty { pub id: Uuid, pub document: String, pub pattern: String, + pub rel: String, pub value: Option, } From f5449cd397d14579ccd905e1034f9f4586a1b037 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 06:31:49 +0100 Subject: [PATCH 30/53] `core`: Fix `r#type` again --- acrate-core/src/schema.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index 5cd7157..cbee252 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -34,6 +34,7 @@ diesel::table! { id -> Uuid, document -> Bpchar, pattern -> Bpchar, + rel -> Bpchar, value -> Nullable, } } From 065fa9c80e30e0b13132685be4e12399eb42b054 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 06:50:51 +0100 Subject: [PATCH 31/53] Eyes are closing, git fire --- acrate-webfinger/Cargo.toml | 1 + acrate-webfinger/src/config.rs | 1 + acrate-webfinger/src/route.rs | 127 +++++++++++++++++++++++++++++++-- 3 files changed, 125 insertions(+), 4 deletions(-) diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml index fa9296b..f74ff6b 100644 --- a/acrate-webfinger/Cargo.toml +++ b/acrate-webfinger/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] acrate-core = { path = "../acrate-core" } +acrate-hostmeta = { path = "../acrate-hostmeta" } anyhow = "1.0.93" axum = { version = "0.7.7", features = ["macros"] } axum-extra = { version = "0.9.4", features = ["query"] } diff --git a/acrate-webfinger/src/config.rs b/acrate-webfinger/src/config.rs index 535a5c4..feb7905 100644 --- a/acrate-webfinger/src/config.rs +++ b/acrate-webfinger/src/config.rs @@ -1,3 +1,4 @@ micronfig::config!( + ACRATE_WEBFINGER_DATABASE_URL: String, ACRATE_WEBFINGER_BIND_ADDRESS: String, ); diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index 47aac61..dc98106 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -1,6 +1,11 @@ -use axum::http::StatusCode; +use axum::body::Body; +use axum::http::{HeaderMap, HeaderValue, StatusCode}; use axum_extra::extract::Query; use serde::Deserialize; +use acrate_core::diesel_async::{AsyncConnection, AsyncPgConnection}; +use acrate_hostmeta::jrd::ResourceDescriptorLinkJRD; +use acrate_hostmeta::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD}; +use crate::config; #[derive(Debug, Clone, Deserialize)] pub struct WebfingerQuery { @@ -10,13 +15,127 @@ pub struct WebfingerQuery { pub rel: Vec, } +const WEBFINGER_DOC: &str = "/.well-known/webfinger"; + #[axum::debug_handler] pub async fn webfinger_handler( - Query(WebfingerQuery {resource, rel}): Query -) -> StatusCode { + Query(WebfingerQuery {resource, rel}): Query, + headers: HeaderMap, +) -> Result<(Body, HeaderMap), StatusCode> { log::info!("Handling a WebFinger request!"); + log::debug!("Resource is: {resource:#?}"); + log::debug!("Rel is: {rel:#?}"); - StatusCode::NO_CONTENT + let accept = headers.get("Accept") + .map(|v| v.to_str()) + .filter(Result::is_ok) + .map(|v| v.unwrap()) + .unwrap_or("application/json") + .to_string(); + log::debug!("Accept is: {accept:#?}"); + + let mut response_headers = HeaderMap::new(); + + let mut conn = AsyncPgConnection::establish(config::ACRATE_WEBFINGER_DATABASE_URL()) + .await + .map_err(|_| StatusCode::BAD_GATEWAY)?; + + let aliases = acrate_core::meta::MetaAlias::query_matching(&mut conn, WEBFINGER_DOC, &resource) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + let properties = acrate_core::meta::MetaProperty::query_matching(&mut conn, WEBFINGER_DOC, &resource) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + let links = acrate_core::meta::MetaLink::query_matching(&mut conn, WEBFINGER_DOC, &resource) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + for mime in accept.split(", ") { + response_headers.insert("Content-Type", mime.parse().unwrap()); + + match mime { + "application/json" | "application/jrd+json" => { + let subject = Some(resource); + + let aliases = aliases + .into_iter() + .map(|alias| alias.alias) + .collect(); + + let properties = properties + .into_iter() + .map(|prop| (prop.rel, prop.value)) + .collect(); + + let links = links + .into_iter() + .map(|link| ResourceDescriptorLinkJRD { + rel: link.rel, + r#type: link.r#type, + href: link.href, + titles: Default::default(), // TODO: Titles + properties: Default::default(), // TODO: Link properties + template: None, // TODO: Template + }) + .collect::>(); + + let rd = acrate_hostmeta::jrd::ResourceDescriptorJRD { + subject, + aliases, + properties, + links, + }; + + let body = rd. + + return Ok(rd, response_headers) + }, + "application/xml" | "application/xrd+xml" => { + let subject = Some(resource); + + let aliases = aliases + .into_iter() + .map(|alias| alias.alias) + .collect(); + + let properties = properties + .into_iter() + .map(|prop| ResourceDescriptorPropertyXRD { + r#type: prop.rel, // TODO: Ah si chiama type? + value: prop.value, + }) + .collect(); + + let links = links + .into_iter() + .map(|link| ResourceDescriptorLinkXRD { + rel: link.rel, + r#type: link.r#type, + href: link.href, + titles: Default::default(), // TODO: Titles + properties: Default::default(), // TODO: Link properties + template: None, // TODO: Template + }) + .collect::>(); + + let rd = acrate_hostmeta::xrd::ResourceDescriptorXRD { + subject, + aliases, + properties, + links, + }; + + return Ok(StatusCode::OK) + }, + _ => { + continue; + } + } + } + + Err(StatusCode::NOT_ACCEPTABLE) } From a020861e3343a858dd54112114fe757fce2e910c Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 17:57:31 +0100 Subject: [PATCH 32/53] `hostmeta`: Make the root element use the XRD tag --- acrate-hostmeta/src/xrd.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/acrate-hostmeta/src/xrd.rs b/acrate-hostmeta/src/xrd.rs index 0e89c1d..f7c80e6 100644 --- a/acrate-hostmeta/src/xrd.rs +++ b/acrate-hostmeta/src/xrd.rs @@ -9,6 +9,7 @@ use crate::jrd::{ResourceDescriptorJRD, ResourceDescriptorLinkJRD}; /// - /// - #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename = "XRD")] pub struct ResourceDescriptorXRD { /// The resource this document refers to. /// From 32f756f8006da52906bdf6b7466681cfa4b555fa Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 18:10:02 +0100 Subject: [PATCH 33/53] `hostmeta`: Fix type not being an attribute --- acrate-hostmeta/src/xrd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acrate-hostmeta/src/xrd.rs b/acrate-hostmeta/src/xrd.rs index f7c80e6..ef92cb4 100644 --- a/acrate-hostmeta/src/xrd.rs +++ b/acrate-hostmeta/src/xrd.rs @@ -133,7 +133,7 @@ pub struct ResourceDescriptorTitleXRD { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ResourceDescriptorPropertyXRD { /// The property identifier, or type. - #[serde(alias = "@type")] + #[serde(rename = "@type")] pub r#type: String, /// The property value. From 49b1b8ba6567019c05165f452978abc8b0ae9445 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 18:10:39 +0100 Subject: [PATCH 34/53] `hostmeta`: Fix value being wrapped in a tag --- acrate-hostmeta/src/xrd.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/acrate-hostmeta/src/xrd.rs b/acrate-hostmeta/src/xrd.rs index ef92cb4..546eb2d 100644 --- a/acrate-hostmeta/src/xrd.rs +++ b/acrate-hostmeta/src/xrd.rs @@ -137,6 +137,7 @@ pub struct ResourceDescriptorPropertyXRD { pub r#type: String, /// The property value. + #[serde(rename = "$text")] pub value: Option, } From c36b6edbfb2fdbdddf5b9602c6c791e68d3128bb Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 18:12:13 +0100 Subject: [PATCH 35/53] `webfinger`: Serve XRD and JRD responses --- acrate-webfinger/Cargo.toml | 2 ++ acrate-webfinger/src/route.rs | 47 ++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml index f74ff6b..5bb8042 100644 --- a/acrate-webfinger/Cargo.toml +++ b/acrate-webfinger/Cargo.toml @@ -12,5 +12,7 @@ axum-extra = { version = "0.9.4", features = ["query"] } log = "0.4.22" micronfig = "0.3.0" pretty_env_logger = "0.5.0" +quick-xml = { version = "0.37.0", features = ["serialize"] } serde = { version = "1.0.215", features = ["derive"] } +serde_json = "1.0.132" tokio = { version = "1.41.1", features = ["macros", "net", "rt-multi-thread"] } diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index dc98106..a94ec6e 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -1,5 +1,4 @@ -use axum::body::Body; -use axum::http::{HeaderMap, HeaderValue, StatusCode}; +use axum::http::{HeaderMap, Response, StatusCode}; use axum_extra::extract::Query; use serde::Deserialize; use acrate_core::diesel_async::{AsyncConnection, AsyncPgConnection}; @@ -9,7 +8,7 @@ use crate::config; #[derive(Debug, Clone, Deserialize)] pub struct WebfingerQuery { - pub resource: String, + pub resource: Option, #[serde(default)] pub rel: Vec, @@ -21,9 +20,10 @@ const WEBFINGER_DOC: &str = "/.well-known/webfinger"; pub async fn webfinger_handler( Query(WebfingerQuery {resource, rel}): Query, headers: HeaderMap, -) -> Result<(Body, HeaderMap), StatusCode> { +) -> Result, StatusCode> { log::info!("Handling a WebFinger request!"); + let resource = resource.unwrap_or_else(|| "".to_string()); log::debug!("Resource is: {resource:#?}"); log::debug!("Rel is: {rel:#?}"); @@ -36,7 +36,7 @@ pub async fn webfinger_handler( .to_string(); log::debug!("Accept is: {accept:#?}"); - let mut response_headers = HeaderMap::new(); + let mut response = Response::new("".to_string()); let mut conn = AsyncPgConnection::establish(config::ACRATE_WEBFINGER_DATABASE_URL()) .await @@ -54,11 +54,19 @@ pub async fn webfinger_handler( .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - for mime in accept.split(", ") { - response_headers.insert("Content-Type", mime.parse().unwrap()); - + for mime in accept.split(",") { + { + let headers = response.headers_mut(); + headers.insert("Content-Type", mime.parse().unwrap()); + } + + let (mime, _params) = match mime.trim().split_once(";") { + Some((mime, params)) => (mime, Some(params)), + None => (mime, None), + }; + match mime { - "application/json" | "application/jrd+json" => { + "*/*" | "application/json" | "application/jrd+json" => { let subject = Some(resource); let aliases = aliases @@ -90,9 +98,15 @@ pub async fn webfinger_handler( links, }; - let body = rd. + let json = serde_json::to_string_pretty(&rd) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - return Ok(rd, response_headers) + { + let body = response.body_mut(); + body.push_str(&json); + } + + return Ok(response) }, "application/xml" | "application/xrd+xml" => { let subject = Some(resource); @@ -129,7 +143,16 @@ pub async fn webfinger_handler( links, }; - return Ok(StatusCode::OK) + let xml = quick_xml::se::to_string(&rd) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + { + let body = response.body_mut(); + body.push_str(""); + body.push_str(&xml); + } + + return Ok(response) }, _ => { continue; From e5412d85badb65018bd09617256f2476dd323592 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 20:43:41 +0100 Subject: [PATCH 36/53] `core`: Update schema with more details --- .../migrations/2024-11-14-031744_meta/up.sql | 17 ++++++++++++++++- acrate-core/src/schema.rs | 15 ++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 1b7f236..b258ed4 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -4,7 +4,6 @@ CREATE TABLE meta_aliases ( pattern BPCHAR NOT NULL, alias BPCHAR NOT NULL, - CONSTRAINT unique_aliases UNIQUE (alias), PRIMARY KEY (id) ); @@ -15,7 +14,13 @@ CREATE TABLE meta_links ( rel BPCHAR NOT NULL, type BPCHAR, href BPCHAR, + template BPCHAR, + CONSTRAINT either_href_or_template_not_null CHECK ( + (href IS NOT NULL AND template IS NULL) + OR + (href IS NULL AND template IS NOT NULL) + ), PRIMARY KEY (id) ); @@ -37,3 +42,13 @@ CREATE TABLE meta_properties ( PRIMARY KEY (id) ); + +CREATE TABLE meta_link_titles ( + id UUID DEFAULT gen_random_uuid(), + meta_link_id UUID REFERENCES meta_links (id) NOT NULL, + lang BPCHAR NOT NULL DEFAULT 'und', + value BPCHAR NOT NULL, + + CONSTRAINT unique_languages UNIQUE (meta_link_id, lang), + PRIMARY KEY(id) +); diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index cbee252..6cd2df7 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -18,14 +18,25 @@ diesel::table! { } } +diesel::table! { + meta_link_titles (id) { + id -> Uuid, + meta_link_id -> Uuid, + lang -> Bpchar, + value -> Bpchar, + } +} + diesel::table! { meta_links (id) { id -> Uuid, document -> Bpchar, pattern -> Bpchar, rel -> Bpchar, - r#type -> Nullable, + #[sql_name = "type"] + type_ -> Nullable, href -> Nullable, + template -> Nullable, } } @@ -40,10 +51,12 @@ diesel::table! { } diesel::joinable!(meta_link_properties -> meta_links (meta_link_id)); +diesel::joinable!(meta_link_titles -> meta_links (meta_link_id)); diesel::allow_tables_to_appear_in_same_query!( meta_aliases, meta_link_properties, + meta_link_titles, meta_links, meta_properties, ); From d1dcbc1fc6f15cbb0aa2c8bd619f529a16db8feb Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 20:44:06 +0100 Subject: [PATCH 37/53] `core`: Give up on renaming `type_` --- acrate-core/src/meta.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index 699cf4e..a5b4d2a 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -20,7 +20,7 @@ pub struct MetaLink { pub document: String, pub pattern: String, pub rel: String, - pub r#type: Option, + pub type_: Option, pub href: Option, } From f2d73c1798976cb9314fd9f497d62ef7ce532fe6 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 20:48:51 +0100 Subject: [PATCH 38/53] `core`: Further schema improvements --- .../migrations/2024-11-14-031744_meta/down.sql | 1 + .../migrations/2024-11-14-031744_meta/up.sql | 14 +++++++------- acrate-core/src/schema.rs | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/down.sql b/acrate-core/migrations/2024-11-14-031744_meta/down.sql index 9b62cb9..2c09392 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/down.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/down.sql @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS meta_properties CASCADE; DROP TABLE IF EXISTS meta_link_properties CASCADE; +DROP TABLE IF EXISTS meta_link_titles CASCADE; DROP TABLE IF EXISTS meta_links CASCADE; DROP TABLE IF EXISTS meta_aliases CASCADE; diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index b258ed4..012feab 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -1,4 +1,4 @@ -CREATE TABLE meta_aliases ( +CREATE TABLE IF NOT EXISTS meta_aliases ( id UUID DEFAULT gen_random_uuid(), document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, @@ -7,7 +7,7 @@ CREATE TABLE meta_aliases ( PRIMARY KEY (id) ); -CREATE TABLE meta_links ( +CREATE TABLE IF NOT EXISTS meta_links ( id UUID DEFAULT gen_random_uuid(), document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, @@ -24,7 +24,7 @@ CREATE TABLE meta_links ( PRIMARY KEY (id) ); -CREATE TABLE meta_link_properties ( +CREATE TABLE IF NOT EXISTS meta_link_properties ( id UUID DEFAULT gen_random_uuid(), meta_link_id UUID REFERENCES meta_links (id) NOT NULL, rel BPCHAR NOT NULL, @@ -33,7 +33,7 @@ CREATE TABLE meta_link_properties ( PRIMARY KEY (id) ); -CREATE TABLE meta_properties ( +CREATE TABLE IF NOT EXISTS meta_properties ( id UUID DEFAULT gen_random_uuid(), document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, @@ -43,12 +43,12 @@ CREATE TABLE meta_properties ( PRIMARY KEY (id) ); -CREATE TABLE meta_link_titles ( +CREATE TABLE IF NOT EXISTS meta_link_titles ( id UUID DEFAULT gen_random_uuid(), meta_link_id UUID REFERENCES meta_links (id) NOT NULL, - lang BPCHAR NOT NULL DEFAULT 'und', + language BPCHAR NOT NULL DEFAULT 'und', value BPCHAR NOT NULL, - CONSTRAINT unique_languages UNIQUE (meta_link_id, lang), + CONSTRAINT unique_languages UNIQUE (meta_link_id, language), PRIMARY KEY(id) ); diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index 6cd2df7..e6544b5 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -22,7 +22,7 @@ diesel::table! { meta_link_titles (id) { id -> Uuid, meta_link_id -> Uuid, - lang -> Bpchar, + language -> Bpchar, value -> Bpchar, } } From 8a49903ecaf087a61530bdd1fc5797f00a0284d6 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 15 Nov 2024 20:53:59 +0100 Subject: [PATCH 39/53] `core`: Support meta titles --- acrate-core/src/meta.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index a5b4d2a..bcfd200 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -22,6 +22,7 @@ pub struct MetaLink { pub rel: String, pub type_: Option, pub href: Option, + pub template: Option, } #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable, Associations)] @@ -34,6 +35,16 @@ pub struct MetaLinkProperty { pub value: Option, } +#[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable, Associations)] +#[diesel(belongs_to(MetaLink))] +#[diesel(table_name = schema::meta_link_titles)] +pub struct MetaLinkTitle { + pub id: Uuid, + pub meta_link_id: Uuid, + pub language: String, + pub value: String, +} + #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] #[diesel(table_name = schema::meta_properties)] pub struct MetaProperty { @@ -44,7 +55,6 @@ pub struct MetaProperty { pub value: Option, } - impl MetaAlias { pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; @@ -88,6 +98,15 @@ impl MetaLink { .load(conn) .await } + + pub async fn query_titles(&self, conn: &mut AsyncPgConnection) -> QueryResult> { + use diesel::prelude::*; + use diesel_async::RunQueryDsl; + + MetaLinkTitle::belonging_to(self) + .load(conn) + .await + } } impl MetaProperty { From 72f3669ef172217bb4a732064e13d3fde453be81 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 01:35:30 +0100 Subject: [PATCH 40/53] `webfinger`: yield to `type_` --- acrate-webfinger/src/route.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index a94ec6e..deea558 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -83,7 +83,7 @@ pub async fn webfinger_handler( .into_iter() .map(|link| ResourceDescriptorLinkJRD { rel: link.rel, - r#type: link.r#type, + r#type: link.type_, href: link.href, titles: Default::default(), // TODO: Titles properties: Default::default(), // TODO: Link properties @@ -128,7 +128,7 @@ pub async fn webfinger_handler( .into_iter() .map(|link| ResourceDescriptorLinkXRD { rel: link.rel, - r#type: link.r#type, + r#type: link.type_, href: link.href, titles: Default::default(), // TODO: Titles properties: Default::default(), // TODO: Link properties From 8b5408f21e247865e9a98c958f6191d1fe3cc59a Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 01:41:57 +0100 Subject: [PATCH 41/53] `hostmeta`: Property.r#type to Property.rel --- acrate-hostmeta/src/jrd.rs | 2 +- acrate-hostmeta/src/xrd.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/acrate-hostmeta/src/jrd.rs b/acrate-hostmeta/src/jrd.rs index 7662b80..f893bc0 100644 --- a/acrate-hostmeta/src/jrd.rs +++ b/acrate-hostmeta/src/jrd.rs @@ -219,7 +219,7 @@ impl From for ResourceDescriptorLinkJRD { impl From for (String, Option) { fn from(value: ResourceDescriptorPropertyXRD) -> Self { - (value.r#type, value.value) + (value.rel, value.value) } } diff --git a/acrate-hostmeta/src/xrd.rs b/acrate-hostmeta/src/xrd.rs index 546eb2d..0a66887 100644 --- a/acrate-hostmeta/src/xrd.rs +++ b/acrate-hostmeta/src/xrd.rs @@ -133,8 +133,8 @@ pub struct ResourceDescriptorTitleXRD { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ResourceDescriptorPropertyXRD { /// The property identifier, or type. - #[serde(rename = "@type")] - pub r#type: String, + #[serde(rename = "@rel")] + pub rel: String, /// The property value. #[serde(rename = "$text")] @@ -236,7 +236,7 @@ impl From for ResourceDescriptorXRD { impl From<(String, Option)> for ResourceDescriptorPropertyXRD { fn from(value: (String, Option)) -> Self { Self { - r#type: value.0, + rel: value.0, value: value.1, } } From a5b9918c43439789ff67badcd3ab7e5c699d333d Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 01:42:04 +0100 Subject: [PATCH 42/53] `webfinger`: Property.r#type to Property.rel --- acrate-webfinger/src/route.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index deea558..4018ae0 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -119,7 +119,7 @@ pub async fn webfinger_handler( let properties = properties .into_iter() .map(|prop| ResourceDescriptorPropertyXRD { - r#type: prop.rel, // TODO: Ah si chiama type? + rel: prop.rel, value: prop.value, }) .collect(); From a5b6485d11ca5f44e4d8f6f244208ea0bcf12bf6 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 02:54:55 +0100 Subject: [PATCH 43/53] `core`: Allow querying meta objects grouped by parent --- acrate-core/src/meta.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index bcfd200..ef66ab7 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -89,21 +89,25 @@ impl MetaLink { .load(conn) .await } - - pub async fn query_properties(&self, conn: &mut AsyncPgConnection) -> QueryResult> { +} + +impl MetaLinkProperty { + pub async fn query_by_link(conn: &mut AsyncPgConnection, links: &[MetaLink]) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; - MetaLinkProperty::belonging_to(self) + Self::belonging_to(links) .load(conn) .await } - - pub async fn query_titles(&self, conn: &mut AsyncPgConnection) -> QueryResult> { +} + +impl MetaLinkTitle { + pub async fn query_by_link(conn: &mut AsyncPgConnection, links: &[MetaLink]) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; - MetaLinkTitle::belonging_to(self) + Self::belonging_to(links) .load(conn) .await } From 86f9aa27f2ad80c4dac2a62950f64e66fa60a197 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 02:55:08 +0100 Subject: [PATCH 44/53] `hostmeta`: Schema improvements --- acrate-hostmeta/src/jrd.rs | 4 ++++ acrate-hostmeta/src/xrd.rs | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/acrate-hostmeta/src/jrd.rs b/acrate-hostmeta/src/jrd.rs index f893bc0..24c7f68 100644 --- a/acrate-hostmeta/src/jrd.rs +++ b/acrate-hostmeta/src/jrd.rs @@ -17,6 +17,7 @@ pub struct ResourceDescriptorJRD { /// /// - /// + #[serde(skip_serializing_if = "Option::is_none")] pub subject: Option, /// Other names the resource described by this document can be referred to. @@ -70,6 +71,7 @@ pub struct ResourceDescriptorLinkJRD { /// /// - /// + #[serde(skip_serializing_if = "Option::is_none")] pub r#type: Option, /// URI to the resource put in relation. @@ -78,6 +80,7 @@ pub struct ResourceDescriptorLinkJRD { /// /// - /// + #[serde(skip_serializing_if = "Option::is_none")] pub href: Option, /// Titles of the resource put in relation in various languages. @@ -104,6 +107,7 @@ pub struct ResourceDescriptorLinkJRD { /// /// - /// + #[serde(skip_serializing_if = "Option::is_none")] pub template: Option, } diff --git a/acrate-hostmeta/src/xrd.rs b/acrate-hostmeta/src/xrd.rs index 0a66887..96e3a73 100644 --- a/acrate-hostmeta/src/xrd.rs +++ b/acrate-hostmeta/src/xrd.rs @@ -18,6 +18,7 @@ pub struct ResourceDescriptorXRD { /// - /// #[serde(rename = "Subject")] + #[serde(skip_serializing_if = "Option::is_none")] pub subject: Option, /// Other names the resource described by this document can be referred to. @@ -59,6 +60,7 @@ pub struct ResourceDescriptorXRD { /// - /// #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename = "Link")] pub struct ResourceDescriptorLinkXRD { /// The kind of relation established by the subject with the attached resource. /// @@ -76,6 +78,7 @@ pub struct ResourceDescriptorLinkXRD { /// - /// #[serde(rename = "@type")] + #[serde(skip_serializing_if = "Option::is_none")] pub r#type: Option, /// URI to the resource put in relation. @@ -85,6 +88,7 @@ pub struct ResourceDescriptorLinkXRD { /// - /// #[serde(rename = "@href")] + #[serde(skip_serializing_if = "Option::is_none")] pub href: Option, /// Titles of the resource put in relation in various languages. @@ -94,6 +98,7 @@ pub struct ResourceDescriptorLinkXRD { /// - /// #[serde(default)] + #[serde(rename = "Title")] pub titles: Vec, /// Additional information about the resource put in relation. @@ -103,6 +108,7 @@ pub struct ResourceDescriptorLinkXRD { /// - /// #[serde(default)] + #[serde(rename = "Property")] pub properties: Vec, /// Template to fill to get the URL to resource-specific information. @@ -112,6 +118,7 @@ pub struct ResourceDescriptorLinkXRD { /// - /// #[serde(rename = "@template")] + #[serde(skip_serializing_if = "Option::is_none")] pub template: Option, } @@ -121,16 +128,19 @@ pub struct ResourceDescriptorLinkXRD { /// /// - #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename = "Title")] pub struct ResourceDescriptorTitleXRD { /// The language of the title. #[serde(rename = "@lang")] pub language: String, /// The title itself. + #[serde(rename = "$text")] pub value: String, } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename = "Property")] pub struct ResourceDescriptorPropertyXRD { /// The property identifier, or type. #[serde(rename = "@rel")] From 5b8b166323bf91b52bc24c7cc592a1db34120c68 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 02:56:21 +0100 Subject: [PATCH 45/53] Obliterate `.idea/misc.xml` from existence --- .gitignore | 3 +++ .idea/misc.xml | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 .idea/misc.xml diff --git a/.gitignore b/.gitignore index 1469e2f..e3745a3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ Cargo.lock # Environment .env.local + +# IntelliJ IDEA thing, mostly broken versioning +.idea/misc.xml diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 30bab2a..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file From d80888c9db55cd1d948889532019b2ae4ed1a977 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 02:58:45 +0100 Subject: [PATCH 46/53] `webfinger`: Add link properties and titles --- acrate-webfinger/src/route.rs | 80 ++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index 4018ae0..b59780a 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -1,9 +1,11 @@ use axum::http::{HeaderMap, Response, StatusCode}; use axum_extra::extract::Query; use serde::Deserialize; +use acrate_core::diesel::GroupedBy; use acrate_core::diesel_async::{AsyncConnection, AsyncPgConnection}; +use acrate_core::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty}; use acrate_hostmeta::jrd::ResourceDescriptorLinkJRD; -use acrate_hostmeta::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD}; +use acrate_hostmeta::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD}; use crate::config; #[derive(Debug, Clone, Deserialize)] @@ -42,22 +44,50 @@ pub async fn webfinger_handler( .await .map_err(|_| StatusCode::BAD_GATEWAY)?; - let aliases = acrate_core::meta::MetaAlias::query_matching(&mut conn, WEBFINGER_DOC, &resource) + let aliases = MetaAlias::query_matching(&mut conn, WEBFINGER_DOC, &resource) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - let properties = acrate_core::meta::MetaProperty::query_matching(&mut conn, WEBFINGER_DOC, &resource) + let properties = MetaProperty::query_matching(&mut conn, WEBFINGER_DOC, &resource) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; - let links = acrate_core::meta::MetaLink::query_matching(&mut conn, WEBFINGER_DOC, &resource) + let links = MetaLink::query_matching(&mut conn, WEBFINGER_DOC, &resource) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + let link_properties = MetaLinkProperty::query_by_link(&mut conn, &links) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? + .grouped_by(&links); + + let link_titles = MetaLinkTitle::query_by_link(&mut conn, &links) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? + .grouped_by(&links); + + let links_full: Vec<(MetaLink, Vec, Vec)> = links + .into_iter() + .zip(link_properties) + .zip(link_titles) + .map(|((link, properties), titles)| (link, properties, titles)) + .collect(); + + { + let headers = response.headers_mut(); + headers.insert( + "Access-Control-Allow-Origin", + "*".parse().unwrap() + ); + } + for mime in accept.split(",") { { let headers = response.headers_mut(); - headers.insert("Content-Type", mime.parse().unwrap()); + headers.insert( + "Content-Type", + mime.parse().map_err(|_| StatusCode::BAD_REQUEST)? + ); } let (mime, _params) = match mime.trim().split_once(";") { @@ -79,15 +109,21 @@ pub async fn webfinger_handler( .map(|prop| (prop.rel, prop.value)) .collect(); - let links = links + let links = links_full .into_iter() - .map(|link| ResourceDescriptorLinkJRD { + .map(|(link, properties, titles)| ResourceDescriptorLinkJRD { rel: link.rel, r#type: link.type_, href: link.href, - titles: Default::default(), // TODO: Titles - properties: Default::default(), // TODO: Link properties - template: None, // TODO: Template + template: link.template, + properties: properties + .into_iter() + .map(|property| (property.rel, property.value)) + .collect(), + titles: titles + .into_iter() + .map(|title| (title.language, title.value)) + .collect(), }) .collect::>(); @@ -116,7 +152,7 @@ pub async fn webfinger_handler( .map(|alias| alias.alias) .collect(); - let properties = properties + let properties: Vec = properties .into_iter() .map(|prop| ResourceDescriptorPropertyXRD { rel: prop.rel, @@ -124,15 +160,27 @@ pub async fn webfinger_handler( }) .collect(); - let links = links + let links = links_full .into_iter() - .map(|link| ResourceDescriptorLinkXRD { + .map(|(link, properties, titles)| ResourceDescriptorLinkXRD { rel: link.rel, r#type: link.type_, href: link.href, - titles: Default::default(), // TODO: Titles - properties: Default::default(), // TODO: Link properties - template: None, // TODO: Template + template: link.template, + properties: properties + .into_iter() + .map(|property| ResourceDescriptorPropertyXRD { + rel: property.rel, + value: property.value, + }) + .collect(), + titles: titles + .into_iter() + .map(|title| ResourceDescriptorTitleXRD { + language: title.language, + value: title.value, + }) + .collect(), }) .collect::>(); From dfee4e510e1f74c2373c102a49c5a9f49b371a51 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 06:16:34 +0100 Subject: [PATCH 47/53] `core`: Add `meta_subjects` to handle redirects --- .../2024-11-14-031744_meta/down.sql | 1 + .../migrations/2024-11-14-031744_meta/up.sql | 9 ++++++ acrate-core/src/meta.rs | 31 +++++++++++++++++-- acrate-core/src/schema.rs | 10 ++++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/down.sql b/acrate-core/migrations/2024-11-14-031744_meta/down.sql index 2c09392..39d835e 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/down.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/down.sql @@ -3,3 +3,4 @@ DROP TABLE IF EXISTS meta_link_properties CASCADE; DROP TABLE IF EXISTS meta_link_titles CASCADE; DROP TABLE IF EXISTS meta_links CASCADE; DROP TABLE IF EXISTS meta_aliases CASCADE; +DROP TABLE IF EXISTS meta_subjects CASCADE; diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index 012feab..c0f6c46 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -1,3 +1,12 @@ +CREATE TABLE IF NOT EXISTS meta_subjects ( + id UUID DEFAULT gen_random_uuid(), + document BPCHAR NOT NULL, + pattern BPCHAR NOT NULL, + redirect BPCHAR NOT NULL, + + PRIMARY KEY (id) +); + CREATE TABLE IF NOT EXISTS meta_aliases ( id UUID DEFAULT gen_random_uuid(), document BPCHAR NOT NULL, diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index ef66ab7..aca144c 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -4,6 +4,15 @@ use uuid::Uuid; use super::schema; +#[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] +#[diesel(table_name = schema::meta_subjects)] +pub struct MetaSubject { + pub id: Uuid, + pub document: String, + pub pattern: String, + pub redirect: Option, +} + #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] #[diesel(table_name = schema::meta_aliases)] pub struct MetaAlias { @@ -55,8 +64,26 @@ pub struct MetaProperty { pub value: Option, } +impl MetaSubject { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { + use diesel::prelude::*; + use diesel_async::RunQueryDsl; + use schema::meta_subjects::dsl::*; + + let document_is_equal = document.eq(doc); + let subject_matches_pattern = subject.into_sql::().ilike(pattern); + + meta_subjects + .filter(document_is_equal) + .filter(subject_matches_pattern) + .select(Self::as_select()) + .load(conn) + .await + } +} + impl MetaAlias { - pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_aliases::dsl::*; @@ -74,7 +101,7 @@ impl MetaAlias { } impl MetaLink { - pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_links::dsl::*; diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index e6544b5..4e9855d 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -50,6 +50,15 @@ diesel::table! { } } +diesel::table! { + meta_subjects (id) { + id -> Uuid, + document -> Bpchar, + pattern -> Bpchar, + redirect -> Bpchar, + } +} + diesel::joinable!(meta_link_properties -> meta_links (meta_link_id)); diesel::joinable!(meta_link_titles -> meta_links (meta_link_id)); @@ -59,4 +68,5 @@ diesel::allow_tables_to_appear_in_same_query!( meta_link_titles, meta_links, meta_properties, + meta_subjects, ); From c83fdc43e6aefe804967d18b6ee627e256c7252e Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 06:16:52 +0100 Subject: [PATCH 48/53] `webfinger`: `text/html` version of the document --- acrate-webfinger/Cargo.toml | 1 + acrate-webfinger/src/main.rs | 12 +++- acrate-webfinger/src/route.rs | 59 ++++++++++++++-- acrate-webfinger/src/webfinger.html.j2 | 98 ++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 acrate-webfinger/src/webfinger.html.j2 diff --git a/acrate-webfinger/Cargo.toml b/acrate-webfinger/Cargo.toml index 5bb8042..cfd73d0 100644 --- a/acrate-webfinger/Cargo.toml +++ b/acrate-webfinger/Cargo.toml @@ -11,6 +11,7 @@ axum = { version = "0.7.7", features = ["macros"] } axum-extra = { version = "0.9.4", features = ["query"] } log = "0.4.22" micronfig = "0.3.0" +minijinja = "2.5.0" pretty_env_logger = "0.5.0" quick-xml = { version = "0.37.0", features = ["serialize"] } serde = { version = "1.0.215", features = ["derive"] } diff --git a/acrate-webfinger/src/main.rs b/acrate-webfinger/src/main.rs index de425ea..7b248b0 100644 --- a/acrate-webfinger/src/main.rs +++ b/acrate-webfinger/src/main.rs @@ -1,4 +1,6 @@ +use std::sync::Arc; use anyhow::Context; +use axum::Extension; mod config; mod route; @@ -8,10 +10,18 @@ mod route; async fn main() -> anyhow::Result { pretty_env_logger::init(); log::debug!("Logging initialized!"); + + log::trace!("Creating Minijinja environment..."); + let mut mj = minijinja::Environment::<'static>::new(); + + log::trace!("Adding webfinger page to the Minijinja environment..."); + mj.add_template("webfinger.html.j2", include_str!("webfinger.html.j2")) + .expect("webfinger.html.j2 to be a valid Minijinja template"); log::trace!("Creating Axum router..."); let app = axum::Router::new() - .route("/.well-known/webfinger", axum::routing::get(route::webfinger_handler)); + .route("/.well-known/webfinger", axum::routing::get(route::webfinger_handler)) + .layer(Extension(Arc::new(mj))); log::trace!("Axum router created successfully!"); log::trace!("Creating Tokio listener..."); diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index b59780a..1ae9cef 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; +use axum::Extension; use axum::http::{HeaderMap, Response, StatusCode}; use axum_extra::extract::Query; use serde::Deserialize; @@ -22,6 +24,7 @@ const WEBFINGER_DOC: &str = "/.well-known/webfinger"; pub async fn webfinger_handler( Query(WebfingerQuery {resource, rel}): Query, headers: HeaderMap, + Extension(mj): Extension>>, ) -> Result, StatusCode> { log::info!("Handling a WebFinger request!"); @@ -142,7 +145,7 @@ pub async fn webfinger_handler( body.push_str(&json); } - return Ok(response) + return Ok(response); }, "application/xml" | "application/xrd+xml" => { let subject = Some(resource); @@ -196,15 +199,63 @@ pub async fn webfinger_handler( { let body = response.body_mut(); - body.push_str(""); + body.push_str(r#""#); body.push_str(&xml); } - return Ok(response) + return Ok(response); + }, + "text/html" => { + let aliases: Vec = aliases.into_iter() + .map(|alias| alias.alias) + .collect(); + + let properties: Vec<(String, Option)> = properties.into_iter() + .map(|prop| { + (prop.rel, prop.value) + }) + .collect(); + + let links: Vec<(String, Option, Option, Option, Vec<(String, Option)>, Vec<(String, String)>)> = links_full + .into_iter() + .map(|(link, properties, titles)| { + ( + link.rel, + link.type_, + link.href, + link.template, + properties.into_iter() + .map(|prop| (prop.rel, prop.value)) + .collect::)>>(), + titles.into_iter() + .map(|title| (title.language, title.value)) + .collect::>() + ) + }) + .collect(); + + let html = mj.get_template("webfinger.html.j2") + .expect("webfinger.html.j2 to exist") + .render( + minijinja::context!( + subject => resource, + aliases => aliases, + properties => properties, + links => links, + ) + ) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + { + let body = response.body_mut(); + body.push_str(&html); + } + + return Ok(response); }, _ => { continue; - } + }, } } diff --git a/acrate-webfinger/src/webfinger.html.j2 b/acrate-webfinger/src/webfinger.html.j2 new file mode 100644 index 0000000..1bb22ce --- /dev/null +++ b/acrate-webfinger/src/webfinger.html.j2 @@ -0,0 +1,98 @@ + + + + {{ subject }} · Acrate Webfinger + + +

+ Acrate Webfinger +

+

+ {{ subject }} +

+ {% if aliases %} +
+

+ Aliases +

+
    + {% for alias in aliases %} +
  • {{ alias }}
  • + {% endfor %} +
+
+ {% endif %} + {% if properties %} +
+

+ Properties +

+
+ {% for property in properties %} +
+ {{ property[0] }} +
+
+ {{ property[1] }} +
+ {% endfor %} +
+
+ {% endif %} + {% if links %} + + {% endif %} + From 7f392bef36f06b9a468e09c7a92d82fbc7b7fd8e Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 06:45:58 +0100 Subject: [PATCH 49/53] `core`: Fix schema --- .../migrations/2024-11-14-031744_meta/up.sql | 2 +- acrate-core/src/meta.rs | 20 ++++++++++++------- acrate-core/src/schema.rs | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/acrate-core/migrations/2024-11-14-031744_meta/up.sql b/acrate-core/migrations/2024-11-14-031744_meta/up.sql index c0f6c46..8387ac9 100644 --- a/acrate-core/migrations/2024-11-14-031744_meta/up.sql +++ b/acrate-core/migrations/2024-11-14-031744_meta/up.sql @@ -2,7 +2,7 @@ CREATE TABLE IF NOT EXISTS meta_subjects ( id UUID DEFAULT gen_random_uuid(), document BPCHAR NOT NULL, pattern BPCHAR NOT NULL, - redirect BPCHAR NOT NULL, + redirect BPCHAR, PRIMARY KEY (id) ); diff --git a/acrate-core/src/meta.rs b/acrate-core/src/meta.rs index aca144c..4fe0343 100644 --- a/acrate-core/src/meta.rs +++ b/acrate-core/src/meta.rs @@ -1,4 +1,4 @@ -use diesel::{Associations, Identifiable, Insertable, QueryResult, Queryable, QueryableByName, Selectable}; +use diesel::{Associations, Identifiable, Insertable, QueryResult, Queryable, QueryableByName, Selectable, pg::Pg}; use diesel_async::AsyncPgConnection; use uuid::Uuid; use super::schema; @@ -6,6 +6,7 @@ use super::schema; #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] #[diesel(table_name = schema::meta_subjects)] +#[diesel(check_for_backend(Pg))] pub struct MetaSubject { pub id: Uuid, pub document: String, @@ -15,6 +16,7 @@ pub struct MetaSubject { #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] #[diesel(table_name = schema::meta_aliases)] +#[diesel(check_for_backend(Pg))] pub struct MetaAlias { pub id: Uuid, pub document: String, @@ -24,6 +26,7 @@ pub struct MetaAlias { #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] #[diesel(table_name = schema::meta_links)] +#[diesel(check_for_backend(Pg))] pub struct MetaLink { pub id: Uuid, pub document: String, @@ -37,6 +40,7 @@ pub struct MetaLink { #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable, Associations)] #[diesel(belongs_to(MetaLink))] #[diesel(table_name = schema::meta_link_properties)] +#[diesel(check_for_backend(Pg))] pub struct MetaLinkProperty { pub id: Uuid, pub meta_link_id: Uuid, @@ -47,6 +51,7 @@ pub struct MetaLinkProperty { #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable, Associations)] #[diesel(belongs_to(MetaLink))] #[diesel(table_name = schema::meta_link_titles)] +#[diesel(check_for_backend(Pg))] pub struct MetaLinkTitle { pub id: Uuid, pub meta_link_id: Uuid, @@ -56,6 +61,7 @@ pub struct MetaLinkTitle { #[derive(Debug, Queryable, QueryableByName, Identifiable, Selectable, Insertable)] #[diesel(table_name = schema::meta_properties)] +#[diesel(check_for_backend(Pg))] pub struct MetaProperty { pub id: Uuid, pub document: String, @@ -65,7 +71,7 @@ pub struct MetaProperty { } impl MetaSubject { - pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_subjects::dsl::*; @@ -83,7 +89,7 @@ impl MetaSubject { } impl MetaAlias { - pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_aliases::dsl::*; @@ -101,7 +107,7 @@ impl MetaAlias { } impl MetaLink { - pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_links::dsl::*; @@ -119,7 +125,7 @@ impl MetaLink { } impl MetaLinkProperty { - pub async fn query_by_link(conn: &mut AsyncPgConnection, links: &[MetaLink]) -> QueryResult> { + pub async fn query_by_link(conn: &mut AsyncPgConnection, links: &[MetaLink]) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; @@ -130,7 +136,7 @@ impl MetaLinkProperty { } impl MetaLinkTitle { - pub async fn query_by_link(conn: &mut AsyncPgConnection, links: &[MetaLink]) -> QueryResult> { + pub async fn query_by_link(conn: &mut AsyncPgConnection, links: &[MetaLink]) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; @@ -141,7 +147,7 @@ impl MetaLinkTitle { } impl MetaProperty { - pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { + pub async fn query_matching(conn: &mut AsyncPgConnection, doc: &str, subject: &str) -> QueryResult> { use diesel::prelude::*; use diesel_async::RunQueryDsl; use schema::meta_properties::dsl::*; diff --git a/acrate-core/src/schema.rs b/acrate-core/src/schema.rs index 4e9855d..94b2aa7 100644 --- a/acrate-core/src/schema.rs +++ b/acrate-core/src/schema.rs @@ -55,7 +55,7 @@ diesel::table! { id -> Uuid, document -> Bpchar, pattern -> Bpchar, - redirect -> Bpchar, + redirect -> Nullable, } } From 0498e45b593981e814efa352435e23f79ee72c71 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 06:46:25 +0100 Subject: [PATCH 50/53] `webfinger`: Handle not found and redirects --- acrate-webfinger/src/route.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/acrate-webfinger/src/route.rs b/acrate-webfinger/src/route.rs index 1ae9cef..13a7d7d 100644 --- a/acrate-webfinger/src/route.rs +++ b/acrate-webfinger/src/route.rs @@ -5,7 +5,7 @@ use axum_extra::extract::Query; use serde::Deserialize; use acrate_core::diesel::GroupedBy; use acrate_core::diesel_async::{AsyncConnection, AsyncPgConnection}; -use acrate_core::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty}; +use acrate_core::meta::{MetaAlias, MetaLink, MetaLinkProperty, MetaLinkTitle, MetaProperty, MetaSubject}; use acrate_hostmeta::jrd::ResourceDescriptorLinkJRD; use acrate_hostmeta::xrd::{ResourceDescriptorLinkXRD, ResourceDescriptorPropertyXRD, ResourceDescriptorTitleXRD}; use crate::config; @@ -47,6 +47,33 @@ pub async fn webfinger_handler( .await .map_err(|_| StatusCode::BAD_GATEWAY)?; + let subjects = MetaSubject::query_matching(&mut conn, WEBFINGER_DOC, &resource) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + let subject = subjects.first() + .ok_or(StatusCode::NOT_FOUND)?; + + if subject.redirect.is_some() { + { + let headers = response.headers_mut(); + headers.insert( + "Location", + subject.redirect + .as_ref() + .expect("redirect not to have become suddenly None") + .parse() + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? + ); + } + { + let status = response.status_mut(); + *status = StatusCode::FOUND; + } + + return Ok(response); + } + let aliases = MetaAlias::query_matching(&mut conn, WEBFINGER_DOC, &resource) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; From 7319a3fe7115e49b439e008f4f27b555853b4e5d Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 07:24:14 +0100 Subject: [PATCH 51/53] `webfinger`: Add basic CSS to the page --- acrate-webfinger/src/webfinger.html.j2 | 267 ++++++++++++++++--------- 1 file changed, 176 insertions(+), 91 deletions(-) diff --git a/acrate-webfinger/src/webfinger.html.j2 b/acrate-webfinger/src/webfinger.html.j2 index 1bb22ce..3fcc79c 100644 --- a/acrate-webfinger/src/webfinger.html.j2 +++ b/acrate-webfinger/src/webfinger.html.j2 @@ -2,97 +2,182 @@ {{ subject }} · Acrate Webfinger + -

- Acrate Webfinger -

-

- {{ subject }} -

- {% if aliases %} -
-

- Aliases -

-
    - {% for alias in aliases %} -
  • {{ alias }}
  • - {% endfor %} -
-
- {% endif %} - {% if properties %} -
-

- Properties -

-
- {% for property in properties %} -
- {{ property[0] }} -
-
- {{ property[1] }} -
- {% endfor %} -
-
- {% endif %} - {% if links %} - - {% endif %} +
+

+ Acrate Webfinger +

+
+
+

+ {{ subject }} +

+ {% if aliases %} +
+
+

+ Aliases +

+
    + {% for alias in aliases %} +
  • {{ alias }}
  • + {% endfor %} +
+
+ {% endif %} + {% if properties %} +
+
+

+ Properties +

+
+ {% for property in properties %} +
+ {{ property[0] }} +
+
+ {{ property[1] }} +
+ {% endfor %} +
+
+ {% endif %} + {% if links %} +
+ + {% endif %} +
From 8ca9d016887f4d5b5af0f2d81711d59adc04aa18 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 07:29:09 +0100 Subject: [PATCH 52/53] `webfinger`: Don't link self --- acrate-webfinger/src/webfinger.html.j2 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/acrate-webfinger/src/webfinger.html.j2 b/acrate-webfinger/src/webfinger.html.j2 index 3fcc79c..3c4f191 100644 --- a/acrate-webfinger/src/webfinger.html.j2 +++ b/acrate-webfinger/src/webfinger.html.j2 @@ -128,7 +128,16 @@ {% for link in links %}

- {{ link[0] }}{% if link[1] is not none %} ({{ link[1] }}){% endif %} + {% if link[0] != "self" %} + {{ link[0] }} + {% else %} + {{ link[0] }} + {% endif %} + {% if link[1] is not none %} + + ({{ link[1] }}) + + {% endif %}

From ee1eb9f47089b2a40788b669d4e522976dcf86a9 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Nov 2024 07:30:35 +0100 Subject: [PATCH 53/53] Add README listing crates --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 814f637..b524419 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,15 @@ Federation database > [!Caution] > > This software suite is in active development! + +## Crates + +### Libraries + +- `acrate-core`: Database stuff +- `acrate-hostmeta`: RFC 6415 serde +- `acrate-nodeinfo`: NodeInfo serde + +### Binaries + +- `acrate-webfinger`: WebFinger server