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

Add ability to specify add-on store metadata URL from within NVDA #17099

Merged
merged 34 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ca63806
Created `addonStoore.network._getBaseUrl` method that currently just …
SaschaCowley Aug 28, 2024
c0aee14
Added a new config item, `addonStore.baseURL`, to store configurable …
SaschaCowley Aug 28, 2024
c4939be
Add mirror option to settings
SaschaCowley Aug 28, 2024
0cd1c06
Start implementation of URL validator for config
SaschaCowley Aug 28, 2024
dd591ab
Refactored DisplayableError calling code into its own private function
SaschaCowley Aug 30, 2024
57a35a1
Update getAllAddons for refactor
SaschaCowley Aug 30, 2024
7336874
Made URL getters more robust
SaschaCowley Aug 30, 2024
23b3b69
Moved helper function down
SaschaCowley Sep 2, 2024
74adc96
Added helpful messages
SaschaCowley Sep 2, 2024
19714c8
Fixed case
SaschaCowley Sep 2, 2024
7e1af57
Merge branch 'master' into addonStoreMirror
SaschaCowley Sep 2, 2024
5eaf961
Added change log entry
SaschaCowley Sep 2, 2024
7e00e7f
Renamed settings controls
SaschaCowley Sep 2, 2024
c31aced
Added documentation
SaschaCowley Sep 2, 2024
0d2a613
Renamed `BASE_URL` to `_DEFAULT_BASE_URL`
SaschaCowley Sep 2, 2024
170464e
Added note to changes for developers
SaschaCowley Sep 2, 2024
3937db0
Apply suggestions from code review
SaschaCowley Sep 3, 2024
c59d7da
Renamed config key to be more descriptive
SaschaCowley Sep 3, 2024
7a5ca61
Removed un-used config.validators file
SaschaCowley Sep 3, 2024
add7e34
Changed mirror url label
SaschaCowley Sep 3, 2024
a409b51
Improved formatting
SaschaCowley Sep 3, 2024
4929e07
Changed wording of error message to exclude 'metadata' and include th…
SaschaCowley Sep 3, 2024
ddd4492
Updated handling of None type for _do_displayError for greater predic…
SaschaCowley Sep 3, 2024
7e3d2e4
Partial implementation of URL validation
SaschaCowley Sep 3, 2024
716dc9d
Updated validation
SaschaCowley Sep 3, 2024
723775d
Removed unused showTip option
SaschaCowley Sep 3, 2024
9c2ffb1
Replaced custom logic with logic from url_normalize
SaschaCowley Sep 3, 2024
70923f1
Simplified generation of Add-on Store URLs now that we have more cert…
SaschaCowley Sep 3, 2024
94fe401
Apply suggestions from code review
SaschaCowley Sep 3, 2024
3ed8206
Moved _stripAccelleratorFromLabel to guiHelper
SaschaCowley Sep 4, 2024
e25076e
Added explicit dependency on url-normalize
SaschaCowley Sep 4, 2024
183a6f6
Removed unused function
SaschaCowley Sep 5, 2024
eb3afba
Updated label of Add-on Store metadata mirror URL box
SaschaCowley Sep 5, 2024
44d9de7
Merge branch 'master' into addonStoreMirror
SaschaCowley Sep 5, 2024
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
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pyserial==3.5
wxPython @ https://github.com/nvaccess/nvda-misc-deps/raw/51ae7db821d1d5166ab0c030fe20ec72dd7a2ad9/python/wxPython-4.2.2a1-cp311-cp311-win32.whl
configobj @ git+https://github.com/DiffSK/configobj@e2ba4457c4651fa54f8d59d8dcdd3da950e956b8#egg=configobj
requests==2.32.0
url-normalize==1.4.3
schedule==1.2.1
-c constraints.txt

Expand Down
57 changes: 45 additions & 12 deletions source/addonStore/dataManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ def _getCachedAddonData(self, cacheFilePath: str) -> Optional[CachedAddonsModel]

# Translators: A title of the dialog shown when fetching add-on data from the store fails
_updateFailureMessage = pgettext("addonStore", "Add-on data update failure")
_updateFailureMirrorSuggestion = pgettext(
"addonStore",
# Translators: A suggestion of what to do when fetching add-on data from the store fails and a metadata mirror is being used.
# {url} will be replaced with the mirror URL.
"Make sure you are connected to the internet, and the Add-on Store mirror URL is valid.\n"
"Mirror URL: {url}",
)
_updateFailureDefaultSuggestion = pgettext(
"addonStore",
# Translators: A suggestion of what to do when fetching add-on data from the store fails and the default metadata URL is being used.
"Make sure you are connected to the internet and try again.",
)

def getLatestCompatibleAddons(
self,
Expand Down Expand Up @@ -234,15 +246,12 @@ def getLatestCompatibleAddons(
cachedLanguage=self._lang,
nvdaAPIVersion=addonAPIVersion.CURRENT,
)
elif onDisplayableError is not None:
from gui.message import DisplayableError

displayableError = DisplayableError(
else:
self._do_displayError(
onDisplayableError,
# Translators: A message shown when fetching add-on data from the store fails
pgettext("addonStore", "Unable to fetch latest add-on data for compatible add-ons."),
self._updateFailureMessage,
)
callLater(delay=0, callable=onDisplayableError.notify, displayableError=displayableError)

if self._compatibleAddonCache is None:
return _createAddonGUICollection()
Expand Down Expand Up @@ -273,20 +282,44 @@ def getLatestAddons(
cachedLanguage=self._lang,
nvdaAPIVersion=_LATEST_API_VER,
)
elif onDisplayableError is not None:
from gui.message import DisplayableError

displayableError = DisplayableError(
else:
self._do_displayError(
onDisplayableError,
# Translators: A message shown when fetching add-on data from the store fails
pgettext("addonStore", "Unable to fetch latest add-on data for incompatible add-ons."),
self._updateFailureMessage,
)
callLater(delay=0, callable=onDisplayableError.notify, displayableError=displayableError)

if self._latestAddonCache is None:
return _createAddonGUICollection()
return deepcopy(self._latestAddonCache.cachedAddonData)

def _do_displayError(
self,
onDisplayableError: "DisplayableError.OnDisplayableErrorT | None",
displayMessage: str,
titleMessage: str | None = None,
):
"""Display a DisplayableMessage if an OnDisplayableError action is given.

See gui.message.DisplayableError for further information.

:param onDisplayableError: The displayable error action.
:param displayMessage: Body of the displayable error.
:param titleMessage: Title of the displayable error. If None, _updateFailureMessage will be used. Defaults to None.
"""
if onDisplayableError is None:
return
from gui.message import DisplayableError

tip = (
self._updateFailureMirrorSuggestion.format(url=url)
if (url := config.conf["addonStore"]["baseServerURL"])
else self._updateFailureDefaultSuggestion
)
displayMessage = f"{displayMessage}\n{tip}"
displayableError = DisplayableError(displayMessage, titleMessage or self._updateFailureMessage)
callLater(delay=0, callable=onDisplayableError.notify, displayableError=displayableError)

def _deleteCacheInstalledAddon(self, addonId: str):
addonCachePath = os.path.join(self._installedAddonDataCacheDir, f"{addonId}.json")
if pathlib.Path(addonCachePath).exists():
Expand Down
13 changes: 10 additions & 3 deletions source/addonStore/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import NVDAState
from NVDAState import WritePaths
from utils.security import sha256_checksum
from config import conf

from .models.addon import (
_AddonGUIModel,
Expand All @@ -40,25 +41,31 @@
from gui.addonStoreGui.viewModels.addonList import AddonListItemVM


BASE_URL = "https://nvaccess.org/addonStore"
_DEFAULT_BASE_URL = "https://nvaccess.org/addonStore"
_LATEST_API_VER = "latest"
"""
A string value used in the add-on store to fetch the latest version of all add-ons,
i.e include older incompatible versions.
"""


def _getBaseURL() -> str:
if url := conf["addonStore"]["baseServerURL"]:
return url
return _DEFAULT_BASE_URL


def _getCurrentApiVersionForURL() -> str:
year, major, minor = addonAPIVersion.CURRENT
return f"{year}.{major}.{minor}"


def _getAddonStoreURL(channel: Channel, lang: str, nvdaApiVersion: str) -> str:
return f"{BASE_URL}/{lang}/{channel.value}/{nvdaApiVersion}.json"
return f"{_getBaseURL()}/{lang}/{channel.value}/{nvdaApiVersion}.json"


def _getCacheHashURL() -> str:
return f"{BASE_URL}/cacheHash.json"
return f"{_getBaseURL()}/cacheHash.json"


class AddonFileDownloader:
Expand Down
1 change: 1 addition & 0 deletions source/config/configSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@
[addonStore]
showWarning = boolean(default=true)
automaticUpdates = option("notify", "disabled", default="notify")
baseServerURL = string(default="")
"""

#: The configuration specification
Expand Down
18 changes: 18 additions & 0 deletions source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
Set,
cast,
)
from url_normalize import url_normalize
seanbudd marked this conversation as resolved.
Show resolved Hide resolved
import core
import keyboardHandler
import characterProcessing
Expand Down Expand Up @@ -3184,10 +3185,27 @@ def makeSettings(self, settingsSizer: wx.BoxSizer) -> None:
index = [x.value for x in AddonsAutomaticUpdate].index(config.conf["addonStore"]["automaticUpdates"])
self.automaticUpdatesComboBox.SetSelection(index)

# Translators: This is the label for a text box in the add-on store settings dialog.
self.addonMetadataMirrorLabelText = _("Server &mirror URL")
self.addonMetadataMirrorTextbox = sHelper.addLabeledControl(
self.addonMetadataMirrorLabelText,
wx.TextCtrl,
)
self.addonMetadataMirrorTextbox.SetValue(config.conf["addonStore"]["baseServerURL"])
self.bindHelpEvent("AddonStoreMetadataMirror", self.addonMetadataMirrorTextbox)
SaschaCowley marked this conversation as resolved.
Show resolved Hide resolved

def isValid(self) -> bool:
self.addonMetadataMirrorTextbox.SetValue(
url_normalize(self.addonMetadataMirrorTextbox.GetValue().strip()).rstrip("/"),
seanbudd marked this conversation as resolved.
Show resolved Hide resolved
)
return True

def onSave(self):
index = self.automaticUpdatesComboBox.GetSelection()
config.conf["addonStore"]["automaticUpdates"] = [x.value for x in AddonsAutomaticUpdate][index]

config.conf["addonStore"]["baseServerURL"] = self.addonMetadataMirrorTextbox.Value.strip().rstrip("/")


class TouchInteractionPanel(SettingsPanel):
# Translators: This is the label for the touch interaction settings panel.
Expand Down
3 changes: 3 additions & 0 deletions user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ In order to use this feature, the application volume adjuster needs to be enable

* When editing in Microsoft PowerPoint text boxes, you can now move per sentence with `alt+upArrow`/`alt+downArrow`. (#17015, @LeonarddeR)
* In Mozilla Firefox, NVDA will report the highlighted text when a URL containing a text fragment is visited. (#16910, @jcsteh)
* It is now possible to specify a mirror URL to use for the Add-on Store. (#14974)

### Changes

Expand Down Expand Up @@ -40,6 +41,8 @@ Add-ons will need to be re-tested and have their manifest updated.
These are breaking API changes.
Please open a GitHub issue if your add-on has an issue with updating to the new API.

* The `addonStore.network.BASE_URL` constant has been removed.
As the Add-on Store base URL is now configurable directly within NVDA, no replacement is planned. (#17099)
* `NVDAObjects.UIA.winConsoleUIA.WinTerminalUIA` has been removed with no public replacement. (#14047, #16820, @codeofdusk)
* `NVDAObjects.IAccessible.ia2TextMozilla.FakeEmbeddingTextInfo` has been removed. (#16768, @jcsteh)

Expand Down
7 changes: 7 additions & 0 deletions user_docs/en/userGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -3073,6 +3073,13 @@ For example, for installed beta add-ons, you will only be notified of updates wi
|Notify |Notify when updates are available to add-ons within the same channel |
|Disabled |Do not automatically check for updates to add-ons |

##### Server mirror URL {#AddonStoreMetadataMirror}

This option allows you to specify an alternative URL to download Add-on Store data from.
This may be of use in locations where access to the NV Access Add-on Store server is slow or unavailable.

Leave this blank to use the default NV Access Add-on Store server.

#### Windows OCR Settings {#Win10OcrSettings}

The settings in this category allow you to configure [Windows OCR](#Win10Ocr).
Expand Down