From d2ad1c4092648af8e50c6591a287c703afed2506 Mon Sep 17 00:00:00 2001 From: Noctis Linden <173088017+noctis-linden@users.noreply.github.com> Date: Tue, 29 Sep 2026 19:02:32 -0400 Subject: Check payment info before opening the L$ packs floater Until the floater can add a payment method, residents without one are sent to the LindeX payment page instead of the floater. A second login probe of BuyCurrencyAddPaymentURL skips the check when it answers 200. --- indra/newview/app_settings/settings.xml | 11 ++++ indra/newview/llbuycurrencyhtml.cpp | 101 +++++++++++++++++++++++++++----- indra/newview/llbuycurrencyhtml.h | 19 +++++- indra/newview/llfloaterbuycurrency.cpp | 40 +++++++++++-- indra/newview/llfloaterbuycurrency.h | 16 +++++ 5 files changed, 165 insertions(+), 22 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ba44b68307..f6f11f9578 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1194,6 +1194,17 @@ Value https://accounts.secondlife.com/packs/floater?lang=[LANGUAGE]&shortfall=[SHORTFALL] + BuyCurrencyAddPaymentURL + + Comment + URL the viewer probes at login; a 200 means the L$ packs floater handles residents without a payment method + Persist + 1 + Type + String + Value + https://accounts.secondlife.com/packs/floater/add-payment-enabled + PaymentMethodURL Comment diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp index 9ad068cf7f..f5bc3b5357 100644 --- a/indra/newview/llbuycurrencyhtml.cpp +++ b/indra/newview/llbuycurrencyhtml.cpp @@ -89,6 +89,8 @@ public: LLBuyCurrencyHTMLHandler gBuyCurrencyHTMLHandler; bool LLBuyCurrencyHTML::sWebFloaterEnabled = false; +bool LLBuyCurrencyHTML::sAddPaymentEnabled = false; +LLFetchAvatarPaymentInfo* LLBuyCurrencyHTML::sPaymentInfoRequest = NULL; //////////////////////////////////////////////////////////////////////////////// // static @@ -109,12 +111,38 @@ static void checkFeatureFlag_coro(std::string check_url) LLBuyCurrencyHTML::sWebFloaterEnabled = !(status.isHttpStatus() && status.getType() == 501); } +// static +static void checkAddPaymentFlag_coro(std::string check_url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter = std::make_shared("CheckBuyCurrencyAddPaymentURL", httpPolicy); + LLCore::HttpRequest::ptr_t httpRequest = std::make_shared(); + + // a redirect to some other page that answers 200 must not read as enabled + LLCore::HttpOptions::ptr_t httpOptions = std::make_shared(); + httpOptions->setRetries(0); + httpOptions->setFollowRedirects(false); + + LLSD result = httpAdapter->getRawAndSuspend(httpRequest, check_url, httpOptions); + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LLBuyCurrencyHTML::sAddPaymentEnabled = status.isHttpStatus() && status.getType() == 200; + LL_INFOS("LLBuyCurrency") << "Add payment probe returned " << status.toString() + << ", in-floater add payment " << (LLBuyCurrencyHTML::sAddPaymentEnabled ? "enabled" : "disabled") << LL_ENDL; +} + // static void LLBuyCurrencyHTML::checkFeatureFlag() { std::string check_url = LLFloaterBuyCurrencyHTML::buildURL(); LLCoros::instance().launch("checkFeatureFlag_coro", [check_url]() { checkFeatureFlag_coro(check_url); }); + + std::string add_payment_url = gSavedSettings.getString("BuyCurrencyAddPaymentURL"); + LLCoros::instance().launch("checkAddPaymentFlag_coro", + [add_payment_url]() { checkAddPaymentFlag_coro(add_payment_url); }); } //////////////////////////////////////////////////////////////////////////////// @@ -124,15 +152,7 @@ void LLBuyCurrencyHTML::checkFeatureFlag() // the case where the amount is not requested. void LLBuyCurrencyHTML::openCurrencyFloater() { - if (gSavedSettings.getBOOL("BuyCurrencyHTML") && sWebFloaterEnabled) - { - LLBuyCurrencyHTML::showDialog(); - } - else - { - // legacy version - LLFloaterBuyCurrency::buyCurrency(); - } + routeCurrencyRequest(false, LLStringUtil::null, 0); } //////////////////////////////////////////////////////////////////////////////// @@ -142,19 +162,68 @@ void LLBuyCurrencyHTML::openCurrencyFloater() // the case where the amount and a string to display are requested. void LLBuyCurrencyHTML::openCurrencyFloater( const std::string& message, S32 sum ) { - if (gSavedSettings.getBOOL("BuyCurrencyHTML") && sWebFloaterEnabled) + routeCurrencyRequest(true, message, sum); +} + +//////////////////////////////////////////////////////////////////////////////// +// static +// Without the in-floater add payment flow, the web floater is opened only for +// residents with payment info on file; the rest go to the LindeX payment page. +void LLBuyCurrencyHTML::routeCurrencyRequest( bool has_target, const std::string& message, S32 sum ) +{ + if (!gSavedSettings.getBOOL("BuyCurrencyHTML") || !sWebFloaterEnabled) { - LLBuyCurrencyHTML::showDialog(sum - gStatusBar->getBalance()); - LLFloaterBuyCurrencyHTML* floater = dynamic_cast(LLFloaterReg::getInstance("buy_currency_html")); - if (floater) + // legacy version, which runs its own payment info check + if (has_target) { - floater->setFallbackContext(message, sum); + LLFloaterBuyCurrency::buyCurrency(message, sum); } + else + { + LLFloaterBuyCurrency::buyCurrency(); + } + } + else if (sAddPaymentEnabled) + { + openWebFloater(has_target, message, sum); } else { - // legacy version - LLFloaterBuyCurrency::buyCurrency( message, sum ); + delete sPaymentInfoRequest; + sPaymentInfoRequest = new LLFetchAvatarPaymentInfo( + [has_target, message, sum](bool has_piof) + { + delete sPaymentInfoRequest; + sPaymentInfoRequest = NULL; + + if (has_piof) + { + openWebFloater(has_target, message, sum); + } + else + { + LL_INFOS("LLBuyCurrency") << "No payment info on file, opening payment method page" << LL_ENDL; + LLFloaterBuyCurrency::openPaymentMethodPage(); + } + }); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLBuyCurrencyHTML::openWebFloater( bool has_target, const std::string& message, S32 sum ) +{ + if (!has_target) + { + LLBuyCurrencyHTML::showDialog(); + return; + } + + LLBuyCurrencyHTML::showDialog(sum - gStatusBar->getBalance()); + LLFloaterBuyCurrencyHTML* floater = dynamic_cast(LLFloaterReg::getInstance("buy_currency_html")); + if (floater) + { + floater->setFallbackContext(message, sum); } } diff --git a/indra/newview/llbuycurrencyhtml.h b/indra/newview/llbuycurrencyhtml.h index 2f78199dcb..c8a98c42a9 100644 --- a/indra/newview/llbuycurrencyhtml.h +++ b/indra/newview/llbuycurrencyhtml.h @@ -29,6 +29,8 @@ #include "llsingleton.h" +class LLFetchAvatarPaymentInfo; + class LLBuyCurrencyHTML { public: @@ -45,10 +47,25 @@ class LLBuyCurrencyHTML // close (and destroy) the currency floater static void closeDialog(); - // probe BuyCurrencyPacksURL once at login; clears sWebFloaterEnabled if 501 + // probe BuyCurrencyPacksURL once at login; clears sWebFloaterEnabled if 501. + // also launches the BuyCurrencyAddPaymentURL probe that sets sAddPaymentEnabled static void checkFeatureFlag(); static bool sWebFloaterEnabled; + + // true only when BuyCurrencyAddPaymentURL answered 200, meaning the web floater + // can add a payment method; otherwise residents without one are sent to the LindeX + static bool sAddPaymentEnabled; + + private: + // route to the legacy floater, the web floater, or the LindeX payment page + static void routeCurrencyRequest( bool has_target, const std::string& message, S32 sum ); + + // open the web floater, with the shortfall and fallback context when there is a target + static void openWebFloater( bool has_target, const std::string& message, S32 sum ); + + // pending payment info check made before opening the web floater + static LLFetchAvatarPaymentInfo* sPaymentInfoRequest; }; #endif // LL_LLBUYCURRENCYHTML_H diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index 56b3229fda..7533145625 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -338,18 +338,38 @@ void LLFloaterBuyCurrency::handleBuyCurrency(bool has_piof, bool has_target, con } else { - const std::string& grid_id = LLGridManager::getInstance()->getGridId(); - const std::string& grid_id_lower = utf8str_tolower(grid_id); - const std::string url = gSavedSettings.getString(grid_id_lower == "damballah" ? "PaymentMethodStagingURL" : "PaymentMethodURL"); - LLWeb::loadURL(url); + openPaymentMethodPage(); } } +// static +void LLFloaterBuyCurrency::openPaymentMethodPage() +{ + const std::string& grid_id = LLGridManager::getInstance()->getGridId(); + const std::string& grid_id_lower = utf8str_tolower(grid_id); + const std::string url = gSavedSettings.getString(grid_id_lower == "damballah" ? "PaymentMethodStagingURL" : "PaymentMethodURL"); + LLWeb::loadURL(url); +} + LLFetchAvatarPaymentInfo::LLFetchAvatarPaymentInfo(bool has_target, const std::string& name, S32 price) : mAvatarID(gAgent.getID()), mHasTarget(has_target), mPrice(price), mName(name) +{ + sendRequest(); +} + +LLFetchAvatarPaymentInfo::LLFetchAvatarPaymentInfo(const callback_t& cb) +: mAvatarID(gAgent.getID()), + mHasTarget(false), + mPrice(0), + mCallback(cb) +{ + sendRequest(); +} + +void LLFetchAvatarPaymentInfo::sendRequest() { LLAvatarPropertiesProcessor* processor = LLAvatarPropertiesProcessor::getInstance(); // register ourselves as an observer @@ -369,6 +389,16 @@ void LLFetchAvatarPaymentInfo::processProperties(void* data, EAvatarProcessorTyp if (data && type == APT_PROPERTIES) { LLAvatarData* avatar_data = static_cast(data); - LLFloaterBuyCurrency::handleBuyCurrency(LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(avatar_data), mHasTarget, mName, mPrice); + bool has_piof = LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(avatar_data); + if (mCallback) + { + // call a local copy, since the callback may delete this observer + callback_t cb = mCallback; + cb(has_piof); + } + else + { + LLFloaterBuyCurrency::handleBuyCurrency(has_piof, mHasTarget, mName, mPrice); + } } } diff --git a/indra/newview/llfloaterbuycurrency.h b/indra/newview/llfloaterbuycurrency.h index 1b04c9c6d2..c6a80de926 100644 --- a/indra/newview/llfloaterbuycurrency.h +++ b/indra/newview/llfloaterbuycurrency.h @@ -30,21 +30,34 @@ #include "llavatarpropertiesprocessor.h" #include "stdtypes.h" #include "llagent.h" + +#include + class LLFloater; class LLFetchAvatarPaymentInfo : public LLAvatarPropertiesObserver { public: + typedef std::function callback_t; + + // hands the result to LLFloaterBuyCurrency::handleBuyCurrency LLFetchAvatarPaymentInfo(bool has_target, const std::string& name = std::string(), S32 price = 0); + + // hands the result to cb, which may delete this observer + LLFetchAvatarPaymentInfo(const callback_t& cb); + ~LLFetchAvatarPaymentInfo(); void processProperties(void* data, EAvatarProcessorType type); private: + void sendRequest(); + LLUUID mAvatarID; bool mHasTarget; std::string mName; S32 mPrice; + callback_t mCallback; }; @@ -62,6 +75,9 @@ public: a space and the price will be appended */ + // open the LindeX page where a resident adds a payment method + static void openPaymentMethodPage(); + static LLFloater* buildFloater(const LLSD& key); static LLFetchAvatarPaymentInfo* sPropertiesRequest; -- cgit v1.3