winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }