Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use backend api to retrieve country listings #303

Merged
merged 6 commits into from
Dec 1, 2023
Merged
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
39 changes: 39 additions & 0 deletions koordinates/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class KoordinatesClient(QObject):
loginChanged = pyqtSignal(bool)
error_occurred = pyqtSignal(str)
explore_sections_retrieved = pyqtSignal(object)
data_options_retrieved = pyqtSignal(dict)

BASE64_ENCODED_SVG_HEADER = 'data:image/svg+xml;base64,'

Expand All @@ -69,6 +70,7 @@ def __init__(self):
KoordinatesClient.__instance = self

self._explore_sections_reply: Optional[QNetworkReply] = None
self._data_options_reply: Optional[QNetworkReply] = None

self.layers = {}
self._dataset_details = {}
Expand Down Expand Up @@ -103,6 +105,10 @@ def login(self, apiKey):
self._explore_sections_reply.finished.connect(
partial(self._sections_reply_finished, self._explore_sections_reply))

self._data_options_reply = self.data_options_async()
self._data_options_reply.finished.connect(
partial(self._data_options_reply_finished, self._data_options_reply))

def logout(self):
oldKey = self.apiKey

Expand Down Expand Up @@ -139,6 +145,25 @@ def _sections_reply_finished(self, reply: QNetworkReply):

self.explore_sections_retrieved.emit(sections)

def _data_options_reply_finished(self, reply: QNetworkReply):
if sip.isdeleted(self):
return

if reply != self._data_options_reply:
# an old reply we don't care about anymore
return

self._data_options_reply = None
if reply.error() == QNetworkReply.OperationCanceledError:
return

if reply.error() != QNetworkReply.NoError:
print('error occurred :(')
return

content = json.loads(reply.readAll().data().decode())
self.data_options_retrieved.emit(content)

def _build_datasets_request(self,
page=1,
query: Optional[DataBrowserQuery] = None,
Expand Down Expand Up @@ -235,6 +260,20 @@ def _build_publishers_request(self,

return endpoint, headers, params

def data_options_async(self) -> QNetworkReply:
"""
Retrieve data OPTIONS request asynchronously
"""
headers = {}
params = {}
endpoint = "data/"

network_request = self._build_request(endpoint, headers, params)

return QgsNetworkAccessManager.instance().sendCustomRequest(
network_request, b"OPTIONS", None
)

def datasets_async(self,
page=1,
query: Optional[DataBrowserQuery] = None,
Expand Down
13 changes: 12 additions & 1 deletion koordinates/api/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ class SortOrder(Enum):
Oldest = 6

@staticmethod
def to_text(order: 'SortOrder'):
def to_text(order: 'SortOrder') -> str:
"""
Converts sort order to user-friendly text
"""
Expand All @@ -197,6 +197,17 @@ def to_text(order: 'SortOrder'):
SortOrder.AlphabeticalZA: 'Alphabetical (Z-A)',
SortOrder.Oldest: 'Oldest'}[order]

def to_button_text(self) -> str:
"""
Converts sort order to user-friendly text for buttons
"""
return {SortOrder.Popularity: 'Popular',
SortOrder.RecentlyAdded: 'Recently Added',
SortOrder.RecentlyUpdated: 'Recently Updated',
SortOrder.AlphabeticalAZ: 'Sort by Alphabetical (A-Z)',
SortOrder.AlphabeticalZA: 'Sort by Alphabetical (Z-A)',
SortOrder.Oldest: 'Oldest'}[self]


class PublisherType(Enum):
"""
Expand Down
76 changes: 51 additions & 25 deletions koordinates/gui/koordinates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
import locale
import os
from functools import partial
from typing import Optional, List
from typing import (
Dict,
Optional,
List
)

from qgis.PyQt import sip
from qgis.PyQt import uic
Expand Down Expand Up @@ -583,16 +587,11 @@ def __init__(self, parent):
self.results_panel.publisher_cleared.connect(
self.filter_widget.remove_publisher_filter)

try:
device_pixel_ratio = self.window().screen().devicePixelRatio()
except AttributeError:
# requires Qt 5.14+
device_pixel_ratio = 1

if os.name == 'nt' or device_pixel_ratio > 1:
self.button_sort_order.setStyleSheet(
'QToolButton { padding-right: 30px; padding-left: 0px; }'
)
self.button_sort_order.setStyleSheet(
"""QToolButton::menu-indicator { image: none }
QToolButton { margin-top: 2px; }
"""
)
self.sort_menu = QMenu(self.button_sort_order)
self.sort_by_popular_action: Optional[QAction] = None
self._sort_menu_event_filter = WidgetActionMenuHoverEventFilter(self.sort_menu)
Expand Down Expand Up @@ -646,6 +645,10 @@ def __init__(self, parent):
self.context_tab_container.setFixedWidth(self.context_container.width())

KoordinatesClient.instance().loginChanged.connect(self._loginChanged)
self._data_options: Optional[Dict] = None
KoordinatesClient.instance().data_options_retrieved.connect(
self._data_options_retrieved
)

self.setMinimumWidth(430)

Expand Down Expand Up @@ -680,9 +683,12 @@ def _sort_order_menu_about_to_show(self):
if action == self.sort_by_popular_action:
action.set_widget_checked(
isinstance(self.filter_widget.sort_order, str)
or self.filter_widget.sort_order == SortOrder.Popularity
)
else:
is_checked = action.data() == self.filter_widget.sort_order
is_checked = (action.data() == self.filter_widget.sort_order or
(self.filter_widget.sort_order == SortOrder.Popularity and
not action.data()))
if isinstance(action, CustomLabelWidgetAction):
action.set_widget_checked(is_checked)

Expand Down Expand Up @@ -731,7 +737,7 @@ def _set_sort_order_button_text(self):
)
else:
self.button_sort_order.setText(
'Sort by {}'.format(SortOrder.to_text(self.filter_widget.sort_order))
self.filter_widget.sort_order.to_button_text()
)

def _show_context_switcher_menu(self):
Expand Down Expand Up @@ -971,24 +977,38 @@ def _loginChanged(self, logged_in: bool):
user = KoordinatesClient.instance().user_details()
self.user_country_action.set_country_code(user['country'])

self._build_sort_menu(user)
self._build_sort_menu()

self._create_context_tabs(user.get('contexts', []))

self.filter_widget.set_logged_in(True)

self.explore()
else:
self.stackedWidget.setCurrentWidget(self.pageAuth)

def _build_sort_menu(self, user_details: dict):
def _data_options_retrieved(self, options: dict):
"""
Called when the data options request is finished
"""
self._data_options = options
self._build_sort_menu()

def _build_sort_menu(self):
"""
Builds the dataset sorting options menu.

This can only be done after a login event
"""
user_details = KoordinatesClient.instance().user_details()
if not user_details or not self._data_options:
return

self.sort_menu.clear()

country_choices = (self._data_options
.get('filters', {})
.get('country', {})
.get('choices', []))

user_country_code = user_details['country']

sort_by_action = CustomLabelWidgetAction(
Expand All @@ -1001,14 +1021,19 @@ def _build_sort_menu(self, user_details: dict):
checkable=True,
parent=self.sort_menu)
self.sort_menu.addAction(self.sort_by_popular_action)
for country, sub_text, code in (
(self.tr('For New Zealand'), None, 'NZ'),
(self.tr('For Australia'), None, 'AU'),
(self.tr('For United Kingdom'), None, 'GB'),
(self.tr('For United States'), None, 'US'),
(self.tr('Anywhere'), self.tr("Don't bias results by location"), '')):
if user_country_code == code:
for country_choice in country_choices:
country = country_choice['display_name']
code = country_choice['value']

if code == 'global':
code = ''

if not code:
sub_text = self.tr("Don't bias results by location")
elif user_country_code == code:
sub_text = "Your Koordinates ID country"
else:
sub_text = None

if code:
icon = EmojiToIconRenderer.render_flag_to_icon(code)
Expand Down Expand Up @@ -1040,7 +1065,8 @@ def _build_sort_menu(self, user_details: dict):
sort_by_action.selected.connect(partial(self._set_sort_order, order))
sort_by_action.setData(order)

self._set_popular_sort_order('')
self.filter_widget.sort_order = ''
self._set_sort_order_button_text()

def _create_context_tabs(self, contexts: List):
"""
Expand Down
Loading