Skip to content

Make URLs in the framework configurable#32957

Open
grliszas14 wants to merge 6 commits intomusescore:masterfrom
grliszas14:au4_updates
Open

Make URLs in the framework configurable#32957
grliszas14 wants to merge 6 commits intomusescore:masterfrom
grliszas14:au4_updates

Conversation

@grliszas14
Copy link
Copy Markdown
Contributor

Resolves: audacity/audacity#10353

  • I signed the CLA
  • The title of the PR describes the problem it addresses
  • Each commit's message describes its purpose and effects, and references the issue it resolves
  • If changes are extensive, there is a sequence of easily reviewable commits
  • The code in the PR follows the coding rules
  • There are no unnecessary changes
  • The code compiles and runs on my machine, preferably after each commit individually
  • I created a unit test or vtest to verify the changes I made (if applicable)

@grliszas14 grliszas14 marked this pull request as ready for review April 9, 2026 09:42
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

This change refactors URL configuration management by centralizing website and privacy policy URLs in the update.cfg configuration file. Two new config entries (app_website_url and privacy_policy_url) are added, and the museScoreUrl() method is removed from the GlobalConfiguration interface and its implementations. The UpdateConfiguration interface methods are renamed from museScoreUrl() and museScorePrivacyPolicyUrl() to appWebSiteUrl() and privacyPolicyUrl() respectively, now reading from the configuration file instead of deriving from GlobalConfiguration. Multiple modules throughout the codebase are updated to use the new UpdateConfiguration accessors, and AppShellConfiguration is updated to inject and use the UpdateConfiguration dependency for URL resolution.

🚥 Pre-merge checks | ✅ 1 | ❌ 4

❌ Failed checks (2 warnings, 2 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR changes are substantially out of scope with the linked issue #10353, which focuses on implementing an in-app notification dialog. The changes here refactor URL configurability but don't directly implement the notification dialog feature. Verify that this PR is the correct baseline for the notification dialog work, or clarify the relationship between URL configurability and the #10353 requirements in a separate issue.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description is incomplete. While it marks most checklist items as done, the author explicitly unchecked the unit test requirement without explanation, and the description lacks detail about what was changed and why. Add a brief explanation of the changes made (e.g., which URLs were made configurable and how) and clarify why no unit tests were added.
Out of Scope Changes check ❓ Inconclusive Most changes align with making URLs configurable (config additions, interface refactoring, implementation updates), but the QML tooltip fix in StyledTextLabel.qml appears unrelated to URL configurability and may be out of scope. Clarify whether the StyledTextLabel.qml mouse event handling fix is necessary for this PR or should be separated into a distinct change.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Make URLs in the framework configurable' clearly and concisely describes the primary change: refactoring framework URLs to be configurable rather than hardcoded.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/appshell/internal/appshellconfiguration.cpp`:
- Around line 205-208: AppShellConfiguration::museScoreUrl() returns the raw
updateConfiguration()->appWebSiteUrl() which can end with a '/' and cause double
slashes when callers append paths; change museScoreUrl() to normalize the result
by trimming any trailing '/' (e.g., get the string from
updateConfiguration()->appWebSiteUrl(), if not empty and back() == '/', remove
the trailing slash) and return the normalized base URL so callers that append
"/..." won't produce '//' in URLs.

In `@src/framework/update/internal/updateconfiguration.cpp`:
- Around line 124-132: The appWebSiteUrl() and privacyPolicyUrl() accessors
currently return whatever m_config.value(...).toString() yields, allowing
empty/missing strings to propagate and cause silent broken links; update
UpdateConfiguration::appWebSiteUrl() and UpdateConfiguration::privacyPolicyUrl()
to check the retrieved value (and trim) and return a safe fallback when the
config key is missing or empty (e.g., return a constant DEFAULT_APP_WEBSITE_URL
/ DEFAULT_PRIVACY_POLICY_URL or "about:blank"); add those constants near the
class (or in an anonymous namespace) and use them in the two functions so
callers always get a non-empty, predictable URL.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ad345f37-fc8e-43e4-bbd7-0fc7d795db13

📥 Commits

Reviewing files that changed from the base of the PR and between 7c68382 and 1cd9745.

📒 Files selected for processing (21)
  • src/app/configs/update.cfg
  • src/appshell/internal/appshellconfiguration.cpp
  • src/appshell/internal/appshellconfiguration.h
  • src/appshell/qml/MuseScore/AppShell/FirstLaunchSetup/tutorialspagemodel.cpp
  • src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp
  • src/framework/global/iglobalconfiguration.h
  • src/framework/global/internal/globalconfiguration.cpp
  • src/framework/global/internal/globalconfiguration.h
  • src/framework/global/tests/mocks/globalconfigurationmock.h
  • src/framework/stubs/update/updateconfigurationstub.cpp
  • src/framework/stubs/update/updateconfigurationstub.h
  • src/framework/uicomponents/qml/Muse/UiComponents/StyledTextLabel.qml
  • src/framework/update/internal/appupdatescenario.cpp
  • src/framework/update/internal/updateconfiguration.cpp
  • src/framework/update/internal/updateconfiguration.h
  • src/framework/update/internal/updateuiactions.h
  • src/framework/update/iupdateconfiguration.h
  • src/framework/update/tests/mocks/updateconfigurationmock.h
  • src/musesounds/internal/musesamplercheckupdatescenario.cpp
  • src/musesounds/internal/musesamplercheckupdatescenario.h
  • src/preferences/qml/MuseScore/Preferences/updatepreferencesmodel.cpp
💤 Files with no reviewable changes (4)
  • src/framework/global/iglobalconfiguration.h
  • src/framework/global/internal/globalconfiguration.h
  • src/framework/global/tests/mocks/globalconfigurationmock.h
  • src/framework/global/internal/globalconfiguration.cpp

Comment on lines 205 to 208
std::string AppShellConfiguration::museScoreUrl() const
{
return globalConfiguration()->museScoreUrl();
return updateConfiguration()->appWebSiteUrl();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Normalize trailing slash in museScoreUrl() to prevent malformed joined links.

Line 207 returns the raw base URL, while other methods append path fragments starting with / (e.g., Line 197/202/212/217). With the current config value ending in /, generated links contain //....

🔧 Proposed fix
 std::string AppShellConfiguration::museScoreUrl() const
 {
-    return updateConfiguration()->appWebSiteUrl();
+    std::string url = updateConfiguration()->appWebSiteUrl();
+    while (!url.empty() && url.back() == '/') {
+        url.pop_back();
+    }
+    return url;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/appshell/internal/appshellconfiguration.cpp` around lines 205 - 208,
AppShellConfiguration::museScoreUrl() returns the raw
updateConfiguration()->appWebSiteUrl() which can end with a '/' and cause double
slashes when callers append paths; change museScoreUrl() to normalize the result
by trimming any trailing '/' (e.g., get the string from
updateConfiguration()->appWebSiteUrl(), if not empty and back() == '/', remove
the trailing slash) and return the normalized base URL so callers that append
"/..." won't produce '//' in URLs.

Comment on lines +124 to 132
std::string UpdateConfiguration::appWebSiteUrl() const
{
return globalConfiguration()->museScoreUrl();
return m_config.value("app_website_url").toString();
}

std::string UpdateConfiguration::museScorePrivacyPolicyUrl() const
std::string UpdateConfiguration::privacyPolicyUrl() const
{
return globalConfiguration()->museScoreUrl() + PRIVACY_POLICY_URL_PATH;
return m_config.value("privacy_policy_url").toString();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add defensive fallbacks for missing URL config keys.

On Line 126 and Line 131, missing/empty config values propagate as empty URLs, causing silent link failures in UI flows. Please add safe defaults.

🛠️ Proposed fix
 std::string UpdateConfiguration::appWebSiteUrl() const
 {
-    return m_config.value("app_website_url").toString();
+    const std::string url = m_config.value("app_website_url").toString();
+    return !url.empty() ? url : "https://www.musescore.org/";
 }
 
 std::string UpdateConfiguration::privacyPolicyUrl() const
 {
-    return m_config.value("privacy_policy_url").toString();
+    const std::string url = m_config.value("privacy_policy_url").toString();
+    return !url.empty() ? url : "https://www.musescore.org/about/desktop-privacy-policy";
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/framework/update/internal/updateconfiguration.cpp` around lines 124 -
132, The appWebSiteUrl() and privacyPolicyUrl() accessors currently return
whatever m_config.value(...).toString() yields, allowing empty/missing strings
to propagate and cause silent broken links; update
UpdateConfiguration::appWebSiteUrl() and UpdateConfiguration::privacyPolicyUrl()
to check the retrieved value (and trim) and return a safe fallback when the
config key is missing or empty (e.g., return a constant DEFAULT_APP_WEBSITE_URL
/ DEFAULT_PRIVACY_POLICY_URL or "about:blank"); add those constants near the
class (or in an anonymous namespace) and use them in the two functions so
callers always get a non-empty, predictable URL.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/framework/update/internal/appupdatescenario.cpp`:
- Around line 137-141: The message assembly in appupdatescenario.cpp uses
configuration()->appWebSiteUrl() directly and relies on QUrl::host(), which
yields empty for empty or schemeless values; update the logic before building
the muse::qtrc string to validate and normalize the configured URL (e.g.,
construct QUrl from the std::string, check QUrl::isValid() and
QUrl::scheme().isEmpty()), and if the URL is empty/invalid or missing a scheme,
prepend a safe default scheme (https://) or fall back to a
non-clickable/display-only fallback (such as the hostless string or
application()->title()) so the href and link text passed into muse::qtrc are
never blank or broken; ensure you reference configuration()->appWebSiteUrl(),
the QUrl instance (url), and url.host() when implementing the guard and fallback
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 66127c19-d885-4a1d-9e57-412ce3be2d01

📥 Commits

Reviewing files that changed from the base of the PR and between 1cd9745 and d0d615f.

📒 Files selected for processing (3)
  • src/framework/update/internal/appupdatescenario.cpp
  • src/framework/update/internal/appupdatescenario.h
  • src/framework/update/qml/Muse/Update/AppReleaseInfoDialog.qml

Comment on lines +137 to +141
std::string webSiteUrl = configuration()->appWebSiteUrl();
QUrl url(QString::fromStdString(webSiteUrl));
const QString str = muse::qtrc("update", "You already have the latest version of %1. "
"Please visit <a href=\"%2\">%3</a> for news on what’s coming next.")
.arg(application()->title().toQString(), QString::fromStdString(webSiteUrl), url.host());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== update config files =="
fd -i 'update\.cfg$' || true

echo
echo "== URL-related keys in config files =="
fd -i 'update\.cfg$' -x rg -n 'app_website_url|privacy_policy_url' {}

echo
echo "== keys that appear to miss URL scheme =="
python - <<'PY'
import pathlib, re
key_re = re.compile(r'^\s*(app_website_url|privacy_policy_url)\s*[:=]\s*("?)([^"\n#]+)\2', re.I)
for p in pathlib.Path('.').rglob('*update*.cfg'):
    try:
        lines = p.read_text(encoding='utf-8', errors='ignore').splitlines()
    except Exception:
        continue
    for i, line in enumerate(lines, 1):
        m = key_re.search(line)
        if not m:
            continue
        key, val = m.group(1), m.group(3).strip()
        if '://' not in val:
            print(f"{p}:{i}: {key} -> {val}")
PY

Repository: musescore/MuseScore

Length of output: 335


🏁 Script executed:

# Check configuration loading and validation in updateconfiguration.cpp
fd -i 'updateconfiguration.cpp' -x cat -n {} | head -200

Repository: musescore/MuseScore

Length of output: 5438


🏁 Script executed:

# Search for any validation or sanitization of URL configuration
rg -n "appWebSiteUrl|app_website_url" -A 5 -B 5

Repository: musescore/MuseScore

Length of output: 9885


🏁 Script executed:

# Check if there are other places that might set this URL value
rg -n "setAppWebSiteUrl|appWebSiteUrl\s*=" -A 3

Repository: musescore/MuseScore

Length of output: 45


Defend against empty or schemeless configured URLs in user-facing message.

Configuration loading has no validation for URL format. The stub returns empty string, which would render a broken message with blank href and link text. Additionally, schemeless URLs (e.g., musescore.org without https://) cause QUrl::host() to return empty.

Proposed fix
-    std::string webSiteUrl = configuration()->appWebSiteUrl();
-    QUrl url(QString::fromStdString(webSiteUrl));
+    const QString configuredUrl = QString::fromStdString(configuration()->appWebSiteUrl()).trimmed();
+    const QUrl url = QUrl::fromUserInput(configuredUrl);
+    const QString href = url.isValid() ? url.toString(QUrl::FullyEncoded) : configuredUrl;
+    const QString hostOrUrl = !url.host().isEmpty() ? url.host() : href;
     const QString str = muse::qtrc("update", "You already have the latest version of %1. "
                                              "Please visit <a href=\"%2\">%3</a> for news on what's coming next.")
-                        .arg(application()->title().toQString(), QString::fromStdString(webSiteUrl), url.host());
+                        .arg(application()->title().toQString().toHtmlEscaped(),
+                             href.toHtmlEscaped(),
+                             hostOrUrl.toHtmlEscaped());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/framework/update/internal/appupdatescenario.cpp` around lines 137 - 141,
The message assembly in appupdatescenario.cpp uses
configuration()->appWebSiteUrl() directly and relies on QUrl::host(), which
yields empty for empty or schemeless values; update the logic before building
the muse::qtrc string to validate and normalize the configured URL (e.g.,
construct QUrl from the std::string, check QUrl::isValid() and
QUrl::scheme().isEmpty()), and if the URL is empty/invalid or missing a scheme,
prepend a safe default scheme (https://) or fall back to a
non-clickable/display-only fallback (such as the hostless string or
application()->title()) so the href and link text passed into muse::qtrc are
never blank or broken; ensure you reference configuration()->appWebSiteUrl(),
the QUrl instance (url), and url.host() when implementing the guard and fallback
behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New Update Available - In-App Notification Dialog

2 participants