Merge branch 'rolling' into PERF/384_optimize-the-performance-of-fetching-results-in-the-websurfx-search-engine-backend
This commit is contained in:
commit
ae9fa5b388
42 changed files with 766 additions and 532 deletions
|
@ -3,7 +3,6 @@
|
|||
|
||||
use crate::handler::paths::{file_path, FileType};
|
||||
|
||||
use crate::models::engine_models::{EngineError, EngineHandler};
|
||||
use crate::models::parser_models::{AggregatorConfig, RateLimiter, Style};
|
||||
use log::LevelFilter;
|
||||
use mlua::Lua;
|
||||
|
@ -29,7 +28,7 @@ pub struct Config {
|
|||
/// It stores the option to whether enable or disable debug mode.
|
||||
pub debug: bool,
|
||||
/// It stores all the engine names that were enabled by the user.
|
||||
pub upstream_search_engines: Vec<EngineHandler>,
|
||||
pub upstream_search_engines: HashMap<String, bool>,
|
||||
/// It stores the time (secs) which controls the server request timeout.
|
||||
pub request_timeout: u8,
|
||||
/// It stores the number of threads which controls the app will use to run.
|
||||
|
@ -109,11 +108,7 @@ impl Config {
|
|||
logging,
|
||||
debug,
|
||||
upstream_search_engines: globals
|
||||
.get::<_, HashMap<String, bool>>("upstream_search_engines")?
|
||||
.into_iter()
|
||||
.filter_map(|(key, value)| value.then_some(key))
|
||||
.map(|engine| EngineHandler::new(&engine))
|
||||
.collect::<Result<Vec<EngineHandler>, error_stack::Report<EngineError>>>()?,
|
||||
.get::<_, HashMap<String, bool>>("upstream_search_engines")?,
|
||||
request_timeout: globals.get::<_, u8>("request_timeout")?,
|
||||
threads,
|
||||
rate_limiter: RateLimiter {
|
||||
|
|
11
src/lib.rs
11
src/lib.rs
|
@ -12,6 +12,7 @@ pub mod handler;
|
|||
pub mod models;
|
||||
pub mod results;
|
||||
pub mod server;
|
||||
pub mod templates;
|
||||
|
||||
use std::net::TcpListener;
|
||||
|
||||
|
@ -23,7 +24,6 @@ use actix_governor::{Governor, GovernorConfigBuilder};
|
|||
use actix_web::{dev::Server, http::header, middleware::Logger, web, App, HttpServer};
|
||||
use cache::cacher::{Cache, SharedCache};
|
||||
use config::parser::Config;
|
||||
use handlebars::Handlebars;
|
||||
use handler::paths::{file_path, FileType};
|
||||
|
||||
/// Runs the web server on the provided TCP listener and returns a `Server` instance.
|
||||
|
@ -48,16 +48,8 @@ use handler::paths::{file_path, FileType};
|
|||
/// let server = run(listener,config,cache).expect("Failed to start server");
|
||||
/// ```
|
||||
pub fn run(listener: TcpListener, config: Config, cache: Cache) -> std::io::Result<Server> {
|
||||
let mut handlebars: Handlebars<'_> = Handlebars::new();
|
||||
|
||||
let public_folder_path: &str = file_path(FileType::Theme)?;
|
||||
|
||||
handlebars
|
||||
.register_templates_directory(".html", format!("{}/templates", public_folder_path))
|
||||
.unwrap();
|
||||
|
||||
let handlebars_ref: web::Data<Handlebars<'_>> = web::Data::new(handlebars);
|
||||
|
||||
let cloned_config_threads_opt: u8 = config.threads;
|
||||
|
||||
let cache = web::Data::new(SharedCache::new(cache));
|
||||
|
@ -75,7 +67,6 @@ pub fn run(listener: TcpListener, config: Config, cache: Cache) -> std::io::Resu
|
|||
|
||||
App::new()
|
||||
.wrap(Logger::default()) // added logging middleware for logging.
|
||||
.app_data(handlebars_ref.clone())
|
||||
.app_data(web::Data::new(config.clone()))
|
||||
.app_data(cache.clone())
|
||||
.wrap(cors)
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
//! This module provides public models for handling, storing and serializing of search results
|
||||
//! data scraped from the upstream search engines.
|
||||
|
||||
use super::engine_models::EngineError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::{engine_models::EngineError, parser_models::Style};
|
||||
|
||||
/// A named struct to store the raw scraped search results scraped search results from the
|
||||
/// upstream search engines before aggregating it.It derives the Clone trait which is needed
|
||||
/// to write idiomatic rust using `Iterators`.
|
||||
|
@ -109,10 +108,6 @@ impl EngineErrorInfo {
|
|||
pub struct SearchResults {
|
||||
/// Stores the individual serializable `SearchResult` struct into a vector of
|
||||
pub results: Vec<SearchResult>,
|
||||
/// Stores the current pages search query `q` provided in the search url.
|
||||
pub page_query: String,
|
||||
/// Stores the theming options for the website.
|
||||
pub style: Style,
|
||||
/// Stores the information on which engines failed with their engine name
|
||||
/// and the type of error that caused it.
|
||||
pub engine_errors_info: Vec<EngineErrorInfo>,
|
||||
|
@ -142,15 +137,9 @@ impl SearchResults {
|
|||
/// the search url.
|
||||
/// * `engine_errors_info` - Takes an array of structs which contains information regarding
|
||||
/// which engines failed with their names, reason and their severity color name.
|
||||
pub fn new(
|
||||
results: Vec<SearchResult>,
|
||||
page_query: &str,
|
||||
engine_errors_info: &[EngineErrorInfo],
|
||||
) -> Self {
|
||||
pub fn new(results: Vec<SearchResult>, engine_errors_info: &[EngineErrorInfo]) -> Self {
|
||||
Self {
|
||||
results,
|
||||
page_query: page_query.to_owned(),
|
||||
style: Style::default(),
|
||||
engine_errors_info: engine_errors_info.to_owned(),
|
||||
disallowed: Default::default(),
|
||||
filtered: Default::default(),
|
||||
|
@ -159,21 +148,11 @@ impl SearchResults {
|
|||
}
|
||||
}
|
||||
|
||||
/// A setter function to add website style to the return search results.
|
||||
pub fn add_style(&mut self, style: &Style) {
|
||||
self.style = style.clone();
|
||||
}
|
||||
|
||||
/// A setter function that sets disallowed to true.
|
||||
pub fn set_disallowed(&mut self) {
|
||||
self.disallowed = true;
|
||||
}
|
||||
|
||||
/// A setter function to set the current page search query.
|
||||
pub fn set_page_query(&mut self, page: &str) {
|
||||
self.page_query = page.to_owned();
|
||||
}
|
||||
|
||||
/// A setter function that sets the filtered to true.
|
||||
pub fn set_filtered(&mut self) {
|
||||
self.filtered = true;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
//! This module provides public models for handling, storing and serializing parsed config file
|
||||
//! options from config.lua by grouping them together.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A named struct which stores,deserializes, serializes and groups the parsed config file options
|
||||
/// of theme and colorscheme names into the Style struct which derives the `Clone`, `Serialize`
|
||||
/// and Deserialize traits where the `Clone` trait is derived for allowing the struct to be
|
||||
|
@ -12,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||
/// order to allow the deserializing the json back to struct in aggregate function in
|
||||
/// aggregator.rs and create a new struct out of it and then serialize it back to json and pass
|
||||
/// it to the template files.
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Style {
|
||||
/// It stores the parsed theme option used to set a theme for the website.
|
||||
pub theme: String,
|
||||
|
|
|
@ -180,7 +180,7 @@ pub async fn aggregate(
|
|||
|
||||
let results: Vec<SearchResult> = result_map.into_values().collect();
|
||||
|
||||
Ok(SearchResults::new(results, query, &engine_errors_info))
|
||||
Ok(SearchResults::new(results, &engine_errors_info))
|
||||
}
|
||||
|
||||
/// Filters a map of search results using a list of regex patterns.
|
||||
|
|
|
@ -7,30 +7,30 @@ use crate::{
|
|||
handler::paths::{file_path, FileType},
|
||||
};
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||
use handlebars::Handlebars;
|
||||
use std::fs::read_to_string;
|
||||
|
||||
/// Handles the route of index page or main page of the `websurfx` meta search engine website.
|
||||
#[get("/")]
|
||||
pub async fn index(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("index", &config.style).unwrap();
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
pub async fn index(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
Ok(HttpResponse::Ok().body(
|
||||
crate::templates::views::index::index(&config.style.colorscheme, &config.style.theme).0,
|
||||
))
|
||||
}
|
||||
|
||||
/// Handles the route of any other accessed route/page which is not provided by the
|
||||
/// website essentially the 404 error page.
|
||||
pub async fn not_found(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("404", &config.style)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body(page_content))
|
||||
.body(
|
||||
crate::templates::views::not_found::not_found(
|
||||
&config.style.colorscheme,
|
||||
&config.style.theme,
|
||||
)
|
||||
.0,
|
||||
))
|
||||
}
|
||||
|
||||
/// Handles the route of robots.txt page of the `websurfx` meta search engine website.
|
||||
|
@ -45,20 +45,26 @@ pub async fn robots_data(_req: HttpRequest) -> Result<HttpResponse, Box<dyn std:
|
|||
|
||||
/// Handles the route of about page of the `websurfx` meta search engine website.
|
||||
#[get("/about")]
|
||||
pub async fn about(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("about", &config.style)?;
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
pub async fn about(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
Ok(HttpResponse::Ok().body(
|
||||
crate::templates::views::about::about(&config.style.colorscheme, &config.style.theme).0,
|
||||
))
|
||||
}
|
||||
|
||||
/// Handles the route of settings page of the `websurfx` meta search engine website.
|
||||
#[get("/settings")]
|
||||
pub async fn settings(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("settings", &config.style)?;
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
Ok(HttpResponse::Ok().body(
|
||||
crate::templates::views::settings::settings(
|
||||
&config.style.colorscheme,
|
||||
&config.style.theme,
|
||||
&config
|
||||
.upstream_search_engines
|
||||
.keys()
|
||||
.collect::<Vec<&String>>(),
|
||||
)?
|
||||
.0,
|
||||
))
|
||||
}
|
||||
|
|
|
@ -6,13 +6,12 @@ use crate::{
|
|||
handler::paths::{file_path, FileType},
|
||||
models::{
|
||||
aggregation_models::SearchResults,
|
||||
engine_models::EngineHandler,
|
||||
engine_models::{EngineError, EngineHandler},
|
||||
server_models::{Cookie, SearchParams},
|
||||
},
|
||||
results::aggregator::aggregate,
|
||||
};
|
||||
use actix_web::{get, web, HttpRequest, HttpResponse};
|
||||
use handlebars::Handlebars;
|
||||
use regex::Regex;
|
||||
use std::{
|
||||
fs::File,
|
||||
|
@ -20,19 +19,6 @@ use std::{
|
|||
};
|
||||
use tokio::join;
|
||||
|
||||
/// Handles the route of any other accessed route/page which is not provided by the
|
||||
/// website essentially the 404 error page.
|
||||
pub async fn not_found(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
config: web::Data<Config>,
|
||||
) -> Result<HttpResponse, Box<dyn std::error::Error>> {
|
||||
let page_content: String = hbs.render("404", &config.style)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("text/html; charset=utf-8")
|
||||
.body(page_content))
|
||||
}
|
||||
|
||||
/// Handles the route of search page of the `websurfx` meta search engine website and it takes
|
||||
/// two search url parameters `q` and `page` where `page` parameter is optional.
|
||||
///
|
||||
|
@ -49,7 +35,6 @@ pub async fn not_found(
|
|||
/// ```
|
||||
#[get("/search")]
|
||||
pub async fn search(
|
||||
hbs: web::Data<Handlebars<'_>>,
|
||||
req: HttpRequest,
|
||||
config: web::Data<Config>,
|
||||
cache: web::Data<SharedCache>,
|
||||
|
@ -58,7 +43,7 @@ pub async fn search(
|
|||
match ¶ms.q {
|
||||
Some(query) => {
|
||||
if query.trim().is_empty() {
|
||||
return Ok(HttpResponse::Found()
|
||||
return Ok(HttpResponse::TemporaryRedirect()
|
||||
.insert_header(("location", "/"))
|
||||
.finish());
|
||||
}
|
||||
|
@ -112,10 +97,17 @@ pub async fn search(
|
|||
)
|
||||
);
|
||||
|
||||
let page_content: String = hbs.render("search", &results?)?;
|
||||
Ok(HttpResponse::Ok().body(page_content))
|
||||
Ok(HttpResponse::Ok().body(
|
||||
crate::templates::views::search::search(
|
||||
&config.style.colorscheme,
|
||||
&config.style.theme,
|
||||
query,
|
||||
&results?,
|
||||
)
|
||||
.0,
|
||||
))
|
||||
}
|
||||
None => Ok(HttpResponse::Found()
|
||||
None => Ok(HttpResponse::TemporaryRedirect()
|
||||
.insert_header(("location", "/"))
|
||||
.finish()),
|
||||
}
|
||||
|
@ -171,8 +163,6 @@ async fn results(
|
|||
|
||||
if _flag {
|
||||
results.set_disallowed();
|
||||
results.add_style(&config.style);
|
||||
results.set_page_query(query);
|
||||
cache.cache_results(&results, &url).await?;
|
||||
results.set_safe_search_level(safe_search_level);
|
||||
return Ok(results);
|
||||
|
@ -221,23 +211,27 @@ async fn results(
|
|||
true => {
|
||||
let mut search_results = SearchResults::default();
|
||||
search_results.set_no_engines_selected();
|
||||
search_results.set_page_query(query);
|
||||
search_results
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
aggregate(
|
||||
query,
|
||||
page,
|
||||
config.aggregator.random_delay,
|
||||
config.debug,
|
||||
&config.upstream_search_engines,
|
||||
config.request_timeout,
|
||||
safe_search_level,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
None => aggregate(
|
||||
query,
|
||||
page,
|
||||
config.aggregator.random_delay,
|
||||
config.debug,
|
||||
&config
|
||||
.upstream_search_engines
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter_map(|(key, value)| value.then_some(key))
|
||||
.map(|engine| EngineHandler::new(&engine))
|
||||
.collect::<Result<Vec<EngineHandler>, error_stack::Report<EngineError>>>(
|
||||
)?,
|
||||
config.request_timeout,
|
||||
safe_search_level,
|
||||
)
|
||||
.await?,
|
||||
};
|
||||
if results.engine_errors_info().is_empty()
|
||||
&& results.results().is_empty()
|
||||
|
@ -245,7 +239,6 @@ async fn results(
|
|||
{
|
||||
results.set_filtered();
|
||||
}
|
||||
results.add_style(&config.style);
|
||||
cache
|
||||
.cache_results(&results, &(format!("{url}{safe_search_level}")))
|
||||
.await?;
|
||||
|
|
5
src/templates/mod.rs
Normal file
5
src/templates/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
//! This module provides other modules to handle both the view and its partials for the `websurfx`
|
||||
//! search engine frontend.
|
||||
|
||||
mod partials;
|
||||
pub mod views;
|
21
src/templates/partials/bar.rs
Normal file
21
src/templates/partials/bar.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
//! A module that handles `bar` partial for the `search_bar` partial and the home/index/main page in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
|
||||
/// A functions that handles the html code for the bar for the `search_bar` partial and the
|
||||
/// home/index/main page in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `query` - It takes the current search query provided by user as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html code for the search bar as a result.
|
||||
pub fn bar(query: &str) -> Markup {
|
||||
html!(
|
||||
(PreEscaped("<div class=\"search_bar\">"))
|
||||
input type="search" name="search-box" value=(query) placeholder="Type to search";
|
||||
button type="submit" onclick="searchWeb()"{"search"}
|
||||
)
|
||||
}
|
29
src/templates/partials/footer.rs
Normal file
29
src/templates/partials/footer.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
//! A module that handles the footer for all the pages in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
|
||||
/// A functions that handles the html code for the footer for all the pages in the search engine
|
||||
/// frontend.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html code for the footer as a result.
|
||||
pub fn footer() -> Markup {
|
||||
html!(
|
||||
footer{
|
||||
div{
|
||||
span{"Powered By "b{"Websurfx"}}span{"-"}span{"a lightening fast, privacy respecting, secure meta
|
||||
search engine"}
|
||||
}
|
||||
div{
|
||||
ul{
|
||||
li{a href="https://github.com/neon-mmd/websurfx"{"Source Code"}}
|
||||
li{a href="https://github.com/neon-mmd/websurfx/issues"{"Issues/Bugs"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
script src="static/settings.js"{}
|
||||
(PreEscaped("</body>"))
|
||||
(PreEscaped("</html>"))
|
||||
)
|
||||
}
|
35
src/templates/partials/header.rs
Normal file
35
src/templates/partials/header.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
//! A module that handles the header for all the pages in the `websurfx` frontend.
|
||||
|
||||
use crate::templates::partials::navbar::navbar;
|
||||
use maud::{html, Markup, PreEscaped, DOCTYPE};
|
||||
|
||||
/// A function that handles the html code for the header for all the pages in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `colorscheme` - It takes the colorscheme name as an argument.
|
||||
/// * `theme` - It takes the theme name as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code for the header as a result.
|
||||
pub fn header(colorscheme: &str, theme: &str) -> Markup {
|
||||
html!(
|
||||
(DOCTYPE)
|
||||
html lang="en"
|
||||
|
||||
head{
|
||||
title{"Websurfx"}
|
||||
meta charset="UTF-8";
|
||||
meta name="viewport" content="width=device-width, initial-scale=1";
|
||||
link href=(format!("static/colorschemes/{colorscheme}.css")) rel="stylesheet" type="text/css";
|
||||
link href=(format!("static/themes/{theme}.css")) rel="stylesheet" type="text/css";
|
||||
}
|
||||
|
||||
(PreEscaped("<body onload=\"getClientSettings()\">"))
|
||||
header{
|
||||
h1{a href="/"{"Websurfx"}}
|
||||
(navbar())
|
||||
}
|
||||
)
|
||||
}
|
8
src/templates/partials/mod.rs
Normal file
8
src/templates/partials/mod.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
//! This module provides other modules to handle the partials for the views in the `websurfx` frontend.
|
||||
|
||||
pub mod bar;
|
||||
pub mod footer;
|
||||
pub mod header;
|
||||
pub mod navbar;
|
||||
pub mod search_bar;
|
||||
pub mod settings_tabs;
|
19
src/templates/partials/navbar.rs
Normal file
19
src/templates/partials/navbar.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
//! A module that handles `navbar` partial for the header partial in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
/// A functions that handles the html code for the header partial.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html code for the navbar as a result.
|
||||
pub fn navbar() -> Markup {
|
||||
html!(
|
||||
nav{
|
||||
ul{
|
||||
li{a href="about"{"about"}}
|
||||
li{a href="settings"{"settings"}}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
76
src/templates/partials/search_bar.rs
Normal file
76
src/templates/partials/search_bar.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
//! A module that handles `search bar` partial for the search page in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
|
||||
use crate::{models::aggregation_models::EngineErrorInfo, templates::partials::bar::bar};
|
||||
|
||||
/// A constant holding the named safe search level options for the corresponding values 0, 1 and 2.
|
||||
const SAFE_SEARCH_LEVELS_NAME: [&str; 3] = ["None", "Low", "Moderate"];
|
||||
|
||||
/// A functions that handles the html code for the search bar for the search page.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `engine_errors_info` - It takes the engine errors list containing errors for each upstream
|
||||
/// search engine which failed to provide results as an argument.
|
||||
/// * `safe_search_level` - It takes the safe search level with values from 0-2 as an argument.
|
||||
/// * `query` - It takes the current search query provided by user as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html code for the search bar as a result.
|
||||
pub fn search_bar(
|
||||
engine_errors_info: &[EngineErrorInfo],
|
||||
safe_search_level: u8,
|
||||
query: &str,
|
||||
) -> Markup {
|
||||
html!(
|
||||
.search_area{
|
||||
(bar(query))
|
||||
.error_box {
|
||||
@if !engine_errors_info.is_empty(){
|
||||
button onclick="toggleErrorBox()" class="error_box_toggle_button"{
|
||||
img src="./images/warning.svg" alt="Info icon for error box";
|
||||
}
|
||||
.dropdown_error_box{
|
||||
@for errors in engine_errors_info{
|
||||
.error_item{
|
||||
span class="engine_name"{(errors.engine)}
|
||||
span class="engine_name"{(errors.error)}
|
||||
span class="severity_color" style="background: {{{this.severity_color}}};"{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@else {
|
||||
button onclick="toggleErrorBox()" class="error_box_toggle_button"{
|
||||
img src="./images/info.svg" alt="Warning icon for error box";
|
||||
}
|
||||
.dropdown_error_box {
|
||||
.no_errors{
|
||||
"Everything looks good 🙂!!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(PreEscaped("</div>"))
|
||||
.search_options {
|
||||
@if safe_search_level >= 3 {
|
||||
(PreEscaped("<select name=\"safe_search_levels\" disabled>"))
|
||||
}
|
||||
@else{
|
||||
(PreEscaped("<select name=\"safe_search_levels\">"))
|
||||
}
|
||||
@for (idx, name) in SAFE_SEARCH_LEVELS_NAME.iter().enumerate() {
|
||||
@if (safe_search_level as usize) == idx {
|
||||
option value=(idx) selected {(format!("SafeSearch: {name}"))}
|
||||
}
|
||||
@else{
|
||||
option value=(idx) {(format!("SafeSearch: {name}"))}
|
||||
}
|
||||
}
|
||||
(PreEscaped("</select>"))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
25
src/templates/partials/settings_tabs/cookies.rs
Normal file
25
src/templates/partials/settings_tabs/cookies.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
//! A module that handles the engines tab for setting page view in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
/// A functions that handles the html code for the cookies tab for the settings page for the search page.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code for the cookies tab.
|
||||
pub fn cookies() -> Markup {
|
||||
html!(
|
||||
div class="cookies tab"{
|
||||
h1{"Cookies"}
|
||||
p class="description"{
|
||||
"This is the cookies are saved on your system and it contains the preferences
|
||||
you chose in the settings page"
|
||||
}
|
||||
input type="text" name="cookie_field" value="" readonly;
|
||||
p class="description"{
|
||||
"The cookies stored are not used by us for any malicious intend or for
|
||||
tracking you in any way."
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
43
src/templates/partials/settings_tabs/engines.rs
Normal file
43
src/templates/partials/settings_tabs/engines.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
//! A module that handles the engines tab for setting page view in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
/// A functions that handles the html code for the engines tab for the settings page for the search page.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `engine_names` - It takes the list of all available engine names as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code for the engines tab.
|
||||
pub fn engines(engine_names: &[&String]) -> Markup {
|
||||
html!(
|
||||
div class="engines tab"{
|
||||
h1{"Engines"}
|
||||
h3{"select search engines"}
|
||||
p class="description"{
|
||||
"Select the search engines from the list of engines that you want results from"
|
||||
}
|
||||
.engine_selection{
|
||||
.toggle_btn{
|
||||
label class="switch"{
|
||||
input type="checkbox" class="select_all" onchange="toggleAllSelection()";
|
||||
span class="slider round"{}
|
||||
}
|
||||
"Select All"
|
||||
}
|
||||
hr;
|
||||
@for engine_name in engine_names{
|
||||
.toggle_btn{
|
||||
label class="switch"{
|
||||
input type="checkbox" class="engine";
|
||||
span class="slider round"{}
|
||||
}
|
||||
(format!("{}{}",engine_name[..1].to_uppercase().to_owned(), engine_name[1..].to_owned()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
28
src/templates/partials/settings_tabs/general.rs
Normal file
28
src/templates/partials/settings_tabs/general.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
//! A module that handles the general tab for setting page view in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
/// A constant holding the named safe search level options for the corresponding values 0, 1 and 2.
|
||||
const SAFE_SEARCH_LEVELS: [(u8, &str); 3] = [(0, "None"), (1, "Low"), (2, "Moderate")];
|
||||
|
||||
/// A functions that handles the html code for the general tab for the settings page for the search page.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code for the general tab.
|
||||
pub fn general() -> Markup {
|
||||
html!(
|
||||
div class="general tab active"{
|
||||
h1{"General"}
|
||||
h3{"Select a safe search level"}
|
||||
p class="description"{
|
||||
"Select a safe search level from the menu below to filter content based on the level."
|
||||
}
|
||||
select name="safe_search_levels"{
|
||||
@for (k,v) in SAFE_SEARCH_LEVELS{
|
||||
option value=(k){(v)}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
7
src/templates/partials/settings_tabs/mod.rs
Normal file
7
src/templates/partials/settings_tabs/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
//! This module provides other modules to handle the partials for the tabs for the settings page
|
||||
//! view in the `websurfx` frontend.
|
||||
|
||||
pub mod cookies;
|
||||
pub mod engines;
|
||||
pub mod general;
|
||||
pub mod user_interface;
|
65
src/templates/partials/settings_tabs/user_interface.rs
Normal file
65
src/templates/partials/settings_tabs/user_interface.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
//! A module that handles the user interface tab for setting page view in the `websurfx` frontend.
|
||||
|
||||
use crate::handler::paths::{file_path, FileType};
|
||||
use maud::{html, Markup};
|
||||
use std::fs::read_dir;
|
||||
|
||||
/// A helper function that helps in building the list of all available colorscheme/theme names
|
||||
/// present in the colorschemes and themes folder respectively.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `style_type` - It takes the style type of the values `theme` and `colorscheme` as an
|
||||
/// argument.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// Returns a list of colorscheme/theme names as a vector of tuple strings on success otherwise
|
||||
/// returns a standard error message.
|
||||
fn style_option_list(
|
||||
style_type: &str,
|
||||
) -> Result<Vec<(String, String)>, Box<dyn std::error::Error + '_>> {
|
||||
let mut style_option_names: Vec<(String, String)> = Vec::new();
|
||||
for file in read_dir(format!(
|
||||
"{}static/{}/",
|
||||
file_path(FileType::Theme)?,
|
||||
style_type,
|
||||
))? {
|
||||
let style_name = file?.file_name().to_str().unwrap().replace(".css", "");
|
||||
style_option_names.push((style_name.clone(), style_name.replace('-', " ")));
|
||||
}
|
||||
|
||||
Ok(style_option_names)
|
||||
}
|
||||
|
||||
/// A functions that handles the html code for the user interface tab for the settings page for the search page.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// It returns the compiled html markup code for the user interface tab on success otherwise
|
||||
/// returns a standard error message.
|
||||
pub fn user_interface() -> Result<Markup, Box<dyn std::error::Error>> {
|
||||
Ok(html!(
|
||||
div class="user_interface tab"{
|
||||
h1{"User Interface"}
|
||||
h3{"select theme"}
|
||||
p class="description"{
|
||||
"Select the theme from the available themes to be used in user interface"
|
||||
}
|
||||
select name="themes"{
|
||||
@for (k,v) in style_option_list("themes")?{
|
||||
option value=(k){(v)}
|
||||
}
|
||||
}
|
||||
h3{"select color scheme"}
|
||||
p class="description"{
|
||||
"Select the color scheme for your theme to be used in user interface"
|
||||
}
|
||||
select name="colorschemes"{
|
||||
@for (k,v) in style_option_list("colorschemes")?{
|
||||
option value=(k){(v)}
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
48
src/templates/views/about.rs
Normal file
48
src/templates/views/about.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
//! A module that handles the view for the about page in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
use crate::templates::partials::{footer::footer, header::header};
|
||||
|
||||
/// A function that handles the html code for the about page view in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `colorscheme` - It takes the colorscheme name as an argument.
|
||||
/// * `theme` - It takes the theme name as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code as a result.
|
||||
pub fn about(colorscheme: &str, theme: &str) -> Markup {
|
||||
html!(
|
||||
(header(colorscheme, theme))
|
||||
main class="about-container"{
|
||||
article {
|
||||
div{
|
||||
h1{"Websurfx"}
|
||||
hr size="4" width="100%" color="#a6e3a1"{}
|
||||
}
|
||||
p{"A modern-looking, lightning-fast, privacy-respecting, secure meta search engine written in Rust. It provides a fast and secure search experience while respecting user privacy."br{}" It aggregates results from multiple search engines and presents them in an unbiased manner, filtering out trackers and ads."
|
||||
}
|
||||
|
||||
h2{"Some of the Top Features:"}
|
||||
|
||||
ul{strong{"Lightning fast "}"- Results load within milliseconds for an instant search experience."}
|
||||
|
||||
ul{strong{"Secure search"}" - All searches are performed over an encrypted connection to prevent snooping."}
|
||||
|
||||
ul{strong{"Ad free results"}" - All search results are ad free and clutter free for a clean search experience."}
|
||||
|
||||
ul{strong{"Privacy focused"}" - Websurfx does not track, store or sell your search data. Your privacy is our priority."}
|
||||
|
||||
ul{strong{"Free and Open source"}" - The entire project's code is open source and available for free on "{a href="https://github.com/neon-mmd/websurfx"{"GitHub"}}" under an GNU Affero General Public License."}
|
||||
|
||||
ul{strong{"Highly customizable"}" - Websurfx comes with 9 built-in color themes and supports creating custom themes effortlessly."}
|
||||
}
|
||||
|
||||
h3{"Devoloped by: "{a href="https://github.com/neon-mmd/websurfx"{"Websurfx team"}}}
|
||||
}
|
||||
(footer())
|
||||
)
|
||||
}
|
28
src/templates/views/index.rs
Normal file
28
src/templates/views/index.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
//! A module that handles the view for the index/home/main page in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
|
||||
use crate::templates::partials::{bar::bar, footer::footer, header::header};
|
||||
|
||||
/// A function that handles the html code for the index/html/main page view in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `colorscheme` - It takes the colorscheme name as an argument.
|
||||
/// * `theme` - It takes the theme name as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code as a result.
|
||||
pub fn index(colorscheme: &str, theme: &str) -> Markup {
|
||||
html!(
|
||||
(header(colorscheme, theme))
|
||||
main class="search-container"{
|
||||
img src="../images/websurfx_logo.png" alt="Websurfx meta-search engine logo";
|
||||
(bar(&String::default()))
|
||||
(PreEscaped("</div>"))
|
||||
}
|
||||
script src="static/index.js"{}
|
||||
(footer())
|
||||
)
|
||||
}
|
8
src/templates/views/mod.rs
Normal file
8
src/templates/views/mod.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
//! This module provides other modules to handle view for each individual page in the
|
||||
//! `websurfx` frontend.
|
||||
|
||||
pub mod about;
|
||||
pub mod index;
|
||||
pub mod not_found;
|
||||
pub mod search;
|
||||
pub mod settings;
|
29
src/templates/views/not_found.rs
Normal file
29
src/templates/views/not_found.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
//! A module that handles the view for the 404 page in the `websurfx` frontend.
|
||||
|
||||
use crate::templates::partials::{footer::footer, header::header};
|
||||
use maud::{html, Markup};
|
||||
|
||||
/// A function that handles the html code for the 404 page view in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `colorscheme` - It takes the colorscheme name as an argument.
|
||||
/// * `theme` - It takes the theme name as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code as a result.
|
||||
pub fn not_found(colorscheme: &str, theme: &str) -> Markup {
|
||||
html!(
|
||||
(header(colorscheme, theme))
|
||||
main class="error_container"{
|
||||
img src="images/robot-404.svg" alt="Image of broken robot.";
|
||||
.error_content{
|
||||
h1{"Aw! snap"}
|
||||
h2{"404 Page Not Found!"}
|
||||
p{"Go to "{a href="/"{"search page"}}}
|
||||
}
|
||||
}
|
||||
(footer())
|
||||
)
|
||||
}
|
122
src/templates/views/search.rs
Normal file
122
src/templates/views/search.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
//! A module that handles the view for the search page in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup, PreEscaped};
|
||||
|
||||
use crate::{
|
||||
models::aggregation_models::SearchResults,
|
||||
templates::partials::{footer::footer, header::header, search_bar::search_bar},
|
||||
};
|
||||
|
||||
/// A function that handles the html code for the search page view in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `colorscheme` - It takes the colorscheme name as an argument.
|
||||
/// * `theme` - It takes the theme name as an argument.
|
||||
/// * `query` - It takes the current search query provided by the user as an argument.
|
||||
/// * `search_results` - It takes the aggregated search results as an argument.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// It returns the compiled html markup code as a result.
|
||||
pub fn search(
|
||||
colorscheme: &str,
|
||||
theme: &str,
|
||||
query: &str,
|
||||
search_results: &SearchResults,
|
||||
) -> Markup {
|
||||
html!(
|
||||
(header(colorscheme, theme))
|
||||
main class="results"{
|
||||
(search_bar(&search_results.engine_errors_info, search_results.safe_search_level, query))
|
||||
.results_aggregated{
|
||||
@if !search_results.results.is_empty() {
|
||||
@for result in search_results.results.iter(){
|
||||
.result {
|
||||
h1{a href=(result.url){(PreEscaped(&result.title))}}
|
||||
small{(result.url)}
|
||||
p{(PreEscaped(&result.description))}
|
||||
.upstream_engines{
|
||||
@for name in result.clone().engine{
|
||||
span{(name)}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@else if search_results.disallowed{
|
||||
.result_disallowed{
|
||||
.description{
|
||||
p{
|
||||
"Your search - "{span class="user_query"{(query)}}" -
|
||||
has been disallowed."
|
||||
}
|
||||
p class="description_paragraph"{"Dear user,"}
|
||||
p class="description_paragraph"{
|
||||
"The query - "{span class="user_query"{(query)}}" - has
|
||||
been blacklisted via server configuration and hence disallowed by the
|
||||
server. Henceforth no results could be displayed for your query."
|
||||
}
|
||||
}
|
||||
img src="./images/barricade.png" alt="Image of a Barricade";
|
||||
}
|
||||
}
|
||||
@else if search_results.filtered {
|
||||
.result_filtered{
|
||||
.description{
|
||||
p{
|
||||
"Your search - "{span class="user_query"{(query)}}" -
|
||||
has been filtered."
|
||||
}
|
||||
p class="description_paragraph"{"Dear user,"}
|
||||
p class="description_paragraph"{
|
||||
"All the search results contain results that has been configured to be
|
||||
filtered out via server configuration and henceforth has been
|
||||
completely filtered out."
|
||||
}
|
||||
}
|
||||
img src="./images/filter.png" alt="Image of a paper inside a funnel";
|
||||
}
|
||||
}
|
||||
@else if search_results.no_engines_selected {
|
||||
.result_engine_not_selected{
|
||||
.description{
|
||||
p{
|
||||
"No results could be fetched for your search '{span class="user_query"{(query)}}'."
|
||||
}
|
||||
p class="description_paragraph"{"Dear user,"}
|
||||
p class="description_paragraph"{
|
||||
"No results could be retrieved from the upstream search engines as no
|
||||
upstream search engines were selected from the settings page."
|
||||
}
|
||||
}
|
||||
img src="./images/no_selection.png" alt="Image of a white cross inside a red circle";
|
||||
}
|
||||
}
|
||||
@else{
|
||||
.result_not_found {
|
||||
p{"Your search - "{(query)}" - did not match any documents."}
|
||||
p class="suggestions"{"Suggestions:"}
|
||||
ul{
|
||||
li{"Make sure that all words are spelled correctly."}
|
||||
li{"Try different keywords."}
|
||||
li{"Try more general keywords."}
|
||||
}
|
||||
img src="./images/no_results.gif" alt="Man fishing gif";
|
||||
}
|
||||
}
|
||||
}
|
||||
.page_navigation {
|
||||
button type="button" onclick="navigate_backward()"{
|
||||
(PreEscaped("←")) "previous"
|
||||
}
|
||||
button type="button" onclick="navigate_forward()"{"next" (PreEscaped("→"))}
|
||||
}
|
||||
}
|
||||
script src="static/index.js"{}
|
||||
script src="static/search_area_options.js"{}
|
||||
script src="static/pagination.js"{}
|
||||
script src="static/error_box.js"{}
|
||||
(footer())
|
||||
)
|
||||
}
|
56
src/templates/views/settings.rs
Normal file
56
src/templates/views/settings.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
//! A module that handles the view for the settings page in the `websurfx` frontend.
|
||||
|
||||
use maud::{html, Markup};
|
||||
|
||||
use crate::templates::partials::{
|
||||
footer::footer,
|
||||
header::header,
|
||||
settings_tabs::{
|
||||
cookies::cookies, engines::engines, general::general, user_interface::user_interface,
|
||||
},
|
||||
};
|
||||
|
||||
/// A function that handles the html code for the settings page view in the search engine frontend.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `colorscheme` - It takes the colorscheme name as an argument.
|
||||
/// * `theme` - It takes the theme name as an argument.
|
||||
/// * `engine_names` - It takes a list of engine names as an argument.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// This function returns a compiled html markup code on success otherwise returns a standard error
|
||||
/// message.
|
||||
pub fn settings(
|
||||
colorscheme: &str,
|
||||
theme: &str,
|
||||
engine_names: &[&String],
|
||||
) -> Result<Markup, Box<dyn std::error::Error>> {
|
||||
Ok(html!(
|
||||
(header(colorscheme, theme))
|
||||
main class="settings"{
|
||||
h1{"Settings"}
|
||||
hr;
|
||||
.settings_container{
|
||||
.sidebar{
|
||||
div class="btn active" onclick="setActiveTab(this)"{"general"}
|
||||
.btn onclick="setActiveTab(this)"{"user interface"}
|
||||
.btn onclick="setActiveTab(this)"{"engines"}
|
||||
.btn onclick="setActiveTab(this)"{"cookies"}
|
||||
}
|
||||
.main_container{
|
||||
(general())
|
||||
(user_interface()?)
|
||||
(engines(engine_names))
|
||||
(cookies())
|
||||
p class="message"{}
|
||||
button type="submit" onclick="setClientSettings()"{"Save"}
|
||||
}
|
||||
}
|
||||
}
|
||||
script src="static/settings.js"{}
|
||||
script src="static/cookies.js"{}
|
||||
(footer())
|
||||
))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue