Merge pull request #848 from not-my-profile/help-route
Introduce `/help` route
This commit is contained in:
		
						commit
						bf987bb608
					
				| @ -1,4 +1,4 @@ | |||||||
| # About [searxng][url_for:index] | # About SearXNG | ||||||
| 
 | 
 | ||||||
| SearXNG is a fork from the well-known [searx] [metasearch engine], aggregating | SearXNG is a fork from the well-known [searx] [metasearch engine], aggregating | ||||||
| the results of other [search engines][url_for:preferences] while not storing | the results of other [search engines][url_for:preferences] while not storing | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								searx/static/themes/simple/css/searxng-rtl.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								searx/static/themes/simple/css/searxng-rtl.min.css
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								searx/static/themes/simple/css/searxng.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								searx/static/themes/simple/css/searxng.min.css
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -221,6 +221,16 @@ div.selectable_url { | |||||||
|   font-size: 90%; |   font-size: 90%; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ul.tabs { | ||||||
|  |   border-bottom: 1px solid var(--color-toolkit-tabs-section-border); | ||||||
|  |   list-style: none; | ||||||
|  |   padding-left: 0; | ||||||
|  | 
 | ||||||
|  |   li { | ||||||
|  |     display: flex; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .tabs { | .tabs { | ||||||
|   display: flex; |   display: flex; | ||||||
|   flex-wrap: wrap; |   flex-wrap: wrap; | ||||||
| @ -235,7 +245,8 @@ div.selectable_url { | |||||||
|     display: none; |     display: none; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   & > label { |   & > label, | ||||||
|  |   & > li > a { | ||||||
|     order: 1; |     order: 1; | ||||||
|     padding: 0.7em; |     padding: 0.7em; | ||||||
|     margin: 0 0.7em; |     margin: 0 0.7em; | ||||||
| @ -243,13 +254,21 @@ div.selectable_url { | |||||||
|     text-transform: uppercase; |     text-transform: uppercase; | ||||||
|     border: solid var(--color-toolkit-tabs-label-border); |     border: solid var(--color-toolkit-tabs-label-border); | ||||||
|     border-width: 0 0 2px 0; |     border-width: 0 0 2px 0; | ||||||
|  |     color: unset; | ||||||
| 
 | 
 | ||||||
|     .disable-user-select(); |     .disable-user-select(); | ||||||
| 
 | 
 | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|  | 
 | ||||||
|  |     &.active { | ||||||
|  |       border-bottom: 2px solid var(--color-categories-item-border-selected); | ||||||
|  |       background: var(--color-categories-item-selected); | ||||||
|  |       color: var(--color-categories-item-selected-font); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   & > label:hover { |   & > label:hover, | ||||||
|  |   & > li > a:hover { | ||||||
|     border-bottom: 2px solid var(--color-categories-item-border-selected); |     border-bottom: 2px solid var(--color-categories-item-border-selected); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,6 +0,0 @@ | |||||||
| {% extends "oscar/base.html" %} |  | ||||||
| {% block title %}{{ _('about') }} - {% endblock %} |  | ||||||
| {% block content %} |  | ||||||
| {{ help.about | safe }} |  | ||||||
| {% include "__common__/aboutextend.html" ignore missing %} |  | ||||||
| {% endblock %} |  | ||||||
							
								
								
									
										12
									
								
								searx/templates/oscar/help.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								searx/templates/oscar/help.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | {% extends "oscar/base.html" %} | ||||||
|  | {% block title %}{{ page.title }} - {% endblock %} | ||||||
|  | {% block content %} | ||||||
|  | <ul class="nav nav-tabs"> | ||||||
|  | {% for name, page in all_pages %} | ||||||
|  |   <li {% if name == page_filename %}class="active"{% endif %}> | ||||||
|  |     <a href="{{name}}">{{page.title}}</a> | ||||||
|  |   </li> | ||||||
|  | {% endfor %} | ||||||
|  | </ul> | ||||||
|  | {{ page.content | safe }} | ||||||
|  | {% endblock %} | ||||||
| @ -3,7 +3,7 @@ | |||||||
|         <a href="{{ url_for('index') }}">{{ instance_name }}</a>{{- "" -}} |         <a href="{{ url_for('index') }}">{{ instance_name }}</a>{{- "" -}} | ||||||
|     </span>{{- "" -}} |     </span>{{- "" -}} | ||||||
|     <span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">{{- "" -}} |     <span class="{% if rtl %}pull-left{% else %}pull-right{% endif %}">{{- "" -}} | ||||||
|         <a href="{{ url_for('about') }}">{{ _('about') }}</a>{{- "" -}} |         <a href="{{ url_for('help_page', pagename='about') }}">{{ _('about') }}</a>{{- "" -}} | ||||||
|         <a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>{{- "" -}} |         <a href="{{ url_for('preferences') }}">{{ _('preferences') }}</a>{{- "" -}} | ||||||
|     </span>{{- "" -}} |     </span>{{- "" -}} | ||||||
| </div> | </div> | ||||||
|  | |||||||
| @ -1,5 +0,0 @@ | |||||||
| {% extends 'simple/page_with_header.html' %} |  | ||||||
| {% block content %} |  | ||||||
| {{ help.about | safe }} |  | ||||||
| {% include "__common__/aboutextend.html" ignore missing %} |  | ||||||
| {% endblock %} |  | ||||||
| @ -58,7 +58,7 @@ | |||||||
|   </main> |   </main> | ||||||
|   <footer> |   <footer> | ||||||
|     <p> |     <p> | ||||||
|     {{ _('Powered by') }} <a href="{{ url_for('about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, hackable metasearch engine') }}<br/> |     {{ _('Powered by') }} <a href="{{ url_for('help_page', pagename='about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, hackable metasearch engine') }}<br/> | ||||||
|         <a href="{{ searx_git_url }}">{{ _('Source code') }}</a> | |         <a href="{{ searx_git_url }}">{{ _('Source code') }}</a> | | ||||||
|         <a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a> | |         <a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a> | | ||||||
|         <a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a> | |         <a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a> | | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								searx/templates/simple/help.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								searx/templates/simple/help.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | {% extends 'simple/page_with_header.html' %} | ||||||
|  | {% block title %}{{ page.title }} - {% endblock %} | ||||||
|  | {% block content %} | ||||||
|  | <ul class="tabs"> | ||||||
|  | {% for name, page in all_pages %} | ||||||
|  |   <li> | ||||||
|  |     <a href="{{name}}" {% if name == page_filename %}class="active"{% endif %}>{{page.title}}</a> | ||||||
|  |   </li> | ||||||
|  | {% endfor %} | ||||||
|  | </ul> | ||||||
|  | {{ page.content | safe }} | ||||||
|  | {% endblock %} | ||||||
| @ -1,5 +1,5 @@ | |||||||
| from typing import Dict | # pyright: basic | ||||||
| import os.path | from typing import Dict, NamedTuple | ||||||
| import pkg_resources | import pkg_resources | ||||||
| 
 | 
 | ||||||
| import flask | import flask | ||||||
| @ -9,8 +9,17 @@ import mistletoe | |||||||
| from . import get_setting | from . import get_setting | ||||||
| from .version import GIT_URL | from .version import GIT_URL | ||||||
| 
 | 
 | ||||||
| HELP: Dict[str, str] = {} | 
 | ||||||
| """ Maps a filename under help/ without the file extension to the rendered HTML. """ | class HelpPage(NamedTuple): | ||||||
|  |     title: str | ||||||
|  |     content: str | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Whenever a new .md file is added to help/ it needs to be added here | ||||||
|  | _TOC = ('about',) | ||||||
|  | 
 | ||||||
|  | PAGES: Dict[str, HelpPage] = {} | ||||||
|  | """ Maps a filename under help/ without the file extension to the rendered page. """ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def render(app: flask.Flask): | def render(app: flask.Flask): | ||||||
| @ -37,12 +46,16 @@ def render(app: flask.Flask): | |||||||
| 
 | 
 | ||||||
|     define_link_targets = ''.join(f'[{name}]: {url}\n' for name, url in link_targets.items()) |     define_link_targets = ''.join(f'[{name}]: {url}\n' for name, url in link_targets.items()) | ||||||
| 
 | 
 | ||||||
|     for filename in pkg_resources.resource_listdir(__name__, 'help'): |     for pagename in _TOC: | ||||||
|         rootname, ext = os.path.splitext(filename) |         file_content = pkg_resources.resource_string(__name__, 'help/' + pagename + '.md').decode() | ||||||
|  |         markdown = define_link_targets + file_content | ||||||
|  |         assert file_content.startswith('# ') | ||||||
|  |         title = file_content.split('\n', maxsplit=1)[0].strip('# ') | ||||||
|  |         content: str = mistletoe.markdown(markdown) | ||||||
| 
 | 
 | ||||||
|         if ext != '.md': |         if pagename == 'about': | ||||||
|             continue |             try: | ||||||
| 
 |                 content += pkg_resources.resource_string(__name__, 'templates/__common__/aboutextend.html').decode() | ||||||
|         markdown = pkg_resources.resource_string(__name__, 'help/' + filename).decode() |             except FileNotFoundError: | ||||||
|         markdown = define_link_targets + markdown |                 pass | ||||||
|         HELP[rootname] = mistletoe.markdown(markdown) |         PAGES[pagename] = HelpPage(title=title, content=content) | ||||||
|  | |||||||
| @ -877,8 +877,21 @@ def __get_translated_errors(unresponsive_engines: Iterable[UnresponsiveEngine]): | |||||||
| 
 | 
 | ||||||
| @app.route('/about', methods=['GET']) | @app.route('/about', methods=['GET']) | ||||||
| def about(): | def about(): | ||||||
|     """Render about page""" |     """Redirect to about page""" | ||||||
|     return render('about.html', help=user_help.HELP) |     return redirect(url_for('help_page', pagename='about')) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @app.route('/help/en/<pagename>', methods=['GET']) | ||||||
|  | def help_page(pagename): | ||||||
|  |     """Render help page""" | ||||||
|  |     page = user_help.PAGES.get(pagename) | ||||||
|  | 
 | ||||||
|  |     if page is None: | ||||||
|  |         flask.abort(404) | ||||||
|  | 
 | ||||||
|  |     return render( | ||||||
|  |         'help.html', page=user_help.PAGES[pagename], all_pages=user_help.PAGES.items(), page_filename=pagename | ||||||
|  |     ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.route('/autocompleter', methods=['GET', 'POST']) | @app.route('/autocompleter', methods=['GET', 'POST']) | ||||||
|  | |||||||
| @ -174,9 +174,9 @@ class ViewsTestCase(SearxTestCase): | |||||||
|         self.assertIn(b'<description>first test content</description>', result.data) |         self.assertIn(b'<description>first test content</description>', result.data) | ||||||
| 
 | 
 | ||||||
|     def test_about(self): |     def test_about(self): | ||||||
|         result = self.app.get('/about') |         result = self.app.get('/help/en/about') | ||||||
|         self.assertEqual(result.status_code, 200) |         self.assertEqual(result.status_code, 200) | ||||||
|         self.assertIn(b'<h1>About <a href="/">searxng</a></h1>', result.data) |         self.assertIn(b'<h1>About SearXNG</h1>', result.data) | ||||||
| 
 | 
 | ||||||
|     def test_health(self): |     def test_health(self): | ||||||
|         result = self.app.get('/healthz') |         result = self.app.get('/healthz') | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user