From 33be9775dcf72c34000ff94d9352e07aa6c234d2 Mon Sep 17 00:00:00 2001 From: Andrew <159703254+andrewsoonqn@users.noreply.github.com> Date: Wed, 13 May 2026 17:58:08 +0800 Subject: [PATCH] Fix inconsistent displayed name (#13645) * Add get_json_string_field helper Introduce get_json_string_field in OrcaCloudServiceAgent.cpp to safely extract string fields from JSON objects. * Add resolve_display_name helper Introduce resolve_display_name to normalize provider metadata labels for the UI. The helper returns the first non-empty value from display_name, nickname, full_name, name, falling back to username, resolving human-facing label across varying provider payloads. * Replace safe_str anonymous function Replace get_json_string_field for better readability. * Replace resolution flow for nickname with function Consolidate both flows into one function for easier maintenance and more consistency. * Update OrcaCloudServiceAgent.hpp * Add OrcaCloudServiceAgent display name tests Add unit tests verifying OrcaCloudServiceAgent resolves a user's display name from various session JSON shapes. --- src/slic3r/Utils/OrcaCloudServiceAgent.cpp | 78 ++++++++++------ src/slic3r/Utils/OrcaCloudServiceAgent.hpp | 7 +- tests/slic3rutils/slic3rutils_tests_main.cpp | 97 ++++++++++++++++++++ 3 files changed, 151 insertions(+), 31 deletions(-) diff --git a/src/slic3r/Utils/OrcaCloudServiceAgent.cpp b/src/slic3r/Utils/OrcaCloudServiceAgent.cpp index abbebef42c..4298f9616c 100644 --- a/src/slic3r/Utils/OrcaCloudServiceAgent.cpp +++ b/src/slic3r/Utils/OrcaCloudServiceAgent.cpp @@ -74,6 +74,32 @@ constexpr const char* SECRET_STORE_SERVICE = "OrcaSlicer/Auth"; constexpr const char* SECRET_STORE_USER = "orca_refresh_token"; constexpr std::chrono::seconds TOKEN_REFRESH_SKEW{900}; // 15 minutes +// Return a JSON field only when it is present as a string. Missing or non-string values normalize to empty. +std::string get_json_string_field(const json& j, const std::string& key) +{ + if (j.contains(key) && j[key].is_string()) { + return j[key].get(); + } + return ""; +} + +// Resolve the human-facing UI label from provider metadata. +std::string resolve_display_name( + const std::string& display_name, + const std::string& nickname, + const std::string& full_name, + const std::string& name, + const std::string& username) +{ + // Providers and payload shapes do not all use the same display-name field. + // Fallback sequence: display_name -> nickname -> full_name -> name + if (!display_name.empty()) return display_name; + if (!nickname.empty()) return nickname; + if (!full_name.empty()) return full_name; + if (!name.empty()) return name; + return username; +} + std::string generate_uuid_for_setting_id(const std::string& name, const std::string& user_id = "") { if (name.empty()) { @@ -1667,47 +1693,43 @@ bool OrcaCloudServiceAgent::set_user_session(const std::string& token, bool OrcaCloudServiceAgent::set_user_session(const json& session_json, bool notify_login) { - auto safe_str = [](const json& j, const std::string& key) -> std::string { - if (j.contains(key) && j[key].is_string()) return j[key].get(); - return ""; - }; - - std::string access_token = safe_str(session_json, "access_token"); + std::string access_token = get_json_string_field(session_json, "access_token"); if (access_token.empty()) { - access_token = safe_str(session_json, "token"); + access_token = get_json_string_field(session_json, "token"); } - std::string refresh_token = safe_str(session_json, "refresh_token"); + std::string refresh_token = get_json_string_field(session_json, "refresh_token"); std::string user_id, username, nickname, avatar; if (session_json.contains("user") && session_json["user"].is_object()) { // Nested format (Orca cloud / GoTrue response) const auto& user = session_json["user"]; - user_id = safe_str(user, "id"); + user_id = get_json_string_field(user, "id"); + if (user.contains("user_metadata") && user["user_metadata"].is_object()) { - const auto& meta = user["user_metadata"]; - username = safe_str(meta, "username"); // Orca Cloud's unique username + username = get_json_string_field(meta, "username"); // Orca Cloud's unique username - nickname = safe_str(meta, "display_name"); // Orca Cloud's primary display name field - // Fallback to different name from different providers if display_name is not set - if (nickname.empty()) - nickname = safe_str(meta, "full_name"); - if (nickname.empty()) - nickname = safe_str(meta, "name"); - if (nickname.empty()) - nickname = username; - - avatar = safe_str(meta, "avatar_url"); + // Orca Cloud's primary display name field is display_name. + // Fallback to different names from different providers if display_name is not set. + nickname = resolve_display_name( + get_json_string_field(meta, "display_name"), + get_json_string_field(meta, "nickname"), + get_json_string_field(meta, "full_name"), + get_json_string_field(meta, "name"), + username); + avatar = get_json_string_field(meta, "avatar_url"); } } else { // Flat format (WebView direct token flow) - user_id = safe_str(session_json, "user_id"); - username = safe_str(session_json, "username"); - nickname = safe_str(session_json, "display_name"); - if(nickname.empty()) - nickname = safe_str(session_json, "nickname"); - - avatar = safe_str(session_json, "avatar"); + user_id = get_json_string_field(session_json, "user_id"); + username = get_json_string_field(session_json, "username"); + nickname = resolve_display_name( + get_json_string_field(session_json, "display_name"), + get_json_string_field(session_json, "nickname"), + get_json_string_field(session_json, "full_name"), + get_json_string_field(session_json, "name"), + username); + avatar = get_json_string_field(session_json, "avatar"); } if (access_token.empty() || user_id.empty()) { diff --git a/src/slic3r/Utils/OrcaCloudServiceAgent.hpp b/src/slic3r/Utils/OrcaCloudServiceAgent.hpp index 2a372810d6..4552b487d4 100644 --- a/src/slic3r/Utils/OrcaCloudServiceAgent.hpp +++ b/src/slic3r/Utils/OrcaCloudServiceAgent.hpp @@ -88,8 +88,8 @@ public: std::string access_token; std::string refresh_token; std::string user_id; - // Orca auth semantics: user_name is unique orca cloud username(orca_xxxxx), user_nickname is - // the display name shown in the UI when available. + // Orca auth semantics: user_name is the unique Orca Cloud username (orca_xxxxx), + // user_nickname is the display name shown in the UI when available. std::string user_name; std::string user_nickname; std::string user_avatar; @@ -276,13 +276,14 @@ public: bool refresh_now(const std::string& refresh_token, const std::string& reason, bool async = false); bool refresh_session_with_token(const std::string& refresh_token); - // Session state helpers + // Session state helpers. nickname is the human-facing UI label after provider fallback resolution. bool set_user_session(const std::string& token, const std::string& user_id, const std::string& username, const std::string& nickname, const std::string& avatar, const std::string& refresh_token = ""); + // Accepts either nested Orca cloud / GoTrue session JSON or flat WebView token JSON. bool set_user_session(const nlohmann::json& session_json, bool notify_login = true); void clear_session(); diff --git a/tests/slic3rutils/slic3rutils_tests_main.cpp b/tests/slic3rutils/slic3rutils_tests_main.cpp index 176e34a5df..fa72272599 100644 --- a/tests/slic3rutils/slic3rutils_tests_main.cpp +++ b/tests/slic3rutils/slic3rutils_tests_main.cpp @@ -1,6 +1,47 @@ #include #include "slic3r/Utils/Http.hpp" +#include "slic3r/Utils/OrcaCloudServiceAgent.hpp" + +#include + +namespace { + +struct WxFixture { + WxFixture() { REQUIRE(initializer.IsOk()); } + + wxInitializer initializer; +}; + +nlohmann::json flat_session_json(const nlohmann::json& fields) +{ + nlohmann::json session = { + {"access_token", "test-token"}, + {"user_id", "test-user-id"} + }; + session.update(fields); + return session; +} + +nlohmann::json nested_session_json(const nlohmann::json& metadata) +{ + return { + {"access_token", "test-token"}, + {"user", { + {"id", "test-user-id"}, + {"user_metadata", metadata} + }} + }; +} + +std::string resolved_display_name(const nlohmann::json& session) +{ + Slic3r::OrcaCloudServiceAgent agent(""); + REQUIRE(agent.set_user_session(session, false)); + return agent.get_user_nickname(); +} + +} // namespace TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") { @@ -20,6 +61,62 @@ TEST_CASE("Check SSL certificates paths", "[Http][NotWorking]") { REQUIRE(status == 200); } +TEST_CASE_METHOD(WxFixture, "Orca cloud flat session resolves display name consistently", "[OrcaCloudServiceAgent]") +{ + CHECK(resolved_display_name(flat_session_json({ + {"username", "orca_username"}, + {"display_name", "Display Name"}, + {"nickname", "Nickname"} + })) == "Display Name"); + + CHECK(resolved_display_name(flat_session_json({ + {"username", "orca_username"}, + {"nickname", "Nickname"} + })) == "Nickname"); + + CHECK(resolved_display_name(flat_session_json({ + {"username", "orca_username"}, + {"full_name", "Full Name"} + })) == "Full Name"); + + CHECK(resolved_display_name(flat_session_json({ + {"username", "orca_username"}, + {"name", "Provider Name"} + })) == "Provider Name"); + + CHECK(resolved_display_name(flat_session_json({ + {"username", "orca_username"} + })) == "orca_username"); +} + +TEST_CASE_METHOD(WxFixture, "Orca cloud nested session resolves display name consistently", "[OrcaCloudServiceAgent]") +{ + CHECK(resolved_display_name(nested_session_json({ + {"username", "orca_username"}, + {"display_name", "Display Name"}, + {"nickname", "Nickname"} + })) == "Display Name"); + + CHECK(resolved_display_name(nested_session_json({ + {"username", "orca_username"}, + {"nickname", "Nickname"} + })) == "Nickname"); + + CHECK(resolved_display_name(nested_session_json({ + {"username", "orca_username"}, + {"full_name", "Full Name"} + })) == "Full Name"); + + CHECK(resolved_display_name(nested_session_json({ + {"username", "orca_username"}, + {"name", "Provider Name"} + })) == "Provider Name"); + + CHECK(resolved_display_name(nested_session_json({ + {"username", "orca_username"} + })) == "orca_username"); +} + TEST_CASE("Http digest authentication", "[Http][NotWorking]") { Slic3r::Http g = Slic3r::Http::get("https://httpbingo.org/digest-auth/auth/guest/guest");