InformationResponseDeserializer.cpp (6916B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "Rest/Schema/IRestClient.h" 5 #include <winget/JsonUtil.h> 6 #include "Rest/Schema/CommonRestConstants.h" 7 #include "AuthenticationInfoParser.h" 8 #include "InformationResponseDeserializer.h" 9 10 namespace AppInstaller::Repository::Rest::Schema 11 { 12 namespace 13 { 14 // Information response constants 15 constexpr std::string_view SourceIdentifier = "SourceIdentifier"sv; 16 constexpr std::string_view ServerSupportedVersions = "ServerSupportedVersions"sv; 17 18 constexpr std::string_view SourceAgreements = "SourceAgreements"sv; 19 constexpr std::string_view SourceAgreementsIdentifier = "AgreementsIdentifier"sv; 20 constexpr std::string_view SourceAgreementsContent = "Agreements"sv; 21 constexpr std::string_view SourceAgreementLabel = "AgreementLabel"sv; 22 constexpr std::string_view SourceAgreementText = "Agreement"sv; 23 constexpr std::string_view SourceAgreementUrl = "AgreementUrl"sv; 24 25 constexpr std::string_view UnsupportedPackageMatchFields = "UnsupportedPackageMatchFields"sv; 26 constexpr std::string_view RequiredPackageMatchFields = "RequiredPackageMatchFields"sv; 27 constexpr std::string_view UnsupportedQueryParameters = "UnsupportedQueryParameters"sv; 28 constexpr std::string_view RequiredQueryParameters = "RequiredQueryParameters"sv; 29 } 30 31 IRestClient::Information InformationResponseDeserializer::Deserialize(const web::json::value& dataObject) const 32 { 33 // Get information result from json output. 34 std::optional<IRestClient::Information> information = DeserializeInformation(dataObject); 35 36 THROW_HR_IF(APPINSTALLER_CLI_ERROR_UNSUPPORTED_RESTSOURCE, !information); 37 38 return information.value(); 39 } 40 41 std::optional<IRestClient::Information> InformationResponseDeserializer::DeserializeInformation(const web::json::value& dataObject) const 42 { 43 try 44 { 45 if (dataObject.is_null()) 46 { 47 AICLI_LOG(Repo, Error, << "Missing json object."); 48 return {}; 49 } 50 51 std::optional<std::reference_wrapper<const web::json::value>> data = JSON::GetJsonValueFromNode(dataObject, JSON::GetUtilityString(Data)); 52 if (!data) 53 { 54 AICLI_LOG(Repo, Error, << "Missing data"); 55 return {}; 56 } 57 58 const auto& dataValue = data.value().get(); 59 std::optional<std::string> sourceId = JSON::GetRawStringValueFromJsonNode(dataValue, JSON::GetUtilityString(SourceIdentifier)); 60 if (!JSON::IsValidNonEmptyStringValue(sourceId)) 61 { 62 AICLI_LOG(Repo, Error, << "Missing source identifier"); 63 return {}; 64 } 65 66 std::vector<std::string> allVersions = JSON::GetRawStringArrayFromJsonNode(dataValue, JSON::GetUtilityString(ServerSupportedVersions)); 67 if (allVersions.size() == 0) 68 { 69 AICLI_LOG(Repo, Error, << "Missing supported versions."); 70 return {}; 71 } 72 73 IRestClient::Information info{ std::move(sourceId.value()), std::move(allVersions) }; 74 75 auto agreements = JSON::GetJsonValueFromNode(dataValue, JSON::GetUtilityString(SourceAgreements)); 76 if (agreements) 77 { 78 const auto& agreementsValue = agreements.value().get(); 79 80 auto agreementsIdentifier = JSON::GetRawStringValueFromJsonNode(agreementsValue, JSON::GetUtilityString(SourceAgreementsIdentifier)); 81 if (!JSON::IsValidNonEmptyStringValue(agreementsIdentifier)) 82 { 83 AICLI_LOG(Repo, Error, << "SourceAgreements node exists but AgreementsIdentifier is missing."); 84 return {}; 85 } 86 87 info.SourceAgreementsIdentifier = std::move(agreementsIdentifier.value()); 88 89 auto agreementsContent = JSON::GetRawJsonArrayFromJsonNode(agreementsValue, JSON::GetUtilityString(SourceAgreementsContent)); 90 if (agreementsContent) 91 { 92 for (auto const& agreementNode : agreementsContent.value().get()) 93 { 94 IRestClient::SourceAgreementEntry agreementEntry; 95 96 std::optional<std::string> label = JSON::GetRawStringValueFromJsonNode(agreementNode, JSON::GetUtilityString(SourceAgreementLabel)); 97 if (JSON::IsValidNonEmptyStringValue(label)) 98 { 99 agreementEntry.Label = std::move(label.value()); 100 } 101 102 std::optional<std::string> text = JSON::GetRawStringValueFromJsonNode(agreementNode, JSON::GetUtilityString(SourceAgreementText)); 103 if (JSON::IsValidNonEmptyStringValue(text)) 104 { 105 agreementEntry.Text = std::move(text.value()); 106 } 107 108 std::optional<std::string> url = JSON::GetRawStringValueFromJsonNode(agreementNode, JSON::GetUtilityString(SourceAgreementUrl)); 109 if (JSON::IsValidNonEmptyStringValue(url)) 110 { 111 agreementEntry.Url = std::move(url.value()); 112 } 113 114 if (!agreementEntry.Label.empty() || !agreementEntry.Text.empty() || !agreementEntry.Url.empty()) 115 { 116 info.SourceAgreements.emplace_back(std::move(agreementEntry)); 117 } 118 } 119 } 120 } 121 122 info.RequiredPackageMatchFields = JSON::GetRawStringArrayFromJsonNode(dataValue, JSON::GetUtilityString(RequiredPackageMatchFields)); 123 info.UnsupportedPackageMatchFields = JSON::GetRawStringArrayFromJsonNode(dataValue, JSON::GetUtilityString(UnsupportedPackageMatchFields)); 124 info.RequiredQueryParameters = JSON::GetRawStringArrayFromJsonNode(dataValue, JSON::GetUtilityString(RequiredQueryParameters)); 125 info.UnsupportedQueryParameters = JSON::GetRawStringArrayFromJsonNode(dataValue, JSON::GetUtilityString(UnsupportedQueryParameters)); 126 127 info.Authentication = ParseAuthenticationInfo(dataValue, ParseAuthenticationInfoType::Source); 128 129 return info; 130 } 131 catch (const std::exception& e) 132 { 133 AICLI_LOG(Repo, Error, << "Error encountered while deserializing Information. Reason: " << e.what()); 134 } 135 catch (...) 136 { 137 AICLI_LOG(Repo, Error, << "Received invalid information."); 138 } 139 140 return {}; 141 } 142 }