feat: display search results
This commit is contained in:
parent
6cc56919e3
commit
cd797fba83
7 changed files with 168 additions and 28 deletions
|
@ -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<Context>,
|
||||
}
|
||||
|
||||
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<Repository>,
|
||||
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<OptionalPage> for Page {
|
|||
}
|
||||
}
|
||||
|
||||
#[get(path = "PAGES.home")]
|
||||
pub async fn home(
|
||||
#[get(path = "PAGES.explore")]
|
||||
pub async fn explore(
|
||||
q: web::Query<OptionalPage>,
|
||||
ctx: WebCtx,
|
||||
db: WebDB,
|
||||
) -> PageResult<impl Responder, HomePage> {
|
||||
) -> PageResult<impl Responder, ExplorePage> {
|
||||
let q = q.into_inner();
|
||||
async fn _home(_ctx: &ArcCtx, db: &BoxDB, p: &Page) -> ServiceResult<Vec<db_core::Repository>> {
|
||||
async fn _explore(
|
||||
_ctx: &ArcCtx,
|
||||
db: &BoxDB,
|
||||
p: &Page,
|
||||
) -> ServiceResult<Vec<db_core::Repository>> {
|
||||
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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
109
src/pages/chart/search.rs
Normal file
109
src/pages/chart/search.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* ForgeFlux StarChart - A federated software forge spider
|
||||
* Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<Context>,
|
||||
}
|
||||
|
||||
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<Repository>,
|
||||
}
|
||||
|
||||
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<crate::search::SearchRepositoryReq>,
|
||||
ctx: WebCtx,
|
||||
db: WebDB,
|
||||
) -> PageResult<impl Responder, SearchPage> {
|
||||
async fn _search(
|
||||
ctx: &ArcCtx,
|
||||
db: &BoxDB,
|
||||
query: String,
|
||||
) -> ServiceResult<Vec<db_core::Repository>> {
|
||||
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))
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
{% extends 'base' %}
|
||||
{% block title %} {{ title }} {% endblock %}
|
||||
{% block nav %} {% include "pub_nav" %} {% endblock %}
|
||||
|
|
11
templates/pages/chart/search.html
Normal file
11
templates/pages/chart/search.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% extends 'base' %}
|
||||
{% block title %} {{ title }} {% endblock %}
|
||||
{% block nav %} {% include "pub_nav" %} {% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<section class="main">
|
||||
{% for repository in payload.repos %}
|
||||
{% include "repo_info" %}
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endblock %}
|
Loading…
Add table
Reference in a new issue