pax_global_header00006660000000000000000000000064152460774560014532gustar00rootroot0000000000000052 comment=5c4a76e5a76868989ac556df305bb35273dfd164 commontk-qRestAPI-5c4a76e/000077500000000000000000000000001524607745600154275ustar00rootroot00000000000000commontk-qRestAPI-5c4a76e/.gitignore000066400000000000000000000000031524607745600174100ustar00rootroot00000000000000*~ commontk-qRestAPI-5c4a76e/CMake/000077500000000000000000000000001524607745600164075ustar00rootroot00000000000000commontk-qRestAPI-5c4a76e/CMake/qRestAPIConfig.cmake.in000066400000000000000000000011761524607745600226010ustar00rootroot00000000000000# qRestAPI package configuration file for use from a build tree. # Re-resolve the Qt dependency first, so the imported target's link interface # is satisfied for downstream consumers. include(CMakeFindDependencyMacro) find_dependency(Qt@qRestAPI_QT_VERSION@ COMPONENTS @qRestAPI_QT_COMPONENTS@) include("@CMAKE_CURRENT_BINARY_DIR@/qRestAPITargets.cmake") set(qRestAPI_CMAKE_DIR "@qRestAPI_CMAKE_DIR@") # Legacy variables (kept for backward compatibility; prefer the imported # qRestAPI target). set(qRestAPI_LIBRARIES qRestAPI) set(qRestAPI_INCLUDE_DIRS "@qRestAPI_INCLUDE_DIRS@") set(qRestAPI_LIBRARY_DIRS "@qRestAPI_LIBRARY_DIRS@") commontk-qRestAPI-5c4a76e/CMake/qRestAPIInstallConfig.cmake.in000066400000000000000000000016601524607745600241260ustar00rootroot00000000000000# qRestAPI package configuration file for use from an install tree. # # Generated with configure_package_config_file(): PACKAGE_PREFIX_DIR is computed # at load time from the location of this file, so the install tree is # relocatable (no absolute paths are baked in). @PACKAGE_INIT@ # Re-resolve the Qt dependency first, so the imported target's link interface # is satisfied for downstream consumers. include(CMakeFindDependencyMacro) find_dependency(Qt@qRestAPI_QT_VERSION@ COMPONENTS @qRestAPI_QT_COMPONENTS@) include("${CMAKE_CURRENT_LIST_DIR}/qRestAPITargets.cmake") set(qRestAPI_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}") # Legacy variables (kept for backward compatibility; prefer the imported # qRestAPI target). set(qRestAPI_LIBRARIES qRestAPI) set_and_check(qRestAPI_INCLUDE_DIRS "@PACKAGE_qRestAPI_INSTALL_INCLUDE_DIR@") set_and_check(qRestAPI_LIBRARY_DIRS "@PACKAGE_qRestAPI_INSTALL_LIB_DIR@") check_required_components(qRestAPI) commontk-qRestAPI-5c4a76e/CMakeLists.txt000066400000000000000000000204731524607745600201750ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.16.3) project(qRestAPI) # -------------------------------------------------------------------------- # CMake variables # -------------------------------------------------------------------------- set(CMAKE_INCLUDE_CURRENT_DIR 1) set(CMAKE_POSITION_INDEPENDENT_CODE 1) # -------------------------------------------------------------------------- # Directories # -------------------------------------------------------------------------- # # CMake: holds the package-config templates (*Config.cmake.in). # set(${PROJECT_NAME}_CMAKE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/CMake) # # Include # set(${PROJECT_NAME}_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "${PROJECT_NAME} include dirs" FORCE) # # Library # set(${PROJECT_NAME}_LIBRARY_DIRS ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "${PROJECT_NAME} library dirs" FORCE) # -------------------------------------------------------------------------- # Options # -------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build shared library" ON) option(BUILD_TESTING "Test the project" ON) # -------------------------------------------------------------------------- # Install directories # -------------------------------------------------------------------------- # These may be set by a parent project (e.g. a superbuild) before this project # is added. When not set, sensible standalone defaults are used. if(NOT DEFINED ${PROJECT_NAME}_INSTALL_BIN_DIR) set(${PROJECT_NAME}_INSTALL_BIN_DIR bin) endif() if(NOT DEFINED ${PROJECT_NAME}_INSTALL_LIB_DIR) set(${PROJECT_NAME}_INSTALL_LIB_DIR lib/${PROJECT_NAME}) endif() if(NOT DEFINED ${PROJECT_NAME}_INSTALL_INCLUDE_DIR) set(${PROJECT_NAME}_INSTALL_INCLUDE_DIR include/${PROJECT_NAME}) endif() if(NOT DEFINED ${PROJECT_NAME}_INSTALL_CMAKE_DIR) set(${PROJECT_NAME}_INSTALL_CMAKE_DIR cmake/${PROJECT_NAME}) endif() # Install the development files (headers, CMake package config, exported # targets) in addition to the runtime library. OFF by default so a plain # install ships only the runtime; turn ON for packaging / standalone install # trees. (CMP0077 is NEW at this cmake_minimum_required, so a parent project may # still override this before add_subdirectory().) option(${PROJECT_NAME}_INSTALL_DEVELOPMENT "Install ${PROJECT_NAME} development files (headers, CMake package config, exported targets)" OFF) # Backward compatibility: honor the deprecated, inverted # ${PROJECT_NAME}_INSTALL_NO_DEVELOPMENT if a consumer still sets it. if(DEFINED ${PROJECT_NAME}_INSTALL_NO_DEVELOPMENT) message(DEPRECATION "${PROJECT_NAME}_INSTALL_NO_DEVELOPMENT is deprecated; use ${PROJECT_NAME}_INSTALL_DEVELOPMENT (inverted value).") if(${PROJECT_NAME}_INSTALL_NO_DEVELOPMENT) set(${PROJECT_NAME}_INSTALL_DEVELOPMENT OFF CACHE BOOL "" FORCE) else() set(${PROJECT_NAME}_INSTALL_DEVELOPMENT ON CACHE BOOL "" FORCE) endif() endif() # -------------------------------------------------------------------------- # Dependencies # -------------------------------------------------------------------------- # # Qt # set(${PROJECT_NAME}_QT_VERSION "5" CACHE STRING "Expected Qt version (5 or 6)") mark_as_advanced(${PROJECT_NAME}_QT_VERSION) set_property(CACHE ${PROJECT_NAME}_QT_VERSION PROPERTY STRINGS 5 6) if(NOT (${PROJECT_NAME}_QT_VERSION VERSION_EQUAL "5" OR ${PROJECT_NAME}_QT_VERSION VERSION_EQUAL "6")) message(FATAL_ERROR "Expected value for ${PROJECT_NAME}_QT_VERSION is either '5' or '6'") endif() set(QT${${PROJECT_NAME}_QT_VERSION}_INSTALL_PREFIX "" CACHE PATH "The install location of Qt${${PROJECT_NAME}_QT_VERSION}") set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QT${${PROJECT_NAME}_QT_VERSION}_INSTALL_PREFIX}) # Qt components used through the public interface of the library. They are # recorded here so the generated package config can re-resolve them through # find_dependency() for downstream consumers. The Test component is required # only when building the tests (see Testing/CMakeLists.txt). set(${PROJECT_NAME}_QT_COMPONENTS Gui Network Qml) find_package(Qt${${PROJECT_NAME}_QT_VERSION} COMPONENTS Core ${${PROJECT_NAME}_QT_COMPONENTS} REQUIRED) if(BUILD_SHARED_LIBS) set(${PROJECT_NAME}_STATIC OFF) else() set(${PROJECT_NAME}_STATIC ON) endif() # -------------------------------------------------------------------------- # Configure headers # -------------------------------------------------------------------------- configure_file( qRestAPI_Export.h.in ${CMAKE_CURRENT_BINARY_DIR}/qRestAPI_Export.h ) set(KIT_SRCS qGirderAPI.cpp qGirderAPI.h qMidasAPI.cpp qMidasAPI.h qRestAPI.cpp qRestAPI.h qRestAPI_p.h qRestResult.cpp qRestResult.h ) set(KIT_MOC_SRCS qGirderAPI.h qMidasAPI.h qRestAPI.h qRestAPI_p.h qRestResult.h ) if(${PROJECT_NAME}_QT_VERSION VERSION_GREATER "5") qt_wrap_cpp(KIT_MOC_OUTPUT ${KIT_MOC_SRCS}) else() qt5_wrap_cpp(KIT_MOC_OUTPUT ${KIT_MOC_SRCS}) endif() # -------------------------------------------------------------------------- # Build qRestAPI library # -------------------------------------------------------------------------- add_library(${PROJECT_NAME} ${KIT_SRCS} ${KIT_MOC_OUTPUT}) # Public usage requirements: consumers get the include directories through the # imported target, resolved differently for the build tree and the install tree. target_include_directories(${PROJECT_NAME} PUBLIC $ $ $ ) target_link_libraries(${PROJECT_NAME} PUBLIC Qt${${PROJECT_NAME}_QT_VERSION}::Gui Qt${${PROJECT_NAME}_QT_VERSION}::Network Qt${${PROJECT_NAME}_QT_VERSION}::Qml) # -------------------------------------------------------------------------- # Export targets for a build tree # -------------------------------------------------------------------------- export(TARGETS ${PROJECT_NAME} FILE ${CMAKE_CURRENT_BINARY_DIR}/qRestAPITargets.cmake) # -------------------------------------------------------------------------- # Install library # -------------------------------------------------------------------------- install(TARGETS ${PROJECT_NAME} EXPORT qRestAPITargets RUNTIME DESTINATION ${${PROJECT_NAME}_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries LIBRARY DESTINATION ${${PROJECT_NAME}_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${${PROJECT_NAME}_INSTALL_LIB_DIR} COMPONENT Development ) # -------------------------------------------------------------------------- # Configure package config file for the build tree # -------------------------------------------------------------------------- configure_file( ${${PROJECT_NAME}_CMAKE_DIR}/qRestAPIConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/qRestAPIConfig.cmake @ONLY) # -------------------------------------------------------------------------- # Install development files # -------------------------------------------------------------------------- if(${PROJECT_NAME}_INSTALL_DEVELOPMENT) # Public headers (exclude private *_p.h headers) file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h") list(FILTER headers EXCLUDE REGEX "_p\\.h$") install( FILES ${headers} DESTINATION ${${PROJECT_NAME}_INSTALL_INCLUDE_DIR} COMPONENT Development) file(GLOB headers "${CMAKE_CURRENT_BINARY_DIR}/*.h") install( FILES ${headers} DESTINATION ${${PROJECT_NAME}_INSTALL_INCLUDE_DIR} COMPONENT Development) # Relocatable package config file for the install tree include(CMakePackageConfigHelpers) configure_package_config_file( ${${PROJECT_NAME}_CMAKE_DIR}/qRestAPIInstallConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/install/qRestAPIConfig.cmake INSTALL_DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKE_DIR} PATH_VARS ${PROJECT_NAME}_INSTALL_INCLUDE_DIR ${PROJECT_NAME}_INSTALL_LIB_DIR ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/install/qRestAPIConfig.cmake DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKE_DIR} COMPONENT Development) # Exported targets for the install tree install( EXPORT qRestAPITargets FILE qRestAPITargets.cmake DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKE_DIR} COMPONENT Development) endif() # -------------------------------------------------------------------------- # Testing # -------------------------------------------------------------------------- if(BUILD_TESTING) include(CTest) add_subdirectory(Testing) endif() commontk-qRestAPI-5c4a76e/CONTRIBUTING.md000066400000000000000000000024121524607745600176570ustar00rootroot00000000000000Contributing ============ Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. Types of Contributions ---------------------- You can contribute in many ways: ### Report Bugs Report bugs at https://github.com/commontk/qRestAPI/issues. If you are reporting a bug, please include: * Any details about your CI setup that might be helpful in troubleshooting. * Detailed steps to reproduce the bug. ### Fix Bugs Look through the GitHub issues for bugs. Anything tagged with "bug" is open to whoever wants to implement it. ### Implement Features Look through the GitHub issues for features. Anything tagged with "feature" is open to whoever wants to implement it. ### Write Documentation The qRestAPI project could always use more documentation. We welcome help with the official qRestAPI docs, in docstrings, or even on blog posts and articles for the web. ### Submit Feedback The best way to send feedback is to file an issue at https://github.com/commontk/qRestAPI/issues. If you are proposing a new feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that contributions are welcome :) commontk-qRestAPI-5c4a76e/LICENSE000066400000000000000000000261411524607745600164400ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITION OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright (c) 2010 Kitware, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. commontk-qRestAPI-5c4a76e/README.md000066400000000000000000000054021524607745600167070ustar00rootroot00000000000000# OVERVIEW qRestAPI is a cross-platform [Qt-based](https://www.qt.io/) library allowing to easily query any [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) web services. It provides the following interfaces: | Interface | RESTful API | |--------------| -----------------| | `qRestAPI` | _any_ | | `qGirderAPI` | [Girder][girder] | | `qMidasAPI` | [Midas][midas] | [girder]: https://github.com/girder/girder [midas]: https://github.com/midasplatform/midas ## Prerequisites * [Qt](https://www.qt.io/) 5.x or 6.x * [CMake](http://www.cmake.org) ## How to build using Qt 5.x git clone git://github.com/commontk/qRestAPI.git mkdir qRestAPI-build cd qRestAPI-build cmake -DQt5_DIR:PATH=/path/to/QtX.Y.Z/X.Y.Z/gcc_64/lib/cmake/Qt5 ../qRestAPI make -j4 ## How to build using Qt 6.x git clone git://github.com/commontk/qRestAPI.git mkdir qRestAPI-build cd qRestAPI-build cmake -DQT6_INSTALL_PREFIX:PATH=/path/to/QtX.Y.Z/X.Y.Z/gcc_64 ../qRestAPI make -j4 ## Installing / packaging By default only the runtime library is installed. To also install the development files (headers, exported CMake targets and the package config file) — e.g. when building a package or a standalone install tree — turn on `qRestAPI_INSTALL_DEVELOPMENT`: cmake -DqRestAPI_INSTALL_DEVELOPMENT=ON -DCMAKE_INSTALL_PREFIX=/path/to/prefix ../qRestAPI make install The install tree is relocatable. Downstream projects consume it with: find_package(qRestAPI REQUIRED) target_link_libraries(MyTarget PRIVATE qRestAPI) The following variables let a parent project (typically a superbuild) override the install layout; each defaults to a standalone-friendly value when unset: | Variable | Default | |--------------------------------|--------------------| | `qRestAPI_INSTALL_DEVELOPMENT` | `OFF` | | `qRestAPI_INSTALL_BIN_DIR` | `bin` | | `qRestAPI_INSTALL_LIB_DIR` | `lib/qRestAPI` | | `qRestAPI_INSTALL_INCLUDE_DIR` | `include/qRestAPI` | | `qRestAPI_INSTALL_CMAKE_DIR` | `cmake/qRestAPI` | ## Testing To run tests checking that queries can successfully be executed. cd qRestAPI-build ctest List of tests expecting servers to be reachable: | Test | Server | |------------------|-----------------------------------| | `qGirderAPITest` | https://data.kitware.com/api/v1 | | `qMidasAPITest` | https://slicer.kitware.com/midas3 | ## Contribute Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. See [CONTRIBUTING.md][contributing] for more details. [contributing]: https://github.com/commontk/qRestAPI/blob/master/CONTRIBUTING.md commontk-qRestAPI-5c4a76e/Testing/000077500000000000000000000000001524607745600170445ustar00rootroot00000000000000commontk-qRestAPI-5c4a76e/Testing/CMakeLists.txt000066400000000000000000000023601524607745600216050ustar00rootroot00000000000000include(MacroAddFileDependencies) set(KIT_TEST_SRCS qGirderAPITest.cpp qMidasAPITest.cpp qRestAPITest.cpp ) create_test_sourcelist(KIT_TESTDRIVER_SRCS qRestAPITests.cpp ${KIT_TEST_SRCS} ) set(KIT_TEST_GENERATE_MOC_SRCS ${KIT_TEST_SRCS}) foreach(file IN LISTS KIT_TEST_GENERATE_MOC_SRCS) get_filename_component(abs_file ${file} ABSOLUTE) get_filename_component(source_name ${file} NAME_WE) set(moc_file ${CMAKE_CURRENT_BINARY_DIR}/moc_${source_name}.cpp) if(qRestAPI_QT_VERSION VERSION_GREATER "5") QT_GENERATE_MOC(${abs_file} ${moc_file}) else() QT5_GENERATE_MOC(${abs_file} ${moc_file}) endif() macro_add_file_dependencies(${abs_file} ${moc_file}) endforeach() add_definitions(-D_CRT_SECURE_NO_DEPRECATE) # The Qt Test component is needed only for the tests, so it is resolved here # rather than as an unconditional dependency of the library. find_package(Qt${qRestAPI_QT_VERSION} COMPONENTS Test REQUIRED) add_executable(qRestAPITests ${KIT_TESTDRIVER_SRCS}) target_link_libraries(qRestAPITests qRestAPI Qt${qRestAPI_QT_VERSION}::Test) macro(SIMPLE_TEST TESTNAME) add_test(NAME ${TESTNAME} COMMAND qRestAPITests ${TESTNAME}) endmacro() SIMPLE_TEST(qGirderAPITest) SIMPLE_TEST(qMidasAPITest) SIMPLE_TEST(qRestAPITest) commontk-qRestAPI-5c4a76e/Testing/qGirderAPITest.cpp000066400000000000000000000104001524607745600223320ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2021 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. ==============================================================================*/ // Qt includes #include #include #include #include #include #include #include #include #include #include // qCDashAPI includes #include "qGirderAPI.h" #include "qRestResult.h" // -------------------------------------------------------------------------- class qGirderAPITester : public QObject { Q_OBJECT private slots: void cleanup(); void testTakeResult(); void testSync(); void testReturnArrayOfData(); void testFinishedSignal_data(); void testFinishedSignal(); private: QString LastTestResult; }; // -------------------------------------------------------------------------- void qGirderAPITester::cleanup() { if (QTest::currentTestFailed() && !this->LastTestResult.isEmpty()) { qDebug() << QTest::currentTestFunction() << "result:" << this->LastTestResult; } this->LastTestResult.clear(); } // -------------------------------------------------------------------------- void qGirderAPITester::testTakeResult() { qGirderAPI girderAPI; girderAPI.setServerUrl("https://data.kitware.com/api/v1/system/version"); QUuid queryUuid = girderAPI.get(""); QVERIFY(!queryUuid.isNull()); QScopedPointer restResult(girderAPI.takeResult(queryUuid)); QVERIFY(!restResult.isNull()); QVERIFY(!restResult->response().isEmpty()); QCOMPARE(restResult->results().size(), 1); } // -------------------------------------------------------------------------- void qGirderAPITester::testSync() { qGirderAPI girderAPI; girderAPI.setServerUrl("https://data.kitware.com/api/v1/system/version"); QUuid queryUuid = girderAPI.get(""); QVERIFY(!queryUuid.isNull()); QList result; QVERIFY(girderAPI.sync(queryUuid, result)); this->LastTestResult = qGirderAPI::qVariantMapListToString(result); QCOMPARE(result.size(), 1); } // -------------------------------------------------------------------------- void qGirderAPITester::testReturnArrayOfData() { qGirderAPI girderAPI; girderAPI.setServerUrl("https://data.kitware.com/api/v1/collection"); qRestAPI::Parameters parameters; parameters["limit"] = "2"; QUuid queryUuid = girderAPI.get("", parameters); QVERIFY(!queryUuid.isNull()); QList result; QVERIFY(girderAPI.sync(queryUuid, result)); this->LastTestResult = qGirderAPI::qVariantMapListToString(result); QCOMPARE(result.size(), 2); } // -------------------------------------------------------------------------- void qGirderAPITester::testFinishedSignal_data() { QTest::addColumn("url"); QTest::addColumn("syncResult"); QTest::newRow("1") << "https://data.kitware.com/api/v1/system/version" << true; QTest::newRow("2") << "https://data.kitware.com/api/v1/unknown" << false; } // -------------------------------------------------------------------------- void qGirderAPITester::testFinishedSignal() { QFETCH(QString, url); QFETCH(bool, syncResult); qGirderAPI girderAPI; girderAPI.setServerUrl(url); QSignalSpy finishedSpy(&girderAPI, SIGNAL(finished(QUuid))); QUuid queryUuid = girderAPI.get(""); QCOMPARE(finishedSpy.count(), 0); QList result; QCOMPARE(girderAPI.sync(queryUuid, result), syncResult); QCOMPARE(finishedSpy.count(), 1); this->LastTestResult = qGirderAPI::qVariantMapListToString(result); } #define main qGirderAPITest QTEST_MAIN(qGirderAPITester) #undef main #include "moc_qGirderAPITest.cpp" commontk-qRestAPI-5c4a76e/Testing/qMidasAPITest.cpp000066400000000000000000000171741524607745600221720ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ // Qt includes #include #include #include #include #include #include #include #include #include #include // qCDashAPI includes #include "qMidasAPI.h" #include "qRestResult.h" // STD includes #include #include // -------------------------------------------------------------------------- class qMidasAPITester : public QObject { Q_OBJECT private slots: void cleanup(); void testQueryLocalFileReleaseFileHandle(); void testServerURL(); void testTakeResult(); void testSync(); void testReturnArrayOfData(); void testFinishedSignal_data(); void testFinishedSignal(); private: QString LastTestResult; }; // -------------------------------------------------------------------------- void qMidasAPITester::cleanup() { if (QTest::currentTestFailed() && !this->LastTestResult.isEmpty()) { qDebug() << QTest::currentTestFunction() << "result:" << this->LastTestResult; } this->LastTestResult.clear(); } // -------------------------------------------------------------------------- void qMidasAPITester::testQueryLocalFileReleaseFileHandle() { QDir tmp = QDir::temp(); QString temporaryDirName = QString("qMidasAPITest1-queryFile.%1").arg(QTime::currentTime().toString("hhmmsszzz")); tmp.mkdir(temporaryDirName); tmp.cd(temporaryDirName); tmp.mkdir("api"); tmp.cd("api"); QFile fileReply(tmp.filePath("json")); QVERIFY2(fileReply.open(QFile::WriteOnly), qPrintable(QString("Failed to create temporary file. %1").arg(tmp.filePath("json")))); fileReply.write( QString("{\"stat\":\"ok\",\"code\":\"0\",\"message\":\"\",\"data\":{" "\"quote\":\"If a day goes past and you do not learn anything, it is a waste of a day.\"," "\"author\" : \"Mike Horn\"}}").toLatin1()); fileReply.close(); qMidasAPI midasAPI; midasAPI.setServerUrl(QUrl::fromLocalFile(QDir::temp().filePath(temporaryDirName)).toString()); QUuid queryUuid = midasAPI.get("midas.quote.of.the.day"); QVERIFY(!queryUuid.isNull()); QList result; QVERIFY(midasAPI.sync(queryUuid, result)); this->LastTestResult = qMidasAPI::qVariantMapListToString(result); QCOMPARE(result.size(), 1); // Attempt to delete 'queryFile' QVERIFY2(QFile::remove(tmp.filePath("json")), qPrintable(QString("Failed to remove queryFile. [%1]").arg(tmp.filePath("json")))); } // -------------------------------------------------------------------------- void qMidasAPITester::testServerURL() { qMidasAPI midasAPI; QString midasUrl("http://slicer.kitware.com/midas3"); midasAPI.setServerUrl(midasUrl); QCOMPARE(midasAPI.serverUrl(), midasUrl); } // -------------------------------------------------------------------------- void qMidasAPITester::testTakeResult() { qMidasAPI midasAPI; midasAPI.setServerUrl("http://slicer.kitware.com/midas3"); QSignalSpy errorSpy(&midasAPI, SIGNAL(errorReceived(QUuid,QString))); QSignalSpy receivedSpy(&midasAPI, SIGNAL(resultReceived(QUuid,QList))); // Successful query: midas.version { QUuid queryUuid = midasAPI.get("midas.version"); QVERIFY(!queryUuid.isNull()); QScopedPointer restResult(midasAPI.takeResult(queryUuid)); QVERIFY(!restResult.isNull()); QVERIFY(!restResult->response().isEmpty()); QCOMPARE(restResult->results().size(), 1); QCOMPARE(errorSpy.count(), 0); QCOMPARE(receivedSpy.count(), 1); } errorSpy.clear(); receivedSpy.clear(); this->LastTestResult.clear(); // Fail query: midas.notafunction { QUuid queryUuid = midasAPI.get("midas.notafunction"); QVERIFY(!queryUuid.isNull()); QScopedPointer restResult(midasAPI.takeResult(queryUuid)); QVERIFY(restResult.isNull()); QCOMPARE(errorSpy.count(), 1); QCOMPARE(receivedSpy.count(), 0); } } // -------------------------------------------------------------------------- void qMidasAPITester::testSync() { qMidasAPI midasAPI; midasAPI.setServerUrl("http://slicer.kitware.com/midas3"); // Synchronous query: midas.info { QUuid queryUuid = midasAPI.get("midas.info"); QVERIFY(!queryUuid.isNull()); QList result; QVERIFY(midasAPI.sync(queryUuid, result)); this->LastTestResult = qMidasAPI::qVariantMapListToString(result); QCOMPARE(result.size(), 1); } // Synchronous fail query: midas.notafunction { QUuid queryUuid = midasAPI.get("midas.notafunction"); QVERIFY(!queryUuid.isNull()); QList result; QVERIFY(!midasAPI.sync(queryUuid, result)); this->LastTestResult = qMidasAPI::qVariantMapListToString(result); QCOMPARE(result.size(), 1); QVERIFY(result.at(0).contains("queryError")); } // Synchronous fail query: midas.login (wrong credentials) { qRestAPI::Parameters wrongParameters; wrongParameters["appname"] = "qMidasAPITest"; wrongParameters["email"] = "john.doe@mail.com"; wrongParameters["apikey"] = "123456789"; QUuid queryUuid = midasAPI.get("midas.login", wrongParameters); QVERIFY(!queryUuid.isNull()); QList result; QVERIFY(!midasAPI.sync(queryUuid, result)); this->LastTestResult = qMidasAPI::qVariantMapListToString(result); QCOMPARE(result.size(), 1); QVERIFY(result.at(0).contains("queryError")); } } // -------------------------------------------------------------------------- void qMidasAPITester::testReturnArrayOfData() { qMidasAPI midasAPI; midasAPI.setServerUrl("http://slicer.kitware.com/midas3"); // Synchronous query: midas.community.list (return array of data) QUuid queryUuid = midasAPI.get("midas.community.list"); QVERIFY(!queryUuid.isNull()); QList result; QVERIFY(midasAPI.sync(queryUuid, result)); this->LastTestResult = qMidasAPI::qVariantMapListToString(result); QVERIFY(result.size() > 0); } // -------------------------------------------------------------------------- void qMidasAPITester::testFinishedSignal_data() { QTest::addColumn("method"); QTest::addColumn("syncResult"); QTest::newRow("1") << "midas.info" << true; QTest::newRow("2") << "midas.notafunction" << false; } // -------------------------------------------------------------------------- void qMidasAPITester::testFinishedSignal() { QFETCH(QString, method); QFETCH(bool, syncResult); qMidasAPI midasAPI; midasAPI.setServerUrl("http://slicer.kitware.com/midas3"); QSignalSpy finishedSpy(&midasAPI, SIGNAL(finished(QUuid))); QUuid queryUuid = midasAPI.get(method); QCOMPARE(finishedSpy.count(), 0); QList result; QCOMPARE(midasAPI.sync(queryUuid, result), syncResult); QCOMPARE(finishedSpy.count(), 1); this->LastTestResult = qMidasAPI::qVariantMapListToString(result); } #define main qMidasAPITest QTEST_MAIN(qMidasAPITester) #undef main #include "moc_qMidasAPITest.cpp" commontk-qRestAPI-5c4a76e/Testing/qRestAPITest.cpp000066400000000000000000000135331524607745600220450ustar00rootroot00000000000000// Qt includes #include // qRestAPI includes #include "qRestAPI.h" #include // -------------------------------------------------------------------------- class qRestAPITester : public QObject { Q_OBJECT private slots: void cleanup(); void testqVariantToString_data(); void testqVariantToString(); void testqVariantMapFlattened_data(); void testqVariantMapFlattened(); private: QVariantMap LastTestInputMap; QVariantMap LastTestOutputMap; QVariantMap LastTestExpectedMap; }; // -------------------------------------------------------------------------- void qRestAPITester::cleanup() { if (QTest::currentTestFailed()) { if (!this->LastTestOutputMap.isEmpty() && !this->LastTestExpectedMap.isEmpty()) { qDebug().noquote().nospace() << QTest::currentTestFunction() << "\ninput:\n" << qRestAPI::qVariantToString(this->LastTestInputMap) << "\noutput:\n" << qRestAPI::qVariantToString(this->LastTestOutputMap) << "\nexpected:\n" << qRestAPI::qVariantToString(this->LastTestExpectedMap); } } this->LastTestInputMap.clear(); this->LastTestOutputMap.clear(); this->LastTestExpectedMap.clear(); } // -------------------------------------------------------------------------- void qRestAPITester::testqVariantToString_data() { QTest::addColumn("input"); QTest::addColumn("expected"); { // input QVariantMap input; input["a"] = "1"; input["b"] = "2"; input["c"] = "3"; QString expected = (QStringList() << "a: 1" << "b: 2" << "c: 3" << "").join("\n"); QTest::newRow("identity") << input << expected; } { // input QVariantMap inputSubmap; inputSubmap["b_a"] = "2-1"; inputSubmap["b_b"] = "2-2"; inputSubmap["b_c"] = "2-3"; QVariantMap input; input["a"] = "1"; input["b"] = inputSubmap; input["c"] = "3"; // expected QString expected = ( QStringList() << "a: 1" << "b: " << " b_a: 2-1" << " b_b: 2-2" << " b_c: 2-3" << "c: 3" << "" ).join("\n"); QTest::newRow("map-of-map") << input << expected; } { // input QVariantMap inputSubmapForB; inputSubmapForB["b_a"] = "2-1"; inputSubmapForB["b_b"] = "2-2"; inputSubmapForB["b_c"] = "2-3"; QVariantMap inputSubmap1ForC; inputSubmap1ForC["c_a_1"] = "3-1_1"; inputSubmap1ForC["c_b_1"] = "3-2_1"; inputSubmap1ForC["c_c_1"] = "3-3_1"; QVariantMap inputSubmap2ForC; inputSubmap2ForC["c_a_2"] = "3-1_2"; inputSubmap2ForC["c_b_2"] = "3-2_2"; QVariantMap input; input["a"] = "1"; input["b"] = inputSubmapForB; input["c"] = QVariantList() << inputSubmap1ForC << inputSubmap2ForC; // expected QString expected = ( QStringList() << "a: 1" << "b: " << " b_a: 2-1" << " b_b: 2-2" << " b_c: 2-3" << "c: " << " 0: " << " c_a_1: 3-1_1" << " c_b_1: 3-2_1" << " c_c_1: 3-3_1" << " 1: " << " c_a_2: 3-1_2" << " c_b_2: 3-2_2" << "" ).join("\n"); QTest::newRow("map-with-list-of-maps") << input << expected; } } // -------------------------------------------------------------------------- void qRestAPITester::testqVariantToString() { QFETCH(QVariantMap, input); QFETCH(QString, expected); QCOMPARE(qRestAPI::qVariantToString(input), expected); } // -------------------------------------------------------------------------- void qRestAPITester::testqVariantMapFlattened_data() { QTest::addColumn("input"); QTest::addColumn("expected"); { // input QVariantMap input; input["a"] = "1"; input["b"] = "2"; input["c"] = "3"; QVariantMap expected = input; QTest::newRow("identity") << input << expected; } { // input QVariantMap inputSubmap; inputSubmap["b_a"] = "2-1"; inputSubmap["b_b"] = "2-2"; inputSubmap["b_c"] = "2-3"; QVariantMap input; input["a"] = "1"; input["b"] = inputSubmap; input["c"] = "3"; // expected QVariantMap expected; expected["a"] = "1"; expected["b.b_a"] = "2-1"; expected["b.b_b"] = "2-2"; expected["b.b_c"] = "2-3"; expected["c"] = "3"; QTest::newRow("map-of-map") << input << expected; } { // input QVariantMap inputSubmapForB; inputSubmapForB["b_a"] = "2-1"; inputSubmapForB["b_b"] = "2-2"; inputSubmapForB["b_c"] = "2-3"; QVariantMap inputSubmap1ForC; inputSubmap1ForC["c_a_1"] = "3-1_1"; inputSubmap1ForC["c_b_1"] = "3-2_1"; inputSubmap1ForC["c_c_1"] = "3-3_1"; QVariantMap inputSubmap2ForC; inputSubmap2ForC["c_a_2"] = "3-1_2"; inputSubmap2ForC["c_b_2"] = "3-2_2"; QVariantMap inputSubmap3ForC; inputSubmap3ForC["c_a_2"] = "3-1_3"; // key already specified in inputSubmap2ForC inputSubmap3ForC["c_b_3"] = "3-2_3"; QVariantMap input; input["a"] = "1"; input["b"] = inputSubmapForB; input["c"] = QVariantList() << inputSubmap1ForC << inputSubmap2ForC << inputSubmap3ForC; // expected QVariantMap expected; expected["a"] = "1"; expected["b.b_a"] = "2-1"; expected["b.b_b"] = "2-2"; expected["b.b_c"] = "2-3"; expected["c.c_a_1"] = "3-1_1"; expected["c.c_b_1"] = "3-2_1"; expected["c.c_c_1"] = "3-3_1"; // expected["c.c_a_2"] = "3-1_2"; expected["c.c_b_2"] = "3-2_2"; expected["c.c_a_2"] = "3-1_3"; expected["c.c_b_3"] = "3-2_3"; QTest::newRow("map-with-list-of-maps") << input << expected; } } // -------------------------------------------------------------------------- void qRestAPITester::testqVariantMapFlattened() { QFETCH(QVariantMap, input); QFETCH(QVariantMap, expected); QVariantMap output = qRestAPI::qVariantMapFlattened(input); this->LastTestInputMap = input; this->LastTestOutputMap = output; this->LastTestExpectedMap = expected; QCOMPARE(output, expected); } #define main qRestAPITest QTEST_MAIN(qRestAPITester) #undef main #include "moc_qRestAPITest.cpp" commontk-qRestAPI-5c4a76e/qGirderAPI.cpp000066400000000000000000000061031524607745600200620ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2021 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. ==============================================================================*/ // Qt includes #include #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) #include #include #else #include #include #endif // qRestAPI includes #include "qGirderAPI.h" #include "qRestResult.h" // -------------------------------------------------------------------------- // qGirderAPI methods // -------------------------------------------------------------------------- qGirderAPI::qGirderAPI(QObject* _parent) : Superclass(_parent) { } // -------------------------------------------------------------------------- qGirderAPI::~qGirderAPI() { } // -------------------------------------------------------------------------- bool qGirderAPI::parseGirderAPIv1Response(const QByteArray& response, QList& result) { #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) QJSEngine scriptEngine; QJSValue scriptValue = scriptEngine .evaluate("JSON.parse") .callWithInstance(QJSValue(), QJSValueList() << QString(response)); #else QScriptEngine scriptEngine; QScriptValue scriptValue = scriptEngine .evaluate("JSON.parse") .call(QScriptValue(), QScriptValueList() << QString(response)); #endif // e.g. {["key1": "value1", ...]} or {"key1": "value1", ...} if (scriptValue.isArray()) { #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) quint32 length = scriptValue.property("length").toUInt(); #else quint32 length = scriptValue.property("length").toUInt32(); #endif for(quint32 i = 0; i < length; ++i) { qRestAPI::appendScriptValueToVariantMapList(result, scriptValue.property(i)); } } else { qRestAPI::appendScriptValueToVariantMapList(result, scriptValue); } return true; } // -------------------------------------------------------------------------- bool qGirderAPI::parseGirderAPIv1Response(qRestResult* restResult, const QByteArray& response) { QList result; bool success = qGirderAPI::parseGirderAPIv1Response(response, result); restResult->setResult(result); return success; } // -------------------------------------------------------------------------- void qGirderAPI::parseResponse(qRestResult* restResult, const QByteArray& response) { Q_UNUSED(response); qGirderAPI::parseGirderAPIv1Response(restResult, response); } commontk-qRestAPI-5c4a76e/qGirderAPI.h000066400000000000000000000026521524607745600175340ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2021 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. ==============================================================================*/ #ifndef __qGirderAPI_h #define __qGirderAPI_h #include "qRestAPI.h" #include "qRestAPI_Export.h" class qRestAPI_EXPORT qGirderAPI : public qRestAPI { Q_OBJECT typedef qRestAPI Superclass; public: explicit qGirderAPI(QObject*parent = 0); virtual ~qGirderAPI(); static bool parseGirderAPIv1Response(const QByteArray& response, QList& result); static bool parseGirderAPIv1Response(qRestResult* restResult, const QByteArray& response); protected: void parseResponse(qRestResult* restResult, const QByteArray& response); private: Q_DISABLE_COPY(qGirderAPI); }; #endif commontk-qRestAPI-5c4a76e/qMidasAPI.cpp000066400000000000000000000117751524607745600177160ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ // Qt includes #include #include #include #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) #include #include #include #else #include #include #endif // qMidasAPI includes #include "qMidasAPI.h" #include "qRestResult.h" // -------------------------------------------------------------------------- // qMidasAPI methods // -------------------------------------------------------------------------- qMidasAPI::qMidasAPI(QObject* _parent) : Superclass(_parent) { } // -------------------------------------------------------------------------- qMidasAPI::~qMidasAPI() { } // -------------------------------------------------------------------------- QUrl qMidasAPI::createUrl(const QString& method, const qRestAPI::Parameters& parameters) { QString responseType = "json"; QUrl url = Superclass::createUrl("/api/" + responseType, parameters); #if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) if (!method.isEmpty()) { url.addQueryItem("method", method); } #else QUrlQuery urlQuery(url); if (!method.isEmpty()) { urlQuery.addQueryItem("method", method); } url.setQuery(urlQuery); #endif return url; } // -------------------------------------------------------------------------- bool qMidasAPI::parseMidasResponse(const QByteArray& response, QList& result, QString& error) { #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) QJSEngine scriptEngine; QJSValue scriptValue = scriptEngine .evaluate("JSON.parse") .callWithInstance(QJSValue(), QJSValueList() << QString(response)); // e.g. {"stat":"ok","code":"0","message":"","data":[{"p1":"v1","p2":"v2",...}]} QJSValue stat = scriptValue.property("stat"); #else QScriptEngine scriptEngine; QScriptValue scriptValue = scriptEngine .evaluate("JSON.parse") .call(QScriptValue(), QScriptValueList() << QString(response)); // e.g. {"stat":"ok","code":"0","message":"","data":[{"p1":"v1","p2":"v2",...}]} QScriptValue stat = scriptValue.property("stat"); #endif if (stat.toString() != "ok") { QString error = QString("Error while parsing outputs:") + " status: " + scriptValue.property("stat").toString() + " code: "; #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) error += QString::number(scriptValue.property("code").toInt()); #else error += QString::number(scriptValue.property("code").toInteger()); #endif error += " msg: " + scriptValue.property("message").toString(); return false; } #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) QJSValue data = scriptValue.property("data"); #else QScriptValue data = scriptValue.property("data"); #endif if (!data.isObject()) { if (data.toString().isEmpty()) { error = "No data"; } else { error = QString("Bad data: ") + data.toString(); } return false; } if (data.isArray()) { #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) quint32 length = data.property("length").toUInt(); #else quint32 length = data.property("length").toUInt32(); #endif for(quint32 i = 0; i < length; ++i) { qRestAPI::appendScriptValueToVariantMapList(result, data.property(i)); } } else { qRestAPI::appendScriptValueToVariantMapList(result, data); } return true; } // -------------------------------------------------------------------------- bool qMidasAPI::parseMidasResponse(qRestResult* restResult, const QByteArray& response) { QList result; QString error; bool success = qMidasAPI::parseMidasResponse(response, result, error); if (success) { restResult->setResult(result); } else { restResult->setError(error, ResponseParseError); } return success; } // -------------------------------------------------------------------------- void qMidasAPI::parseResponse(qRestResult* restResult, const QByteArray& response) { bool success = qMidasAPI::parseMidasResponse(restResult, response); if (success) { emit resultReceived(restResult->queryId(), restResult->results()); } else { emit errorReceived(restResult->queryId(), restResult->error()); } } commontk-qRestAPI-5c4a76e/qMidasAPI.h000066400000000000000000000066201524607745600173540ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ #ifndef __qMidasAPI_h #define __qMidasAPI_h #include "qRestAPI.h" #include "qRestAPI_Export.h" /// qMidasAPI is a simple interface class to communicate with a Midas3 public /// API. /// Queries are posted to the server and answers reported back. /// qMidasAPI works in synchronous or unsynchronous way. /// Usage: /// /// qMidasAPI midas; /// midas.setMidasUrl("http://slicer.kitware.com/midas3"); /// connect(&midas, SIGNAL(resultReceived(QUuid,QList)), /// myApp, SLOT(processResult(QUuid,QList))); /// midas.query("midas.version"); /// ... /// class qRestAPI_EXPORT qMidasAPI : public qRestAPI { Q_OBJECT typedef qRestAPI Superclass; public: explicit qMidasAPI(QObject*parent = 0); virtual ~qMidasAPI(); /// Parse a Midas JSON \a response /// /// Response is expected to be formated like `{"stat":"ok","code":"0","message":"","data":[{"p1":"v1","p2":"v2",...}]}` or /// `{"stat":"ok","code":"0","message":"","data":{"p1":"v1","p2":"v2",...}}` /// /// Returns \a False and set \a error in the following cases: /// * If `stat` attribute value is different from `ok`, sets \a error to `Error while parsing outputs: status: {stat} code: {code} msg: {message}` /// * If `data` attribute is empty, sets \a error to `No data` /// * If `data` attribute is not a valid JSON object, sets \a error to `Bad data: {data}` /// /// Returns \a True and set \a result a list of `QVariantMap` if `data` attribute is either set to /// an array of objects with attribute-value pairs or a single object with attribute-value pairs. static bool parseMidasResponse(const QByteArray& response, QList& result, QString& error); /// Parse a Midas JSON \a response /// /// If \a response is successfully parsed, set result and returns \a True otherwise /// set error and returns \a False. /// /// \sa parseMidasResponse(const QByteArray& response, QList& result, QString& error) /// \sa qRestResult::setResult(const QList& result) /// \sa qRestResult::setError(const QString& error, qRestAPI::ErrorType errorType) static bool parseMidasResponse(qRestResult* restResult, const QByteArray& response); signals: void errorReceived(QUuid queryId, QString error); void resultReceived(QUuid queryId, QList result); protected: QUrl createUrl(const QString& method, const qRestAPI::Parameters& parameters); void parseResponse(qRestResult* restResult, const QByteArray& response); private: Q_DISABLE_COPY(qMidasAPI); }; #endif commontk-qRestAPI-5c4a76e/qRestAPI.cpp000066400000000000000000000547521524607745600176000ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ // Qt includes #include #include #include #include #include #include #include #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) #include #include #else #include #endif // qRestAPI includes #include "qRestAPI.h" #include "qRestAPI_p.h" #include "qRestResult.h" // -------------------------------------------------------------------------- // Static file local error messages static QString unknownErrorStr = "Unknown error"; static QString unknownUuidStr = "Unknown uuid %1"; static QString timeoutErrorStr = "Request timed out"; // -------------------------------------------------------------------------- // qRestAPIPrivate methods qRestAPIPrivate::StaticInit qRestAPIPrivate::_staticInit; // -------------------------------------------------------------------------- qRestAPIPrivate::qRestAPIPrivate(qRestAPI* object) : q_ptr(object) , NetworkManager(NULL) , TimeOut(0) , SuppressSslErrors(true) , ErrorCode(qRestAPI::UnknownError) , ErrorString(unknownErrorStr) { } // -------------------------------------------------------------------------- qRestAPIPrivate::~qRestAPIPrivate() { NetworkManager->deleteLater(); } // -------------------------------------------------------------------------- void qRestAPIPrivate::staticInit() { qRegisterMetaType("QUuid"); qRegisterMetaType >("QList"); } // -------------------------------------------------------------------------- void qRestAPIPrivate::init() { this->NetworkManager = new QNetworkAccessManager(); QObject::connect(this->NetworkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(processReply(QNetworkReply*))); #ifndef QRESTAPI_QT_NO_SSL if (QSslSocket::supportsSsl()) { QObject::connect(this->NetworkManager, SIGNAL(sslErrors(QNetworkReply*, QList)), this, SLOT(onSslErrors(QNetworkReply*, QList))); } #endif } // -------------------------------------------------------------------------- void qRestAPI::setHttpNetworkProxy(const QNetworkProxy &proxy) { Q_D(qRestAPI); if (d->NetworkManager != NULL) { d->NetworkManager->setProxy(proxy); } } // -------------------------------------------------------------------------- QNetworkReply* qRestAPI::sendRequest(QNetworkAccessManager::Operation operation, const QUrl& url, const qRestAPI::RawHeaders& rawHeaders, const QByteArray &data) { Q_D(qRestAPI); QNetworkRequest queryRequest; queryRequest.setUrl(url); #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) // In Qt6, redirects are followed by default, but it has to be manually enabled in Qt5. queryRequest.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); #endif for (QMapIterator it(d->DefaultRawHeaders); it.hasNext();) { it.next(); queryRequest.setRawHeader(it.key(), it.value()); } for (QMapIterator it(rawHeaders); it.hasNext();) { it.next(); queryRequest.setRawHeader(it.key(), it.value()); } QNetworkReply* queryReply; switch (operation) { case QNetworkAccessManager::GetOperation: queryReply = d->NetworkManager->get(queryRequest); break; case QNetworkAccessManager::DeleteOperation: queryReply = d->NetworkManager->deleteResource(queryRequest); break; case QNetworkAccessManager::PutOperation: queryReply = d->NetworkManager->put(queryRequest, data); break; case QNetworkAccessManager::PostOperation: queryReply = d->NetworkManager->post(queryRequest, data); break; case QNetworkAccessManager::HeadOperation: queryReply = d->NetworkManager->head(queryRequest); break; default: // TODO return 0; } if (d->TimeOut > 0) { QTimer* timeOut = new QTimer(queryReply); timeOut->setSingleShot(true); QObject::connect(timeOut, SIGNAL(timeout()), d, SLOT(queryTimeOut())); timeOut->start(d->TimeOut); } QUuid queryId = QUuid::createUuid(); queryReply->setProperty("uuid", queryId.toString()); qRestResult* result = new qRestResult(queryId); d->results[queryId] = result; // QObject::connect(this, SIGNAL(resultReceived(QUuid,QList)), // result, SLOT(setResult(QList))); // QObject::connect(this, SIGNAL(errorReceived(QUuid,QString)), // result, SLOT(setError(QString))); return queryReply; } // -------------------------------------------------------------------------- #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) QVariantMap qRestAPI::scriptValueToMap(const QJSValue& value) #else QVariantMap qRestAPI::scriptValueToMap(const QScriptValue& value) #endif { #if QT_VERSION >= 0x040700 return value.toVariant().toMap(); #else QVariantMap result; for (QScriptValueIterator it(value); it.hasNext();) { it.next(); result.insert(it.name(), it.value().toVariant()); } return result; #endif } // -------------------------------------------------------------------------- #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) void qRestAPI::appendScriptValueToVariantMapList(QList& result, const QJSValue& data) #else void qRestAPI::appendScriptValueToVariantMapList(QList& result, const QScriptValue& data) #endif { QVariantMap map = scriptValueToMap(data); if (!map.isEmpty()) { result << scriptValueToMap(data); } } // -------------------------------------------------------------------------- QVariantMap qRestAPI::qVariantMapFlattened(const QVariantMap& map) { QVariantMap output; foreach(const QString& key, map.keys()) { QVariant value = map.value(key); if (value.canConvert()) { value = QVariant::fromValue(QVariantList() << value.toMap()); } if (value.canConvert()) { foreach(const QVariant& item, value.toList()) { QVariantMap subMap = qRestAPI::qVariantMapFlattened(item.toMap()); foreach(const QString& subKey, subMap.keys()) { output.insert(QString("%1.%2").arg(key).arg(subKey), subMap.value(subKey)); } } } else { output.insert(key, value); } } return output; } // -------------------------------------------------------------------------- void qRestAPIPrivate::processReply(QNetworkReply* reply) { Q_Q(qRestAPI); QUuid queryId(reply->property("uuid").toString()); qRestResult* restResult = results[queryId]; Q_ASSERT(restResult); if (reply->error() != QNetworkReply::NoError) { qRestAPI::ErrorType errorCode = qRestAPI::NetworkError; switch (reply->error()) { case QNetworkReply::TimeoutError: errorCode = qRestAPI::TimeoutError; break; case QNetworkReply::SslHandshakeFailedError: errorCode = qRestAPI::SslError; break; case QNetworkReply::AuthenticationRequiredError: errorCode = qRestAPI::AuthenticationError; break; default: ; } restResult->setError(queryId.toString() + ": " + QString::number(static_cast(reply->error())) + ": " + reply->errorString(), errorCode); } else { restResult->Reponse = reply->readAll(); q->parseResponse(restResult, restResult->response()); } #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) foreach(const QNetworkReply::RawHeaderPair& rawHeaderPair, reply->rawHeaderPairs()) { restResult->setRawHeader(rawHeaderPair.first, rawHeaderPair.second); } #else foreach(const QByteArray& headerName, reply->rawHeaderList()) { restResult->setRawHeader(headerName, reply->rawHeader(headerName)); } #endif reply->close(); reply->deleteLater(); q->emit finished(queryId); } void qRestAPIPrivate::onSslErrors(QNetworkReply* reply, const QList& errors) { #ifdef QRESTAPI_QT_NO_SSL Q_UNUSED(reply) Q_UNUSED(errors) #else if (!this->SuppressSslErrors) { QString errorString; foreach (const QSslError& error, errors) { if (!errorString.isEmpty()) { errorString.append(", "); } errorString.append(error.errorString()); } QString plural(errors.empty() ? " has" : "s have"); QString error = QString("SSL error%1 occurred: %2").arg(plural).arg(errorString); QUuid queryId(reply->property("uuid").toString()); qRestResult* restResult = results[queryId]; restResult->setError(error, qRestAPI::SslError); } else { reply->ignoreSslErrors(); } #endif } // -------------------------------------------------------------------------- void qRestAPIPrivate::queryProgress(qint64 bytesTransmitted, qint64 bytesTotal) { Q_UNUSED(bytesTransmitted); Q_UNUSED(bytesTotal); QNetworkReply* reply = qobject_cast(this->sender()); // We received some progress so we postpone the timeout if any. QTimer* timer = reply->findChild(); if (timer) { timer->start(); } } // -------------------------------------------------------------------------- void qRestAPIPrivate::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) { Q_Q(qRestAPI); QNetworkReply* reply = qobject_cast(this->sender()); QUuid queryId(reply->property("uuid").toString()); double progress = static_cast(bytesReceived) / bytesTotal; q->emit progress(queryId, progress); } // -------------------------------------------------------------------------- void qRestAPIPrivate::uploadProgress(qint64 bytesSent, qint64 bytesTotal) { Q_Q(qRestAPI); QNetworkReply* reply = qobject_cast(this->sender()); Q_ASSERT(reply); if (!reply) { return; } QUuid queryId(reply->property("uuid").toString()); double progress = static_cast(bytesSent) / bytesTotal; q->emit progress(queryId, progress); } // -------------------------------------------------------------------------- void qRestAPIPrivate::queryTimeOut() { QTimer* timer = qobject_cast(this->sender()); Q_ASSERT(timer); QNetworkReply* reply = qobject_cast(timer->parent()); Q_ASSERT(reply); reply->abort(); //reply->setError(QNetworkReply::TimeoutError, // q->tr("Time out: No progress for %1 seconds.").arg(timer->interval())); } // -------------------------------------------------------------------------- // qRestAPI methods // -------------------------------------------------------------------------- qRestAPI::qRestAPI(QObject* _parent) : Superclass(_parent) , d_ptr(new qRestAPIPrivate(this)) { Q_D(qRestAPI); d->init(); } // -------------------------------------------------------------------------- qRestAPI::~qRestAPI() { } // -------------------------------------------------------------------------- QString qRestAPI::serverUrl()const { Q_D(const qRestAPI); return d->ServerUrl; } // -------------------------------------------------------------------------- void qRestAPI::setServerUrl(const QString& serverUrl) { Q_D(qRestAPI); d->ServerUrl = serverUrl; } // -------------------------------------------------------------------------- int qRestAPI::timeOut()const { Q_D(const qRestAPI); return d->TimeOut; } // -------------------------------------------------------------------------- void qRestAPI::setTimeOut(int msecs) { Q_D(qRestAPI); d->TimeOut = msecs; } // -------------------------------------------------------------------------- qRestAPI::RawHeaders qRestAPI::defaultRawHeaders()const { Q_D(const qRestAPI); return d->DefaultRawHeaders; } // -------------------------------------------------------------------------- void qRestAPI::setDefaultRawHeaders(const qRestAPI::RawHeaders& defaultRawHeaders) { Q_D(qRestAPI); d->DefaultRawHeaders = defaultRawHeaders; } // -------------------------------------------------------------------------- bool qRestAPI::suppressSslErrors()const { Q_D(const qRestAPI); return d->SuppressSslErrors; } // -------------------------------------------------------------------------- void qRestAPI::setSuppressSslErrors(bool suppressSslErrors) { Q_D(qRestAPI); d->SuppressSslErrors = suppressSslErrors; } // -------------------------------------------------------------------------- QUrl qRestAPI::createUrl(const QString& resource, const qRestAPI::Parameters& parameters) { Q_D(qRestAPI); QUrl url(d->ServerUrl + resource); #if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) foreach(const QString& parameter, parameters.keys()) { url.addQueryItem(parameter, parameters[parameter]); } #else QUrlQuery urlQuery(url); foreach(const QString& parameter, parameters.keys()) { urlQuery.addQueryItem(parameter, parameters[parameter]); } url.setQuery(urlQuery); #endif return url; } // -------------------------------------------------------------------------- void qRestAPI::parseResponse(qRestResult* restResult, const QByteArray& response) { Q_UNUSED(response); QList result; restResult->setResult(result); } // -------------------------------------------------------------------------- QUuid qRestAPI::get(const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { QUrl url = createUrl(resource, parameters); QNetworkReply* queryReply = sendRequest(QNetworkAccessManager::GetOperation, url, rawHeaders); QUuid queryId(queryReply->property("uuid").toString()); return queryId; } // -------------------------------------------------------------------------- QUuid qRestAPI::get(QIODevice* output, const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { Q_D(qRestAPI); QUrl url = createUrl(resource, parameters); if (!output->open(QIODevice::WriteOnly)) { QUuid queryId; // TODO How to raise the error? We do not have a qRestResult object yet... // emit errorReceived(queryId, "Cannot open device for writing."); return queryId; } QNetworkReply* queryReply = sendRequest(QNetworkAccessManager::GetOperation, url, rawHeaders); QUuid queryId = QUuid(queryReply->property("uuid").toString()); qRestResult* result = new qRestResult(queryId, queryReply); result->ioDevice = output; connect(queryReply, SIGNAL(downloadProgress(qint64,qint64)), d, SLOT(downloadProgress(qint64,qint64))); connect(queryReply, SIGNAL(readyRead()), result, SLOT(downloadReadyRead())); connect(queryReply, SIGNAL(finished()), result, SLOT(downloadFinished())); return queryId; } // -------------------------------------------------------------------------- QUuid qRestAPI::head(const QString resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { QUrl url = createUrl(resource, parameters); QNetworkReply* queryReply = sendRequest(QNetworkAccessManager::HeadOperation, url, rawHeaders); QUuid queryId = QUuid(queryReply->property("uuid").toString()); return queryId; } // -------------------------------------------------------------------------- QUuid qRestAPI::download(const QString& fileName, const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { Q_UNUSED(rawHeaders); Q_D(qRestAPI); QIODevice* output = new QFile(fileName); QUuid queryId = get(output, resource, parameters); output->setParent(d->results[queryId]); return queryId; } // -------------------------------------------------------------------------- QUuid qRestAPI::del(const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { QUrl url = createUrl(resource, parameters); QNetworkReply* queryReply = sendRequest(QNetworkAccessManager::DeleteOperation, url, rawHeaders); QUuid queryId(queryReply->property("uuid").toString()); return queryId; } // -------------------------------------------------------------------------- QUuid qRestAPI::post(const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { QUrl url = createUrl(resource, parameters); QNetworkReply* queryReply = sendRequest(QNetworkAccessManager::PostOperation, url, rawHeaders); QUuid queryId(queryReply->property("uuid").toString()); return queryId; } // -------------------------------------------------------------------------- QUuid qRestAPI::put(const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { QUrl url = createUrl(resource, parameters); QNetworkReply* queryReply = sendRequest(QNetworkAccessManager::PutOperation, url, rawHeaders); QUuid queryId(queryReply->property("uuid").toString()); return queryId; } QUuid qRestAPI::put(QIODevice *input, const QString &resource, const qRestAPI::Parameters ¶meters, const qRestAPI::RawHeaders &rawHeaders) { Q_D(qRestAPI); QUrl url = createUrl(resource, parameters); if (!input->isOpen() && !input->open(QIODevice::ReadOnly)) { QUuid uid = QUuid::createUuid(); qRestResult* restResult = new qRestResult(uid); restResult->setError(uid.toString() + ": " + "Could not open file for upload!", qRestAPI::FileError); d->results[uid] = restResult; return uid; } QByteArray data = input->readAll(); QNetworkReply* queryReply = sendRequest(QNetworkAccessManager::PutOperation, url, rawHeaders, data); QUuid queryId (queryReply->property("uuid").toString()); qRestResult* result = d->results[queryId]; result->ioDevice = input; connect(queryReply, SIGNAL(uploadProgress(qint64,qint64)), d, SLOT(uploadProgress(qint64,qint64))); connect(queryReply, SIGNAL(finished()), result, SLOT(uploadFinished())); return queryId; } // -------------------------------------------------------------------------- QUuid qRestAPI::upload(const QString& fileName, const QString& resource, const Parameters& parameters, const qRestAPI::RawHeaders& rawHeaders) { Q_D(qRestAPI); QIODevice* input = new QFile(fileName); QUuid queryId = this->put(input, resource, parameters, rawHeaders); input->setParent(d->results[queryId]); return queryId; } // -------------------------------------------------------------------------- bool qRestAPI::sync(const QUuid& queryId) { QList result; return this->sync(queryId, result); } // -------------------------------------------------------------------------- bool qRestAPI::sync(const QUuid& queryId, QList& result) { Q_D(qRestAPI); result.clear(); if (d->results.contains(queryId)) { bool ok = d->results[queryId]->waitForDone(); qRestResult* queryResult = d->results.take(queryId); if (!ok) { QVariantMap map; map["queryError"] = queryResult->Error; queryResult->Result.push_front(map); d->ErrorCode = queryResult->errorType(); d->ErrorString = queryResult->error(); } result = queryResult->Result; delete queryResult; return ok; } d->ErrorCode = UnknownUuidError; d->ErrorString = unknownUuidStr.arg(queryId.toString()); return false; } // -------------------------------------------------------------------------- QString qRestAPI::qVariantMapListToString(const QList& list) { QStringList values; foreach(const QVariantMap& map, list) { foreach(const QString& key, map.keys()) { values << QString("%1: %2").arg(key, map[key].toString()); } } return values.join("\n"); } // -------------------------------------------------------------------------- QString qRestAPI::qVariantToString(const QVariant &value, int indent) { QString output; bool isVariantList = value.canConvert(); bool isVariantMap = value.canConvert(); if ((isVariantList || isVariantMap) && indent > 0) { output += "\n"; } if (isVariantList) { QVariantList list = value.toList(); for(int idx=0; idx < list.count(); ++idx) { output.append(QString("%1%2: ").arg(QString(indent, ' ')).arg(idx)); output.append(qRestAPI::qVariantToString(list.at(idx), indent + 2)); } } else if (isVariantMap) { QVariantMap map = value.toMap(); foreach(const QString& key, map.keys()) { output.append(QString("%1%2: ").arg(QString(indent, ' ')).arg(key)); output.append(qRestAPI::qVariantToString(map.value(key), indent + 2)); } } else { return value.toString() + "\n"; } return output; } // -------------------------------------------------------------------------- qRestResult* qRestAPI::takeResult(const QUuid& queryId) { Q_D(qRestAPI); if (d->results.contains(queryId)) { // Do /not/ try to .take() the query before calling waitForDone(); // the latter triggers SIGNALs which access d->results. bool ok = d->results[queryId]->waitForDone(); qRestResult* result = d->results.take(queryId); if (ok) { return result; } else { d->ErrorCode = result->errorType(); d->ErrorString = result->error(); delete result; return NULL; } } d->ErrorCode = UnknownUuidError; d->ErrorString = QString::number(UnknownUuidError); return NULL; } // -------------------------------------------------------------------------- qRestAPI::ErrorType qRestAPI::error() const { Q_D(const qRestAPI); return d->ErrorCode; } // -------------------------------------------------------------------------- QString qRestAPI::errorString() const { Q_D(const qRestAPI); return d->ErrorString; } //// -------------------------------------------------------------------------- //void qRestAPIPrivate::onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator) //{ // Q_D(qRestAPI); // authenticator->setUser(d->userName); // authenticator->setPassword(d->password); //} commontk-qRestAPI-5c4a76e/qRestAPI.h000066400000000000000000000317221524607745600172350ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ #ifndef __qRestAPI_h #define __qRestAPI_h // Qt includes #include #include #include #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) #include #else #include #endif #include #include #include "qRestAPI_Export.h" template class QMap; typedef QMap QVariantMap; class QNetworkReply; class qRestAPIPrivate; class qRestResult; /// qRestAPI is a simple interface class to communicate with web services /// through a public RESTful API. /// Requests are sent to the server and answers reported back. /// qRestAPI works in synchronous or asynchronous way. /// The class should be adopted to specific web services by subclassing. The /// derived class should define how to construct the requests and how to /// interpret the responses. /// The library provides a sample implementation to interact with Midas servers. /// Usage: /// /// qRestAPI* midas = new qMidasAPI(); /// midas->setServerUrl("http://slicer.kitware.com/midas3"); /// connect(midas, SIGNAL(resultReceived(QUuid,QList)), /// myApp, SLOT(processResult(QUuid,QList))); /// midas->query("midas.version"); /// ... /// delete midas; /// class qRestAPI_EXPORT qRestAPI : public QObject { Q_OBJECT /// URL of the web application. E.g. "http://slicer.kitware.com/midas3" Q_PROPERTY(QString serverUrl READ serverUrl WRITE setServerUrl) /// Max time to wait until last progress of a query Q_PROPERTY(int timeOut READ timeOut WRITE setTimeOut) /// Default raw headers to be set for each requests. E.g. it can be used to set /// the user-agent or authentication information. Q_PROPERTY(RawHeaders defaultRawHeaders READ defaultRawHeaders WRITE setDefaultRawHeaders) /// Suppress SSL errors. Can be used to bypass self-signed certificates. Q_PROPERTY(bool suppressSslErrors READ suppressSslErrors WRITE setSuppressSslErrors) typedef QObject Superclass; public: enum ErrorType { UnknownError = -1, /// An unknown uuid was used UnknownUuidError = 1, /// A time-out error TimeoutError = 2, /// Error related to SSL connections SslError = 3, /// Error parsing the response ResponseParseError = 4, /// The remote server requires authentication but the credentials /// provided were not accepted (if any). AuthenticationError = 5, /// Error is raised if a file could not be opened FileError = 6, /// General network error not covered by more specific error types NetworkError = 100 }; /// Constructs a qRestAPI object. explicit qRestAPI(QObject*parent = 0); /// Destructs a qRestAPI object. virtual ~qRestAPI(); /// Type of the parameter list of a REST request. typedef QMap Parameters; /// Type of the raw header list of a REST request. typedef QMap RawHeaders; /// Returns the URL of the web application. QString serverUrl()const; /// Sets the URL of the web application. void setServerUrl(const QString& serverUrl); /// Sets the HTTP network proxy that will be used for all queries void setHttpNetworkProxy(const QNetworkProxy& proxy); /// Returns the raw headers that are set for every request. RawHeaders defaultRawHeaders()const; /// Sets the raw headers to be set for every request. void setDefaultRawHeaders(const RawHeaders& defaultRawHeaders); /// Tells if the SSL errors are suppressed or not. bool suppressSslErrors()const; /// Sets if the SSL errors are to be suppressed or not. void setSuppressSslErrors(bool suppressSslErrors); void setTimeOut(int msecs); int timeOut()const; /// Sends a GET request to the web service. /// The \a resource and \parameters are used to compose the URL. /// \a rawHeaders can be used to set the raw headers of the request to send. /// These headers will be set additionally to those defined by the /// \a defaultRawHeaders property. /// errorReceived() is emitted if no server is found or if the server sends /// errors. /// resultReceived() is emitted when a result is received from the server, /// it is fired even if errors are received. /// Returns a unique identifier of the posted query. virtual QUuid get(const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); virtual QUuid get(QIODevice* output, const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); /// Sends a HEAD request to the web service. /// The \a resource and \parameters are used to compose the URL. /// \a rawHeaders can be used to set the raw headers of the request to send. /// These headers will be set additionally to those defined by the /// \a defaultRawHeaders property. /// errorReceived() is emitted if no server is found or if the server sends /// errors. /// resultReceived() is emitted when a result is received from the server, /// it is fired even if errors are received. /// Returns a unique identifier of the posted query. virtual QUuid head(const QString resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); /// Downloads a file from the web service. /// \a fileName is the name of the output file. /// The \a resource and \parameters are used to compose the URL. /// \a rawHeaders can be used to set the raw headers of the request to send. /// These headers will be set additionally to those defined by the /// \a defaultRawHeaders property. /// errorReceived() is emitted if no server is found or if the server sends /// errors. /// resultReceived() is emitted when a result is received from the server, /// it is fired even if errors are received. /// Returns a unique identifier of the posted query. virtual QUuid download(const QString& fileName, const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); /// Sends a DELETE request to the web service. /// The \a resource and \parameters are used to compose the URL. /// \a rawHeaders can be used to set the raw headers of the request to send. /// These headers will be set additionally to those defined by the /// \a defaultRawHeaders property. /// errorReceived() is emitted if no server is found or if the server sends /// errors. /// resultReceived() is emitted when a result is received from the server, /// it is fired even if errors are received. /// Returns a unique identifier of the posted query. QUuid del(const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); /// Sends a POST request to the web service. /// The \a resource and \parameters are used to compose the URL. /// \a rawHeaders can be used to set the raw headers of the request to send. /// These headers will be set additionally to those defined by the /// \a defaultRawHeaders property. /// errorReceived() is emitted if no server is found or if the server sends /// errors. /// resultReceived() is emitted when a result is received from the server, /// it is fired even if errors are received. /// Returns a unique identifier of the posted query. QUuid post(const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); /// Sends a PUT request to the web service. /// The \a resource and \parameters are used to compose the URL. /// \a rawHeaders can be used to set the raw headers of the request to send. /// These headers will be set additionally to those defined by the /// \a defaultRawHeaders property. /// If an \a input is specified it will be send together with the request. /// errorReceived() is emitted if no server is found or if the server sends /// errors. /// resultReceived() is emitted when a result is received from the server, /// it is fired even if errors are received. /// Returns a unique identifier of the posted query. QUuid put(const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); virtual QUuid put(QIODevice* input, const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); QUuid upload(const QString& fileName, const QString& resource, const Parameters& parameters = Parameters(), const RawHeaders& rawHeaders = RawHeaders()); /// Blocks until the result for the uuid \a queryId is available. /// Returns false if an error occured. /// \sa ErrorType /// \sa error() /// \sa errorString() bool sync(const QUuid& queryId); /// Blocks until the results for the uuid \a queryId is available and /// stores the results in the given \a result parameter. /// Returns false if an error occured. /// \sa ErrorType /// \sa error() /// \sa errorString() bool sync(const QUuid& queryId, QList& result); /// Get a qRestResult object for the specified QUuid. /// If the \a queryId parameter is unknown, this function /// returns NULL and sets the error state to ErrorType::UnknownUuid. qRestResult* takeResult(const QUuid& queryId); /// Get the error code for the last error which occured. ErrorType error() const; /// Get the error description for the last error which occured. QString errorString() const; /// Utility function that transforms a QList of QVariantMap into a string. /// Mostly for debug purpose. static QString qVariantMapListToString(const QList& variants); /// \brief Return an indented representation of a QVariant considering map and list. /// /// \example /// /// ``` /// a: 1 /// b: /// b_a: 2-1 /// b_b: 2-2 /// b_c: 2-3 /// c: /// 0: /// c_a_1: 3-1_1 /// c_b_1: 3-2_1 /// c_c_1: 3-3_1 /// 1: /// c_a_2: 3-1_3 /// c_b_2: 3-2_2 /// c_b_3: 3-2_3 /// ``` static QString qVariantToString(const QVariant &value, int indent=0); #if (QT_VERSION >= QT_VERSION_CHECK(5,0,0)) static QVariantMap scriptValueToMap(const QJSValue& value); static void appendScriptValueToVariantMapList(QList& result, const QJSValue& value); #else static QVariantMap scriptValueToMap(const QScriptValue& value); static void appendScriptValueToVariantMapList(QList& result, const QScriptValue& value); #endif /// \brief Flatten a QVariantMap of nested QVariantList, QVariantMap and QVariant. /// /// Given a dictionnary like the following: /// /// ``` /// { /// "a": "1", /// "b": { /// "b_a": "2-1", /// "b_b": "2-2", /// "b_c": "2-3" /// }, /// "c": [ /// { /// "c_a_1": "3-1_1", /// "c_b_1": "3-2_1", /// "c_c_1": "3-3_1" /// }, /// { /// "c_a_2": "3-1_2", /// "c_b_2": "3-2_2" /// } /// ] /// } /// ``` /// /// It returns this flattened dictionnary: /// /// ``` /// { /// "a": "1", /// "b.b_a": "2-1", /// "b.b_b": "2-2", /// "b.b_c": "2-3", /// "c.c_a_1": "3-1_1", /// "c.c_b_1": "3-2_1", /// "c.c_c_1": "3-3_1", /// "c.c_a_2": "3-1_2", /// "c.c_b_2": "3-2_2" /// } /// ``` /// /// \warning In list of dictionnaries where the same key is found in multiple /// dictionnaries, only the value associated associated with the key found in /// the last list is kept. /// static QVariantMap qVariantMapFlattened(const QVariantMap& value); signals: void finished(const QUuid& queryId); void progress(const QUuid& queryId, double progress); protected: QNetworkReply* sendRequest(QNetworkAccessManager::Operation operation, const QUrl& url, const RawHeaders& rawHeaders = RawHeaders(), const QByteArray& data = QByteArray()); virtual QUrl createUrl(const QString& method, const qRestAPI::Parameters& parameters); virtual void parseResponse(qRestResult* restResult, const QByteArray& response); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(qRestAPI); Q_DISABLE_COPY(qRestAPI); }; #endif commontk-qRestAPI-5c4a76e/qRestAPI_Export.h.in000066400000000000000000000013551524607745600212020ustar00rootroot00000000000000 // .NAME __qRestAPI_Export - manage Windows system differences // .SECTION Description // The __qRestAPI_Export captures some system differences between Unix // and Windows operating systems. #ifndef __qRestAPI_Export_h #define __qRestAPI_Export_h #include #cmakedefine qRestAPI_STATIC #if !defined(qRestAPI_STATIC) # if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) # if defined(qRestAPI_EXPORTS) # define qRestAPI_EXPORT Q_DECL_EXPORT # else # define qRestAPI_EXPORT Q_DECL_IMPORT # endif # endif #else # define qRestAPI_EXPORT #endif #if !defined(qRestAPI_EXPORT) # if !defined(qRestAPI_STATIC) # define qRestAPI_EXPORT Q_DECL_EXPORT # else # define qRestAPI_EXPORT # endif #endif #endif commontk-qRestAPI-5c4a76e/qRestAPI_p.h000066400000000000000000000054431524607745600175550ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ #ifndef __qRestAPI_p_h #define __qRestAPI_p_h // Qt includes #include #if QT_VERSION >= 0x050000 #include #endif #include #include #include // qRestAPI includes #include "qRestAPI.h" class QIODevice; #if (QT_VERSION < QT_VERSION_CHECK(5, 3, 0)) #ifdef QT_NO_OPENSSL #define QRESTAPI_QT_NO_SSL #endif #else #ifdef QT_NO_SSL #define QRESTAPI_QT_NO_SSL #endif #endif #ifdef QRESTAPI_QT_NO_SSL struct QSslError{}; #endif // -------------------------------------------------------------------------- class qRestAPIPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(qRestAPI); qRestAPI* const q_ptr; private: static struct StaticInit { StaticInit() { qRestAPIPrivate::staticInit(); } } _staticInit; static void staticInit(); public: qRestAPIPrivate(qRestAPI* object); ~qRestAPIPrivate(); virtual void init(); public slots: void processReply(QNetworkReply* reply); /// Called when a query hasn't had any progress for a given TimeOut time. /// Note: sender() is used. void queryTimeOut(); void queryProgress(qint64 bytesReceived, qint64 bytesTotal); void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); void uploadProgress(qint64 bytesSent, qint64 bytesTotal); void onSslErrors(QNetworkReply* reply, const QList& errors); // void onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator); public: QString ServerUrl; QNetworkAccessManager* NetworkManager; int TimeOut; qRestAPI::RawHeaders DefaultRawHeaders; bool SuppressSslErrors; qRestAPI::ErrorType ErrorCode; QString ErrorString; // In Qt5 QHash should be used. QUuid does not have a hash function in Qt4, // so the QUuid's would be converted to QString what is expensive. #if QT_VERSION >= 0x050000 QHash results; #else QMap results; #endif }; #endif commontk-qRestAPI-5c4a76e/qRestResult.cpp000066400000000000000000000113011524607745600204240ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ #include "qRestResult.h" #include #include #include #include // -------------------------------------------------------------------------- // qRestAPIResult methods // -------------------------------------------------------------------------- qRestResult::qRestResult(const QUuid& queryId, QObject* parent) : QObject(parent) , QueryId(queryId) , ErrorCode(qRestAPI::UnknownError) , done(false) { } // -------------------------------------------------------------------------- qRestResult::~qRestResult() { } // -------------------------------------------------------------------------- const QUuid& qRestResult::queryId() const { return this->QueryId; } // -------------------------------------------------------------------------- const QList& qRestResult::results() const { return this->Result; } // -------------------------------------------------------------------------- const QVariantMap qRestResult::result() const { return this->Result.isEmpty() ? QVariantMap() : this->Result[0]; } // -------------------------------------------------------------------------- const QString& qRestResult::error() const { return this->Error; } // -------------------------------------------------------------------------- qRestAPI::ErrorType qRestResult::errorType() const { return this->ErrorCode; } // -------------------------------------------------------------------------- QByteArray qRestResult::rawHeader(const QByteArray& name) const { if (this->RawHeaders.contains(name)) { return this->RawHeaders[name]; } return QByteArray(); } // -------------------------------------------------------------------------- QMap qRestResult::rawHeaders() const { return this->RawHeaders; } // -------------------------------------------------------------------------- QByteArray qRestResult::response()const { return this->Reponse; } // -------------------------------------------------------------------------- void qRestResult::setResult() { this->done = true; emit ready(); } // -------------------------------------------------------------------------- void qRestResult::setResult(const QList& result) { this->Result.clear(); for (int i = 0; i < result.size(); ++i) this->Result.push_back(result[i]); // this->Result = result; this->done = true; emit ready(); } // -------------------------------------------------------------------------- void qRestResult::setError(const QString& error, qRestAPI::ErrorType errorType) { this->ErrorCode = errorType; this->Error = error; this->done = true; emit ready(); } // -------------------------------------------------------------------------- bool qRestResult::waitForDone() { if (!done) { QEventLoop eventLoop; // Time out will fire an error which will quit the event loop. QObject::connect(this, SIGNAL(ready()), &eventLoop, SLOT(quit())); eventLoop.exec(); } // We require that the error code in case of an actual error is // never UnknownError for qRestResult objects. return this->ErrorCode == qRestAPI::UnknownError; } // -------------------------------------------------------------------------- void qRestResult::downloadReadyRead() { QNetworkReply* reply = qobject_cast(this->sender()); ioDevice->write(reply->readAll()); } // -------------------------------------------------------------------------- void qRestResult::downloadFinished() { ioDevice->close(); } // -------------------------------------------------------------------------- void qRestResult::uploadFinished() { ioDevice->close(); } // -------------------------------------------------------------------------- void qRestResult::setRawHeader(const QByteArray& name, const QByteArray& value) { this->RawHeaders[name] = value; } commontk-qRestAPI-5c4a76e/qRestResult.h000066400000000000000000000047151524607745600201040ustar00rootroot00000000000000/*============================================================================== Library: qRestAPI Copyright (c) 2010 Kitware Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 ==============================================================================*/ #ifndef __qRestResult_h #define __qRestResult_h // qRestAPI includes #include "qRestAPI.h" #include "qRestAPI_Export.h" class QIODevice; // -------------------------------------------------------------------------- class qRestAPI_EXPORT qRestResult : public QObject { Q_OBJECT friend class qRestAPI; friend class qRestAPIPrivate; QUuid QueryId; QByteArray Reponse; QList Result; QString Error; qRestAPI::ErrorType ErrorCode; QMap RawHeaders; bool done; QIODevice* ioDevice; public: qRestResult(const QUuid& queryId, QObject* parent = 0); virtual ~qRestResult(); const QUuid& queryId() const; bool waitForDone(); const QList& results() const; const QVariantMap result() const; // FIXME: for consistency with the qRestAPI class, this method should be called errorString() const QString& error() const; // FIXME: for consistency with the qRestAPI class, this method should be called error() qRestAPI::ErrorType errorType() const; QByteArray rawHeader(const QByteArray& name) const; QMap rawHeaders() const; QByteArray response()const; public slots: void setResult(); void setResult(const QList& result); // FIXME: should be called setResults(), see getters void setError(const QString& error, qRestAPI::ErrorType errorType = qRestAPI::UnknownError); void downloadReadyRead(); void downloadFinished(); void uploadFinished(); signals: void ready(); private: void setRawHeader(const QByteArray& name, const QByteArray& value); }; #endif