alamin655 commited on
Commit
ae9fa5b
2 Parent(s): a46a223 0139fc5

Merge branch 'rolling' into PERF/384_optimize-the-performance-of-fetching-results-in-the-websurfx-search-engine-backend

Browse files
Files changed (42) hide show
  1. Cargo.lock +49 -98
  2. Cargo.toml +1 -1
  3. public/templates/404.html +0 -10
  4. public/templates/about.html +0 -29
  5. public/templates/bar.html +0 -3
  6. public/templates/cookies_tab.html +0 -12
  7. public/templates/engines_tab.html +0 -32
  8. public/templates/footer.html +0 -16
  9. public/templates/general_tab.html +0 -13
  10. public/templates/header.html +0 -16
  11. public/templates/index.html +0 -8
  12. public/templates/navbar.html +0 -6
  13. public/templates/search.html +0 -86
  14. public/templates/search_bar.html +0 -36
  15. public/templates/settings.html +0 -22
  16. public/templates/user_interface_tab.html +0 -28
  17. src/config/parser.rs +2 -7
  18. src/lib.rs +1 -10
  19. src/models/aggregation_models.rs +2 -23
  20. src/models/parser_models.rs +1 -3
  21. src/results/aggregator.rs +1 -1
  22. src/server/router.rs +26 -20
  23. src/server/routes/search.rs +29 -36
  24. src/templates/mod.rs +5 -0
  25. src/templates/partials/bar.rs +21 -0
  26. src/templates/partials/footer.rs +29 -0
  27. src/templates/partials/header.rs +35 -0
  28. src/templates/partials/mod.rs +8 -0
  29. src/templates/partials/navbar.rs +19 -0
  30. src/templates/partials/search_bar.rs +76 -0
  31. src/templates/partials/settings_tabs/cookies.rs +25 -0
  32. src/templates/partials/settings_tabs/engines.rs +43 -0
  33. src/templates/partials/settings_tabs/general.rs +28 -0
  34. src/templates/partials/settings_tabs/mod.rs +7 -0
  35. src/templates/partials/settings_tabs/user_interface.rs +65 -0
  36. src/templates/views/about.rs +48 -0
  37. src/templates/views/index.rs +28 -0
  38. src/templates/views/mod.rs +8 -0
  39. src/templates/views/not_found.rs +29 -0
  40. src/templates/views/search.rs +122 -0
  41. src/templates/views/settings.rs +56 -0
  42. tests/index.rs +2 -16
Cargo.lock CHANGED
@@ -1416,21 +1416,6 @@ version = "1.8.2"
1416
  source = "registry+https://github.com/rust-lang/crates.io-index"
1417
  checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
1418
 
1419
- [[package]]
1420
- name = "handlebars"
1421
- version = "4.5.0"
1422
- source = "registry+https://github.com/rust-lang/crates.io-index"
1423
- checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225"
1424
- dependencies = [
1425
- "log",
1426
- "pest",
1427
- "pest_derive",
1428
- "serde",
1429
- "serde_json",
1430
- "thiserror",
1431
- "walkdir",
1432
- ]
1433
-
1434
  [[package]]
1435
  name = "hashbrown"
1436
  version = "0.12.3"
@@ -1925,6 +1910,30 @@ version = "0.1.10"
1925
  source = "registry+https://github.com/rust-lang/crates.io-index"
1926
  checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
1927
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1928
  [[package]]
1929
  name = "maybe-uninit"
1930
  version = "2.0.0"
@@ -2329,51 +2338,6 @@ version = "2.3.0"
2329
  source = "registry+https://github.com/rust-lang/crates.io-index"
2330
  checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
2331
 
2332
- [[package]]
2333
- name = "pest"
2334
- version = "2.7.5"
2335
- source = "registry+https://github.com/rust-lang/crates.io-index"
2336
- checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5"
2337
- dependencies = [
2338
- "memchr",
2339
- "thiserror",
2340
- "ucd-trie",
2341
- ]
2342
-
2343
- [[package]]
2344
- name = "pest_derive"
2345
- version = "2.7.5"
2346
- source = "registry+https://github.com/rust-lang/crates.io-index"
2347
- checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2"
2348
- dependencies = [
2349
- "pest",
2350
- "pest_generator",
2351
- ]
2352
-
2353
- [[package]]
2354
- name = "pest_generator"
2355
- version = "2.7.5"
2356
- source = "registry+https://github.com/rust-lang/crates.io-index"
2357
- checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227"
2358
- dependencies = [
2359
- "pest",
2360
- "pest_meta",
2361
- "proc-macro2 1.0.69",
2362
- "quote 1.0.33",
2363
- "syn 2.0.39",
2364
- ]
2365
-
2366
- [[package]]
2367
- name = "pest_meta"
2368
- version = "2.7.5"
2369
- source = "registry+https://github.com/rust-lang/crates.io-index"
2370
- checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6"
2371
- dependencies = [
2372
- "once_cell",
2373
- "pest",
2374
- "sha2",
2375
- ]
2376
-
2377
  [[package]]
2378
  name = "phf"
2379
  version = "0.7.24"
@@ -2548,6 +2512,30 @@ version = "0.1.1"
2548
  source = "registry+https://github.com/rust-lang/crates.io-index"
2549
  checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
2550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2551
  [[package]]
2552
  name = "proc-macro2"
2553
  version = "0.4.30"
@@ -3223,17 +3211,6 @@ dependencies = [
3223
  "digest",
3224
  ]
3225
 
3226
- [[package]]
3227
- name = "sha2"
3228
- version = "0.10.8"
3229
- source = "registry+https://github.com/rust-lang/crates.io-index"
3230
- checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
3231
- dependencies = [
3232
- "cfg-if 1.0.0",
3233
- "cpufeatures",
3234
- "digest",
3235
- ]
3236
-
3237
  [[package]]
3238
  name = "signal-hook-registry"
3239
  version = "1.4.1"
@@ -3504,26 +3481,6 @@ dependencies = [
3504
  "utf-8",
3505
  ]
3506
 
3507
- [[package]]
3508
- name = "thiserror"
3509
- version = "1.0.50"
3510
- source = "registry+https://github.com/rust-lang/crates.io-index"
3511
- checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
3512
- dependencies = [
3513
- "thiserror-impl",
3514
- ]
3515
-
3516
- [[package]]
3517
- name = "thiserror-impl"
3518
- version = "1.0.50"
3519
- source = "registry+https://github.com/rust-lang/crates.io-index"
3520
- checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
3521
- dependencies = [
3522
- "proc-macro2 1.0.69",
3523
- "quote 1.0.33",
3524
- "syn 2.0.39",
3525
- ]
3526
-
3527
  [[package]]
3528
  name = "thousands"
3529
  version = "0.2.0"
@@ -3855,12 +3812,6 @@ version = "1.17.0"
3855
  source = "registry+https://github.com/rust-lang/crates.io-index"
3856
  checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
3857
 
3858
- [[package]]
3859
- name = "ucd-trie"
3860
- version = "0.1.6"
3861
- source = "registry+https://github.com/rust-lang/crates.io-index"
3862
- checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
3863
-
3864
  [[package]]
3865
  name = "unicase"
3866
  version = "2.7.0"
@@ -4104,9 +4055,9 @@ dependencies = [
4104
  "error-stack",
4105
  "fake-useragent",
4106
  "futures 0.3.29",
4107
- "handlebars",
4108
  "lightningcss",
4109
  "log",
 
4110
  "md5",
4111
  "mimalloc",
4112
  "mini-moka",
 
1416
  source = "registry+https://github.com/rust-lang/crates.io-index"
1417
  checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
1418
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1419
  [[package]]
1420
  name = "hashbrown"
1421
  version = "0.12.3"
 
1910
  source = "registry+https://github.com/rust-lang/crates.io-index"
1911
  checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
1912
 
1913
+ [[package]]
1914
+ name = "maud"
1915
+ version = "0.25.0"
1916
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1917
+ checksum = "b0bab19cef8a7fe1c18a43e881793bfc9d4ea984befec3ae5bd0415abf3ecf00"
1918
+ dependencies = [
1919
+ "actix-web",
1920
+ "futures-util",
1921
+ "itoa 1.0.9",
1922
+ "maud_macros",
1923
+ ]
1924
+
1925
+ [[package]]
1926
+ name = "maud_macros"
1927
+ version = "0.25.0"
1928
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1929
+ checksum = "0be95d66c3024ffce639216058e5bae17a83ecaf266ffc6e4d060ad447c9eed2"
1930
+ dependencies = [
1931
+ "proc-macro-error",
1932
+ "proc-macro2 1.0.69",
1933
+ "quote 1.0.33",
1934
+ "syn 1.0.109",
1935
+ ]
1936
+
1937
  [[package]]
1938
  name = "maybe-uninit"
1939
  version = "2.0.0"
 
2338
  source = "registry+https://github.com/rust-lang/crates.io-index"
2339
  checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
2340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2341
  [[package]]
2342
  name = "phf"
2343
  version = "0.7.24"
 
2512
  source = "registry+https://github.com/rust-lang/crates.io-index"
2513
  checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
2514
 
2515
+ [[package]]
2516
+ name = "proc-macro-error"
2517
+ version = "1.0.4"
2518
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2519
+ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
2520
+ dependencies = [
2521
+ "proc-macro-error-attr",
2522
+ "proc-macro2 1.0.69",
2523
+ "quote 1.0.33",
2524
+ "syn 1.0.109",
2525
+ "version_check",
2526
+ ]
2527
+
2528
+ [[package]]
2529
+ name = "proc-macro-error-attr"
2530
+ version = "1.0.4"
2531
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2532
+ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
2533
+ dependencies = [
2534
+ "proc-macro2 1.0.69",
2535
+ "quote 1.0.33",
2536
+ "version_check",
2537
+ ]
2538
+
2539
  [[package]]
2540
  name = "proc-macro2"
2541
  version = "0.4.30"
 
3211
  "digest",
3212
  ]
3213
 
 
 
 
 
 
 
 
 
 
 
 
3214
  [[package]]
3215
  name = "signal-hook-registry"
3216
  version = "1.4.1"
 
3481
  "utf-8",
3482
  ]
3483
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3484
  [[package]]
3485
  name = "thousands"
3486
  version = "0.2.0"
 
3812
  source = "registry+https://github.com/rust-lang/crates.io-index"
3813
  checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
3814
 
 
 
 
 
 
 
3815
  [[package]]
3816
  name = "unicase"
3817
  version = "2.7.0"
 
4055
  "error-stack",
4056
  "fake-useragent",
4057
  "futures 0.3.29",
 
4058
  "lightningcss",
4059
  "log",
4060
+ "maud",
4061
  "md5",
4062
  "mimalloc",
4063
  "mini-moka",
Cargo.toml CHANGED
@@ -17,7 +17,7 @@ reqwest = {version="0.11.22", default-features=false, features=["rustls-tls","br
17
  tokio = {version="1.32.0",features=["rt-multi-thread","macros"], default-features = false}
18
  serde = {version="1.0.190", default-features=false, features=["derive"]}
19
  serde_json = {version="1.0.108", default-features=false}
20
- handlebars = { version = "4.4.0", features = ["dir_source"], default-features = false }
21
  scraper = {version="0.18.1", default-features = false}
22
  actix-web = {version="4.4.0", features = ["cookies", "macros"], default-features=false}
23
  actix-files = {version="0.6.2", default-features=false}
 
17
  tokio = {version="1.32.0",features=["rt-multi-thread","macros"], default-features = false}
18
  serde = {version="1.0.190", default-features=false, features=["derive"]}
19
  serde_json = {version="1.0.108", default-features=false}
20
+ maud = {version="0.25.0", default-features=false, features=["actix-web"]}
21
  scraper = {version="0.18.1", default-features = false}
22
  actix-web = {version="4.4.0", features = ["cookies", "macros"], default-features=false}
23
  actix-files = {version="0.6.2", default-features=false}
public/templates/404.html DELETED
@@ -1,10 +0,0 @@
1
- {{>header this}}
2
- <main class="error_container">
3
- <img src="images/robot-404.svg" alt="Image of broken robot." />
4
- <div class="error_content">
5
- <h1>Aw! snap</h1>
6
- <h2>404 Page Not Found!</h2>
7
- <p>Go to <a href="/">search page</a></p>
8
- </div>
9
- </main>
10
- {{>footer}}
 
 
 
 
 
 
 
 
 
 
 
public/templates/about.html DELETED
@@ -1,29 +0,0 @@
1
- {{>header this}}
2
- <main class="about-container">
3
- <article >
4
- <div>
5
- <h1 >Websurfx</h1>
6
- <hr size="4" width="100%" color="#a6e3a1">
7
- </div>
8
- <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.
9
- </p>
10
-
11
- <h2>Some of the Top Features:</h2>
12
-
13
- <ul><strong>Lightning fast </strong>- Results load within milliseconds for an instant search experience.</ul>
14
-
15
- <ul><strong>Secure search</strong> - All searches are performed over an encrypted connection to prevent snooping.</ul>
16
-
17
- <ul><strong>Ad free results</strong> - All search results are ad free and clutter free for a clean search experience.</ul>
18
-
19
- <ul><strong>Privacy focused</strong> - Websurface does not track, store or sell your search data. Your privacy is our priority.</ul>
20
-
21
- <ul><strong>Free and Open source</strong> - The entire project's code is open source and available for free on <a href="https://github.com/neon-mmd/websurfx">GitHub</a> under an GNU Affero General Public License.</ul>
22
-
23
- <ul><strong>Highly customizable</strong> - Websurface comes with 9 built-in color themes and supports creating custom themes effortlessly.</ul>
24
- </article>
25
-
26
- <h3>Devoloped by: <a href="https://github.com/neon-mmd/websurfx">Websurfx team</a></h3>
27
- </main>
28
- {{>footer}}
29
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/bar.html DELETED
@@ -1,3 +0,0 @@
1
- <div class="search_bar">
2
- <input type="search" name="search-box" value="{{this.pageQuery}}" placeholder="Type to search" />
3
- <button type="submit" onclick="searchWeb()">search</button>
 
 
 
 
public/templates/cookies_tab.html DELETED
@@ -1,12 +0,0 @@
1
- <div class="cookies tab">
2
- <h1>Cookies</h1>
3
- <p class="description">
4
- This is the cookies are saved on your system and it contains the preferences
5
- you chose in the settings page
6
- </p>
7
- <input type="text" name="cookie_field" value="" readonly />
8
- <p class="description">
9
- The cookies stored are not used by us for any malicious intend or for
10
- tracking you in any way.
11
- </p>
12
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/engines_tab.html DELETED
@@ -1,32 +0,0 @@
1
- <div class="engines tab">
2
- <h1>Engines</h1>
3
- <h3>select search engines</h3>
4
- <p class="description">
5
- Select the search engines from the list of engines that you want results
6
- from
7
- </p>
8
- <div class="engine_selection">
9
- <div class="toggle_btn">
10
- <label class="switch">
11
- <input type="checkbox" class="select_all" onchange="toggleAllSelection()" />
12
- <span class="slider round"></span>
13
- </label>
14
- Select All
15
- </div>
16
- <hr />
17
- <div class="toggle_btn">
18
- <label class="switch">
19
- <input type="checkbox" class="engine" />
20
- <span class="slider round"></span>
21
- </label>
22
- DuckDuckGo
23
- </div>
24
- <div class="toggle_btn">
25
- <label class="switch">
26
- <input type="checkbox" class="engine" />
27
- <span class="slider round"></span>
28
- </label>
29
- Searx
30
- </div>
31
- </div>
32
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/footer.html DELETED
@@ -1,16 +0,0 @@
1
- <footer>
2
- <div>
3
- <span>Powered By <b>Websurfx</b></span><span>-</span><span>a lightening fast, privacy respecting, secure meta
4
- search engine</span>
5
- </div>
6
- <div>
7
- <ul>
8
- <li><a href="https://github.com/neon-mmd/websurfx">Source Code</a></li>
9
- <li><a href="https://github.com/neon-mmd/websurfx/issues">Issues/Bugs</a></li>
10
- </ul>
11
- </div>
12
- </footer>
13
- <script src="static/settings.js"></script>
14
- </body>
15
-
16
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/general_tab.html DELETED
@@ -1,13 +0,0 @@
1
- <div class="general tab active">
2
- <h1>General</h1>
3
- <h3>Select a safe search level</h3>
4
- <p class="description">
5
- Select a safe search level from the menu below to filter content based on
6
- the level.
7
- </p>
8
- <select name="safe_search_levels">
9
- <option value=0>None</option>
10
- <option value=1>Low</option>
11
- <option value=2>Moderate</option>
12
- </select>
13
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/header.html DELETED
@@ -1,16 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
-
4
- <head>
5
- <title>Websurfx</title>
6
- <meta charset="UTF-8" />
7
- <meta name="viewport" content="width=device-width, initial-scale=1" />
8
- <link href="static/colorschemes/{{colorscheme}}.css" rel="stylesheet" type="text/css" />
9
- <link href="static/themes/{{theme}}.css" rel="stylesheet" type="text/css" />
10
- </head>
11
-
12
- <body onload="getClientSettings()">
13
- <header>
14
- <h1><a href="/">Websurfx</a></h1>
15
- {{>navbar}}
16
- </header>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/index.html DELETED
@@ -1,8 +0,0 @@
1
- {{>header this}}
2
- <main class="search-container">
3
- <img src="../images/websurfx_logo.png" alt="Websurfx meta-search engine logo" />
4
- {{>bar}}
5
- </div>
6
- </main>
7
- <script src="static/index.js"></script>
8
- {{>footer}}
 
 
 
 
 
 
 
 
 
public/templates/navbar.html DELETED
@@ -1,6 +0,0 @@
1
- <nav>
2
- <ul>
3
- <li><a href="about">about</a></li>
4
- <li><a href="settings">settings</a></li>
5
- </ul>
6
- </nav>
 
 
 
 
 
 
 
public/templates/search.html DELETED
@@ -1,86 +0,0 @@
1
- {{>header this.style}}
2
- <main class="results">
3
- {{>search_bar this}}
4
- <div class="results_aggregated">
5
- {{#if results}} {{#each results}}
6
- <div class="result">
7
- <h1><a href="{{{this.url}}}">{{{this.title}}}</a></h1>
8
- <small>{{{this.url}}}</small>
9
- <p>{{{this.description}}}</p>
10
- <div class="upstream_engines">
11
- {{#each engine}}
12
- <span>{{{this}}}</span>
13
- {{/each}}
14
- </div>
15
- </div>
16
- {{/each}} {{else}} {{#if disallowed}}
17
- <div class="result_disallowed">
18
- <div class="description">
19
- <p>
20
- Your search - <span class="user_query">{{{this.pageQuery}}}</span> -
21
- has been disallowed.
22
- </p>
23
- <p class="description_paragraph">Dear user,</p>
24
- <p class="description_paragraph">
25
- The query - <span class="user_query">{{{this.pageQuery}}}</span> - has
26
- been blacklisted via server configuration and hence disallowed by the
27
- server. Henceforth no results could be displayed for your query.
28
- </p>
29
- </div>
30
- <img src="./images/barricade.png" alt="Image of a Barricade" />
31
- </div>
32
- {{else}} {{#if filtered}}
33
- <div class="result_filtered">
34
- <div class="description">
35
- <p>
36
- Your search - <span class="user_query">{{{this.pageQuery}}}</span> -
37
- has been filtered.
38
- </p>
39
- <p class="description_paragraph">Dear user,</p>
40
- <p class="description_paragraph">
41
- All the search results contain results that has been configured to be
42
- filtered out via server configuration and henceforth has been
43
- completely filtered out.
44
- </p>
45
- </div>
46
- <img src="./images/filter.png" alt="Image of a paper inside a funnel" />
47
- </div>
48
- {{else}} {{#if noEnginesSelected}}
49
- <div class="result_engine_not_selected">
50
- <div class="description">
51
- <p>
52
- No results could be fetched for your search "<span class="user_query">{{{this.pageQuery}}}</span>" .
53
- </p>
54
- <p class="description_paragraph">Dear user,</p>
55
- <p class="description_paragraph">
56
- No results could be retrieved from the upstream search engines as no
57
- upstream search engines were selected from the settings page.
58
- </p>
59
- </div>
60
- <img src="./images/no_selection.png" alt="Image of a white cross inside a red circle" />
61
- </div>
62
- {{else}}
63
- <div class="result_not_found">
64
- <p>Your search - {{{this.pageQuery}}} - did not match any documents.</p>
65
- <p class="suggestions">Suggestions:</p>
66
- <ul>
67
- <li>Make sure that all words are spelled correctly.</li>
68
- <li>Try different keywords.</li>
69
- <li>Try more general keywords.</li>
70
- </ul>
71
- <img src="./images/no_results.gif" alt="Man fishing gif" />
72
- </div>
73
- {{/if}} {{/if}} {{/if}} {{/if}}
74
- </div>
75
- <div class="page_navigation">
76
- <button type="button" onclick="navigate_backward()">
77
- &#8592; previous
78
- </button>
79
- <button type="button" onclick="navigate_forward()">next &#8594;</button>
80
- </div>
81
- </main>
82
- <script src="static/index.js"></script>
83
- <script src="static/search_area_options.js"></script>
84
- <script src="static/pagination.js"></script>
85
- <script src="static/error_box.js"></script>
86
- {{>footer}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/search_bar.html DELETED
@@ -1,36 +0,0 @@
1
- <div class="search_area">
2
- {{>bar this}}
3
- <div class="error_box">
4
- {{#if engineErrorsInfo}}
5
- <button onclick="toggleErrorBox()" class="error_box_toggle_button">
6
- <img src="./images/warning.svg" alt="Info icon for error box" />
7
- </button>
8
- <div class="dropdown_error_box">
9
- {{#each engineErrorsInfo}}
10
- <div class="error_item">
11
- <span class="engine_name">{{{this.engine}}}</span>
12
- <span class="engine_name">{{{this.error}}}</span>
13
- <span class="severity_color" style="background: {{{this.severity_color}}};"></span>
14
- </div>
15
- {{/each}}
16
- </div>
17
- {{else}}
18
- <button onclick="toggleErrorBox()" class="error_box_toggle_button">
19
- <img src="./images/info.svg" alt="Warning icon for error box" />
20
- </button>
21
- <div class="dropdown_error_box">
22
- <div class="no_errors">
23
- Everything looks good 🙂!!
24
- </div>
25
- </div>
26
- {{/if}}
27
- </div>
28
- </div>
29
- <div class="search_options">
30
- <select name="safe_search_levels" {{#if (gte safeSearchLevel 3)}} disabled {{/if}}>
31
- <option value=0 {{#if (eq safeSearchLevel 0)}} selected {{/if}}>SafeSearch: None</option>
32
- <option value=1 {{#if (eq safeSearchLevel 1)}} selected {{/if}}>SafeSearch: Low</option>
33
- <option value=2 {{#if (eq safeSearchLevel 2)}} selected {{/if}}>SafeSearch: Moderate</option>
34
- </select>
35
- </div>
36
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/settings.html DELETED
@@ -1,22 +0,0 @@
1
- {{>header this}}
2
- <main class="settings" >
3
- <h1>Settings</h1>
4
- <hr />
5
- <div class="settings_container">
6
- <div class="sidebar">
7
- <div class="btn active" onclick="setActiveTab(this)">general</div>
8
- <div class="btn" onclick="setActiveTab(this)">user interface</div>
9
- <div class="btn" onclick="setActiveTab(this)">engines</div>
10
- <div class="btn" onclick="setActiveTab(this)">cookies</div>
11
- </div>
12
- <div class="main_container">
13
- {{> general_tab}} {{> user_interface_tab}} {{> engines_tab}} {{>
14
- cookies_tab}}
15
- <p class="message"></p>
16
- <button type="submit" onclick="setClientSettings()">Save</button>
17
- </div>
18
- </div>
19
- </main>
20
- <script src="static/settings.js"></script>
21
- <script src="static/cookies.js"></script>
22
- {{>footer}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public/templates/user_interface_tab.html DELETED
@@ -1,28 +0,0 @@
1
- <div class="user_interface tab">
2
- <h1>User Interface</h1>
3
- <h3>select theme</h3>
4
- <p class="description">
5
- Select the theme from the available themes to be used in user interface
6
- </p>
7
- <select name="themes">
8
- <option value="simple">simple</option>
9
- </select>
10
- <h3>select color scheme</h3>
11
- <p class="description">
12
- Select the color scheme for your theme to be used in user interface
13
- </p>
14
- <select name="colorschemes">
15
- <option value="catppuccin-mocha">catppuccin mocha</option>
16
- <option value="dark-chocolate">dark chocolate</option>
17
- <option value="dracula">dracula</option>
18
- <option value="gruvbox-dark">gruvbox dark</option>
19
- <option value="monokai">monokai</option>
20
- <option value="nord">nord</option>
21
- <option value="oceanic-next">oceanic next</option>
22
- <option value="one-dark">one dark</option>
23
- <option value="solarized-dark">solarized dark</option>
24
- <option value="solarized-light">solarized light</option>
25
- <option value="tokyo-night">tokyo night</option>
26
- <option value="tomorrow-night">tomorrow night</option>
27
- </select>
28
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/config/parser.rs CHANGED
@@ -3,7 +3,6 @@
3
 
4
  use crate::handler::paths::{file_path, FileType};
5
 
6
- use crate::models::engine_models::{EngineError, EngineHandler};
7
  use crate::models::parser_models::{AggregatorConfig, RateLimiter, Style};
8
  use log::LevelFilter;
9
  use mlua::Lua;
@@ -29,7 +28,7 @@ pub struct Config {
29
  /// It stores the option to whether enable or disable debug mode.
30
  pub debug: bool,
31
  /// It stores all the engine names that were enabled by the user.
32
- pub upstream_search_engines: Vec<EngineHandler>,
33
  /// It stores the time (secs) which controls the server request timeout.
34
  pub request_timeout: u8,
35
  /// It stores the number of threads which controls the app will use to run.
@@ -109,11 +108,7 @@ impl Config {
109
  logging,
110
  debug,
111
  upstream_search_engines: globals
112
- .get::<_, HashMap<String, bool>>("upstream_search_engines")?
113
- .into_iter()
114
- .filter_map(|(key, value)| value.then_some(key))
115
- .map(|engine| EngineHandler::new(&engine))
116
- .collect::<Result<Vec<EngineHandler>, error_stack::Report<EngineError>>>()?,
117
  request_timeout: globals.get::<_, u8>("request_timeout")?,
118
  threads,
119
  rate_limiter: RateLimiter {
 
3
 
4
  use crate::handler::paths::{file_path, FileType};
5
 
 
6
  use crate::models::parser_models::{AggregatorConfig, RateLimiter, Style};
7
  use log::LevelFilter;
8
  use mlua::Lua;
 
28
  /// It stores the option to whether enable or disable debug mode.
29
  pub debug: bool,
30
  /// It stores all the engine names that were enabled by the user.
31
+ pub upstream_search_engines: HashMap<String, bool>,
32
  /// It stores the time (secs) which controls the server request timeout.
33
  pub request_timeout: u8,
34
  /// It stores the number of threads which controls the app will use to run.
 
108
  logging,
109
  debug,
110
  upstream_search_engines: globals
111
+ .get::<_, HashMap<String, bool>>("upstream_search_engines")?,
 
 
 
 
112
  request_timeout: globals.get::<_, u8>("request_timeout")?,
113
  threads,
114
  rate_limiter: RateLimiter {
src/lib.rs CHANGED
@@ -12,6 +12,7 @@ pub mod handler;
12
  pub mod models;
13
  pub mod results;
14
  pub mod server;
 
15
 
16
  use std::net::TcpListener;
17
 
@@ -23,7 +24,6 @@ use actix_governor::{Governor, GovernorConfigBuilder};
23
  use actix_web::{dev::Server, http::header, middleware::Logger, web, App, HttpServer};
24
  use cache::cacher::{Cache, SharedCache};
25
  use config::parser::Config;
26
- use handlebars::Handlebars;
27
  use handler::paths::{file_path, FileType};
28
 
29
  /// Runs the web server on the provided TCP listener and returns a `Server` instance.
@@ -48,16 +48,8 @@ use handler::paths::{file_path, FileType};
48
  /// let server = run(listener,config,cache).expect("Failed to start server");
49
  /// ```
50
  pub fn run(listener: TcpListener, config: Config, cache: Cache) -> std::io::Result<Server> {
51
- let mut handlebars: Handlebars<'_> = Handlebars::new();
52
-
53
  let public_folder_path: &str = file_path(FileType::Theme)?;
54
 
55
- handlebars
56
- .register_templates_directory(".html", format!("{}/templates", public_folder_path))
57
- .unwrap();
58
-
59
- let handlebars_ref: web::Data<Handlebars<'_>> = web::Data::new(handlebars);
60
-
61
  let cloned_config_threads_opt: u8 = config.threads;
62
 
63
  let cache = web::Data::new(SharedCache::new(cache));
@@ -75,7 +67,6 @@ pub fn run(listener: TcpListener, config: Config, cache: Cache) -> std::io::Resu
75
 
76
  App::new()
77
  .wrap(Logger::default()) // added logging middleware for logging.
78
- .app_data(handlebars_ref.clone())
79
  .app_data(web::Data::new(config.clone()))
80
  .app_data(cache.clone())
81
  .wrap(cors)
 
12
  pub mod models;
13
  pub mod results;
14
  pub mod server;
15
+ pub mod templates;
16
 
17
  use std::net::TcpListener;
18
 
 
24
  use actix_web::{dev::Server, http::header, middleware::Logger, web, App, HttpServer};
25
  use cache::cacher::{Cache, SharedCache};
26
  use config::parser::Config;
 
27
  use handler::paths::{file_path, FileType};
28
 
29
  /// Runs the web server on the provided TCP listener and returns a `Server` instance.
 
48
  /// let server = run(listener,config,cache).expect("Failed to start server");
49
  /// ```
50
  pub fn run(listener: TcpListener, config: Config, cache: Cache) -> std::io::Result<Server> {
 
 
51
  let public_folder_path: &str = file_path(FileType::Theme)?;
52
 
 
 
 
 
 
 
53
  let cloned_config_threads_opt: u8 = config.threads;
54
 
55
  let cache = web::Data::new(SharedCache::new(cache));
 
67
 
68
  App::new()
69
  .wrap(Logger::default()) // added logging middleware for logging.
 
70
  .app_data(web::Data::new(config.clone()))
71
  .app_data(cache.clone())
72
  .wrap(cors)
src/models/aggregation_models.rs CHANGED
@@ -1,11 +1,10 @@
1
  //! This module provides public models for handling, storing and serializing of search results
2
  //! data scraped from the upstream search engines.
3
 
 
4
  use serde::{Deserialize, Serialize};
5
  use smallvec::SmallVec;
6
 
7
- use super::{engine_models::EngineError, parser_models::Style};
8
-
9
  /// A named struct to store the raw scraped search results scraped search results from the
10
  /// upstream search engines before aggregating it.It derives the Clone trait which is needed
11
  /// to write idiomatic rust using `Iterators`.
@@ -109,10 +108,6 @@ impl EngineErrorInfo {
109
  pub struct SearchResults {
110
  /// Stores the individual serializable `SearchResult` struct into a vector of
111
  pub results: Vec<SearchResult>,
112
- /// Stores the current pages search query `q` provided in the search url.
113
- pub page_query: String,
114
- /// Stores the theming options for the website.
115
- pub style: Style,
116
  /// Stores the information on which engines failed with their engine name
117
  /// and the type of error that caused it.
118
  pub engine_errors_info: Vec<EngineErrorInfo>,
@@ -142,15 +137,9 @@ impl SearchResults {
142
  /// the search url.
143
  /// * `engine_errors_info` - Takes an array of structs which contains information regarding
144
  /// which engines failed with their names, reason and their severity color name.
145
- pub fn new(
146
- results: Vec<SearchResult>,
147
- page_query: &str,
148
- engine_errors_info: &[EngineErrorInfo],
149
- ) -> Self {
150
  Self {
151
  results,
152
- page_query: page_query.to_owned(),
153
- style: Style::default(),
154
  engine_errors_info: engine_errors_info.to_owned(),
155
  disallowed: Default::default(),
156
  filtered: Default::default(),
@@ -159,21 +148,11 @@ impl SearchResults {
159
  }
160
  }
161
 
162
- /// A setter function to add website style to the return search results.
163
- pub fn add_style(&mut self, style: &Style) {
164
- self.style = style.clone();
165
- }
166
-
167
  /// A setter function that sets disallowed to true.
168
  pub fn set_disallowed(&mut self) {
169
  self.disallowed = true;
170
  }
171
 
172
- /// A setter function to set the current page search query.
173
- pub fn set_page_query(&mut self, page: &str) {
174
- self.page_query = page.to_owned();
175
- }
176
-
177
  /// A setter function that sets the filtered to true.
178
  pub fn set_filtered(&mut self) {
179
  self.filtered = true;
 
1
  //! This module provides public models for handling, storing and serializing of search results
2
  //! data scraped from the upstream search engines.
3
 
4
+ use super::engine_models::EngineError;
5
  use serde::{Deserialize, Serialize};
6
  use smallvec::SmallVec;
7
 
 
 
8
  /// A named struct to store the raw scraped search results scraped search results from the
9
  /// upstream search engines before aggregating it.It derives the Clone trait which is needed
10
  /// to write idiomatic rust using `Iterators`.
 
108
  pub struct SearchResults {
109
  /// Stores the individual serializable `SearchResult` struct into a vector of
110
  pub results: Vec<SearchResult>,
 
 
 
 
111
  /// Stores the information on which engines failed with their engine name
112
  /// and the type of error that caused it.
113
  pub engine_errors_info: Vec<EngineErrorInfo>,
 
137
  /// the search url.
138
  /// * `engine_errors_info` - Takes an array of structs which contains information regarding
139
  /// which engines failed with their names, reason and their severity color name.
140
+ pub fn new(results: Vec<SearchResult>, engine_errors_info: &[EngineErrorInfo]) -> Self {
 
 
 
 
141
  Self {
142
  results,
 
 
143
  engine_errors_info: engine_errors_info.to_owned(),
144
  disallowed: Default::default(),
145
  filtered: Default::default(),
 
148
  }
149
  }
150
 
 
 
 
 
 
151
  /// A setter function that sets disallowed to true.
152
  pub fn set_disallowed(&mut self) {
153
  self.disallowed = true;
154
  }
155
 
 
 
 
 
 
156
  /// A setter function that sets the filtered to true.
157
  pub fn set_filtered(&mut self) {
158
  self.filtered = true;
src/models/parser_models.rs CHANGED
@@ -1,8 +1,6 @@
1
  //! This module provides public models for handling, storing and serializing parsed config file
2
  //! options from config.lua by grouping them together.
3
 
4
- use serde::{Deserialize, Serialize};
5
-
6
  /// A named struct which stores,deserializes, serializes and groups the parsed config file options
7
  /// of theme and colorscheme names into the Style struct which derives the `Clone`, `Serialize`
8
  /// and Deserialize traits where the `Clone` trait is derived for allowing the struct to be
@@ -12,7 +10,7 @@ use serde::{Deserialize, Serialize};
12
  /// order to allow the deserializing the json back to struct in aggregate function in
13
  /// aggregator.rs and create a new struct out of it and then serialize it back to json and pass
14
  /// it to the template files.
15
- #[derive(Serialize, Deserialize, Clone, Default)]
16
  pub struct Style {
17
  /// It stores the parsed theme option used to set a theme for the website.
18
  pub theme: String,
 
1
  //! This module provides public models for handling, storing and serializing parsed config file
2
  //! options from config.lua by grouping them together.
3
 
 
 
4
  /// A named struct which stores,deserializes, serializes and groups the parsed config file options
5
  /// of theme and colorscheme names into the Style struct which derives the `Clone`, `Serialize`
6
  /// and Deserialize traits where the `Clone` trait is derived for allowing the struct to be
 
10
  /// order to allow the deserializing the json back to struct in aggregate function in
11
  /// aggregator.rs and create a new struct out of it and then serialize it back to json and pass
12
  /// it to the template files.
13
+ #[derive(Clone, Default)]
14
  pub struct Style {
15
  /// It stores the parsed theme option used to set a theme for the website.
16
  pub theme: String,
src/results/aggregator.rs CHANGED
@@ -180,7 +180,7 @@ pub async fn aggregate(
180
 
181
  let results: Vec<SearchResult> = result_map.into_values().collect();
182
 
183
- Ok(SearchResults::new(results, query, &engine_errors_info))
184
  }
185
 
186
  /// Filters a map of search results using a list of regex patterns.
 
180
 
181
  let results: Vec<SearchResult> = result_map.into_values().collect();
182
 
183
+ Ok(SearchResults::new(results, &engine_errors_info))
184
  }
185
 
186
  /// Filters a map of search results using a list of regex patterns.
src/server/router.rs CHANGED
@@ -7,30 +7,30 @@ use crate::{
7
  handler::paths::{file_path, FileType},
8
  };
9
  use actix_web::{get, web, HttpRequest, HttpResponse};
10
- use handlebars::Handlebars;
11
  use std::fs::read_to_string;
12
 
13
  /// Handles the route of index page or main page of the `websurfx` meta search engine website.
14
  #[get("/")]
15
- pub async fn index(
16
- hbs: web::Data<Handlebars<'_>>,
17
- config: web::Data<Config>,
18
- ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
19
- let page_content: String = hbs.render("index", &config.style).unwrap();
20
- Ok(HttpResponse::Ok().body(page_content))
21
  }
22
 
23
  /// Handles the route of any other accessed route/page which is not provided by the
24
  /// website essentially the 404 error page.
25
  pub async fn not_found(
26
- hbs: web::Data<Handlebars<'_>>,
27
  config: web::Data<Config>,
28
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
29
- let page_content: String = hbs.render("404", &config.style)?;
30
-
31
  Ok(HttpResponse::Ok()
32
  .content_type("text/html; charset=utf-8")
33
- .body(page_content))
 
 
 
 
 
 
34
  }
35
 
36
  /// 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:
45
 
46
  /// Handles the route of about page of the `websurfx` meta search engine website.
47
  #[get("/about")]
48
- pub async fn about(
49
- hbs: web::Data<Handlebars<'_>>,
50
- config: web::Data<Config>,
51
- ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
52
- let page_content: String = hbs.render("about", &config.style)?;
53
- Ok(HttpResponse::Ok().body(page_content))
54
  }
55
 
56
  /// Handles the route of settings page of the `websurfx` meta search engine website.
57
  #[get("/settings")]
58
  pub async fn settings(
59
- hbs: web::Data<Handlebars<'_>>,
60
  config: web::Data<Config>,
61
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
62
- let page_content: String = hbs.render("settings", &config.style)?;
63
- Ok(HttpResponse::Ok().body(page_content))
 
 
 
 
 
 
 
 
 
64
  }
 
7
  handler::paths::{file_path, FileType},
8
  };
9
  use actix_web::{get, web, HttpRequest, HttpResponse};
 
10
  use std::fs::read_to_string;
11
 
12
  /// Handles the route of index page or main page of the `websurfx` meta search engine website.
13
  #[get("/")]
14
+ pub async fn index(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn std::error::Error>> {
15
+ Ok(HttpResponse::Ok().body(
16
+ crate::templates::views::index::index(&config.style.colorscheme, &config.style.theme).0,
17
+ ))
 
 
18
  }
19
 
20
  /// Handles the route of any other accessed route/page which is not provided by the
21
  /// website essentially the 404 error page.
22
  pub async fn not_found(
 
23
  config: web::Data<Config>,
24
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
 
 
25
  Ok(HttpResponse::Ok()
26
  .content_type("text/html; charset=utf-8")
27
+ .body(
28
+ crate::templates::views::not_found::not_found(
29
+ &config.style.colorscheme,
30
+ &config.style.theme,
31
+ )
32
+ .0,
33
+ ))
34
  }
35
 
36
  /// Handles the route of robots.txt page of the `websurfx` meta search engine website.
 
45
 
46
  /// Handles the route of about page of the `websurfx` meta search engine website.
47
  #[get("/about")]
48
+ pub async fn about(config: web::Data<Config>) -> Result<HttpResponse, Box<dyn std::error::Error>> {
49
+ Ok(HttpResponse::Ok().body(
50
+ crate::templates::views::about::about(&config.style.colorscheme, &config.style.theme).0,
51
+ ))
 
 
52
  }
53
 
54
  /// Handles the route of settings page of the `websurfx` meta search engine website.
55
  #[get("/settings")]
56
  pub async fn settings(
 
57
  config: web::Data<Config>,
58
  ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
59
+ Ok(HttpResponse::Ok().body(
60
+ crate::templates::views::settings::settings(
61
+ &config.style.colorscheme,
62
+ &config.style.theme,
63
+ &config
64
+ .upstream_search_engines
65
+ .keys()
66
+ .collect::<Vec<&String>>(),
67
+ )?
68
+ .0,
69
+ ))
70
  }
src/server/routes/search.rs CHANGED
@@ -6,13 +6,12 @@ use crate::{
6
  handler::paths::{file_path, FileType},
7
  models::{
8
  aggregation_models::SearchResults,
9
- engine_models::EngineHandler,
10
  server_models::{Cookie, SearchParams},
11
  },
12
  results::aggregator::aggregate,
13
  };
14
  use actix_web::{get, web, HttpRequest, HttpResponse};
15
- use handlebars::Handlebars;
16
  use regex::Regex;
17
  use std::{
18
  fs::File,
@@ -20,19 +19,6 @@ use std::{
20
  };
21
  use tokio::join;
22
 
23
- /// Handles the route of any other accessed route/page which is not provided by the
24
- /// website essentially the 404 error page.
25
- pub async fn not_found(
26
- hbs: web::Data<Handlebars<'_>>,
27
- config: web::Data<Config>,
28
- ) -> Result<HttpResponse, Box<dyn std::error::Error>> {
29
- let page_content: String = hbs.render("404", &config.style)?;
30
-
31
- Ok(HttpResponse::Ok()
32
- .content_type("text/html; charset=utf-8")
33
- .body(page_content))
34
- }
35
-
36
  /// Handles the route of search page of the `websurfx` meta search engine website and it takes
37
  /// two search url parameters `q` and `page` where `page` parameter is optional.
38
  ///
@@ -49,7 +35,6 @@ pub async fn not_found(
49
  /// ```
50
  #[get("/search")]
51
  pub async fn search(
52
- hbs: web::Data<Handlebars<'_>>,
53
  req: HttpRequest,
54
  config: web::Data<Config>,
55
  cache: web::Data<SharedCache>,
@@ -58,7 +43,7 @@ pub async fn search(
58
  match &params.q {
59
  Some(query) => {
60
  if query.trim().is_empty() {
61
- return Ok(HttpResponse::Found()
62
  .insert_header(("location", "/"))
63
  .finish());
64
  }
@@ -112,10 +97,17 @@ pub async fn search(
112
  )
113
  );
114
 
115
- let page_content: String = hbs.render("search", &results?)?;
116
- Ok(HttpResponse::Ok().body(page_content))
 
 
 
 
 
 
 
117
  }
118
- None => Ok(HttpResponse::Found()
119
  .insert_header(("location", "/"))
120
  .finish()),
121
  }
@@ -171,8 +163,6 @@ async fn results(
171
 
172
  if _flag {
173
  results.set_disallowed();
174
- results.add_style(&config.style);
175
- results.set_page_query(query);
176
  cache.cache_results(&results, &url).await?;
177
  results.set_safe_search_level(safe_search_level);
178
  return Ok(results);
@@ -221,23 +211,27 @@ async fn results(
221
  true => {
222
  let mut search_results = SearchResults::default();
223
  search_results.set_no_engines_selected();
224
- search_results.set_page_query(query);
225
  search_results
226
  }
227
  }
228
  }
229
- None => {
230
- aggregate(
231
- query,
232
- page,
233
- config.aggregator.random_delay,
234
- config.debug,
235
- &config.upstream_search_engines,
236
- config.request_timeout,
237
- safe_search_level,
238
- )
239
- .await?
240
- }
 
 
 
 
 
241
  };
242
  if results.engine_errors_info().is_empty()
243
  && results.results().is_empty()
@@ -245,7 +239,6 @@ async fn results(
245
  {
246
  results.set_filtered();
247
  }
248
- results.add_style(&config.style);
249
  cache
250
  .cache_results(&results, &(format!("{url}{safe_search_level}")))
251
  .await?;
 
6
  handler::paths::{file_path, FileType},
7
  models::{
8
  aggregation_models::SearchResults,
9
+ engine_models::{EngineError, EngineHandler},
10
  server_models::{Cookie, SearchParams},
11
  },
12
  results::aggregator::aggregate,
13
  };
14
  use actix_web::{get, web, HttpRequest, HttpResponse};
 
15
  use regex::Regex;
16
  use std::{
17
  fs::File,
 
19
  };
20
  use tokio::join;
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  /// Handles the route of search page of the `websurfx` meta search engine website and it takes
23
  /// two search url parameters `q` and `page` where `page` parameter is optional.
24
  ///
 
35
  /// ```
36
  #[get("/search")]
37
  pub async fn search(
 
38
  req: HttpRequest,
39
  config: web::Data<Config>,
40
  cache: web::Data<SharedCache>,
 
43
  match &params.q {
44
  Some(query) => {
45
  if query.trim().is_empty() {
46
+ return Ok(HttpResponse::TemporaryRedirect()
47
  .insert_header(("location", "/"))
48
  .finish());
49
  }
 
97
  )
98
  );
99
 
100
+ Ok(HttpResponse::Ok().body(
101
+ crate::templates::views::search::search(
102
+ &config.style.colorscheme,
103
+ &config.style.theme,
104
+ query,
105
+ &results?,
106
+ )
107
+ .0,
108
+ ))
109
  }
110
+ None => Ok(HttpResponse::TemporaryRedirect()
111
  .insert_header(("location", "/"))
112
  .finish()),
113
  }
 
163
 
164
  if _flag {
165
  results.set_disallowed();
 
 
166
  cache.cache_results(&results, &url).await?;
167
  results.set_safe_search_level(safe_search_level);
168
  return Ok(results);
 
211
  true => {
212
  let mut search_results = SearchResults::default();
213
  search_results.set_no_engines_selected();
 
214
  search_results
215
  }
216
  }
217
  }
218
+ None => aggregate(
219
+ query,
220
+ page,
221
+ config.aggregator.random_delay,
222
+ config.debug,
223
+ &config
224
+ .upstream_search_engines
225
+ .clone()
226
+ .into_iter()
227
+ .filter_map(|(key, value)| value.then_some(key))
228
+ .map(|engine| EngineHandler::new(&engine))
229
+ .collect::<Result<Vec<EngineHandler>, error_stack::Report<EngineError>>>(
230
+ )?,
231
+ config.request_timeout,
232
+ safe_search_level,
233
+ )
234
+ .await?,
235
  };
236
  if results.engine_errors_info().is_empty()
237
  && results.results().is_empty()
 
239
  {
240
  results.set_filtered();
241
  }
 
242
  cache
243
  .cache_results(&results, &(format!("{url}{safe_search_level}")))
244
  .await?;
src/templates/mod.rs ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ //! This module provides other modules to handle both the view and its partials for the `websurfx`
2
+ //! search engine frontend.
3
+
4
+ mod partials;
5
+ pub mod views;
src/templates/partials/bar.rs ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles `bar` partial for the `search_bar` partial and the home/index/main page in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup, PreEscaped};
4
+
5
+ /// A functions that handles the html code for the bar for the `search_bar` partial and the
6
+ /// home/index/main page in the search engine frontend.
7
+ ///
8
+ /// # Arguments
9
+ ///
10
+ /// * `query` - It takes the current search query provided by user as an argument.
11
+ ///
12
+ /// # Returns
13
+ ///
14
+ /// It returns the compiled html code for the search bar as a result.
15
+ pub fn bar(query: &str) -> Markup {
16
+ html!(
17
+ (PreEscaped("<div class=\"search_bar\">"))
18
+ input type="search" name="search-box" value=(query) placeholder="Type to search";
19
+ button type="submit" onclick="searchWeb()"{"search"}
20
+ )
21
+ }
src/templates/partials/footer.rs ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the footer for all the pages in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup, PreEscaped};
4
+
5
+ /// A functions that handles the html code for the footer for all the pages in the search engine
6
+ /// frontend.
7
+ ///
8
+ /// # Returns
9
+ ///
10
+ /// It returns the compiled html code for the footer as a result.
11
+ pub fn footer() -> Markup {
12
+ html!(
13
+ footer{
14
+ div{
15
+ span{"Powered By "b{"Websurfx"}}span{"-"}span{"a lightening fast, privacy respecting, secure meta
16
+ search engine"}
17
+ }
18
+ div{
19
+ ul{
20
+ li{a href="https://github.com/neon-mmd/websurfx"{"Source Code"}}
21
+ li{a href="https://github.com/neon-mmd/websurfx/issues"{"Issues/Bugs"}}
22
+ }
23
+ }
24
+ }
25
+ script src="static/settings.js"{}
26
+ (PreEscaped("</body>"))
27
+ (PreEscaped("</html>"))
28
+ )
29
+ }
src/templates/partials/header.rs ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the header for all the pages in the `websurfx` frontend.
2
+
3
+ use crate::templates::partials::navbar::navbar;
4
+ use maud::{html, Markup, PreEscaped, DOCTYPE};
5
+
6
+ /// A function that handles the html code for the header for all the pages in the search engine frontend.
7
+ ///
8
+ /// # Arguments
9
+ ///
10
+ /// * `colorscheme` - It takes the colorscheme name as an argument.
11
+ /// * `theme` - It takes the theme name as an argument.
12
+ ///
13
+ /// # Returns
14
+ ///
15
+ /// It returns the compiled html markup code for the header as a result.
16
+ pub fn header(colorscheme: &str, theme: &str) -> Markup {
17
+ html!(
18
+ (DOCTYPE)
19
+ html lang="en"
20
+
21
+ head{
22
+ title{"Websurfx"}
23
+ meta charset="UTF-8";
24
+ meta name="viewport" content="width=device-width, initial-scale=1";
25
+ link href=(format!("static/colorschemes/{colorscheme}.css")) rel="stylesheet" type="text/css";
26
+ link href=(format!("static/themes/{theme}.css")) rel="stylesheet" type="text/css";
27
+ }
28
+
29
+ (PreEscaped("<body onload=\"getClientSettings()\">"))
30
+ header{
31
+ h1{a href="/"{"Websurfx"}}
32
+ (navbar())
33
+ }
34
+ )
35
+ }
src/templates/partials/mod.rs ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ //! This module provides other modules to handle the partials for the views in the `websurfx` frontend.
2
+
3
+ pub mod bar;
4
+ pub mod footer;
5
+ pub mod header;
6
+ pub mod navbar;
7
+ pub mod search_bar;
8
+ pub mod settings_tabs;
src/templates/partials/navbar.rs ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles `navbar` partial for the header partial in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup};
4
+
5
+ /// A functions that handles the html code for the header partial.
6
+ ///
7
+ /// # Returns
8
+ ///
9
+ /// It returns the compiled html code for the navbar as a result.
10
+ pub fn navbar() -> Markup {
11
+ html!(
12
+ nav{
13
+ ul{
14
+ li{a href="about"{"about"}}
15
+ li{a href="settings"{"settings"}}
16
+ }
17
+ }
18
+ )
19
+ }
src/templates/partials/search_bar.rs ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles `search bar` partial for the search page in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup, PreEscaped};
4
+
5
+ use crate::{models::aggregation_models::EngineErrorInfo, templates::partials::bar::bar};
6
+
7
+ /// A constant holding the named safe search level options for the corresponding values 0, 1 and 2.
8
+ const SAFE_SEARCH_LEVELS_NAME: [&str; 3] = ["None", "Low", "Moderate"];
9
+
10
+ /// A functions that handles the html code for the search bar for the search page.
11
+ ///
12
+ /// # Arguments
13
+ ///
14
+ /// * `engine_errors_info` - It takes the engine errors list containing errors for each upstream
15
+ /// search engine which failed to provide results as an argument.
16
+ /// * `safe_search_level` - It takes the safe search level with values from 0-2 as an argument.
17
+ /// * `query` - It takes the current search query provided by user as an argument.
18
+ ///
19
+ /// # Returns
20
+ ///
21
+ /// It returns the compiled html code for the search bar as a result.
22
+ pub fn search_bar(
23
+ engine_errors_info: &[EngineErrorInfo],
24
+ safe_search_level: u8,
25
+ query: &str,
26
+ ) -> Markup {
27
+ html!(
28
+ .search_area{
29
+ (bar(query))
30
+ .error_box {
31
+ @if !engine_errors_info.is_empty(){
32
+ button onclick="toggleErrorBox()" class="error_box_toggle_button"{
33
+ img src="./images/warning.svg" alt="Info icon for error box";
34
+ }
35
+ .dropdown_error_box{
36
+ @for errors in engine_errors_info{
37
+ .error_item{
38
+ span class="engine_name"{(errors.engine)}
39
+ span class="engine_name"{(errors.error)}
40
+ span class="severity_color" style="background: {{{this.severity_color}}};"{}
41
+ }
42
+ }
43
+ }
44
+ }
45
+ @else {
46
+ button onclick="toggleErrorBox()" class="error_box_toggle_button"{
47
+ img src="./images/info.svg" alt="Warning icon for error box";
48
+ }
49
+ .dropdown_error_box {
50
+ .no_errors{
51
+ "Everything looks good 🙂!!"
52
+ }
53
+ }
54
+ }
55
+ }
56
+ (PreEscaped("</div>"))
57
+ .search_options {
58
+ @if safe_search_level >= 3 {
59
+ (PreEscaped("<select name=\"safe_search_levels\" disabled>"))
60
+ }
61
+ @else{
62
+ (PreEscaped("<select name=\"safe_search_levels\">"))
63
+ }
64
+ @for (idx, name) in SAFE_SEARCH_LEVELS_NAME.iter().enumerate() {
65
+ @if (safe_search_level as usize) == idx {
66
+ option value=(idx) selected {(format!("SafeSearch: {name}"))}
67
+ }
68
+ @else{
69
+ option value=(idx) {(format!("SafeSearch: {name}"))}
70
+ }
71
+ }
72
+ (PreEscaped("</select>"))
73
+ }
74
+ }
75
+ )
76
+ }
src/templates/partials/settings_tabs/cookies.rs ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the engines tab for setting page view in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup};
4
+
5
+ /// A functions that handles the html code for the cookies tab for the settings page for the search page.
6
+ ///
7
+ /// # Returns
8
+ ///
9
+ /// It returns the compiled html markup code for the cookies tab.
10
+ pub fn cookies() -> Markup {
11
+ html!(
12
+ div class="cookies tab"{
13
+ h1{"Cookies"}
14
+ p class="description"{
15
+ "This is the cookies are saved on your system and it contains the preferences
16
+ you chose in the settings page"
17
+ }
18
+ input type="text" name="cookie_field" value="" readonly;
19
+ p class="description"{
20
+ "The cookies stored are not used by us for any malicious intend or for
21
+ tracking you in any way."
22
+ }
23
+ }
24
+ )
25
+ }
src/templates/partials/settings_tabs/engines.rs ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the engines tab for setting page view in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup};
4
+
5
+ /// A functions that handles the html code for the engines tab for the settings page for the search page.
6
+ ///
7
+ /// # Arguments
8
+ ///
9
+ /// * `engine_names` - It takes the list of all available engine names as an argument.
10
+ ///
11
+ /// # Returns
12
+ ///
13
+ /// It returns the compiled html markup code for the engines tab.
14
+ pub fn engines(engine_names: &[&String]) -> Markup {
15
+ html!(
16
+ div class="engines tab"{
17
+ h1{"Engines"}
18
+ h3{"select search engines"}
19
+ p class="description"{
20
+ "Select the search engines from the list of engines that you want results from"
21
+ }
22
+ .engine_selection{
23
+ .toggle_btn{
24
+ label class="switch"{
25
+ input type="checkbox" class="select_all" onchange="toggleAllSelection()";
26
+ span class="slider round"{}
27
+ }
28
+ "Select All"
29
+ }
30
+ hr;
31
+ @for engine_name in engine_names{
32
+ .toggle_btn{
33
+ label class="switch"{
34
+ input type="checkbox" class="engine";
35
+ span class="slider round"{}
36
+ }
37
+ (format!("{}{}",engine_name[..1].to_uppercase().to_owned(), engine_name[1..].to_owned()))
38
+ }
39
+ }
40
+ }
41
+ }
42
+ )
43
+ }
src/templates/partials/settings_tabs/general.rs ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the general tab for setting page view in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup};
4
+
5
+ /// A constant holding the named safe search level options for the corresponding values 0, 1 and 2.
6
+ const SAFE_SEARCH_LEVELS: [(u8, &str); 3] = [(0, "None"), (1, "Low"), (2, "Moderate")];
7
+
8
+ /// A functions that handles the html code for the general tab for the settings page for the search page.
9
+ ///
10
+ /// # Returns
11
+ ///
12
+ /// It returns the compiled html markup code for the general tab.
13
+ pub fn general() -> Markup {
14
+ html!(
15
+ div class="general tab active"{
16
+ h1{"General"}
17
+ h3{"Select a safe search level"}
18
+ p class="description"{
19
+ "Select a safe search level from the menu below to filter content based on the level."
20
+ }
21
+ select name="safe_search_levels"{
22
+ @for (k,v) in SAFE_SEARCH_LEVELS{
23
+ option value=(k){(v)}
24
+ }
25
+ }
26
+ }
27
+ )
28
+ }
src/templates/partials/settings_tabs/mod.rs ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ //! This module provides other modules to handle the partials for the tabs for the settings page
2
+ //! view in the `websurfx` frontend.
3
+
4
+ pub mod cookies;
5
+ pub mod engines;
6
+ pub mod general;
7
+ pub mod user_interface;
src/templates/partials/settings_tabs/user_interface.rs ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the user interface tab for setting page view in the `websurfx` frontend.
2
+
3
+ use crate::handler::paths::{file_path, FileType};
4
+ use maud::{html, Markup};
5
+ use std::fs::read_dir;
6
+
7
+ /// A helper function that helps in building the list of all available colorscheme/theme names
8
+ /// present in the colorschemes and themes folder respectively.
9
+ ///
10
+ /// # Arguments
11
+ ///
12
+ /// * `style_type` - It takes the style type of the values `theme` and `colorscheme` as an
13
+ /// argument.
14
+ ///
15
+ /// # Error
16
+ ///
17
+ /// Returns a list of colorscheme/theme names as a vector of tuple strings on success otherwise
18
+ /// returns a standard error message.
19
+ fn style_option_list(
20
+ style_type: &str,
21
+ ) -> Result<Vec<(String, String)>, Box<dyn std::error::Error + '_>> {
22
+ let mut style_option_names: Vec<(String, String)> = Vec::new();
23
+ for file in read_dir(format!(
24
+ "{}static/{}/",
25
+ file_path(FileType::Theme)?,
26
+ style_type,
27
+ ))? {
28
+ let style_name = file?.file_name().to_str().unwrap().replace(".css", "");
29
+ style_option_names.push((style_name.clone(), style_name.replace('-', " ")));
30
+ }
31
+
32
+ Ok(style_option_names)
33
+ }
34
+
35
+ /// A functions that handles the html code for the user interface tab for the settings page for the search page.
36
+ ///
37
+ /// # Error
38
+ ///
39
+ /// It returns the compiled html markup code for the user interface tab on success otherwise
40
+ /// returns a standard error message.
41
+ pub fn user_interface() -> Result<Markup, Box<dyn std::error::Error>> {
42
+ Ok(html!(
43
+ div class="user_interface tab"{
44
+ h1{"User Interface"}
45
+ h3{"select theme"}
46
+ p class="description"{
47
+ "Select the theme from the available themes to be used in user interface"
48
+ }
49
+ select name="themes"{
50
+ @for (k,v) in style_option_list("themes")?{
51
+ option value=(k){(v)}
52
+ }
53
+ }
54
+ h3{"select color scheme"}
55
+ p class="description"{
56
+ "Select the color scheme for your theme to be used in user interface"
57
+ }
58
+ select name="colorschemes"{
59
+ @for (k,v) in style_option_list("colorschemes")?{
60
+ option value=(k){(v)}
61
+ }
62
+ }
63
+ }
64
+ ))
65
+ }
src/templates/views/about.rs ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the view for the about page in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup};
4
+
5
+ use crate::templates::partials::{footer::footer, header::header};
6
+
7
+ /// A function that handles the html code for the about page view in the search engine frontend.
8
+ ///
9
+ /// # Arguments
10
+ ///
11
+ /// * `colorscheme` - It takes the colorscheme name as an argument.
12
+ /// * `theme` - It takes the theme name as an argument.
13
+ ///
14
+ /// # Returns
15
+ ///
16
+ /// It returns the compiled html markup code as a result.
17
+ pub fn about(colorscheme: &str, theme: &str) -> Markup {
18
+ html!(
19
+ (header(colorscheme, theme))
20
+ main class="about-container"{
21
+ article {
22
+ div{
23
+ h1{"Websurfx"}
24
+ hr size="4" width="100%" color="#a6e3a1"{}
25
+ }
26
+ 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."
27
+ }
28
+
29
+ h2{"Some of the Top Features:"}
30
+
31
+ ul{strong{"Lightning fast "}"- Results load within milliseconds for an instant search experience."}
32
+
33
+ ul{strong{"Secure search"}" - All searches are performed over an encrypted connection to prevent snooping."}
34
+
35
+ ul{strong{"Ad free results"}" - All search results are ad free and clutter free for a clean search experience."}
36
+
37
+ ul{strong{"Privacy focused"}" - Websurfx does not track, store or sell your search data. Your privacy is our priority."}
38
+
39
+ 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."}
40
+
41
+ ul{strong{"Highly customizable"}" - Websurfx comes with 9 built-in color themes and supports creating custom themes effortlessly."}
42
+ }
43
+
44
+ h3{"Devoloped by: "{a href="https://github.com/neon-mmd/websurfx"{"Websurfx team"}}}
45
+ }
46
+ (footer())
47
+ )
48
+ }
src/templates/views/index.rs ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the view for the index/home/main page in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup, PreEscaped};
4
+
5
+ use crate::templates::partials::{bar::bar, footer::footer, header::header};
6
+
7
+ /// A function that handles the html code for the index/html/main page view in the search engine frontend.
8
+ ///
9
+ /// # Arguments
10
+ ///
11
+ /// * `colorscheme` - It takes the colorscheme name as an argument.
12
+ /// * `theme` - It takes the theme name as an argument.
13
+ ///
14
+ /// # Returns
15
+ ///
16
+ /// It returns the compiled html markup code as a result.
17
+ pub fn index(colorscheme: &str, theme: &str) -> Markup {
18
+ html!(
19
+ (header(colorscheme, theme))
20
+ main class="search-container"{
21
+ img src="../images/websurfx_logo.png" alt="Websurfx meta-search engine logo";
22
+ (bar(&String::default()))
23
+ (PreEscaped("</div>"))
24
+ }
25
+ script src="static/index.js"{}
26
+ (footer())
27
+ )
28
+ }
src/templates/views/mod.rs ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ //! This module provides other modules to handle view for each individual page in the
2
+ //! `websurfx` frontend.
3
+
4
+ pub mod about;
5
+ pub mod index;
6
+ pub mod not_found;
7
+ pub mod search;
8
+ pub mod settings;
src/templates/views/not_found.rs ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the view for the 404 page in the `websurfx` frontend.
2
+
3
+ use crate::templates::partials::{footer::footer, header::header};
4
+ use maud::{html, Markup};
5
+
6
+ /// A function that handles the html code for the 404 page view in the search engine frontend.
7
+ ///
8
+ /// # Arguments
9
+ ///
10
+ /// * `colorscheme` - It takes the colorscheme name as an argument.
11
+ /// * `theme` - It takes the theme name as an argument.
12
+ ///
13
+ /// # Returns
14
+ ///
15
+ /// It returns the compiled html markup code as a result.
16
+ pub fn not_found(colorscheme: &str, theme: &str) -> Markup {
17
+ html!(
18
+ (header(colorscheme, theme))
19
+ main class="error_container"{
20
+ img src="images/robot-404.svg" alt="Image of broken robot.";
21
+ .error_content{
22
+ h1{"Aw! snap"}
23
+ h2{"404 Page Not Found!"}
24
+ p{"Go to "{a href="/"{"search page"}}}
25
+ }
26
+ }
27
+ (footer())
28
+ )
29
+ }
src/templates/views/search.rs ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the view for the search page in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup, PreEscaped};
4
+
5
+ use crate::{
6
+ models::aggregation_models::SearchResults,
7
+ templates::partials::{footer::footer, header::header, search_bar::search_bar},
8
+ };
9
+
10
+ /// A function that handles the html code for the search page view in the search engine frontend.
11
+ ///
12
+ /// # Arguments
13
+ ///
14
+ /// * `colorscheme` - It takes the colorscheme name as an argument.
15
+ /// * `theme` - It takes the theme name as an argument.
16
+ /// * `query` - It takes the current search query provided by the user as an argument.
17
+ /// * `search_results` - It takes the aggregated search results as an argument.
18
+ ///
19
+ /// # Returns
20
+ ///
21
+ /// It returns the compiled html markup code as a result.
22
+ pub fn search(
23
+ colorscheme: &str,
24
+ theme: &str,
25
+ query: &str,
26
+ search_results: &SearchResults,
27
+ ) -> Markup {
28
+ html!(
29
+ (header(colorscheme, theme))
30
+ main class="results"{
31
+ (search_bar(&search_results.engine_errors_info, search_results.safe_search_level, query))
32
+ .results_aggregated{
33
+ @if !search_results.results.is_empty() {
34
+ @for result in search_results.results.iter(){
35
+ .result {
36
+ h1{a href=(result.url){(PreEscaped(&result.title))}}
37
+ small{(result.url)}
38
+ p{(PreEscaped(&result.description))}
39
+ .upstream_engines{
40
+ @for name in result.clone().engine{
41
+ span{(name)}
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ @else if search_results.disallowed{
48
+ .result_disallowed{
49
+ .description{
50
+ p{
51
+ "Your search - "{span class="user_query"{(query)}}" -
52
+ has been disallowed."
53
+ }
54
+ p class="description_paragraph"{"Dear user,"}
55
+ p class="description_paragraph"{
56
+ "The query - "{span class="user_query"{(query)}}" - has
57
+ been blacklisted via server configuration and hence disallowed by the
58
+ server. Henceforth no results could be displayed for your query."
59
+ }
60
+ }
61
+ img src="./images/barricade.png" alt="Image of a Barricade";
62
+ }
63
+ }
64
+ @else if search_results.filtered {
65
+ .result_filtered{
66
+ .description{
67
+ p{
68
+ "Your search - "{span class="user_query"{(query)}}" -
69
+ has been filtered."
70
+ }
71
+ p class="description_paragraph"{"Dear user,"}
72
+ p class="description_paragraph"{
73
+ "All the search results contain results that has been configured to be
74
+ filtered out via server configuration and henceforth has been
75
+ completely filtered out."
76
+ }
77
+ }
78
+ img src="./images/filter.png" alt="Image of a paper inside a funnel";
79
+ }
80
+ }
81
+ @else if search_results.no_engines_selected {
82
+ .result_engine_not_selected{
83
+ .description{
84
+ p{
85
+ "No results could be fetched for your search '{span class="user_query"{(query)}}'."
86
+ }
87
+ p class="description_paragraph"{"Dear user,"}
88
+ p class="description_paragraph"{
89
+ "No results could be retrieved from the upstream search engines as no
90
+ upstream search engines were selected from the settings page."
91
+ }
92
+ }
93
+ img src="./images/no_selection.png" alt="Image of a white cross inside a red circle";
94
+ }
95
+ }
96
+ @else{
97
+ .result_not_found {
98
+ p{"Your search - "{(query)}" - did not match any documents."}
99
+ p class="suggestions"{"Suggestions:"}
100
+ ul{
101
+ li{"Make sure that all words are spelled correctly."}
102
+ li{"Try different keywords."}
103
+ li{"Try more general keywords."}
104
+ }
105
+ img src="./images/no_results.gif" alt="Man fishing gif";
106
+ }
107
+ }
108
+ }
109
+ .page_navigation {
110
+ button type="button" onclick="navigate_backward()"{
111
+ (PreEscaped("&#8592;")) "previous"
112
+ }
113
+ button type="button" onclick="navigate_forward()"{"next" (PreEscaped("&#8594;"))}
114
+ }
115
+ }
116
+ script src="static/index.js"{}
117
+ script src="static/search_area_options.js"{}
118
+ script src="static/pagination.js"{}
119
+ script src="static/error_box.js"{}
120
+ (footer())
121
+ )
122
+ }
src/templates/views/settings.rs ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! A module that handles the view for the settings page in the `websurfx` frontend.
2
+
3
+ use maud::{html, Markup};
4
+
5
+ use crate::templates::partials::{
6
+ footer::footer,
7
+ header::header,
8
+ settings_tabs::{
9
+ cookies::cookies, engines::engines, general::general, user_interface::user_interface,
10
+ },
11
+ };
12
+
13
+ /// A function that handles the html code for the settings page view in the search engine frontend.
14
+ ///
15
+ /// # Arguments
16
+ ///
17
+ /// * `colorscheme` - It takes the colorscheme name as an argument.
18
+ /// * `theme` - It takes the theme name as an argument.
19
+ /// * `engine_names` - It takes a list of engine names as an argument.
20
+ ///
21
+ /// # Error
22
+ ///
23
+ /// This function returns a compiled html markup code on success otherwise returns a standard error
24
+ /// message.
25
+ pub fn settings(
26
+ colorscheme: &str,
27
+ theme: &str,
28
+ engine_names: &[&String],
29
+ ) -> Result<Markup, Box<dyn std::error::Error>> {
30
+ Ok(html!(
31
+ (header(colorscheme, theme))
32
+ main class="settings"{
33
+ h1{"Settings"}
34
+ hr;
35
+ .settings_container{
36
+ .sidebar{
37
+ div class="btn active" onclick="setActiveTab(this)"{"general"}
38
+ .btn onclick="setActiveTab(this)"{"user interface"}
39
+ .btn onclick="setActiveTab(this)"{"engines"}
40
+ .btn onclick="setActiveTab(this)"{"cookies"}
41
+ }
42
+ .main_container{
43
+ (general())
44
+ (user_interface()?)
45
+ (engines(engine_names))
46
+ (cookies())
47
+ p class="message"{}
48
+ button type="submit" onclick="setClientSettings()"{"Save"}
49
+ }
50
+ }
51
+ }
52
+ script src="static/settings.js"{}
53
+ script src="static/cookies.js"{}
54
+ (footer())
55
+ ))
56
+ }
tests/index.rs CHANGED
@@ -1,7 +1,6 @@
1
  use std::net::TcpListener;
2
 
3
- use handlebars::Handlebars;
4
- use websurfx::{config::parser::Config, run};
5
 
6
  // Starts a new instance of the HTTP server, bound to a random available port
7
  fn spawn_app() -> String {
@@ -21,18 +20,6 @@ fn spawn_app() -> String {
21
  format!("http://127.0.0.1:{}/", port)
22
  }
23
 
24
- // Creates a new instance of Handlebars and registers the templates directory.
25
- // This is used to compare the rendered template with the response body.
26
- fn handlebars() -> Handlebars<'static> {
27
- let mut handlebars = Handlebars::new();
28
-
29
- handlebars
30
- .register_templates_directory(".html", "./public/templates")
31
- .unwrap();
32
-
33
- handlebars
34
- }
35
-
36
  #[tokio::test]
37
  async fn test_index() {
38
  let address = spawn_app();
@@ -41,9 +28,8 @@ async fn test_index() {
41
  let res = client.get(address).send().await.unwrap();
42
  assert_eq!(res.status(), 200);
43
 
44
- let handlebars = handlebars();
45
  let config = Config::parse(true).unwrap();
46
- let template = handlebars.render("index", &config.style).unwrap();
47
  assert_eq!(res.text().await.unwrap(), template);
48
  }
49
 
 
1
  use std::net::TcpListener;
2
 
3
+ use websurfx::{config::parser::Config, run, templates::views};
 
4
 
5
  // Starts a new instance of the HTTP server, bound to a random available port
6
  fn spawn_app() -> String {
 
20
  format!("http://127.0.0.1:{}/", port)
21
  }
22
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  #[tokio::test]
24
  async fn test_index() {
25
  let address = spawn_app();
 
28
  let res = client.get(address).send().await.unwrap();
29
  assert_eq!(res.status(), 200);
30
 
 
31
  let config = Config::parse(true).unwrap();
32
+ let template = views::index::index(&config.style.colorscheme, &config.style.theme).0;
33
  assert_eq!(res.text().await.unwrap(), template);
34
  }
35