feat: display search results

This commit is contained in:
Aravinth Manivannan 2023-03-04 18:59:10 +05:30
parent 6cc56919e3
commit cd797fba83
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88
7 changed files with 168 additions and 28 deletions

View file

@ -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))

View file

@ -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
View 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))
}

View file

@ -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,

View file

@ -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)
}
}

View file

@ -1,4 +1,3 @@
{% extends 'base' %}
{% block title %} {{ title }} {% endblock %}
{% block nav %} {% include "pub_nav" %} {% endblock %}

View 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 %}