Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions qtribu/gui/dock_search_content.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>gsDockWidget</class>
<widget class="QgsDockWidget" name="gsDockWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>581</width>
<height>206</height>
</rect>
</property>
<property name="windowTitle">
<string>gsDockWidget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLCDNumber" name="lcd_results_counter">
<property name="minimumSize">
<size>
<width>50</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>75</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QgsCheckableComboBox" name="cbb_tags"/>
</item>
<item row="2" column="0" colspan="2">
<widget class="QTableWidget" name="tbl_results"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="lbl_table_results">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QgsCheckableComboBox</class>
<extends>QComboBox</extends>
<header>qgscheckablecombobox.h</header>
</customwidget>
<customwidget>
<class>QgsDockWidget</class>
<extends>QDockWidget</extends>
<header>qgsdockwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
1 change: 1 addition & 0 deletions qtribu/logic/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#! python3 # noqa: E265
from .custom_datatypes import RssItem # noqa: F401
from .rss_reader import RssMiniReader # noqa: F401
from .search_widget import SearchWidget # noqa: F401
from .splash_changer import SplashChanger # noqa: F401
from .web_viewer import WebViewer # noqa: F401
90 changes: 90 additions & 0 deletions qtribu/logic/search_widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#! python3 # noqa: E265


"""
Search within Geotribu contents.
"""

# ############################################################################
# ########## Imports ###############
# ##################################

# Standard library
import json
from datetime import datetime, timedelta
from pathlib import Path

# project
from qtribu.toolbelt import PlgLogger, PlgOptionsManager
from qtribu.toolbelt.file_downloader import get_from_http

# ############################################################################
# ########## Classes ###############
# ##################################


class SearchWidget:
"""Search widget within Geotribu contents and CDN."""

CDN_IDX_PATH: Path = Path().home() / ".geotribu/search/cdn_search_index.json"
CDN_IDX_EXPIRE_HOURS: int = 12
CONTENT_IDX_PATH: Path = Path().home() / ".geotribu/search/site_search_index.json"
CONTENT_IDX_EXPIRE_HOURS: int = 168

def __init__(self):
"""Class initialization."""
self.log = PlgLogger().log
self.settings = PlgOptionsManager.get_plg_settings()

# make sure that folders exist
self.CONTENT_IDX_PATH.parent.mkdir(parents=True, exist_ok=True)
self.CDN_IDX_PATH.parent.mkdir(parents=True, exist_ok=True)

def download_search_index(self, index_to_download: str = "content"):
"""Download search index from Geotribu."""
if index_to_download == "content":
remote_uri = f"{self.settings.website_url}/search/search_index.json"
local_filepath = self.CONTENT_IDX_PATH
expiration_hours = self.CONTENT_IDX_EXPIRE_HOURS
elif index_to_download == "cdn":
remote_uri = f"{self.settings.cdn_url}/img/search-index.json"
local_filepath = self.CDN_IDX_PATH
expiration_hours = self.CDN_IDX_EXPIRE_HOURS
else:
self.log(
message=f"Unrecognized index type to download: {index_to_download}. "
"Expected one of: 'content' or 'cdn'.",
log_level=4,
)

# content search index
if local_filepath.exists():
f_creation = datetime.fromtimestamp(local_filepath.stat().st_ctime)
if (datetime.now() - f_creation) < timedelta(hours=expiration_hours):
self.log(
message=f"Local search index ({local_filepath}) is up to date. "
"No download needed.",
log_level=4,
)
return
else:
local_filepath.unlink()

# download the remote file into local
get_from_http(
uri=remote_uri,
output_path=str(local_filepath.resolve()),
)

def load_search_index(self):
"""Load search index from local file."""
if not self.CONTENT_IDX_PATH.exists():
self.download_search_index(index_to_download="content")
if not self.CDN_IDX_PATH.exists():
self.download_search_index(index_to_download="cdn")

with self.CONTENT_IDX_PATH.open(mode="r", encoding="UTF8") as in_json:
search_index = json.load(in_json)

self.log(search_index.keys())
self.log(len(search_index.get("docs")))
27 changes: 25 additions & 2 deletions qtribu/plugin_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@
from qtribu.__about__ import DIR_PLUGIN_ROOT, __icon_path__, __title__, __uri_homepage__
from qtribu.gui.dlg_settings import PlgOptionsFactory
from qtribu.gui.form_rdp_news import RdpNewsForm
from qtribu.logic import RssMiniReader, SplashChanger, WebViewer
from qtribu.toolbelt import NetworkRequestsManager, PlgLogger, PlgOptionsManager
from qtribu.logic import RssMiniReader, SearchWidget, SplashChanger, WebViewer
from qtribu.toolbelt import (
NetworkRequestsManager,
PlgLogger,
PlgOptionsManager,
PlgTranslator,
)

# ############################################################################
# ########## Classes ###############
Expand Down Expand Up @@ -53,6 +58,7 @@ def __init__(self, iface: QgisInterface):

# sub-modules
self.rss_rdr = RssMiniReader()
self.search_widget = SearchWidget()
self.splash_chgr = SplashChanger(self)
self.web_viewer = WebViewer()

Expand All @@ -75,6 +81,16 @@ def initGui(self):
self.action_run.setToolTip(self.tr("Newest article"))
self.action_run.triggered.connect(self.run)

self.action_search = QAction(
QIcon(QgsApplication.iconPath("search.svg")),
self.tr("Search", context="GeotribuPlugin"),
self.iface.mainWindow(),
)
self.action_search.setToolTip(
self.tr(text="Search within contents", context="GeotribuPlugin")
)
self.action_search.triggered.connect(self.search_run)

self.action_rdp_news = QAction(
QIcon(QgsApplication.iconPath("mActionHighlightFeature.svg")),
self.tr("Propose a news to the next GeoRDP"),
Expand Down Expand Up @@ -107,6 +123,7 @@ def initGui(self):

# -- Menu
self.iface.addPluginToWebMenu(__title__, self.action_run)
self.iface.addPluginToWebMenu(__title__, self.action_search)
self.iface.addPluginToWebMenu(__title__, self.action_rdp_news)
self.iface.addPluginToWebMenu(__title__, self.action_splash)
self.iface.addPluginToWebMenu(__title__, self.action_settings)
Expand Down Expand Up @@ -164,6 +181,7 @@ def unload(self):
self.iface.removePluginWebMenu(__title__, self.action_help)
self.iface.removePluginWebMenu(__title__, self.action_rdp_news)
self.iface.removePluginWebMenu(__title__, self.action_run)
self.iface.removePluginWebMenu(__title__, self.action_search)
self.iface.removePluginWebMenu(__title__, self.action_settings)
self.iface.removePluginWebMenu(__title__, self.action_splash)

Expand Down Expand Up @@ -263,6 +281,11 @@ def run(self):
except Exception as err:
raise err

def search_run(self):
"""Display search widget"""
self.log("Search widget called", log_level=3)
self.search_widget.load_search_index()

def open_form_rdp_news(self) -> None:
"""Open the form to create a GeoRDP news."""
if not self.form_rdp_news:
Expand Down
53 changes: 53 additions & 0 deletions qtribu/toolbelt/file_downloader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#! python3 # noqa: E265

"""
Download remote files.
"""

# Standard library
import logging

# PyQGIS
from qgis.core import QgsFileDownloader
from qgis.PyQt.QtCore import QEventLoop, QUrl

# project
from qtribu.toolbelt.log_handler import PlgLogger

# ############################################################################
# ########## Globals ###############
# ##################################

logger = logging.getLogger(__name__)
plg_logger = PlgLogger()

# ############################################################################
# ########## Functions #############
# ##################################


def get_from_http(uri: str, output_path: str) -> str:
"""Download a file from a remote web server accessible through HTTP.

:param uri: web URL to the QGIS project
:type uri: str
:param output_path: path to the local file
:type output_path: str

:return: output path
:rtype: str
"""
msg_log = f"Downloading file from {uri} to {output_path}"
logger.debug(msg_log)
plg_logger.log(msg_log)
# download it
loop = QEventLoop()
project_download = QgsFileDownloader(
url=QUrl(uri), outputFileName=output_path, delayStart=True
)
project_download.downloadExited.connect(loop.quit)
project_download.startDownload()
loop.exec_()

plg_logger.log(message=f"Download of {uri} succeedeed", log_level=3)
return output_path
6 changes: 4 additions & 2 deletions qtribu/toolbelt/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ class PlgSettingsStructure:
debug_mode: bool = False
version: str = __version__

# RSS feed
rss_source: str = "https://static.geotribu.fr/feed_rss_created.xml"
# remote
website_url: str = "https://static.geotribu.fr"
cdn_url: str = "https://cdn.geotribu.fr"
rss_source: str = f"{website_url}/feed_rss_created.xml"

# usage
browser: int = 1
Expand Down
Loading