diff --git a/src/pages/chart/home.rs b/src/pages/chart/home.rs index 396e879..8b3b775 100644 --- a/src/pages/chart/home.rs +++ b/src/pages/chart/home.rs @@ -32,15 +32,17 @@ use crate::*; pub use crate::pages::*; pub const TITLE: &str = "Explore"; -pub const HOME: TemplateFile = TemplateFile::new("home_page", "pages/chart/index.html"); +pub const EXPLORE: TemplateFile = TemplateFile::new("explore_page", "pages/chart/index.html"); pub const REPO_INFO: TemplateFile = TemplateFile::new("repo_info", "pages/chart/components/repo_info.html"); -pub struct HomePage { +pub const SEARCH_BAR: TemplateFile = TemplateFile::new("search_bar", "components/nav/search.html"); + +pub struct ExplorePage { ctx: RefCell, } -impl CtxError for HomePage { +impl CtxError for ExplorePage { fn with_error(&self, e: &ReadableError) -> String { self.ctx.borrow_mut().insert(ERROR_KEY, e); self.render() @@ -48,14 +50,14 @@ impl CtxError for HomePage { } #[derive(Clone, Debug, PartialEq, Eq, Default, Deserialize, Serialize)] -pub struct HomePagePayload { +pub struct ExplorePagePayload { pub repos: Vec, pub next_page: String, pub prev_page: String, } -impl HomePage { - fn new(settings: &Settings, payload: &HomePagePayload) -> Self { +impl ExplorePage { + fn new(settings: &Settings, payload: &ExplorePagePayload) -> Self { let ctx = RefCell::new(ctx(settings)); ctx.borrow_mut().insert(TITLE_KEY, TITLE); ctx.borrow_mut().insert(PAYLOAD_KEY, payload); @@ -63,17 +65,17 @@ impl HomePage { } pub fn render(&self) -> String { - TEMPLATES.render(HOME.name, &self.ctx.borrow()).unwrap() + TEMPLATES.render(EXPLORE.name, &self.ctx.borrow()).unwrap() } - pub fn page(s: &Settings, payload: &HomePagePayload) -> String { + pub fn page(s: &Settings, payload: &ExplorePagePayload) -> String { let p = Self::new(s, payload); p.render() } } pub fn services(cfg: &mut web::ServiceConfig) { - cfg.service(home); + cfg.service(explore); } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -109,14 +111,18 @@ impl From for Page { } } -#[get(path = "PAGES.home")] -pub async fn home( +#[get(path = "PAGES.explore")] +pub async fn explore( q: web::Query, ctx: WebCtx, db: WebDB, -) -> PageResult { +) -> PageResult { let q = q.into_inner(); - async fn _home(_ctx: &ArcCtx, db: &BoxDB, p: &Page) -> ServiceResult> { + async fn _explore( + _ctx: &ArcCtx, + db: &BoxDB, + p: &Page, + ) -> ServiceResult> { const LIMIT: u32 = 10; let offset = p.page * LIMIT; let responses = db.get_all_repositories(offset, LIMIT).await?; @@ -124,17 +130,17 @@ pub async fn home( } let q: Page = q.into(); - let repos = _home(&ctx, &db, &q).await.map_err(|e| { - let x = HomePagePayload::default(); - PageError::new(HomePage::new(&ctx.settings, &x), e) + let repos = _explore(&ctx, &db, &q).await.map_err(|e| { + let x = ExplorePagePayload::default(); + PageError::new(ExplorePage::new(&ctx.settings, &x), e) })?; - let payload = HomePagePayload { + let payload = ExplorePagePayload { repos, - next_page: PAGES.home_next(q.next()), - prev_page: PAGES.home_next(q.prev()), + next_page: PAGES.explore_next(q.next()), + prev_page: PAGES.explore_next(q.prev()), }; - let page = HomePage::page(&ctx.settings, &payload); + let page = ExplorePage::page(&ctx.settings, &payload); let html = ContentType::html(); Ok(HttpResponse::Ok().content_type(html).body(page)) diff --git a/src/pages/chart/mod.rs b/src/pages/chart/mod.rs index 7e1a82d..d659e14 100644 --- a/src/pages/chart/mod.rs +++ b/src/pages/chart/mod.rs @@ -17,16 +17,22 @@ */ pub mod home; -pub use home::HOME; +pub mod search; +pub use home::EXPLORE; pub use home::REPO_INFO; +pub use home::SEARCH_BAR; +pub use search::SEARCH_RESULTS; pub use super::{ctx, TemplateFile, ERROR_KEY, PAGES, PAYLOAD_KEY, TITLE_KEY}; pub fn register_templates(t: &mut tera::Tera) { - HOME.register(t).expect(HOME.name); + EXPLORE.register(t).expect(EXPLORE.name); REPO_INFO.register(t).expect(REPO_INFO.name); + SEARCH_BAR.register(t).expect(SEARCH_BAR.name); + SEARCH_RESULTS.register(t).expect(SEARCH_RESULTS.name); } pub fn services(cfg: &mut actix_web::web::ServiceConfig) { home::services(cfg); + search::services(cfg); } diff --git a/src/pages/chart/search.rs b/src/pages/chart/search.rs new file mode 100644 index 0000000..8fc9096 --- /dev/null +++ b/src/pages/chart/search.rs @@ -0,0 +1,109 @@ +/* + * ForgeFlux StarChart - A federated software forge spider + * Copyright © 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_web::http::header::ContentType; +use actix_web::{HttpResponse, Responder}; +use actix_web_codegen_const_routes::post; +use serde::{Deserialize, Serialize}; +use std::cell::RefCell; +use tera::Context; + +use db_core::prelude::*; + +use crate::errors::ServiceResult; +use crate::pages::errors::*; +use crate::settings::Settings; +use crate::*; + +pub use crate::pages::*; + +pub const TITLE: &str = "Search"; +pub const SEARCH_QUERY_KEY: &str = "search_query"; +pub const SEARCH_RESULTS: TemplateFile = + TemplateFile::new("search_results", "pages/chart/search.html"); + +pub struct SearchPage { + ctx: RefCell, +} + +impl CtxError for SearchPage { + fn with_error(&self, e: &ReadableError) -> String { + self.ctx.borrow_mut().insert(ERROR_KEY, e); + self.render() + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Default, Deserialize, Serialize)] +pub struct SearchPagePayload { + pub repos: Vec, +} + +impl SearchPage { + fn new(settings: &Settings, payload: &SearchPagePayload, search_query: Option<&str>) -> Self { + let ctx = RefCell::new(ctx(settings)); + ctx.borrow_mut().insert(TITLE_KEY, TITLE); + ctx.borrow_mut().insert(PAYLOAD_KEY, payload); + if let Some(search_query) = search_query { + ctx.borrow_mut().insert(SEARCH_QUERY_KEY, search_query); + } + Self { ctx } + } + + pub fn render(&self) -> String { + TEMPLATES + .render(SEARCH_RESULTS.name, &self.ctx.borrow()) + .unwrap() + } + + pub fn page(s: &Settings, payload: &SearchPagePayload, search_query: Option<&str>) -> String { + let p = Self::new(s, payload, search_query); + p.render() + } +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(search); +} + +#[post(path = "PAGES.search")] +pub async fn search( + payload: web::Form, + ctx: WebCtx, + db: WebDB, +) -> PageResult { + async fn _search( + ctx: &ArcCtx, + db: &BoxDB, + query: String, + ) -> ServiceResult> { + let responses = ctx.search_repository(&db, query).await?; + + Ok(responses) + } + + let query = payload.into_inner().query; + let repos = _search(&ctx, &db, query.clone()).await.map_err(|e| { + let x = SearchPagePayload::default(); + PageError::new(SearchPage::new(&ctx.settings, &x, Some(&query)), e) + })?; + + let payload = SearchPagePayload { repos }; + let page = SearchPage::page(&ctx.settings, &payload, Some(&query)); + + let html = ContentType::html(); + Ok(HttpResponse::Ok().content_type(html).body(page)) +} diff --git a/src/pages/mod.rs b/src/pages/mod.rs index 9a771bc..02f6ef5 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -143,7 +143,7 @@ mod tests { PUB_NAV, auth::AUTH_CHALLENGE, auth::AUTH_ADD, - chart::HOME, + chart::EXPLORE, // auth::AUTH_BASE, // auth::login::LOGIN, // auth::register::REGISTER, diff --git a/src/pages/routes.rs b/src/pages/routes.rs index 392183f..6c1ad64 100644 --- a/src/pages/routes.rs +++ b/src/pages/routes.rs @@ -25,6 +25,8 @@ pub const PAGES: Pages = Pages::new(); pub struct Pages { /// home page pub home: &'static str, + pub explore: &'static str, + pub search: &'static str, /// auth routes pub auth: Auth, } @@ -32,13 +34,20 @@ pub struct Pages { impl Pages { /// create new instance of Routes const fn new() -> Pages { - let home = "/"; + let explore = "/explore"; + let home = explore; + let search = "/search"; let auth = Auth::new(); - Pages { home, auth } + Pages { + home, + auth, + explore, + search, + } } - pub fn home_next(&self, page: u32) -> String { - format!("{}?page={page}", self.home) + pub fn explore_next(&self, page: u32) -> String { + format!("{}?page={page}", self.explore) } } diff --git a/templates/pages/chart/index.html b/templates/pages/chart/index.html index dc347c8..b9d5971 100644 --- a/templates/pages/chart/index.html +++ b/templates/pages/chart/index.html @@ -1,4 +1,3 @@ - {% extends 'base' %} {% block title %} {{ title }} {% endblock %} {% block nav %} {% include "pub_nav" %} {% endblock %} diff --git a/templates/pages/chart/search.html b/templates/pages/chart/search.html new file mode 100644 index 0000000..e6a3f2c --- /dev/null +++ b/templates/pages/chart/search.html @@ -0,0 +1,11 @@ +{% extends 'base' %} +{% block title %} {{ title }} {% endblock %} +{% block nav %} {% include "pub_nav" %} {% endblock %} + +{% block main %} +
+ {% for repository in payload.repos %} + {% include "repo_info" %} + {% endfor %} +
+{% endblock %}