diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 962e0fc583..38f4c66f4b 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -464,7 +464,6 @@ void AssetServer::loadMappingsFromFile() { shouldDrop = true; } - if (!isValidHash(it.value().toString())) { qWarning() << "Will not keep mapping for" << it.key() << "since it does not have a valid hash."; shouldDrop = true; diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 8819d1100c..d45527a1f4 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -21,7 +21,7 @@ import "dialogs" Window { id: root objectName: "AssetServer" - title: "Asset Server" + title: "My Asset Server" resizable: true destroyOnInvisible: true x: 40; y: 40 @@ -56,12 +56,13 @@ Window { Assets.deleteMappings(path, function(err) { if (err) { console.log("Error deleting path: ", path, err); - errorMessage("There was an error deleting:\n" + path + "\n\nPlease try again."); + + box = errorMessageBox("There was an error deleting:\n" + path + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { console.log("Finished deleting path: ", path); + reload(); } - - reload(); }); } @@ -80,7 +81,8 @@ Window { Assets.renameMapping(oldPath, newPath, function(err) { if (err) { console.log("Error renaming: ", oldPath, "=>", newPath, " - error ", err); - errorMessage("There was an error renaming:\n" + oldPath + " to " + newPath + "\n\nPlease try again."); + box = errorMessageBox("There was an error renaming:\n" + oldPath + " to " + newPath + "\n" + Assets.getErrorString(err)); + box.selected.connect(reload); } else { console.log("Finished rename: ", oldPath, "=>", newPath); } @@ -95,12 +97,11 @@ Window { function askForOverride(path, callback) { var object = desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Question, + icon: hifi.icons.question, buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.No, - text: "Override?", - informativeText: "The following file already exists:\n" + path + - "\nDo you want to override it?" + defaultButton: OriginalDialogs.StandardButton.Yes, + title: "Overwrite File", + text: path + "\n" + "This file already exists. Do you want to overwrite it?" }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { @@ -123,29 +124,32 @@ Window { Assets.mappingModel.refresh(); } - function handleGetMappingsError() { - errorMessage("There was a problem retreiving the list of assets from your Asset Server.\n" - + "Please make sure you are connected to the Asset Server and try again. "); + function handleGetMappingsError(errorCode) { + errorMessageBox( + "There was a problem retreiving the list of assets from your Asset Server.\n" + + Assets.getErrorString(errorCode) + ); } function addToWorld() { - var url = assetMappingsModel.data(treeView.currentIndex, 0x102); + var url = assetProxyModel.data(treeView.currentIndex, 0x103); if (!url) { return; } - - Entities.addModelEntity(url, MyAvatar.position); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); + Entities.addModelEntity(url, addPosition); } - function copyURLToClipboard(index) { + function copyURLToClipboard() { if (!index) { index = treeView.currentIndex; } - var path = assetProxyModel.data(index, 0x103); - if (!path) { + + var url = assetProxyModel.data(treeView.currentIndex, 0x103); + if (!url) { return; } - Window.copyToClipboard(path); + Window.copyToClipboard(url); } function renameFile(index) { @@ -159,7 +163,7 @@ Window { var object = desktop.inputDialog({ label: "Enter new path:", - prefilledText: path, + current: path, placeholderText: "Enter path here" }); object.selected.connect(function(destinationPath) { @@ -188,13 +192,11 @@ Window { var typeString = isFolder ? 'folder' : 'file'; var object = desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Question, - buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.No, - text: "Deleting", - informativeText: "You are about to delete the following " + typeString + ":\n" + - path + - "\nDo you want to continue?" + icon: hifi.icons.question, + buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.Yes, + title: "Delete", + text: "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?" }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { @@ -214,36 +216,39 @@ Window { }); } + property var uploadOpen: false; function uploadClicked() { + if (uploadOpen) { + return; + } + uploadOpen = true; + var fileUrl = fileUrlTextField.text var addToWorld = addToWorldCheckBox.checked var path = assetProxyModel.data(treeView.currentIndex, 0x100); - var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : ""; + var directory = path ? path.slice(0, path.lastIndexOf('/') + 1) : "/"; var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); - var object = desktop.inputDialog({ - label: "Enter asset path:", - prefilledText: directory + filename, - placeholderText: "Enter path here" - }); - object.selected.connect(function(destinationPath) { - if (fileExists(destinationPath)) { - askForOverride(fileUrl, function() { - doUploadFile(fileUrl, destinationPath, addToWorld); - }); + Assets.uploadFile(fileUrl, directory + filename, function(err) { + if (err) { + console.log("Error uploading: ", fileUrl, " - error ", err); + errorMessage("There was an error uploading:\n" + fileUrl + "\n\nPlease try again."); } else { - doUploadFile(fileUrl, destinationPath, addToWorld); + console.log("Finished uploading: ", fileUrl); } + + reload(); }); + uploadOpen = false; } - function errorMessage(message) { - desktop.messageBox({ - icon: OriginalDialogs.StandardIcon.Error, - buttons: OriginalDialogs.StandardButton.Ok, - text: "Error", - informativeText: message + function errorMessageBox(message) { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message }); } diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index fa702090d3..4a25c51012 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -96,6 +96,7 @@ ModalWindow { } lineHeight: 2 lineHeightMode: Text.ProportionalHeight + horizontalAlignment: Text.AlignHCenter } RalewaySemiBold { diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 754851030c..48df9a41ce 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -34,12 +34,10 @@ ModalWindow { property var items; property string label property var result; - // FIXME not current honored - property var current; + property alias current: textResult.text // For text boxes property alias placeholderText: textResult.placeholderText - property alias prefilledText: textResult.text // For combo boxes property bool editable: true; diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 32cf61117b..09cba6d462 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -35,7 +35,7 @@ Item { glyph = hifi.glyphs.alert; break; case hifi.icons.critical: - glyph = hifi.glyphs.critical; + glyph = hifi.glyphs.error; break; case hifi.icons.placemark: glyph = hifi.glyphs.placemark; @@ -159,36 +159,6 @@ Item { readonly property real disclosureButton: dimensions.largeScreen ? 20 : 15 } - Item { - id: glyphs - readonly property string alert: "+" - readonly property string backward: "E" - readonly property string caratDn: "5" - readonly property string caratR: "3" - readonly property string caratUp: "6" - readonly property string close: "w" - readonly property string closeInverted: "x" - readonly property string closeSmall: "C" - readonly property string critical: "=" - readonly property string disclosureButtonCollapse: "M" - readonly property string disclosureButtonExpand: "L" - readonly property string disclosureCollapse: "Z" - readonly property string disclosureExpand: "B" - readonly property string forward: "D" - readonly property string info: "[" - readonly property string noIcon: "" - readonly property string pin: "y" - readonly property string pinInverted: "z" - readonly property string placemark: "U" - readonly property string question: "]" - readonly property string reloadSmall: "a" - readonly property string resizeHandle: "A" - readonly property string upload: "j" - readonly property string reload: "a" - readonly property string back: "1" - - } - Item { id: icons // Values per OffscreenUi::Icon @@ -221,4 +191,103 @@ Item { id: effects readonly property int fadeInDuration: 300 } + Item { + id: glyphs + readonly property string noIcon: "" + readonly property string hmd: "b" + readonly property string screen: "c" + readonly property string keyboard: "d" + readonly property string handControllers: "e" + readonly property string headphonesMic: "f" + readonly property string gamepad: "g" + readonly property string headphones: "h" + readonly property string mic: "i" + readonly property string upload: "j" + readonly property string script: "k" + readonly property string text: "l" + readonly property string cube: "m" + readonly property string sphere: "n" + readonly property string zone: "o" + readonly property string light: "p" + readonly property string web: "q" + readonly property string web2: "r" + readonly property string edit: "s" + readonly property string market: "t" + readonly property string directory: "u" + readonly property string menu: "v" + readonly property string close: "w" + readonly property string closeInverted: "x" + readonly property string pin: "y" + readonly property string pinInverted: "z" + readonly property string resizeHandle: "A" + readonly property string disclosureExpand: "B" + readonly property string reloadSmall: "a" + readonly property string closeSmall: "C" + readonly property string forward: "D" + readonly property string backward: "E" + readonly property string reload: "F" + readonly property string unmuted: "G" + readonly property string muted: "H" + readonly property string minimize: "I" + readonly property string maximize: "J" + readonly property string maximizeInverted: "K" + readonly property string disclosureButtonExpand: "L" + readonly property string disclosureButtonCollapse: "M" + readonly property string scriptStop: "N" + readonly property string scriptReload: "O" + readonly property string scriptRun: "P" + readonly property string scriptNew: "Q" + readonly property string hifiForum: "2" + readonly property string hifiLogoSmall: "S" + readonly property string avatar1: "T" + readonly property string placemark: "U" + readonly property string box: "V" + readonly property string community: "0" + readonly property string grabHandle: "X" + readonly property string search: "Y" + readonly property string disclosureCollapse: "Z" + readonly property string scriptUpload: "R" + readonly property string code: "W" + readonly property string avatar: "<" + readonly property string arrowsH: ":" + readonly property string arrowsV: ";" + readonly property string arrows: "`" + readonly property string compress: "!" + readonly property string expand: "\"" + readonly property string placemark1: "#" + readonly property string circle: "$" + readonly property string handPointer: "9" + readonly property string plusSquareO: "%" + readonly property string sliders: "&" + readonly property string square: "'" + readonly property string alignCenter: "8" + readonly property string alignJustify: ")" + readonly property string alignLeft: "*" + readonly property string alignRight: "^" + readonly property string bars: "7" + readonly property string circleSlash: "," + readonly property string sync: "()" + readonly property string key: "-" + readonly property string link: "." + readonly property string location: "/" + readonly property string caratR: "3" + readonly property string caratL: "4" + readonly property string caratDn: "5" + readonly property string caratUp: "6" + readonly property string folderLg: ">" + readonly property string folderSm: "?" + readonly property string levelUp: "1" + readonly property string info: "[" + readonly property string question: "]" + readonly property string alert: "+" + readonly property string home: "_" + readonly property string error: "=" + readonly property string settings: "@" + readonly property string trash: "{" + readonly property string objectGroup: "" + readonly property string cm: "}" + readonly property string msvg79: "~" + readonly property string deg: "\\" + readonly property string px: "|" + } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2660acfa00..a8e64513ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -66,7 +66,6 @@ #include #include #include -#include #include #include #include @@ -142,6 +141,7 @@ #include "ModelPackager.h" #include "PluginContainerProxy.h" #include "scripting/AccountScriptingInterface.h" +#include "scripting/AssetMappingsScriptingInterface.h" #include "scripting/AudioDeviceScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" #include "scripting/DesktopScriptingInterface.h" @@ -426,7 +426,6 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); DependencyManager::set(); @@ -1296,7 +1295,7 @@ void Application::initializeUi() { rootContext->setContextProperty("Quat", new Quat()); rootContext->setContextProperty("Vec3", new Vec3()); rootContext->setContextProperty("Uuid", new ScriptUUID()); - rootContext->setContextProperty("Assets", DependencyManager::get().data()); + rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface()); rootContext->setContextProperty("AvatarList", DependencyManager::get().data()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 58617bcb7c..0724e75ea1 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -95,10 +95,6 @@ Menu::Menu() { addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, qApp, SLOT(toggleRunningScriptsWidget())); - // Edit > Asset Server - addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, 0, - qApp, SLOT(toggleAssetServerWidget())); - // Edit > Open and Run Script from File... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, qApp, SLOT(loadDialog()), @@ -131,10 +127,16 @@ Menu::Menu() { SLOT(toggleConsole()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + editMenu->addSeparator(); + + // Edit > My Asset Server + addActionToQMenuAndActionHash(editMenu, MenuOption::AssetServer, Qt::CTRL | Qt::SHIFT | Qt::Key_A, + qApp, SLOT(toggleAssetServerWidget())); + // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - + // Edit > Package Model... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9ed7a605dc..93394828ec 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -34,7 +34,7 @@ namespace MenuOption { const QString AnimDebugDrawDefaultPose = "Debug Draw Default Pose"; const QString AnimDebugDrawPosition= "Debug Draw Position"; const QString AssetMigration = "ATP Asset Migration"; - const QString AssetServer = "Asset Server"; + const QString AssetServer = "My Asset Server"; const QString Attachments = "Attachments..."; const QString AudioNetworkStats = "Audio Network Stats"; const QString AudioNoiseReduction = "Audio Noise Reduction"; diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp similarity index 69% rename from libraries/script-engine/src/AssetMappingsScriptingInterface.cpp rename to interface/src/scripting/AssetMappingsScriptingInterface.cpp index 77cc435fb8..11a14c7686 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -12,11 +12,13 @@ #include "AssetMappingsScriptingInterface.h" #include +#include #include #include #include #include +#include AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.setSourceModel(&_assetMappingModel); @@ -25,17 +27,38 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() { _proxyModel.sort(0); } +QString AssetMappingsScriptingInterface::getErrorString(int errorCode) const { + switch (errorCode) { + case MappingRequest::NoError: + return "No error"; + case MappingRequest::NotFound: + return "Asset not found"; + case MappingRequest::NetworkError: + return "Unable to communicate with Asset Server"; + case MappingRequest::PermissionDenied: + return "Permission denied"; + case MappingRequest::InvalidPath: + return "Path is invalid"; + case MappingRequest::InvalidHash: + return "Hash is invalid"; + case MappingRequest::UnknownError: + return "Asset Server internal error"; + default: + return QString(); + } +} + void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createSetMappingRequest(path, hash); connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -46,28 +69,64 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback auto request = assetClient->createGetMappingRequest(path); connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()), request->getHash() }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); } +void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, QJSValue callback) { + auto offscreenUi = DependencyManager::get(); + auto result = offscreenUi->inputDialog(OffscreenUi::ICON_NONE, "Enter asset path:", "", mapping); + + if (!result.isValid()) { + return; + } + mapping = result.toString(); + + // Check for override + if (isKnownMapping(mapping)) { + auto message = path + "\n" + "This file already exists. Do you want to overwrite it?"; + auto button = offscreenUi->messageBox(OffscreenUi::ICON_QUESTION, "Overwrite File", message, + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (button == QMessageBox::No) { + return; + } + } + + auto upload = DependencyManager::get()->createUpload(path); + QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable { + if (upload->getError() != AssetUpload::NoError) { + if (callback.isCallable()) { + QJSValueList args { uint8_t(upload->getError()) }; + callback.call(args); + } + } else { + setMapping(mapping, hash, callback); + } + + upload->deleteLater(); + }); + + upload->start(); +} + void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) { auto assetClient = DependencyManager::get(); auto request = assetClient->createDeleteMappingsRequest(paths); connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -85,12 +144,12 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) { map.setProperty(kv.first, kv.second); } - QJSValueList args { uint8_t(request->getError()), map }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); @@ -101,34 +160,28 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new auto request = assetClient->createRenameMappingRequest(oldPath, newPath); connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable { - QJSValueList args { uint8_t(request->getError()) }; - - callback.call(args); + if (callback.isCallable()) { + QJSValueList args { uint8_t(request->getError()) }; + callback.call(args); + } request->deleteLater(); - }); request->start(); } -AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) - : name(name), +AssetMappingItem::AssetMappingItem(const QString& name, const QString& fullPath, bool isFolder) : + name(name), fullPath(fullPath), - isFolder(isFolder) { + isFolder(isFolder) +{ } static int assetMappingModelMetatypeId = qRegisterMetaType("AssetMappingModel*"); -AssetMappingModel::AssetMappingModel() { -} - -AssetMappingModel::~AssetMappingModel() { - qDebug() << " DEST"; -} - void AssetMappingModel::refresh() { qDebug() << "Refreshing asset mapping model"; auto assetClient = DependencyManager::get(); @@ -184,7 +237,7 @@ void AssetMappingModel::refresh() { while (it != existingPaths.end()) { Q_ASSERT(_pathToItemMap.contains(*it)); auto item = _pathToItemMap[*it]; - if (item->data(Qt::UserRole + 1).toBool()) { + if (item && item->data(Qt::UserRole + 1).toBool()) { it = existingPaths.erase(it); } else { ++it; @@ -222,7 +275,7 @@ void AssetMappingModel::refresh() { } } } else { - emit errorGettingMappings(uint8_t(request->getError())); + emit errorGettingMappings(static_cast(request->getError())); } }); diff --git a/libraries/script-engine/src/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h similarity index 78% rename from libraries/script-engine/src/AssetMappingsScriptingInterface.h rename to interface/src/scripting/AssetMappingsScriptingInterface.h index 67c0856730..3a7711b340 100644 --- a/libraries/script-engine/src/AssetMappingsScriptingInterface.h +++ b/interface/src/scripting/AssetMappingsScriptingInterface.h @@ -33,24 +33,19 @@ class AssetMappingModel : public QStandardItemModel { Q_OBJECT public: - AssetMappingModel(); - ~AssetMappingModel(); - -// QVariant AssetMappingModel::data(const QModelIndex& index, int role) const; - Q_INVOKABLE void refresh(); bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }; signals: - void errorGettingMappings(uint8_t error); + void errorGettingMappings(int error); private: QHash _pathToItemMap; }; -class AssetMappingsScriptingInterface : public QObject, public Dependency { +class AssetMappingsScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(AssetMappingModel* mappingModel READ getAssetMappingModel CONSTANT) Q_PROPERTY(QAbstractProxyModel* proxyModel READ getProxyModel CONSTANT) @@ -62,12 +57,15 @@ public: Q_INVOKABLE bool isKnownMapping(QString path) const { return _assetMappingModel.isKnownMapping(path); }; - Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback); - Q_INVOKABLE void getMapping(QString path, QJSValue callback); + Q_INVOKABLE QString getErrorString(int errorCode) const; + + Q_INVOKABLE void setMapping(QString path, QString hash, QJSValue callback = QJSValue()); + Q_INVOKABLE void getMapping(QString path, QJSValue callback = QJSValue()); + Q_INVOKABLE void uploadFile(QString path, QString mapping, QJSValue callback = QJSValue()); Q_INVOKABLE void deleteMappings(QStringList paths, QJSValue callback); - Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback); } - Q_INVOKABLE void getAllMappings(QJSValue callback); - Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback); + Q_INVOKABLE void deleteMapping(QString path, QJSValue callback) { deleteMappings(QStringList(path), callback = QJSValue()); } + Q_INVOKABLE void getAllMappings(QJSValue callback = QJSValue()); + Q_INVOKABLE void renameMapping(QString oldPath, QString newPath, QJSValue callback = QJSValue()); protected: QSet _pendingRequests; diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 52ed7336c2..ac3d819ae2 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -31,7 +31,7 @@ const size_t SHA256_HASH_LENGTH = 32; const size_t SHA256_HASH_HEX_LENGTH = 64; const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB -const QString ASSET_PATH_REGEX_STRING = "^\\/(?:[^\\/]|\\/(?!\\/))*$"; +const QString ASSET_PATH_REGEX_STRING = "^\\/(?!\\/)(?:[^\\/]|\\/(?!\\/))*$"; const QString ASSET_HASH_REGEX_STRING = QString("^[a-fA-F0-9]{%1}$").arg(SHA256_HASH_HEX_LENGTH); enum AssetServerError : uint8_t { diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 6f76d1103f..2cc28c03be 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -109,7 +109,7 @@ void SetMappingRequest::doStart() { auto validPath = isValidPath(_path); auto validHash = isValidHash(_hash); if (!validPath || !validHash) { - _error = validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; + _error = !validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash; emit finished(this); return; } diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index c6a27e0274..504a0cb2fa 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -64,6 +64,7 @@ class SetMappingRequest : public MappingRequest { public: SetMappingRequest(const AssetPath& path, const AssetHash& hash); + AssetPath getPath() const { return _path; } AssetHash getHash() const { return _hash; } signals: