diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index e394884dc2..d2bcbf2886 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -470,7 +470,6 @@ void EntityServer::startDynamicDomainVerification() { // Delete the entity if it doesn't pass static certificate verification tree->deleteEntity(i.value(), true); } else { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest; networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); @@ -490,9 +489,13 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() - << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); - tree->deleteEntity(i.value(), true); + if (entity->getAge() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { + qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() + << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); + tree->deleteEntity(i.value(), true); + } else { + qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << i.value(); + } } else { qCDebug(entities) << "Entity passed dynamic domain verification:" << i.value(); } diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 3152a1eed6..c0cf45d292 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -96,6 +96,7 @@ Rectangle { root.activeView = "checkoutFailure"; UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); } else { + root.certificateId = result.data.certificate_id; root.itemHref = result.data.download_url; if (result.data.categories.indexOf("Wearables") > -1) { root.itemType = "wearable"; @@ -188,7 +189,7 @@ Rectangle { onItemHrefChanged: { if (root.itemHref.indexOf(".fst") > -1) { root.itemType = "avatar"; - } else if (root.itemHref.indexOf('.json.gz') > -1) { + } else if (root.itemHref.indexOf('.json.gz') > -1 || root.itemHref.indexOf('.content.zip') > -1) { root.itemType = "contentSet"; } else if (root.itemHref.indexOf('.app.json') > -1) { root.itemType = "app"; @@ -772,7 +773,7 @@ Rectangle { lightboxPopup.button1text = "CANCEL"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemHref + "');" + + lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemHref + "', '" + root.certificateId + "');" + "root.visible = false;rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start();" + "UserActivityLogger.commerceEntityRezzed('" + root.itemId + "', 'checkout', '" + root.itemType + "');"; lightboxPopup.visible = true; diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 4cfa61c9ed..2aac269d56 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -564,7 +564,7 @@ Item { onClicked: { Tablet.playSound(TabletEnums.ButtonClick); if (root.itemType === "contentSet") { - sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref}); + sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId}); } else if (root.itemType === "avatar") { sendToPurchases({method: 'showChangeAvatarLightbox', itemName: root.itemName, itemHref: root.itemHref}); } else if (root.itemType === "app") { diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 726e6bd338..cdcfa4a13e 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -486,7 +486,7 @@ Rectangle { lightboxPopup.button1text = "CANCEL"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemHref + "'); root.visible = false;"; + lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemHref + "', '" + msg.certID + "'); root.visible = false;"; lightboxPopup.visible = true; } else if (msg.method === "showChangeAvatarLightbox") { lightboxPopup.titleText = "Change Avatar"; @@ -792,7 +792,7 @@ Rectangle { currentItemType = "avatar"; } else if (currentCategories.indexOf("Wearables") > -1) { currentItemType = "wearable"; - } else if (currentRootFileUrl.endsWith('.json.gz')) { + } else if (currentRootFileUrl.endsWith('.json.gz') || currentRootFileUrl.endsWith('.content.zip')) { currentItemType = "contentSet"; } else if (currentRootFileUrl.endsWith('.app.json')) { currentItemType = "app"; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 0a9e867323..cb06cdfed7 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -293,7 +293,7 @@ void Ledger::account() { // The api/failResponse is called just for the side effect of logging. void Ledger::updateLocationSuccess(QNetworkReply& reply) { apiResponse("updateLocation", reply); } void Ledger::updateLocationFailure(QNetworkReply& reply) { failResponse("updateLocation", reply); } -void Ledger::updateLocation(const QString& asset_id, const QString location, const bool controlledFailure) { +void Ledger::updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings, const bool controlledFailure) { auto wallet = DependencyManager::get(); auto walletScriptingInterface = DependencyManager::get(); uint walletStatus = walletScriptingInterface->getWalletStatus(); @@ -308,6 +308,9 @@ void Ledger::updateLocation(const QString& asset_id, const QString location, con QJsonObject transaction; transaction["certificate_id"] = asset_id; transaction["place_name"] = location; + if (alsoUpdateSiblings) { + transaction["also_update_siblings"] = true; + } QJsonDocument transactionDoc{ transaction }; auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index da97206bbc..1ccab9c2b1 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -31,7 +31,7 @@ public: void inventory(const QStringList& keys); void history(const QStringList& keys, const int& pageNumber); void account(); - void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false); + void updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings = false, const bool controlledFailure = false); void certificateInfo(const QString& certificateId); void transferHfcToNode(const QString& hfc_key, const QString& nodeID, const int& amount, const QString& optionalMessage); void transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 8e956249cc..7e91ffaa62 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -190,7 +190,9 @@ void QmlCommerce::transferHfcToUsername(const QString& username, const int& amou ledger->transferHfcToUsername(key, username, amount, optionalMessage); } -void QmlCommerce::replaceContentSet(const QString& itemHref) { +void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) { + auto ledger = DependencyManager::get(); + ledger->updateLocation(certificateID, DependencyManager::get()->getPlaceName(), true); qApp->replaceDomainContent(itemHref); QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index a3a0ebfd32..f58726e1d7 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -84,7 +84,7 @@ protected: Q_INVOKABLE void transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage); Q_INVOKABLE void transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage); - Q_INVOKABLE void replaceContentSet(const QString& itemHref); + Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID); Q_INVOKABLE QString getInstalledApps(); Q_INVOKABLE bool installApp(const QString& appHref);