diff --git a/domain-server/src/ContentSettingsBackupHandler.cpp b/domain-server/src/ContentSettingsBackupHandler.cpp index a905a0bc03..b3748a66a3 100644 --- a/domain-server/src/ContentSettingsBackupHandler.cpp +++ b/domain-server/src/ContentSettingsBackupHandler.cpp @@ -33,12 +33,6 @@ ContentSettingsBackupHandler::ContentSettingsBackupHandler(DomainServerSettingsM } static const QString CONTENT_SETTINGS_BACKUP_FILENAME = "content-settings.json"; -static const QString INSTALLED_CONTENT = "installed_content"; -static const QString INSTALLED_CONTENT_FILENAME = "filename"; -static const QString INSTALLED_CONTENT_NAME = "name"; -static const QString INSTALLED_CONTENT_CREATION_TIME = "creation_time"; -static const QString INSTALLED_CONTENT_INSTALL_TIME = "install_time"; -static const QString INSTALLED_CONTENT_INSTALLED_BY = "installed_by"; void ContentSettingsBackupHandler::createBackup(const QString& backupName, QuaZip& zip) { diff --git a/domain-server/src/DomainContentBackupManager.h b/domain-server/src/DomainContentBackupManager.h index 1f4e72b4c6..f5957d74f5 100644 --- a/domain-server/src/DomainContentBackupManager.h +++ b/domain-server/src/DomainContentBackupManager.h @@ -37,6 +37,12 @@ const QString DATETIME_FORMAT_RE { "\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}" }; const QString AUTOMATIC_BACKUP_PREFIX { "autobackup-" }; const QString MANUAL_BACKUP_PREFIX { "backup-" }; +const QString INSTALLED_CONTENT = "installed_content"; +const QString INSTALLED_CONTENT_FILENAME = "filename"; +const QString INSTALLED_CONTENT_NAME = "name"; +const QString INSTALLED_CONTENT_CREATION_TIME = "creation_time"; +const QString INSTALLED_CONTENT_INSTALL_TIME = "install_time"; +const QString INSTALLED_CONTENT_INSTALLED_BY = "installed_by"; struct BackupItemInfo { BackupItemInfo(QString pId, QString pName, QString pAbsolutePath, QDateTime pCreatedAt, bool pIsManualBackup) : diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9dfbb46ca5..44688d0b88 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2606,7 +2606,7 @@ bool DomainServer::processPendingContent(HTTPConnection* connection, QString ite if (itemName == "restore-file" || itemName == "restore-file-chunk-final" || itemName == "restore-file-chunk-only") { // invoke our method to hand the new octree file off to the octree server QMetaObject::invokeMethod(this, "handleOctreeFileReplacement", - Qt::QueuedConnection, Q_ARG(QByteArray, _pendingUploadedContent)); + Qt::QueuedConnection, Q_ARG(QByteArray, _pendingUploadedContent), Q_ARG(QString, filename), Q_ARG(QString, QString())); _pendingUploadedContents.erase(sessionId); } } else { @@ -3491,7 +3491,7 @@ void DomainServer::maybeHandleReplacementEntityFile() { } } -void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { +void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name) { OctreeUtils::RawEntityData data; if (data.readOctreeDataInfoFromData(octreeFile)) { data.resetIdAndVersion(); @@ -3507,6 +3507,18 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { // process it when it comes back up qInfo() << "Wrote octree replacement file to" << replacementFilePath << "- stopping server"; + QJsonObject installed_content { + { INSTALLED_CONTENT_FILENAME, sourceFilename }, + { INSTALLED_CONTENT_NAME, name }, + { INSTALLED_CONTENT_CREATION_TIME, 0 }, + { INSTALLED_CONTENT_INSTALL_TIME, QDateTime::currentDateTime().currentMSecsSinceEpoch() }, + { INSTALLED_CONTENT_INSTALLED_BY, "" } + }; + + QJsonObject jsonObject { { INSTALLED_CONTENT, installed_content } }; + + _settingsManager.recurseJSONObjectAndOverwriteSettings(jsonObject, ContentSettings); + QMetaObject::invokeMethod(this, "restart", Qt::QueuedConnection); } else { qWarning() << "Could not write replacement octree data to file - refusing to process"; @@ -3516,6 +3528,8 @@ void DomainServer::handleOctreeFileReplacement(QByteArray octreeFile) { } } +static const QString CONTENT_SET_NAME_QUERY_PARAM = "name"; + void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer message) { qInfo() << "Received request to replace content from a url"; auto node = DependencyManager::get()->findNodeWithAddr(message->getSenderSockAddr()); @@ -3527,13 +3541,16 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointererror(); if (networkError == QNetworkReply::NoError) { if (modelsURL.fileName().endsWith(".json.gz")) { - handleOctreeFileReplacement(reply->readAll()); + QUrlQuery urlQuery(modelsURL.query(QUrl::FullyEncoded)); + + QString itemName = urlQuery.queryItemValue(CONTENT_SET_NAME_QUERY_PARAM); + handleOctreeFileReplacement(reply->readAll(), modelsURL.fileName(), itemName); } else if (modelsURL.fileName().endsWith(".zip")) { auto deferred = makePromise("recoverFromUploadedBackup"); _contentManager->recoverFromUploadedBackup(deferred, reply->readAll()); @@ -3548,6 +3565,6 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer message) { auto node = DependencyManager::get()->nodeWithLocalID(message->getSourceID()); if (node->getCanReplaceContent()) { - handleOctreeFileReplacement(message->readAll()); + handleOctreeFileReplacement(message->readAll(), QString(), QString()); } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 54b7fbe466..1f28169040 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -99,7 +99,7 @@ private slots: void handleDomainContentReplacementFromURLRequest(QSharedPointer message); void handleOctreeFileReplacementRequest(QSharedPointer message); - void handleOctreeFileReplacement(QByteArray octreeFile); + void handleOctreeFileReplacement(QByteArray octreeFile, QString sourceFilename, QString name); void processOctreeDataRequestMessage(QSharedPointer message); void processOctreeDataPersistMessage(QSharedPointer message); diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 3ace6f381f..41ac9232e2 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -786,7 +786,7 @@ Rectangle { } lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = function() { - Commerce.replaceContentSet(root.itemHref, root.certificateId); + Commerce.replaceContentSet(root.itemHref, root.certificateId, root.itemName); lightboxPopup.visible = false; rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start(); diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml index 966f359e92..157f3dda6a 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -36,7 +36,7 @@ Rectangle { break; case "content set": urlHandler.handleUrl("hifi://localhost/0,0,0"); - Commerce.replaceContentSet(toUrl(resource), ""); + Commerce.replaceContentSet(toUrl(resource), "", ""); break; case "entity": case "wearable": diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 0e3402a6a9..1dbcd34cce 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -729,7 +729,7 @@ Item { onClicked: { Tablet.playSound(TabletEnums.ButtonClick); if (root.itemType === "contentSet") { - sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId}); + sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId, itemName: root.itemName}); } 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 9a2bf62e08..03fbbb178e 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -609,7 +609,7 @@ Rectangle { } lightboxPopup.button2text = "CONFIRM"; lightboxPopup.button2method = function() { - Commerce.replaceContentSet(msg.itemHref, msg.certID); + Commerce.replaceContentSet(msg.itemHref, msg.certID, msg.itemName); lightboxPopup.visible = false; }; lightboxPopup.visible = true; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ad38599dcf..fd7102a07f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7788,9 +7788,15 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { return true; } -void Application::replaceDomainContent(const QString& url) { +static const QString CONTENT_SET_NAME_QUERY_PARAM = "name"; + +void Application::replaceDomainContent(const QString& url, const QString& itemName) { qCDebug(interfaceapp) << "Attempting to replace domain content"; - QByteArray urlData(url.toUtf8()); + QUrl msgUrl(url); + QUrlQuery urlQuery(msgUrl.query()); + urlQuery.addQueryItem(CONTENT_SET_NAME_QUERY_PARAM, itemName); + msgUrl.setQuery(urlQuery.query(QUrl::QUrl::FullyEncoded)); + QByteArray urlData(msgUrl.toString(QUrl::QUrl::FullyEncoded).toUtf8()); auto limitedNodeList = DependencyManager::get(); const auto& domainHandler = limitedNodeList->getDomainHandler(); @@ -7824,7 +7830,7 @@ bool Application::askToReplaceDomainContent(const QString& url) { QString details; if (static_cast(answer.toInt()) == QMessageBox::Yes) { // Given confirmation, send request to domain server to replace content - replaceDomainContent(url); + replaceDomainContent(url, QString()); details = "SuccessfulRequestToReplaceContent"; } else { details = "UserDeclinedToReplaceContent"; diff --git a/interface/src/Application.h b/interface/src/Application.h index 1e7180e203..913671473d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -326,7 +326,7 @@ public: bool isInterstitialMode() const { return _interstitialMode; } bool failedToConnectToEntityServer() const { return _failedToConnectToEntityServer; } - void replaceDomainContent(const QString& url); + void replaceDomainContent(const QString& url, const QString& itemName); void loadAvatarScripts(const QVector& urls); void unloadAvatarScripts(); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 046e697b6d..c8ea044f4b 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -259,7 +259,7 @@ void QmlCommerce::authorizeAssetTransfer(const QString& couponID, ledger->authorizeAssetTransfer(key, couponID, certificateID, amount, optionalMessage); } -void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) { +void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID, const QString& itemName) { if (!certificateID.isEmpty()) { auto ledger = DependencyManager::get(); ledger->updateLocation( @@ -267,7 +267,7 @@ void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& cert DependencyManager::get()->getPlaceName(), true); } - qApp->replaceDomainContent(itemHref); + qApp->replaceDomainContent(itemHref, itemName); QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, { "content_set_url", itemHref } }; diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 99b3e32e8b..713a5ee94f 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -90,7 +90,7 @@ protected: Q_INVOKABLE void transferAssetToUsername(const QString& username, const QString& certificateID, const int& amount, const QString& optionalMessage); Q_INVOKABLE void authorizeAssetTransfer(const QString& couponID, const QString& certificateID, const int& amount, const QString& optionalMessage); - Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID); + Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID, const QString& itemName); Q_INVOKABLE QString getInstalledApps(const QString& justInstalledAppID = ""); Q_INVOKABLE bool installApp(const QString& appHref, const bool& alsoOpenImmediately = false);