diff --git a/Cargo.lock b/Cargo.lock index b3aca2d8..b0e0a8d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,7 +139,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -212,7 +212,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -365,7 +365,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -445,7 +445,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.55", + "syn", ] [[package]] @@ -456,7 +456,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -826,9 +826,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -1222,7 +1222,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -1302,7 +1302,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -1569,7 +1569,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -1641,7 +1641,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -1845,17 +1845,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.55" @@ -1902,7 +1891,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -1986,7 +1975,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -2118,7 +2107,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", ] [[package]] @@ -2175,11 +2164,10 @@ dependencies = [ [[package]] name = "tracing-test" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a2c0ff408fe918a94c428a3f2ad04e4afd5c95bbc08fcf868eff750c15728a4" +checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68" dependencies = [ - "lazy_static", "tracing-core", "tracing-subscriber", "tracing-test-macro", @@ -2187,13 +2175,12 @@ dependencies = [ [[package]] name = "tracing-test-macro" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bc1c4f8e2e73a977812ab339d503e6feeb92700f6d07a6de4d321522d5c08" +checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ - "lazy_static", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -2361,7 +2348,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn", "wasm-bindgen-shared", ] @@ -2383,7 +2370,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index dc1f8a55..07858de8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ tokio = { version = "1", features = ["rt", "macros", "rt-multi-thread"] } tokio-test = "0.4.2" tower = "0.4.13" tower-http = { version = "0.5.0", features = ["trace", "fs", "cors"] } -hyper = "1.0.1" +hyper = "1.4.1" regex = "1.5.4" thiserror = "1.0.56" tracing = "0.1" diff --git a/dsp-meta-cmd/src/main-server.rs b/dsp-meta-cmd/src/main-server.rs index b552ad77..308b6820 100644 --- a/dsp-meta-cmd/src/main-server.rs +++ b/dsp-meta-cmd/src/main-server.rs @@ -12,6 +12,7 @@ use tokio::net::TcpListener; use tracing::info; use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; +use url::Url; fn main() { // Do the pid1 magic. Needs to be the first thing executed. @@ -64,12 +65,17 @@ async fn init_server() { .get::("public_dir") .unwrap_or("/public".to_string()); + let base_url = settings + .get::("base_url") + .unwrap_or(Url::parse("http://localhost:3000").unwrap()); + let shared_state = Arc::new(AppState { project_metadata_service: ProjectMetadataService::new(ProjectMetadataRepository::new( Path::new(&data_dir), )), public_dir, version: VERSION, + base_url, }); // start the server diff --git a/dsp-meta/src/api/handler/health.rs b/dsp-meta/src/api/handler/health.rs index 50d9b26d..ff97b68b 100644 --- a/dsp-meta/src/api/handler/health.rs +++ b/dsp-meta/src/api/handler/health.rs @@ -1,6 +1,6 @@ use tracing::trace; -pub(crate) async fn health_handler() -> &'static str { +pub(crate) async fn health() -> &'static str { trace!("entered health_handler()"); "healthy" } diff --git a/dsp-meta/src/api/handler/mod.rs b/dsp-meta/src/api/handler/mod.rs index d67ef8a5..91f59bf3 100644 --- a/dsp-meta/src/api/handler/mod.rs +++ b/dsp-meta/src/api/handler/mod.rs @@ -1,2 +1,4 @@ pub mod health; -pub mod project_metadata_handler; +pub mod robots_txt; +pub mod sitemap_xml; +pub mod v1; diff --git a/dsp-meta/src/api/handler/robots_txt.rs b/dsp-meta/src/api/handler/robots_txt.rs new file mode 100644 index 00000000..beba0c6d --- /dev/null +++ b/dsp-meta/src/api/handler/robots_txt.rs @@ -0,0 +1,26 @@ +use std::sync::Arc; + +use axum::extract::State; +use axum::http::{Response, StatusCode}; + +use crate::app_state::AppState; +use crate::error::DspMetaError; + +pub async fn robots_txt( + State(state): State>, +) -> Result, DspMetaError> { + let sitemap_xml = state + .base_url + .join("sitemap.xml") + .expect("valid url") + .to_string(); + let response = Response::builder() + .status(StatusCode::OK) + .header("Content-Type", "text/plain") + .body(format!( + "Sitemap: {}\nUser-agent: *\nDisallow:\n", + sitemap_xml + )) + .expect("Failed to build response"); + Ok(response) +} diff --git a/dsp-meta/src/api/handler/sitemap_xml.rs b/dsp-meta/src/api/handler/sitemap_xml.rs new file mode 100644 index 00000000..8adc0110 --- /dev/null +++ b/dsp-meta/src/api/handler/sitemap_xml.rs @@ -0,0 +1,43 @@ +use std::sync::Arc; + +use axum::extract::State; +use axum::http::StatusCode; +use axum::response::Response; +use tracing::instrument; + +use crate::app_state::AppState; +use crate::domain::service::project_metadata_api_contract::ProjectMetadataApiContract; +use crate::error::DspMetaError; + +#[instrument(skip(state))] +pub async fn sitemap_xml( + State(state): State>, +) -> Result, DspMetaError> { + let base_url = state.base_url.clone(); + let mut xml = String::from("\n"); + xml.push_str("\n"); + xml.push_str( + format!( + "{}weekly\n", + base_url + ) + .as_str(), + ); + for meta in state.project_metadata_service.find_all()? { + let mut url = base_url.to_string() + "projects/"; + url.push_str(&meta.project.shortcode.as_string()); + let line = format!( + "{}weekly\n", + url + ); + xml.push_str(line.as_str()); + } + xml.push_str("\n"); + + let resp = Response::builder() + .status(StatusCode::OK) + .header("Content-Type", "application/xml") + .body(xml) + .expect("Failed to build response"); + Ok(resp) +} diff --git a/dsp-meta/src/api/handler/v1/mod.rs b/dsp-meta/src/api/handler/v1/mod.rs new file mode 100644 index 00000000..b42e1c67 --- /dev/null +++ b/dsp-meta/src/api/handler/v1/mod.rs @@ -0,0 +1 @@ +pub mod projects; diff --git a/dsp-meta/src/api/handler/project_metadata_handler.rs b/dsp-meta/src/api/handler/v1/projects/handlers.rs similarity index 91% rename from dsp-meta/src/api/handler/project_metadata_handler.rs rename to dsp-meta/src/api/handler/v1/projects/handlers.rs index eb1fea54..85e52e1f 100644 --- a/dsp-meta/src/api/handler/project_metadata_handler.rs +++ b/dsp-meta/src/api/handler/v1/projects/handlers.rs @@ -6,7 +6,9 @@ use axum::response::{IntoResponse, Response}; use axum::Json; use tracing::{instrument, trace}; -use crate::api::model::project_metadata_dto::{ProjectMetadataDto, ProjectMetadataWithInfoDto}; +use crate::api::handler::v1::projects::responses::{ + ProjectMetadataDto, ProjectMetadataWithInfoDto, +}; use crate::app_state::AppState; use crate::domain::model::draft_model::Shortcode; use crate::domain::service::project_metadata_api_contract::ProjectMetadataApiContract; @@ -18,7 +20,7 @@ use crate::error::DspMetaError; /// /// TODO: Add error handling with correct status codes #[instrument(skip(state))] -pub async fn get_project_metadata_by_shortcode( +pub async fn get_by_shortcode( Path(shortcode): Path, State(state): State>, ) -> Result { @@ -37,7 +39,7 @@ pub async fn get_project_metadata_by_shortcode( } #[instrument(skip(state))] -pub async fn get_all_project_metadata( +pub async fn get_by_page_and_filter( State(state): State>, pagination: Option>, filter: Option>, diff --git a/dsp-meta/src/api/handler/v1/projects/mod.rs b/dsp-meta/src/api/handler/v1/projects/mod.rs new file mode 100644 index 00000000..6108acf9 --- /dev/null +++ b/dsp-meta/src/api/handler/v1/projects/mod.rs @@ -0,0 +1,2 @@ +pub mod handlers; +pub mod responses; diff --git a/dsp-meta/src/api/model/project_metadata_dto.rs b/dsp-meta/src/api/handler/v1/projects/responses.rs similarity index 100% rename from dsp-meta/src/api/model/project_metadata_dto.rs rename to dsp-meta/src/api/handler/v1/projects/responses.rs diff --git a/dsp-meta/src/api/mod.rs b/dsp-meta/src/api/mod.rs index 1c78b6d7..f984e2d6 100644 --- a/dsp-meta/src/api/mod.rs +++ b/dsp-meta/src/api/mod.rs @@ -1,4 +1,3 @@ pub mod convert; mod handler; -mod model; pub mod router; diff --git a/dsp-meta/src/api/model/mod.rs b/dsp-meta/src/api/model/mod.rs deleted file mode 100644 index 97b864c9..00000000 --- a/dsp-meta/src/api/model/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod project_metadata_dto; -pub mod project_metadata_graph_dto; diff --git a/dsp-meta/src/api/model/project_metadata_graph_dto.rs b/dsp-meta/src/api/model/project_metadata_graph_dto.rs deleted file mode 100644 index 624541bf..00000000 --- a/dsp-meta/src/api/model/project_metadata_graph_dto.rs +++ /dev/null @@ -1,18 +0,0 @@ -use axum::http::StatusCode; -use axum::response::{IntoResponse, Response}; - -use crate::api::convert::rdf::project_metadata::ProjectMetadataGraph; - -pub struct ProjectMetadataGraphDto(pub Option); - -/// Convert `ProjectMetadataGraph` into a response. -impl IntoResponse for ProjectMetadataGraphDto { - fn into_response(self) -> Response { - match self.0 { - Some(metadata_graph) => { - (StatusCode::OK, metadata_graph.to_turtle_string()).into_response() - } - None => StatusCode::NOT_FOUND.into_response(), - } - } -} diff --git a/dsp-meta/src/api/router.rs b/dsp-meta/src/api/router.rs index 14fad46b..938edb4f 100644 --- a/dsp-meta/src/api/router.rs +++ b/dsp-meta/src/api/router.rs @@ -13,7 +13,7 @@ use tower_http::services::{ServeDir, ServeFile}; use tower_http::trace::TraceLayer; use tracing::{error, info_span, warn, Span}; -use crate::api::handler::{health, project_metadata_handler}; +use crate::api::handler::{health, robots_txt, sitemap_xml, v1}; use crate::app_state::AppState; /// Having a function that produces our router makes it easy to call it from tests @@ -27,14 +27,16 @@ pub fn router(shared_state: Arc) -> Router { Router::new() .route( "/api/v1/projects", - get(project_metadata_handler::get_all_project_metadata), + get(v1::projects::handlers::get_by_page_and_filter), ) .route( "/api/v1/projects/:shortcode", - get(project_metadata_handler::get_project_metadata_by_shortcode), + get(v1::projects::handlers::get_by_shortcode), ) - .route("/health", get(health::health_handler)) + .route("/health", get(health::health)) .route("/version.txt", get(shared_state.version)) + .route("/robots.txt", get(robots_txt::robots_txt)) + .route("/sitemap.xml", get(sitemap_xml::sitemap_xml)) .fallback_service( ServeDir::new(shared_state.public_dir.as_str()).fallback(ServeFile::new(format!( "{}/index.html", @@ -84,9 +86,12 @@ mod tests { use axum::body::Body; use axum::http::StatusCode; - use http_body_util::BodyExt; // for `collect` - use tower::ServiceExt; // for `oneshot` and `ready` + use http_body_util::BodyExt; + // for `collect` + use tower::ServiceExt; + use url::Url; + // for `oneshot` and `ready` use super::*; use crate::domain::service::project_metadata_service::ProjectMetadataService; use crate::repo::service::project_metadata_repository::ProjectMetadataRepository; @@ -101,6 +106,7 @@ mod tests { )), public_dir: "".to_string(), version: "", + base_url: Url::parse("http://localhost:3000").unwrap(), }); let router = router(shared_state); @@ -133,6 +139,7 @@ mod tests { )), public_dir: "".to_string(), version: "", + base_url: Url::parse("http://localhost:3000").unwrap(), }); let router = router(shared_state); diff --git a/dsp-meta/src/app_state.rs b/dsp-meta/src/app_state.rs index cb4ad636..868ce50a 100644 --- a/dsp-meta/src/app_state.rs +++ b/dsp-meta/src/app_state.rs @@ -1,3 +1,5 @@ +use url::Url; + use crate::domain::service::project_metadata_service::ProjectMetadataService; use crate::repo::service::project_metadata_repository::ProjectMetadataRepository; @@ -6,4 +8,5 @@ pub struct AppState { pub project_metadata_service: ProjectMetadataService, pub public_dir: String, pub version: &'static str, + pub base_url: Url, } diff --git a/dsp-meta/src/domain/service/project_metadata_api_contract.rs b/dsp-meta/src/domain/service/project_metadata_api_contract.rs index fc3b577a..2c31d86c 100644 --- a/dsp-meta/src/domain/service/project_metadata_api_contract.rs +++ b/dsp-meta/src/domain/service/project_metadata_api_contract.rs @@ -4,6 +4,7 @@ use crate::error::DspMetaError; pub trait ProjectMetadataApiContract { fn find_by_id(&self, id: &Shortcode) -> Result, DspMetaError>; + fn find_all(&self) -> Result, DspMetaError>; fn find( &self, filter: &Filter, diff --git a/dsp-meta/src/domain/service/project_metadata_service.rs b/dsp-meta/src/domain/service/project_metadata_service.rs index be375f0f..32519d10 100644 --- a/dsp-meta/src/domain/service/project_metadata_service.rs +++ b/dsp-meta/src/domain/service/project_metadata_service.rs @@ -28,6 +28,10 @@ where self.repo.find_by_id(id) } + fn find_all(&self) -> Result, DspMetaError> { + self.repo.find_all() + } + #[instrument(skip(self))] fn find( &self, diff --git a/dsp-meta/src/domain/service/repository_contract.rs b/dsp-meta/src/domain/service/repository_contract.rs index 4dd15460..284ae79c 100644 --- a/dsp-meta/src/domain/service/repository_contract.rs +++ b/dsp-meta/src/domain/service/repository_contract.rs @@ -34,9 +34,12 @@ pub trait RepositoryContract { /// If the entity does not exist, `None` is returned. fn find_by_id(&self, id: &Id) -> Result, Error>; - /// Returns all entities. + /// Returns all entities with filter and pagination. fn find(&self, filter: &Filter, pagination: &Pagination) -> Result, Error>; + /// Returns all entities. + fn find_all(&self) -> Result, Error>; + /// Returns the number of entities. fn count(&self) -> Result; } diff --git a/dsp-meta/src/repo/service/project_metadata_repository.rs b/dsp-meta/src/repo/service/project_metadata_repository.rs index 7c8f90c9..815c8793 100644 --- a/dsp-meta/src/repo/service/project_metadata_repository.rs +++ b/dsp-meta/src/repo/service/project_metadata_repository.rs @@ -106,6 +106,12 @@ impl RepositoryContract for ProjectMetad Ok(Page { data, total }) } + fn find_all(&self) -> Result, DspMetaError> { + let db = self.db.read().unwrap(); + let v = db.iter().map(|(_, v)| v.clone()).collect(); + Ok(v) + } + fn count(&self) -> Result { let db = self.db.read().unwrap(); Ok(db.len()) diff --git a/web-frontend/src/Snackbar.svelte b/web-frontend/src/Snackbar.svelte index 3f786c12..eec1be5f 100644 --- a/web-frontend/src/Snackbar.svelte +++ b/web-frontend/src/Snackbar.svelte @@ -18,7 +18,7 @@ }) -
+
{$handleSnackbar.message}
diff --git a/web-frontend/src/project-page/ProjectPage.svelte b/web-frontend/src/project-page/ProjectPage.svelte index d3ff1446..d64c1ca8 100644 --- a/web-frontend/src/project-page/ProjectPage.svelte +++ b/web-frontend/src/project-page/ProjectPage.svelte @@ -94,7 +94,7 @@ {/if} {#if $projectMetadata} -
+
{#if mobileResolution}
{/if} -
+
{#if $pagedResults && $pagedResults.length} {#each $pagedResults as project}