alamin655 commited on
Commit
5c9559b
2 Parent(s): 831ab5a 1ec26d6

Merge pull request #258 from neon-mmd/feat-safe-search-setting-ui

Browse files
Cargo.lock CHANGED
@@ -3932,7 +3932,7 @@ dependencies = [
3932
 
3933
  [[package]]
3934
  name = "websurfx"
3935
- version = "0.21.6"
3936
  dependencies = [
3937
  "actix-cors",
3938
  "actix-files",
 
3932
 
3933
  [[package]]
3934
  name = "websurfx"
3935
+ version = "0.22.0"
3936
  dependencies = [
3937
  "actix-cors",
3938
  "actix-files",
Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
  [package]
2
  name = "websurfx"
3
- version = "0.21.6"
4
  edition = "2021"
5
  description = "An open-source alternative to Searx that provides clean, ad-free, and organic results with incredible speed while keeping privacy and security in mind."
6
  repository = "https://github.com/neon-mmd/websurfx"
 
1
  [package]
2
  name = "websurfx"
3
+ version = "0.22.0"
4
  edition = "2021"
5
  description = "An open-source alternative to Searx that provides clean, ad-free, and organic results with incredible speed while keeping privacy and security in mind."
6
  repository = "https://github.com/neon-mmd/websurfx"
public/static/cookies.js CHANGED
@@ -16,8 +16,9 @@ document.addEventListener(
16
  let cookie = decodeURIComponent(document.cookie)
17
  // Set the value of the input field to the decoded cookie value if it is not empty
18
  // Otherwise, display a message indicating that no cookies have been saved on the user's system
19
- document.querySelector('.cookies input').value =
20
- cookie !== '' ? cookie : 'No cookies have been saved on your system'
 
21
  } catch (error) {
22
  // If there is an error decoding the cookie, log the error to the console
23
  // and display an error message in the input field
@@ -25,5 +26,5 @@ document.addEventListener(
25
  document.querySelector('.cookies input').value = 'Error decoding cookie'
26
  }
27
  },
28
- false
29
  )
 
16
  let cookie = decodeURIComponent(document.cookie)
17
  // Set the value of the input field to the decoded cookie value if it is not empty
18
  // Otherwise, display a message indicating that no cookies have been saved on the user's system
19
+ document.querySelector('.cookies input').value = cookie.length
20
+ ? cookie
21
+ : 'No cookies have been saved on your system'
22
  } catch (error) {
23
  // If there is an error decoding the cookie, log the error to the console
24
  // and display an error message in the input field
 
26
  document.querySelector('.cookies input').value = 'Error decoding cookie'
27
  }
28
  },
29
+ false,
30
  )
public/static/index.js CHANGED
@@ -2,16 +2,25 @@
2
  * Selects the input element for the search box
3
  * @type {HTMLInputElement}
4
  */
5
- const searchBox = document.querySelector('input');
6
 
7
  /**
8
  * Redirects the user to the search results page with the query parameter
9
  */
10
  function searchWeb() {
11
- const query = searchBox.value.trim();
12
- if (query) {
13
- window.location.href = `search?q=${encodeURIComponent(query)}`;
14
- }
 
 
 
 
 
 
 
 
 
15
  }
16
 
17
  /**
@@ -19,7 +28,7 @@ function searchWeb() {
19
  * @param {KeyboardEvent} e - The keyboard event object
20
  */
21
  searchBox.addEventListener('keyup', (e) => {
22
- if (e.key === 'Enter') {
23
- searchWeb();
24
- }
25
- });
 
2
  * Selects the input element for the search box
3
  * @type {HTMLInputElement}
4
  */
5
+ const searchBox = document.querySelector('input')
6
 
7
  /**
8
  * Redirects the user to the search results page with the query parameter
9
  */
10
  function searchWeb() {
11
+ const query = searchBox.value.trim()
12
+ try {
13
+ let safeSearchLevel = document.querySelector('.search_options select').value
14
+ if (query) {
15
+ window.location.href = `search?q=${encodeURIComponent(
16
+ query,
17
+ )}&safesearch=${encodeURIComponent(safeSearchLevel)}`
18
+ }
19
+ } catch (error) {
20
+ if (query) {
21
+ window.location.href = `search?q=${encodeURIComponent(query)}`
22
+ }
23
+ }
24
  }
25
 
26
  /**
 
28
  * @param {KeyboardEvent} e - The keyboard event object
29
  */
30
  searchBox.addEventListener('keyup', (e) => {
31
+ if (e.key === 'Enter') {
32
+ searchWeb()
33
+ }
34
+ })
public/static/pagination.js CHANGED
@@ -3,8 +3,8 @@
3
  * @returns {void}
4
  */
5
  function navigate_forward() {
6
- const url = new URL(window.location);
7
- const searchParams = url.searchParams;
8
 
9
  let q = searchParams.get('q');
10
  let page = parseInt(searchParams.get('page'));
@@ -23,8 +23,8 @@ function navigate_forward() {
23
  * @returns {void}
24
  */
25
  function navigate_backward() {
26
- const url = new URL(window.location);
27
- const searchParams = url.searchParams;
28
 
29
  let q = searchParams.get('q');
30
  let page = parseInt(searchParams.get('page'));
 
3
  * @returns {void}
4
  */
5
  function navigate_forward() {
6
+ let url = new URL(window.location);
7
+ let searchParams = url.searchParams;
8
 
9
  let q = searchParams.get('q');
10
  let page = parseInt(searchParams.get('page'));
 
23
  * @returns {void}
24
  */
25
  function navigate_backward() {
26
+ let url = new URL(window.location);
27
+ let searchParams = url.searchParams;
28
 
29
  let q = searchParams.get('q');
30
  let page = parseInt(searchParams.get('page'));
public/static/search_area_options.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener(
2
+ 'DOMContentLoaded',
3
+ () => {
4
+ let url = new URL(window.location)
5
+ let searchParams = url.searchParams
6
+
7
+ let safeSearchLevel = searchParams.get('safesearch')
8
+
9
+ if (
10
+ safeSearchLevel >= 0 &&
11
+ safeSearchLevel <= 2 &&
12
+ safeSearchLevel !== null
13
+ ) {
14
+ document.querySelector('.search_options select').value = safeSearchLevel
15
+ }
16
+ },
17
+ false,
18
+ )
public/static/settings.js CHANGED
@@ -1,5 +1,5 @@
1
  /**
2
- * This function handles the toggling of selections of all upstream search engines
3
  * options in the settings page under the tab engines.
4
  */
5
  function toggleAllSelection() {
@@ -8,12 +8,12 @@ function toggleAllSelection() {
8
  .forEach(
9
  (engine_checkbox) =>
10
  (engine_checkbox.checked =
11
- document.querySelector('.select_all').checked)
12
  )
13
  }
14
 
15
  /**
16
- * This function adds the functionality to sidebar buttons to only show settings
17
  * related to that tab.
18
  * @param {HTMLElement} current_tab - The current tab that was clicked.
19
  */
@@ -43,20 +43,28 @@ function setClientSettings() {
43
 
44
  // Loop through all select tags and add their values to the cookie dictionary
45
  document.querySelectorAll('select').forEach((select_tag) => {
46
- if (select_tag.name === 'themes') {
47
- cookie_dictionary['theme'] = select_tag.value
48
- } else if (select_tag.name === 'colorschemes') {
49
- cookie_dictionary['colorscheme'] = select_tag.value
 
 
 
 
 
 
50
  }
51
  })
52
 
53
  // Loop through all engine checkboxes and add their values to the cookie dictionary
54
  let engines = []
 
55
  document.querySelectorAll('.engine').forEach((engine_checkbox) => {
56
- if (engine_checkbox.checked === true) {
57
  engines.push(engine_checkbox.parentNode.parentNode.innerText.trim())
58
  }
59
  })
 
60
  cookie_dictionary['engines'] = engines
61
 
62
  // Set the expiration date for the cookie to 1 year from the current date
@@ -65,7 +73,7 @@ function setClientSettings() {
65
 
66
  // Save the cookie to the user's machine
67
  document.cookie = `appCookie=${JSON.stringify(
68
- cookie_dictionary
69
  )}; expires=${expiration_date.toUTCString()}`
70
 
71
  // Display a success message to the user
@@ -79,9 +87,9 @@ function setClientSettings() {
79
  }
80
 
81
  /**
82
- * This functions gets the saved cookies if it is present on the user's machine If it
83
- * is available then it is parsed and converted to an object which is then used to
84
- * retrieve the preferences that the user had selected previously and is then loaded in the
85
  * website otherwise the function does nothing and the default server side settings are loaded.
86
  */
87
  function getClientSettings() {
@@ -89,21 +97,19 @@ function getClientSettings() {
89
  let cookie = decodeURIComponent(document.cookie)
90
 
91
  // If the cookie is not empty, parse it and use it to set the user's preferences
92
- if (cookie !== '') {
93
- let cookie_value = decodeURIComponent(document.cookie)
94
  .split(';')
95
  .map((item) => item.split('='))
96
  .reduce((acc, [_, v]) => (acc = JSON.parse(v)) && acc, {})
97
 
98
  // Loop through all link tags and update their href values to match the user's preferences
99
- let links = Array.from(document.querySelectorAll('link')).forEach(
100
- (item) => {
101
- if (item.href.includes('static/themes')) {
102
- item.href = `static/themes/${cookie_value['theme']}.css`
103
- } else if (item.href.includes('static/colorschemes')) {
104
- item.href = `static/colorschemes/${cookie_value['colorscheme']}.css`
105
- }
106
  }
107
- )
108
  }
109
  }
 
1
  /**
2
+ * This function handles the toggling of selections of all upstream search engines
3
  * options in the settings page under the tab engines.
4
  */
5
  function toggleAllSelection() {
 
8
  .forEach(
9
  (engine_checkbox) =>
10
  (engine_checkbox.checked =
11
+ document.querySelector('.select_all').checked),
12
  )
13
  }
14
 
15
  /**
16
+ * This function adds the functionality to sidebar buttons to only show settings
17
  * related to that tab.
18
  * @param {HTMLElement} current_tab - The current tab that was clicked.
19
  */
 
43
 
44
  // Loop through all select tags and add their values to the cookie dictionary
45
  document.querySelectorAll('select').forEach((select_tag) => {
46
+ switch (select_tag.name) {
47
+ case 'themes':
48
+ cookie_dictionary['theme'] = select_tag.value
49
+ break
50
+ case 'colorschemes':
51
+ cookie_dictionary['colorscheme'] = select_tag.value
52
+ break
53
+ case 'safe_search_levels':
54
+ cookie_dictionary['safe_search_level'] = Number(select_tag.value)
55
+ break
56
  }
57
  })
58
 
59
  // Loop through all engine checkboxes and add their values to the cookie dictionary
60
  let engines = []
61
+
62
  document.querySelectorAll('.engine').forEach((engine_checkbox) => {
63
+ if (engine_checkbox.checked) {
64
  engines.push(engine_checkbox.parentNode.parentNode.innerText.trim())
65
  }
66
  })
67
+
68
  cookie_dictionary['engines'] = engines
69
 
70
  // Set the expiration date for the cookie to 1 year from the current date
 
73
 
74
  // Save the cookie to the user's machine
75
  document.cookie = `appCookie=${JSON.stringify(
76
+ cookie_dictionary,
77
  )}; expires=${expiration_date.toUTCString()}`
78
 
79
  // Display a success message to the user
 
87
  }
88
 
89
  /**
90
+ * This functions gets the saved cookies if it is present on the user's machine If it
91
+ * is available then it is parsed and converted to an object which is then used to
92
+ * retrieve the preferences that the user had selected previously and is then loaded in the
93
  * website otherwise the function does nothing and the default server side settings are loaded.
94
  */
95
  function getClientSettings() {
 
97
  let cookie = decodeURIComponent(document.cookie)
98
 
99
  // If the cookie is not empty, parse it and use it to set the user's preferences
100
+ if (cookie.length) {
101
+ let cookie_value = cookie
102
  .split(';')
103
  .map((item) => item.split('='))
104
  .reduce((acc, [_, v]) => (acc = JSON.parse(v)) && acc, {})
105
 
106
  // Loop through all link tags and update their href values to match the user's preferences
107
+ Array.from(document.querySelectorAll('link')).forEach((item) => {
108
+ if (item.href.includes('static/themes')) {
109
+ item.href = `static/themes/${cookie_value['theme']}.css`
110
+ } else if (item.href.includes('static/colorschemes')) {
111
+ item.href = `static/colorschemes/${cookie_value['colorscheme']}.css`
 
 
112
  }
113
+ })
114
  }
115
  }
public/static/themes/simple.css CHANGED
@@ -70,6 +70,28 @@ body {
70
  filter: brightness(1.2);
71
  }
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  .result_not_found {
74
  display: flex;
75
  flex-direction: column;
@@ -499,7 +521,8 @@ footer {
499
  color: var(--foreground-color);
500
  }
501
 
502
- .settings_container .user_interface select {
 
503
  margin: 0.7rem 0;
504
  width: 20rem;
505
  background-color: var(--background-color);
@@ -511,7 +534,8 @@ footer {
511
  text-transform: capitalize;
512
  }
513
 
514
- .settings_container .user_interface option:hover {
 
515
  background-color: var(--color-one);
516
  }
517
 
 
70
  filter: brightness(1.2);
71
  }
72
 
73
+ .search_area .search_options {
74
+ display: flex;
75
+ justify-content: space-between;
76
+ align-items: center;
77
+ }
78
+
79
+ .search_area .search_options select {
80
+ margin: 0.7rem 0;
81
+ width: 20rem;
82
+ background-color: var(--color-one);
83
+ color: var(--foreground-color);
84
+ padding: 1rem 2rem;
85
+ border-radius: 0.5rem;
86
+ outline: none;
87
+ border: none;
88
+ text-transform: capitalize;
89
+ }
90
+
91
+ .search_area .search_options option:hover {
92
+ background-color: var(--color-one);
93
+ }
94
+
95
  .result_not_found {
96
  display: flex;
97
  flex-direction: column;
 
521
  color: var(--foreground-color);
522
  }
523
 
524
+ .settings_container .user_interface select,
525
+ .settings_container .general select {
526
  margin: 0.7rem 0;
527
  width: 20rem;
528
  background-color: var(--background-color);
 
534
  text-transform: capitalize;
535
  }
536
 
537
+ .settings_container .user_interface option:hover,
538
+ .settings_container .general option:hover {
539
  background-color: var(--color-one);
540
  }
541
 
public/templates/engines_tab.html CHANGED
@@ -1,4 +1,5 @@
1
  <div class="engines tab">
 
2
  <h3>select search engines</h3>
3
  <p class="description">
4
  Select the search engines from the list of engines that you want results
 
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
public/templates/general_tab.html CHANGED
@@ -1,4 +1,13 @@
1
  <div class="general tab active">
2
  <h1>General</h1>
3
- <p class="description">Coming soon!!</p>
 
 
 
 
 
 
 
 
 
4
  </div>
 
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/search.html CHANGED
@@ -66,6 +66,7 @@
66
  </div>
67
  </main>
68
  <script src="static/index.js"></script>
 
69
  <script src="static/pagination.js"></script>
70
  <script src="static/error_box.js"></script>
71
  {{>footer}}
 
66
  </div>
67
  </main>
68
  <script src="static/index.js"></script>
69
+ <script src="static/search_area_options.js"></script>
70
  <script src="static/pagination.js"></script>
71
  <script src="static/error_box.js"></script>
72
  {{>footer}}
public/templates/search_bar.html CHANGED
@@ -1,27 +1,36 @@
1
- {{>bar this}}
2
- <div class="error_box">
3
- {{#if engineErrorsInfo}}
4
- <button onclick="toggleErrorBox()" class="error_box_toggle_button">
5
- <img src="./images/warning.svg" alt="Info icon for error box" />
6
- </button>
7
- <div class="dropdown_error_box">
8
- {{#each engineErrorsInfo}}
9
- <div class="error_item">
10
- <span class="engine_name">{{{this.engine}}}</span>
11
- <span class="engine_name">{{{this.error}}}</span>
12
- <span class="severity_color" style="background: {{{this.severity_color}}};"></span>
 
 
 
13
  </div>
14
- {{/each}}
15
- </div>
16
- {{else}}
17
- <button onclick="toggleErrorBox()" class="error_box_toggle_button">
18
- <img src="./images/info.svg" alt="Warning icon for error box" />
19
- </button>
20
- <div class="dropdown_error_box">
21
- <div class="no_errors">
22
- Everything looks good 🙂!!
23
  </div>
 
24
  </div>
25
- {{/if}}
 
 
 
 
 
 
26
  </div>
27
  </div>
 
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/user_interface_tab.html CHANGED
@@ -1,4 +1,5 @@
1
  <div class="user_interface tab">
 
2
  <h3>select theme</h3>
3
  <p class="description">
4
  Select the theme from the available themes to be used in user interface
 
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
src/models/aggregation_models.rs CHANGED
@@ -122,6 +122,8 @@ pub struct SearchResults {
122
  /// search query was filtered when the safe search level set to 3 and it
123
  /// was present in the `Blocklist` file.
124
  pub filtered: bool,
 
 
125
  }
126
 
127
  impl SearchResults {
@@ -147,6 +149,7 @@ impl SearchResults {
147
  engine_errors_info: engine_errors_info.to_owned(),
148
  disallowed: Default::default(),
149
  filtered: Default::default(),
 
150
  }
151
  }
152
 
@@ -178,4 +181,9 @@ impl SearchResults {
178
  pub fn results(&mut self) -> Vec<SearchResult> {
179
  self.results.clone()
180
  }
 
 
 
 
 
181
  }
 
122
  /// search query was filtered when the safe search level set to 3 and it
123
  /// was present in the `Blocklist` file.
124
  pub filtered: bool,
125
+ /// Stores the safe search level `safesearch` provided in the search url.
126
+ pub safe_search_level: u8,
127
  }
128
 
129
  impl SearchResults {
 
149
  engine_errors_info: engine_errors_info.to_owned(),
150
  disallowed: Default::default(),
151
  filtered: Default::default(),
152
+ safe_search_level: Default::default(),
153
  }
154
  }
155
 
 
181
  pub fn results(&mut self) -> Vec<SearchResult> {
182
  self.results.clone()
183
  }
184
+
185
+ /// A setter function to set the current page safe search level.
186
+ pub fn set_safe_search_level(&mut self, safe_search_level: u8) {
187
+ self.safe_search_level = safe_search_level;
188
+ }
189
  }
src/models/server_models.rs CHANGED
@@ -26,4 +26,6 @@ pub struct Cookie<'a> {
26
  pub colorscheme: &'a str,
27
  /// It stores the user selected upstream search engines selected from the UI.
28
  pub engines: Vec<&'a str>,
 
 
29
  }
 
26
  pub colorscheme: &'a str,
27
  /// It stores the user selected upstream search engines selected from the UI.
28
  pub engines: Vec<&'a str>,
29
+ /// It stores the user selected safe search level from the UI.
30
+ pub safe_search_level: u8,
31
  }
src/server/routes/search.rs CHANGED
@@ -67,61 +67,48 @@ pub async fn search(
67
  None => 1,
68
  };
69
 
70
- let safe_search: u8 = match config.safe_search {
71
- 3..=4 => config.safe_search,
72
- _ => match &params.safesearch {
73
- Some(safesearch) => match safesearch {
74
- 0..=2 => *safesearch,
75
- _ => 1,
76
- },
77
- None => config.safe_search,
78
- },
79
- };
80
-
81
  let (_, results, _) = join!(
82
  results(
83
  format!(
84
- "http://{}:{}/search?q={}&page={}&safesearch={}",
85
  config.binding_ip,
86
  config.port,
87
  query,
88
  page - 1,
89
- safe_search
90
  ),
91
  &config,
92
  &cache,
93
  query,
94
  page - 1,
95
  req.clone(),
96
- safe_search
97
  ),
98
  results(
99
  format!(
100
- "http://{}:{}/search?q={}&page={}&safesearch={}",
101
- config.binding_ip, config.port, query, page, safe_search
102
  ),
103
  &config,
104
  &cache,
105
  query,
106
  page,
107
  req.clone(),
108
- safe_search
109
  ),
110
  results(
111
  format!(
112
- "http://{}:{}/search?q={}&page={}&safesearch={}",
113
  config.binding_ip,
114
  config.port,
115
  query,
116
  page + 1,
117
- safe_search
118
  ),
119
  &config,
120
  &cache,
121
  query,
122
  page + 1,
123
  req.clone(),
124
- safe_search
125
  )
126
  );
127
 
@@ -156,7 +143,7 @@ async fn results(
156
  query: &str,
157
  page: u32,
158
  req: HttpRequest,
159
- safe_search: u8,
160
  ) -> Result<SearchResults, Box<dyn std::error::Error>> {
161
  // fetch the cached results json.
162
  let cached_results = cache.cached_json(&url).await;
@@ -165,7 +152,18 @@ async fn results(
165
  match cached_results {
166
  Ok(results) => Ok(results),
167
  Err(_) => {
168
- if safe_search == 4 {
 
 
 
 
 
 
 
 
 
 
 
169
  let mut results: SearchResults = SearchResults::default();
170
  let mut _flag: bool =
171
  is_match_from_filter_list(file_path(FileType::BlockList)?, query)?;
@@ -176,6 +174,7 @@ async fn results(
176
  results.add_style(&config.style);
177
  results.set_page_query(query);
178
  cache.cache_results(&results, &url).await?;
 
179
  return Ok(results);
180
  }
181
  }
@@ -195,6 +194,17 @@ async fn results(
195
  .filter_map(|name| EngineHandler::new(name))
196
  .collect();
197
 
 
 
 
 
 
 
 
 
 
 
 
198
  aggregate(
199
  query,
200
  page,
@@ -202,7 +212,7 @@ async fn results(
202
  config.debug,
203
  &engines,
204
  config.request_timeout,
205
- safe_search,
206
  )
207
  .await?
208
  }
@@ -214,7 +224,7 @@ async fn results(
214
  config.debug,
215
  &config.upstream_search_engines,
216
  config.request_timeout,
217
- safe_search,
218
  )
219
  .await?
220
  }
@@ -223,7 +233,10 @@ async fn results(
223
  results.set_filtered();
224
  }
225
  results.add_style(&config.style);
226
- cache.cache_results(&results, &url).await?;
 
 
 
227
  Ok(results)
228
  }
229
  }
 
67
  None => 1,
68
  };
69
 
 
 
 
 
 
 
 
 
 
 
 
70
  let (_, results, _) = join!(
71
  results(
72
  format!(
73
+ "http://{}:{}/search?q={}&page={}&safesearch=",
74
  config.binding_ip,
75
  config.port,
76
  query,
77
  page - 1,
 
78
  ),
79
  &config,
80
  &cache,
81
  query,
82
  page - 1,
83
  req.clone(),
84
+ &params.safesearch
85
  ),
86
  results(
87
  format!(
88
+ "http://{}:{}/search?q={}&page={}&safesearch=",
89
+ config.binding_ip, config.port, query, page
90
  ),
91
  &config,
92
  &cache,
93
  query,
94
  page,
95
  req.clone(),
96
+ &params.safesearch
97
  ),
98
  results(
99
  format!(
100
+ "http://{}:{}/search?q={}&page={}&safesearch=",
101
  config.binding_ip,
102
  config.port,
103
  query,
104
  page + 1,
 
105
  ),
106
  &config,
107
  &cache,
108
  query,
109
  page + 1,
110
  req.clone(),
111
+ &params.safesearch
112
  )
113
  );
114
 
 
143
  query: &str,
144
  page: u32,
145
  req: HttpRequest,
146
+ safe_search: &Option<u8>,
147
  ) -> Result<SearchResults, Box<dyn std::error::Error>> {
148
  // fetch the cached results json.
149
  let cached_results = cache.cached_json(&url).await;
 
152
  match cached_results {
153
  Ok(results) => Ok(results),
154
  Err(_) => {
155
+ let mut safe_search_level: u8 = match config.safe_search {
156
+ 3..=4 => config.safe_search,
157
+ _ => match safe_search {
158
+ Some(safesearch) => match safesearch {
159
+ 0..=2 => *safesearch,
160
+ _ => config.safe_search,
161
+ },
162
+ None => config.safe_search,
163
+ },
164
+ };
165
+
166
+ if safe_search_level == 4 {
167
  let mut results: SearchResults = SearchResults::default();
168
  let mut _flag: bool =
169
  is_match_from_filter_list(file_path(FileType::BlockList)?, query)?;
 
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);
179
  }
180
  }
 
194
  .filter_map(|name| EngineHandler::new(name))
195
  .collect();
196
 
197
+ safe_search_level = match config.safe_search {
198
+ 3..=4 => config.safe_search,
199
+ _ => match safe_search {
200
+ Some(safesearch) => match safesearch {
201
+ 0..=2 => *safesearch,
202
+ _ => config.safe_search,
203
+ },
204
+ None => cookie_value.safe_search_level,
205
+ },
206
+ };
207
+
208
  aggregate(
209
  query,
210
  page,
 
212
  config.debug,
213
  &engines,
214
  config.request_timeout,
215
+ safe_search_level,
216
  )
217
  .await?
218
  }
 
224
  config.debug,
225
  &config.upstream_search_engines,
226
  config.request_timeout,
227
+ safe_search_level,
228
  )
229
  .await?
230
  }
 
233
  results.set_filtered();
234
  }
235
  results.add_style(&config.style);
236
+ cache
237
+ .cache_results(&results, &(format!("{url}{safe_search_level}")))
238
+ .await?;
239
+ results.set_safe_search_level(safe_search_level);
240
  Ok(results)
241
  }
242
  }