Compare commits

..

9 commits

Author SHA1 Message Date
Kirill
dc4c430231 refactor(tgbot-front): replaced the context usage with a new thread-safe one 2025-12-06 05:05:10 +03:00
Kirill
a6848bb4d7 refactor(tgbot-front): replaced the context usage with a new thread-safe one 2025-12-06 05:02:34 +03:00
Kirill
b1c035ae35 feat(tgbot-front): start creating thread-safe user context 2025-12-06 02:44:24 +03:00
Kirill
a7b47c564a refactor(tgbot-front): small cosmetics 2025-12-06 01:59:28 +03:00
Kirill
7e0222d6f1 refactor(tgbot-front): change editMessage args 2025-12-06 01:11:34 +03:00
Kirill
19164b8d9d refactor(tgbot-front): moved the navigation handler to a separate file 2025-12-05 23:42:30 +03:00
Kirill
a22c96e7a0 build(tgbot-gen): fixing a generator error with a tag
The generator makes an error when generating tags with a link to the tag. At the moment, this is fixed by direct insertion. This is not the best solution. If a better option is found, we will fix it.
2025-12-05 23:27:02 +03:00
Kirill
20cf8b1fc2 build(tgbot-gen): Changes and additions required to generate the API client with auth (cookie)
I use a standard set of templates, changes are made in api-header.mustache and api-source.mustache. Their _old versions contain the originals. Additions are necessary for the header argument in the generated functions so that you can authenticate using cookies.
2025-12-05 22:49:14 +03:00
Kirill
ba4dfec459 refactor(tgbot): change the location of the CMakeLists.txt 2025-12-05 20:28:03 +03:00
42 changed files with 4544 additions and 243 deletions

View file

@ -0,0 +1,59 @@
# C++ API client
{{#appDescriptionWithNewLines}}
{{{.}}}
{{/appDescriptionWithNewLines}}
## Overview
This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [OpenAPI spec](https://openapis.org) from a remote server, you can easily generate an API client.
- API version: {{appVersion}}
- Package version: {{packageVersion}}
{{^hideGenerationTimestamp}}
- Build date: {{generatedDate}}
{{/hideGenerationTimestamp}}
- Generator version: {{generatorVersion}}
- Build package: {{generatorClass}}
{{#infoUrl}}
For more information, please visit [{{{infoUrl}}}]({{{infoUrl}}})
{{/infoUrl}}
- API namespace: {{{apiPackage}}}
- Model namespace: {{{modelPackage}}}
## Installation
### Prerequisites
Install [cpprestsdk](https://github.com/Microsoft/cpprestsdk).
- Windows: `vcpkg install cpprestsdk cpprestsdk:x64-windows boost-uuid boost-uuid:x64-windows`
- Mac: `brew install cpprestsdk`
- Linux: `sudo apt-get install libcpprest-dev`
### Build
```sh
cmake -DCPPREST_ROOT=/usr -DCMAKE_CXX_FLAGS="-I/usr/local/opt/openssl/include" -DCMAKE_MODULE_LINKER_FLAGS="-L/usr/local/opt/openssl/lib"
make
```
### Build on Windows with Visual Studio (VS2017)
- Right click on folder containing source code
- Select 'Open in visual studio'
- Once visual studio opens, CMake should show up in top menu bar.
- Select CMake > Build All.
*Note: If the CMake menu item doesn't show up in Visual Studio, CMake
for Visual Studio must be installed. In this case, open the 'Visual Studio
Installer' application. Select 'modify' Visual Studio 2017. Make sure
'Desktop Development with C++' is installed, and specifically that 'Visual
C++ tools for CMake' is selected in the 'Installation Details' section.
Also be sure to review the CMakeLists.txt file. Edits are likely required.*
## Author
{{#apiInfo}}{{#apis}}{{#-last}}{{infoEmail}}
{{/-last}}{{/apis}}{{/apiInfo}}

View file

@ -0,0 +1,46 @@
{{>licenseInfo}}
/*
* AnyType.h
*
* This is the implementation of an any JSON type.
*/
#ifndef {{modelHeaderGuardPrefix}}_AnyType_H_
#define {{modelHeaderGuardPrefix}}_AnyType_H_
{{{defaultInclude}}}
#include "{{packageName}}/Object.h"
#include <cpprest/details/basic_types.h>
#include <cpprest/json.h>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
class {{declspec}} AnyType : public Object {
public:
AnyType();
virtual ~AnyType();
/////////////////////////////////////////////
/// ModelBase overrides
void validate() override;
web::json::value toJson() const override;
bool fromJson(const web::json::value &json) override;
void toMultipart(std::shared_ptr<MultipartFormData> multipart,
const utility::string_t &namePrefix) const override;
bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart,
const utility::string_t &namePrefix) override;
private:
web::json::value m_value;
};
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_AnyType_H_ */

View file

@ -0,0 +1,40 @@
{{>licenseInfo}}
#include "{{packageName}}/AnyType.h"
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
AnyType::AnyType() { m_value = web::json::value::null(); }
AnyType::~AnyType() {}
void AnyType::validate() {}
web::json::value AnyType::toJson() const { return m_value; }
bool AnyType::fromJson(const web::json::value &val) {
m_value = val;
m_IsSet = true;
return isSet();
}
void AnyType::toMultipart(std::shared_ptr<MultipartFormData> multipart,
const utility::string_t &prefix) const {
if (m_value.is_object()) {
return Object::toMultipart(multipart, prefix);
}
throw std::runtime_error("AnyType::toMultipart: unsupported type");
}
bool AnyType::fromMultiPart(std::shared_ptr<MultipartFormData> multipart,
const utility::string_t &prefix) {
if (m_value.is_object()) {
return Object::fromMultiPart(multipart, prefix);
}
return false;
}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}

View file

@ -0,0 +1,41 @@
{{>licenseInfo}}
{{#operations}}
#ifndef {{apiHeaderGuardPrefix}}_{{classname}}GMock_H_
#define {{apiHeaderGuardPrefix}}_{{classname}}GMock_H_
#include <gmock/gmock.h>
#include "{{classname}}.h"
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
using namespace {{modelNamespace}};
class {{declspec}} {{classname}}Mock : public I{{classname}}
{
public:
using Base = I{{classname}};
{{classname}}Mock() = default;
explicit {{classname}}Mock( std::shared_ptr<ApiClient> apiClient ) { };
~{{classname}}Mock() override = default;
{{#operation}}
MOCK_METHOD{{allParams.size}}( {{operationId}}, pplx::task<{{{returnType}}}{{^returnType}}void{{/returnType}}> (
{{#allParams}}
{{^required}}boost::optional<{{/required}}{{#isFile}}std::shared_ptr<{{/isFile}}{{{dataType}}}{{#isFile}}>{{/isFile}}{{^required}}>{{/required}} {{paramName}}{{^-last}},{{/-last}}
{{/allParams}}
) );
{{/operation}}
};
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
#endif /* {{apiHeaderGuardPrefix}}_{{classname}}GMock_H_ */
{{/operations}}

View file

@ -0,0 +1,86 @@
{{>licenseInfo}}
{{#operations}}/*
* {{classname}}.h
*
* {{description}}
*/
#ifndef {{apiHeaderGuardPrefix}}_{{classname}}_H_
#define {{apiHeaderGuardPrefix}}_{{classname}}_H_
{{{defaultInclude}}}
#include "{{packageName}}/ApiClient.h"
{{^hasModelImport}}#include "{{packageName}}/ModelBase.h"{{/hasModelImport}}
{{#imports}}{{{import}}}
{{/imports}}
#include <boost/optional.hpp>
#include <map> // <-- добавлено для std::map
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
using namespace {{modelNamespace}};
{{#gmockApis}}
class {{declspec}} I{{classname}}
{
public:
I{{classname}}() = default;
virtual ~I{{classname}}() = default;
{{#operation}}
virtual pplx::task<{{{returnType}}}{{^returnType}}void{{/returnType}}> {{operationId}}(
{{#allParams}}
{{^required}}boost::optional<{{/required}}{{{dataType}}}{{^required}}>{{/required}} {{paramName}},{{/allParams}}
const std::map<utility::string_t, utility::string_t>& customHeaders = {} // <-- добавлено
) const = 0;
{{/operation}}
};{{/gmockApis}}
class {{declspec}} {{classname}} {{#gmockApis}} : public I{{classname}} {{/gmockApis}}
{
public:
{{#gmockApis}}
using Base = I{{classname}};
{{/gmockApis}}
explicit {{classname}}( std::shared_ptr<const ApiClient> apiClient );
{{#gmockApis}}
~{{classname}}() override;
{{/gmockApis}}
{{^gmockApis}}
virtual ~{{classname}}();
{{/gmockApis}}
{{#operation}}
/// <summary>
/// {{summary}}
/// </summary>
/// <remarks>
/// {{notes}}
/// </remarks>
{{#allParams}}
/// <param name="{{paramName}}">{{#lambda.multiline_comment_4}}{{description}}{{/lambda.multiline_comment_4}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
{{/allParams}}
/// <param name="customHeaders">Additional HTTP headers to send with the request (optional)</param>
pplx::task<{{{returnType}}}{{^returnType}}void{{/returnType}}> {{operationId}}(
{{#allParams}}
{{^required}}boost::optional<{{/required}}{{{dataType}}}{{^required}}>{{/required}} {{paramName}},{{/allParams}}
const std::map<utility::string_t, utility::string_t>& customHeaders = {} // <-- добавлено
) const{{#gmockApis}} override{{/gmockApis}};
{{/operation}}
protected:
std::shared_ptr<const ApiClient> m_ApiClient;
};
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
#endif /* {{apiHeaderGuardPrefix}}_{{classname}}_H_ */
{{/operations}}

View file

@ -0,0 +1,84 @@
{{>licenseInfo}}
{{#operations}}/*
* {{classname}}.h
*
* {{description}}
*/
#ifndef {{apiHeaderGuardPrefix}}_{{classname}}_H_
#define {{apiHeaderGuardPrefix}}_{{classname}}_H_
{{{defaultInclude}}}
#include "{{packageName}}/ApiClient.h"
{{^hasModelImport}}#include "{{packageName}}/ModelBase.h"{{/hasModelImport}}
{{#imports}}{{{import}}}
{{/imports}}
#include <boost/optional.hpp>
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
using namespace {{modelNamespace}};
{{#gmockApis}}
class {{declspec}} I{{classname}}
{
public:
I{{classname}}() = default;
virtual ~I{{classname}}() = default;
{{#operation}}
virtual pplx::task<{{{returnType}}}{{^returnType}}void{{/returnType}}> {{operationId}}(
{{#allParams}}
{{^required}}boost::optional<{{/required}}{{{dataType}}}{{^required}}>{{/required}} {{paramName}}{{^-last}},{{/-last}}
{{/allParams}}
) const = 0;
{{/operation}}
};{{/gmockApis}}
class {{declspec}} {{classname}} {{#gmockApis}} : public I{{classname}} {{/gmockApis}}
{
public:
{{#gmockApis}}
using Base = I{{classname}};
{{/gmockApis}}
explicit {{classname}}( std::shared_ptr<const ApiClient> apiClient );
{{#gmockApis}}
~{{classname}}() override;
{{/gmockApis}}
{{^gmockApis}}
virtual ~{{classname}}();
{{/gmockApis}}
{{#operation}}
/// <summary>
/// {{summary}}
/// </summary>
/// <remarks>
/// {{notes}}
/// </remarks>
{{#allParams}}
/// <param name="{{paramName}}">{{#lambda.multiline_comment_4}}{{description}}{{/lambda.multiline_comment_4}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
{{/allParams}}
pplx::task<{{{returnType}}}{{^returnType}}void{{/returnType}}> {{operationId}}(
{{#allParams}}
{{^required}}boost::optional<{{/required}}{{{dataType}}}{{^required}}>{{/required}} {{paramName}}{{^-last}},{{/-last}}
{{/allParams}}
) const{{#gmockApis}} override{{/gmockApis}};
{{/operation}}
protected:
std::shared_ptr<const ApiClient> m_ApiClient;
};
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
#endif /* {{apiHeaderGuardPrefix}}_{{classname}}_H_ */
{{/operations}}

View file

@ -0,0 +1,375 @@
{{>licenseInfo}}
{{#operations}}
#include "{{packageName}}/api/{{classname}}.h"
#include "{{packageName}}/IHttpBody.h"
#include "{{packageName}}/JsonBody.h"
#include "{{packageName}}/MultipartFormData.h"
#include <boost/algorithm/string/replace.hpp>
#include <unordered_set>
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
using namespace {{modelNamespace}};
{{classname}}::{{classname}}( std::shared_ptr<const ApiClient> apiClient )
: m_ApiClient(apiClient)
{
}
{{classname}}::~{{classname}}()
{
}
{{#operation}}
pplx::task<{{{returnType}}}{{^returnType}}void{{/returnType}}> {{classname}}::{{operationId}}({{#allParams}}{{^required}}boost::optional<{{/required}}{{{dataType}}}{{^required}}>{{/required}} {{paramName}}, {{/allParams}}const std::map<utility::string_t, utility::string_t>& customHeaders) const // <-- изменено: все параметры с запятой, + customHeaders
{
{{#allParams}}{{#required}}{{^isPrimitiveType}}{{^isContainer}}
// verify the required parameter '{{paramName}}' is set
if ({{paramName}} == nullptr)
{
throw ApiException(400, utility::conversions::to_string_t("Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}"));
}
{{/isContainer}}{{/isPrimitiveType}}{{/required}}{{/allParams}}
std::shared_ptr<const ApiConfiguration> localVarApiConfiguration( m_ApiClient->getConfiguration() );
utility::string_t localVarPath = utility::conversions::to_string_t("{{{path}}}");
{{#pathParams}}
boost::replace_all(localVarPath, utility::conversions::to_string_t("{") + utility::conversions::to_string_t("{{baseName}}") + utility::conversions::to_string_t("}"), web::uri::encode_uri(ApiClient::parameterToString({{{paramName}}})));
{{/pathParams}}
std::map<utility::string_t, utility::string_t> localVarQueryParams;
std::map<utility::string_t, utility::string_t> localVarHeaderParams( localVarApiConfiguration->getDefaultHeaders() ); // <-- уже содержит defaultHeaders
std::map<utility::string_t, utility::string_t> localVarFormParams;
std::map<utility::string_t, std::shared_ptr<HttpContent>> localVarFileParams;
std::unordered_set<utility::string_t> localVarResponseHttpContentTypes;
{{#produces}}
localVarResponseHttpContentTypes.insert( utility::conversions::to_string_t("{{{mediaType}}}") );
{{/produces}}
utility::string_t localVarResponseHttpContentType;
// use JSON if possible
if ( localVarResponseHttpContentTypes.size() == 0 )
{
{{#vendorExtensions.x-codegen-response.isString}}
localVarResponseHttpContentType = utility::conversions::to_string_t("text/plain");
{{/vendorExtensions.x-codegen-response.isString}}
{{^vendorExtensions.x-codegen-response.isString}}
localVarResponseHttpContentType = utility::conversions::to_string_t("application/json");
{{/vendorExtensions.x-codegen-response.isString}}
}
// JSON
else if ( localVarResponseHttpContentTypes.find(utility::conversions::to_string_t("application/json")) != localVarResponseHttpContentTypes.end() )
{
localVarResponseHttpContentType = utility::conversions::to_string_t("application/json");
}
// multipart formdata
else if( localVarResponseHttpContentTypes.find(utility::conversions::to_string_t("multipart/form-data")) != localVarResponseHttpContentTypes.end() )
{
localVarResponseHttpContentType = utility::conversions::to_string_t("multipart/form-data");
}
{{#vendorExtensions.x-codegen-response.isString}}
// plain text
else if( localVarResponseHttpContentTypes.find(utility::conversions::to_string_t("text/plain")) != localVarResponseHttpContentTypes.end() )
{
localVarResponseHttpContentType = utility::conversions::to_string_t("text/plain");
}
{{/vendorExtensions.x-codegen-response.isString}}
{{#vendorExtensions.x-codegen-response-ishttpcontent}}
else
{
//It's going to be binary, so just use the first one.
localVarResponseHttpContentType = *localVarResponseHttpContentTypes.begin();
}
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
{{^vendorExtensions.x-codegen-response-ishttpcontent}}
else
{
throw ApiException(400, utility::conversions::to_string_t("{{classname}}->{{operationId}} does not produce any supported media type"));
}
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
localVarHeaderParams[utility::conversions::to_string_t("Accept")] = localVarResponseHttpContentType;
std::unordered_set<utility::string_t> localVarConsumeHttpContentTypes;
{{#consumes}}
localVarConsumeHttpContentTypes.insert( utility::conversions::to_string_t("{{{mediaType}}}") );
{{/consumes}}
{{#allParams}}
{{^isBodyParam}}
{{^isPathParam}}
{{#required}}
{{^isPrimitiveType}}
{{^isContainer}}
if ({{paramName}} != nullptr)
{{/isContainer}}
{{/isPrimitiveType}}
{{/required}}
{{^required}}
{{^isPrimitiveType}}
{{^isContainer}}
if ({{paramName}} && *{{paramName}} != nullptr)
{{/isContainer}}
{{/isPrimitiveType}}
{{#isPrimitiveType}}
{{#isFile}}
if ({{paramName}} && *{{paramName}} != nullptr)
{{/isFile}}
{{^isFile}}
if ({{paramName}})
{{/isFile}}
{{/isPrimitiveType}}
{{#isContainer}}
if ({{paramName}})
{{/isContainer}}
{{/required}}
{
{{#isQueryParam}}
localVarQueryParams[utility::conversions::to_string_t("{{baseName}}")] = ApiClient::parameterToString({{^required}}*{{/required}}{{paramName}});
{{/isQueryParam}}
{{#isHeaderParam}}
localVarHeaderParams[utility::conversions::to_string_t("{{baseName}}")] = ApiClient::parameterToString({{^required}}*{{/required}}{{paramName}});
{{/isHeaderParam}}
{{#isFormParam}}
{{#isFile}}
localVarFileParams[ utility::conversions::to_string_t("{{baseName}}") ] = {{^required}}*{{/required}}{{paramName}};
{{/isFile}}
{{^isFile}}
localVarFormParams[ utility::conversions::to_string_t("{{baseName}}") ] = ApiClient::parameterToString({{^required}}*{{/required}}{{paramName}});
{{/isFile}}
{{/isFormParam}}
}
{{/isPathParam}}
{{/isBodyParam}}
{{/allParams}}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Apply customHeaders AFTER all other headers (so they can override)
for (const auto& header : customHeaders) {
localVarHeaderParams[header.first] = header.second;
}
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
std::shared_ptr<IHttpBody> localVarHttpBody;
utility::string_t localVarRequestHttpContentType;
// use JSON if possible
if ( localVarConsumeHttpContentTypes.size() == 0 || localVarConsumeHttpContentTypes.find(utility::conversions::to_string_t("application/json")) != localVarConsumeHttpContentTypes.end() )
{
localVarRequestHttpContentType = utility::conversions::to_string_t("application/json");
{{#bodyParam}}
web::json::value localVarJson;
{{#isPrimitiveType}}
localVarJson = ModelBase::toJson({{paramName}}{{^required}}.get(){{/required}});
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isArray}}
{
std::vector<web::json::value> localVarJsonArray;
for( auto& localVarItem : {{paramName}}{{^required}}.get(){{/required}} )
{
{{#items.isPrimitiveType}}localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
{{/items.isPrimitiveType}}{{^items.isPrimitiveType}}{{#items.isString}}localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
{{/items.isString}}{{^items.isString}}{{#items.isDateTime}}localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
{{/items.isDateTime}}{{^items.isDateTime}}localVarJsonArray.push_back( localVarItem.get() ? localVarItem->toJson() : web::json::value::null() );
{{/items.isDateTime}}{{/items.isString}}{{/items.isPrimitiveType}}
}
localVarJson = web::json::value::array(localVarJsonArray);
}
{{/isArray}}
{{^isArray}}{{#required}}localVarJson = ModelBase::toJson({{paramName}});
{{/required}}{{^required}}if ({{paramName}})
localVarJson = ModelBase::toJson(*{{paramName}});{{/required}}
{{/isArray}}
{{/isPrimitiveType}}
localVarHttpBody = std::shared_ptr<IHttpBody>( new JsonBody( localVarJson ) );
{{/bodyParam}}
}
// multipart formdata
else if( localVarConsumeHttpContentTypes.find(utility::conversions::to_string_t("multipart/form-data")) != localVarConsumeHttpContentTypes.end() )
{
localVarRequestHttpContentType = utility::conversions::to_string_t("multipart/form-data");
{{#bodyParam}}
std::shared_ptr<MultipartFormData> localVarMultipart(new MultipartFormData);
{{#isPrimitiveType}}
localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), {{paramName}}{{^required}}.get(){{/required}}));
{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isArray}}
{
std::vector<web::json::value> localVarJsonArray;
for( auto& localVarItem : {{paramName}}{{^required}}.get(){{/required}} )
{
localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
}
localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), localVarJsonArray, utility::conversions::to_string_t("application/json")));
}{{/isArray}}{{#isMap}}
{
std::map<utility::string_t, web::json::value> localVarJsonMap;
for( auto& localVarItem : {{paramName}}{{^required}}.get(){{/required}} )
{
web::json::value jval;
localVarJsonMap.insert( std::pair<utility::string_t, web::json::value>(localVarItem.first, ModelBase::toJson(localVarItem.second) ));
}
localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), localVarJsonMap, utility::conversions::to_string_t("application/json")));
}{{/isMap}}
{{^isArray}}{{^isMap}}{{#isString}}localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), {{paramName}}));
{{/isString}}{{^isString}}if({{^required}}{{paramName}} && (*{{paramName}}){{/required}}{{#required}}{{paramName}}{{/required}}.get())
{
{{^required}}(*{{/required}}{{paramName}}{{^required}}){{/required}}->toMultipart(localVarMultipart, utility::conversions::to_string_t("{{paramName}}"));
}
{{/isString}}
{{/isMap}}{{/isArray}}{{/isPrimitiveType}}
localVarHttpBody = localVarMultipart;
localVarRequestHttpContentType += utility::conversions::to_string_t("; boundary=") + localVarMultipart->getBoundary();
{{/bodyParam}}
}
else if (localVarConsumeHttpContentTypes.find(utility::conversions::to_string_t("application/x-www-form-urlencoded")) != localVarConsumeHttpContentTypes.end())
{
localVarRequestHttpContentType = utility::conversions::to_string_t("application/x-www-form-urlencoded");
}
else
{
throw ApiException(415, utility::conversions::to_string_t("{{classname}}->{{operationId}} does not consume any supported media type"));
}
{{#authMethods}}
// authentication ({{name}}) required
{{#isApiKey}}
{{#isKeyInHeader}}
{
utility::string_t localVarApiKey = localVarApiConfiguration->getApiKey(utility::conversions::to_string_t("{{keyParamName}}"));
if ( localVarApiKey.size() > 0 )
{
localVarHeaderParams[utility::conversions::to_string_t("{{keyParamName}}")] = localVarApiKey;
}
}
{{/isKeyInHeader}}
{{#isKeyInQuery}}
{
utility::string_t localVarApiKey = localVarApiConfiguration->getApiKey(utility::conversions::to_string_t("{{keyParamName}}"));
if ( localVarApiKey.size() > 0 )
{
localVarQueryParams[utility::conversions::to_string_t("{{keyParamName}}")] = localVarApiKey;
}
}
{{/isKeyInQuery}}
{{/isApiKey}}
{{#isBasicBasic}}
// Basic authentication is added automatically as part of the http_client_config
{{/isBasicBasic}}
{{#isOAuth}}
// oauth2 authentication is added automatically as part of the http_client_config
{{/isOAuth}}
{{/authMethods}}
return m_ApiClient->callApi(localVarPath, utility::conversions::to_string_t("{{httpMethod}}"), localVarQueryParams, localVarHttpBody, localVarHeaderParams, localVarFormParams, localVarFileParams, localVarRequestHttpContentType)
.then([=, this](web::http::http_response localVarResponse)
{
if (m_ApiClient->getResponseHandler())
{
m_ApiClient->getResponseHandler()(localVarResponse.status_code(), localVarResponse.headers());
}
// 1xx - informational : OK
// 2xx - successful : OK
// 3xx - redirection : OK
// 4xx - client error : not OK
// 5xx - client error : not OK
if (localVarResponse.status_code() >= 400)
{
throw ApiException(localVarResponse.status_code()
, utility::conversions::to_string_t("error calling {{operationId}}: ") + localVarResponse.reason_phrase()
, std::make_shared<std::stringstream>(localVarResponse.extract_utf8string(true).get()));
}
// check response content type
if(localVarResponse.headers().has(utility::conversions::to_string_t("Content-Type")))
{
utility::string_t localVarContentType = localVarResponse.headers()[utility::conversions::to_string_t("Content-Type")];
if( localVarContentType.find(localVarResponseHttpContentType) == std::string::npos )
{
throw ApiException(500
, utility::conversions::to_string_t("error calling {{operationId}}: unexpected response type: ") + localVarContentType
, std::make_shared<std::stringstream>(localVarResponse.extract_utf8string(true).get()));
}
}
{{#vendorExtensions.x-codegen-response-ishttpcontent}}
return localVarResponse.extract_vector();
})
.then([=, this](std::vector<unsigned char> localVarResponse)
{
{{{returnType}}} localVarResult = std::make_shared<HttpContent>();
std::shared_ptr<std::stringstream> stream = std::make_shared<std::stringstream>(std::string(localVarResponse.begin(), localVarResponse.end()));
localVarResult->setData(stream);
return localVarResult;
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
{{^vendorExtensions.x-codegen-response-ishttpcontent}}
return localVarResponse.extract_string();
})
.then([=, this](utility::string_t localVarResponse)
{
{{^returnType}}
return void();
{{/returnType}}
{{#returnType}}
{{#returnContainer}}
{{{returnType}}} localVarResult;
{{/returnContainer}}
{{^returnContainer}}
{{{returnType}}} localVarResult({{{defaultResponse}}});
{{/returnContainer}}
if(localVarResponseHttpContentType == utility::conversions::to_string_t("application/json"))
{
web::json::value localVarJson = web::json::value::parse(localVarResponse);
{{#isArray}}
for( auto& localVarItem : localVarJson.as_array() )
{
{{{vendorExtensions.x-codegen-response.items.datatype}}} localVarItemObj;
ModelBase::fromJson(localVarItem, localVarItemObj);
localVarResult.push_back(localVarItemObj);
}{{/isArray}}{{#isMap}}
for( auto& localVarItem : localVarJson.as_object() )
{
{{{vendorExtensions.x-codegen-response.items.datatype}}} localVarItemObj;
ModelBase::fromJson(localVarItem.second, localVarItemObj);
localVarResult[localVarItem.first] = localVarItemObj;
}{{/isMap}}{{^isArray}}{{^isMap}}
ModelBase::fromJson(localVarJson, localVarResult);{{/isMap}}{{/isArray}}
}{{#vendorExtensions.x-codegen-response.isString}}
else if(localVarResponseHttpContentType == utility::conversions::to_string_t("text/plain"))
{
localVarResult = localVarResponse;
}{{/vendorExtensions.x-codegen-response.isString}}
// else if(localVarResponseHttpContentType == utility::conversions::to_string_t("multipart/form-data"))
// {
// TODO multipart response parsing
// }
else
{
throw ApiException(500
, utility::conversions::to_string_t("error calling {{operationId}}: unsupported response type"));
}
return localVarResult;
{{/returnType}}
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
});
}
{{/operation}}
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
{{/operations}}

View file

@ -0,0 +1,368 @@
{{>licenseInfo}}
{{#operations}}
#include "{{packageName}}/api/{{classname}}.h"
#include "{{packageName}}/IHttpBody.h"
#include "{{packageName}}/JsonBody.h"
#include "{{packageName}}/MultipartFormData.h"
#include <boost/algorithm/string/replace.hpp>
#include <unordered_set>
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
using namespace {{modelNamespace}};
{{classname}}::{{classname}}( std::shared_ptr<const ApiClient> apiClient )
: m_ApiClient(apiClient)
{
}
{{classname}}::~{{classname}}()
{
}
{{#operation}}
pplx::task<{{{returnType}}}{{^returnType}}void{{/returnType}}> {{classname}}::{{operationId}}({{#allParams}}{{^required}}boost::optional<{{/required}}{{{dataType}}}{{^required}}>{{/required}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) const
{
{{#allParams}}{{#required}}{{^isPrimitiveType}}{{^isContainer}}
// verify the required parameter '{{paramName}}' is set
if ({{paramName}} == nullptr)
{
throw ApiException(400, utility::conversions::to_string_t("Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}"));
}
{{/isContainer}}{{/isPrimitiveType}}{{/required}}{{/allParams}}
std::shared_ptr<const ApiConfiguration> localVarApiConfiguration( m_ApiClient->getConfiguration() );
utility::string_t localVarPath = utility::conversions::to_string_t("{{{path}}}");
{{#pathParams}}
boost::replace_all(localVarPath, utility::conversions::to_string_t("{") + utility::conversions::to_string_t("{{baseName}}") + utility::conversions::to_string_t("}"), web::uri::encode_uri(ApiClient::parameterToString({{{paramName}}})));
{{/pathParams}}
std::map<utility::string_t, utility::string_t> localVarQueryParams;
std::map<utility::string_t, utility::string_t> localVarHeaderParams( localVarApiConfiguration->getDefaultHeaders() );
std::map<utility::string_t, utility::string_t> localVarFormParams;
std::map<utility::string_t, std::shared_ptr<HttpContent>> localVarFileParams;
std::unordered_set<utility::string_t> localVarResponseHttpContentTypes;
{{#produces}}
localVarResponseHttpContentTypes.insert( utility::conversions::to_string_t("{{{mediaType}}}") );
{{/produces}}
utility::string_t localVarResponseHttpContentType;
// use JSON if possible
if ( localVarResponseHttpContentTypes.size() == 0 )
{
{{#vendorExtensions.x-codegen-response.isString}}
localVarResponseHttpContentType = utility::conversions::to_string_t("text/plain");
{{/vendorExtensions.x-codegen-response.isString}}
{{^vendorExtensions.x-codegen-response.isString}}
localVarResponseHttpContentType = utility::conversions::to_string_t("application/json");
{{/vendorExtensions.x-codegen-response.isString}}
}
// JSON
else if ( localVarResponseHttpContentTypes.find(utility::conversions::to_string_t("application/json")) != localVarResponseHttpContentTypes.end() )
{
localVarResponseHttpContentType = utility::conversions::to_string_t("application/json");
}
// multipart formdata
else if( localVarResponseHttpContentTypes.find(utility::conversions::to_string_t("multipart/form-data")) != localVarResponseHttpContentTypes.end() )
{
localVarResponseHttpContentType = utility::conversions::to_string_t("multipart/form-data");
}
{{#vendorExtensions.x-codegen-response.isString}}
// plain text
else if( localVarResponseHttpContentTypes.find(utility::conversions::to_string_t("text/plain")) != localVarResponseHttpContentTypes.end() )
{
localVarResponseHttpContentType = utility::conversions::to_string_t("text/plain");
}
{{/vendorExtensions.x-codegen-response.isString}}
{{#vendorExtensions.x-codegen-response-ishttpcontent}}
else
{
//It's going to be binary, so just use the first one.
localVarResponseHttpContentType = *localVarResponseHttpContentTypes.begin();
}
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
{{^vendorExtensions.x-codegen-response-ishttpcontent}}
else
{
throw ApiException(400, utility::conversions::to_string_t("{{classname}}->{{operationId}} does not produce any supported media type"));
}
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
localVarHeaderParams[utility::conversions::to_string_t("Accept")] = localVarResponseHttpContentType;
std::unordered_set<utility::string_t> localVarConsumeHttpContentTypes;
{{#consumes}}
localVarConsumeHttpContentTypes.insert( utility::conversions::to_string_t("{{{mediaType}}}") );
{{/consumes}}
{{#allParams}}
{{^isBodyParam}}
{{^isPathParam}}
{{#required}}
{{^isPrimitiveType}}
{{^isContainer}}
if ({{paramName}} != nullptr)
{{/isContainer}}
{{/isPrimitiveType}}
{{/required}}
{{^required}}
{{^isPrimitiveType}}
{{^isContainer}}
if ({{paramName}} && *{{paramName}} != nullptr)
{{/isContainer}}
{{/isPrimitiveType}}
{{#isPrimitiveType}}
{{#isFile}}
if ({{paramName}} && *{{paramName}} != nullptr)
{{/isFile}}
{{^isFile}}
if ({{paramName}})
{{/isFile}}
{{/isPrimitiveType}}
{{#isContainer}}
if ({{paramName}})
{{/isContainer}}
{{/required}}
{
{{#isQueryParam}}
localVarQueryParams[utility::conversions::to_string_t("{{baseName}}")] = ApiClient::parameterToString({{^required}}*{{/required}}{{paramName}});
{{/isQueryParam}}
{{#isHeaderParam}}
localVarHeaderParams[utility::conversions::to_string_t("{{baseName}}")] = ApiClient::parameterToString({{^required}}*{{/required}}{{paramName}});
{{/isHeaderParam}}
{{#isFormParam}}
{{#isFile}}
localVarFileParams[ utility::conversions::to_string_t("{{baseName}}") ] = {{^required}}*{{/required}}{{paramName}};
{{/isFile}}
{{^isFile}}
localVarFormParams[ utility::conversions::to_string_t("{{baseName}}") ] = ApiClient::parameterToString({{^required}}*{{/required}}{{paramName}});
{{/isFile}}
{{/isFormParam}}
}
{{/isPathParam}}
{{/isBodyParam}}
{{/allParams}}
std::shared_ptr<IHttpBody> localVarHttpBody;
utility::string_t localVarRequestHttpContentType;
// use JSON if possible
if ( localVarConsumeHttpContentTypes.size() == 0 || localVarConsumeHttpContentTypes.find(utility::conversions::to_string_t("application/json")) != localVarConsumeHttpContentTypes.end() )
{
localVarRequestHttpContentType = utility::conversions::to_string_t("application/json");
{{#bodyParam}}
web::json::value localVarJson;
{{#isPrimitiveType}}
localVarJson = ModelBase::toJson({{paramName}}{{^required}}.get(){{/required}});
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isArray}}
{
std::vector<web::json::value> localVarJsonArray;
for( auto& localVarItem : {{paramName}}{{^required}}.get(){{/required}} )
{
{{#items.isPrimitiveType}}localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
{{/items.isPrimitiveType}}{{^items.isPrimitiveType}}{{#items.isString}}localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
{{/items.isString}}{{^items.isString}}{{#items.isDateTime}}localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
{{/items.isDateTime}}{{^items.isDateTime}}localVarJsonArray.push_back( localVarItem.get() ? localVarItem->toJson() : web::json::value::null() );
{{/items.isDateTime}}{{/items.isString}}{{/items.isPrimitiveType}}
}
localVarJson = web::json::value::array(localVarJsonArray);
}
{{/isArray}}
{{^isArray}}{{#required}}localVarJson = ModelBase::toJson({{paramName}});
{{/required}}{{^required}}if ({{paramName}})
localVarJson = ModelBase::toJson(*{{paramName}});{{/required}}
{{/isArray}}
{{/isPrimitiveType}}
localVarHttpBody = std::shared_ptr<IHttpBody>( new JsonBody( localVarJson ) );
{{/bodyParam}}
}
// multipart formdata
else if( localVarConsumeHttpContentTypes.find(utility::conversions::to_string_t("multipart/form-data")) != localVarConsumeHttpContentTypes.end() )
{
localVarRequestHttpContentType = utility::conversions::to_string_t("multipart/form-data");
{{#bodyParam}}
std::shared_ptr<MultipartFormData> localVarMultipart(new MultipartFormData);
{{#isPrimitiveType}}
localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), {{paramName}}{{^required}}.get(){{/required}}));
{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isArray}}
{
std::vector<web::json::value> localVarJsonArray;
for( auto& localVarItem : {{paramName}}{{^required}}.get(){{/required}} )
{
localVarJsonArray.push_back(ModelBase::toJson(localVarItem));
}
localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), localVarJsonArray, utility::conversions::to_string_t("application/json")));
}{{/isArray}}{{#isMap}}
{
std::map<utility::string_t, web::json::value> localVarJsonMap;
for( auto& localVarItem : {{paramName}}{{^required}}.get(){{/required}} )
{
web::json::value jval;
localVarJsonMap.insert( std::pair<utility::string_t, web::json::value>(localVarItem.first, ModelBase::toJson(localVarItem.second) ));
}
localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), localVarJsonMap, utility::conversions::to_string_t("application/json")));
}{{/isMap}}
{{^isArray}}{{^isMap}}{{#isString}}localVarMultipart->add(ModelBase::toHttpContent(utility::conversions::to_string_t("{{paramName}}"), {{paramName}}));
{{/isString}}{{^isString}}if({{^required}}{{paramName}} && (*{{paramName}}){{/required}}{{#required}}{{paramName}}{{/required}}.get())
{
{{^required}}(*{{/required}}{{paramName}}{{^required}}){{/required}}->toMultipart(localVarMultipart, utility::conversions::to_string_t("{{paramName}}"));
}
{{/isString}}
{{/isMap}}{{/isArray}}{{/isPrimitiveType}}
localVarHttpBody = localVarMultipart;
localVarRequestHttpContentType += utility::conversions::to_string_t("; boundary=") + localVarMultipart->getBoundary();
{{/bodyParam}}
}
else if (localVarConsumeHttpContentTypes.find(utility::conversions::to_string_t("application/x-www-form-urlencoded")) != localVarConsumeHttpContentTypes.end())
{
localVarRequestHttpContentType = utility::conversions::to_string_t("application/x-www-form-urlencoded");
}
else
{
throw ApiException(415, utility::conversions::to_string_t("{{classname}}->{{operationId}} does not consume any supported media type"));
}
{{#authMethods}}
// authentication ({{name}}) required
{{#isApiKey}}
{{#isKeyInHeader}}
{
utility::string_t localVarApiKey = localVarApiConfiguration->getApiKey(utility::conversions::to_string_t("{{keyParamName}}"));
if ( localVarApiKey.size() > 0 )
{
localVarHeaderParams[utility::conversions::to_string_t("{{keyParamName}}")] = localVarApiKey;
}
}
{{/isKeyInHeader}}
{{#isKeyInQuery}}
{
utility::string_t localVarApiKey = localVarApiConfiguration->getApiKey(utility::conversions::to_string_t("{{keyParamName}}"));
if ( localVarApiKey.size() > 0 )
{
localVarQueryParams[utility::conversions::to_string_t("{{keyParamName}}")] = localVarApiKey;
}
}
{{/isKeyInQuery}}
{{/isApiKey}}
{{#isBasicBasic}}
// Basic authentication is added automatically as part of the http_client_config
{{/isBasicBasic}}
{{#isOAuth}}
// oauth2 authentication is added automatically as part of the http_client_config
{{/isOAuth}}
{{/authMethods}}
return m_ApiClient->callApi(localVarPath, utility::conversions::to_string_t("{{httpMethod}}"), localVarQueryParams, localVarHttpBody, localVarHeaderParams, localVarFormParams, localVarFileParams, localVarRequestHttpContentType)
.then([=, this](web::http::http_response localVarResponse)
{
if (m_ApiClient->getResponseHandler())
{
m_ApiClient->getResponseHandler()(localVarResponse.status_code(), localVarResponse.headers());
}
// 1xx - informational : OK
// 2xx - successful : OK
// 3xx - redirection : OK
// 4xx - client error : not OK
// 5xx - client error : not OK
if (localVarResponse.status_code() >= 400)
{
throw ApiException(localVarResponse.status_code()
, utility::conversions::to_string_t("error calling {{operationId}}: ") + localVarResponse.reason_phrase()
, std::make_shared<std::stringstream>(localVarResponse.extract_utf8string(true).get()));
}
// check response content type
if(localVarResponse.headers().has(utility::conversions::to_string_t("Content-Type")))
{
utility::string_t localVarContentType = localVarResponse.headers()[utility::conversions::to_string_t("Content-Type")];
if( localVarContentType.find(localVarResponseHttpContentType) == std::string::npos )
{
throw ApiException(500
, utility::conversions::to_string_t("error calling {{operationId}}: unexpected response type: ") + localVarContentType
, std::make_shared<std::stringstream>(localVarResponse.extract_utf8string(true).get()));
}
}
{{#vendorExtensions.x-codegen-response-ishttpcontent}}
return localVarResponse.extract_vector();
})
.then([=, this](std::vector<unsigned char> localVarResponse)
{
{{{returnType}}} localVarResult = std::make_shared<HttpContent>();
std::shared_ptr<std::stringstream> stream = std::make_shared<std::stringstream>(std::string(localVarResponse.begin(), localVarResponse.end()));
localVarResult->setData(stream);
return localVarResult;
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
{{^vendorExtensions.x-codegen-response-ishttpcontent}}
return localVarResponse.extract_string();
})
.then([=, this](utility::string_t localVarResponse)
{
{{^returnType}}
return void();
{{/returnType}}
{{#returnType}}
{{#returnContainer}}
{{{returnType}}} localVarResult;
{{/returnContainer}}
{{^returnContainer}}
{{{returnType}}} localVarResult({{{defaultResponse}}});
{{/returnContainer}}
if(localVarResponseHttpContentType == utility::conversions::to_string_t("application/json"))
{
web::json::value localVarJson = web::json::value::parse(localVarResponse);
{{#isArray}}
for( auto& localVarItem : localVarJson.as_array() )
{
{{{vendorExtensions.x-codegen-response.items.datatype}}} localVarItemObj;
ModelBase::fromJson(localVarItem, localVarItemObj);
localVarResult.push_back(localVarItemObj);
}{{/isArray}}{{#isMap}}
for( auto& localVarItem : localVarJson.as_object() )
{
{{{vendorExtensions.x-codegen-response.items.datatype}}} localVarItemObj;
ModelBase::fromJson(localVarItem.second, localVarItemObj);
localVarResult[localVarItem.first] = localVarItemObj;
}{{/isMap}}{{^isArray}}{{^isMap}}
ModelBase::fromJson(localVarJson, localVarResult);{{/isMap}}{{/isArray}}
}{{#vendorExtensions.x-codegen-response.isString}}
else if(localVarResponseHttpContentType == utility::conversions::to_string_t("text/plain"))
{
localVarResult = localVarResponse;
}{{/vendorExtensions.x-codegen-response.isString}}
// else if(localVarResponseHttpContentType == utility::conversions::to_string_t("multipart/form-data"))
// {
// TODO multipart response parsing
// }
else
{
throw ApiException(500
, utility::conversions::to_string_t("error calling {{operationId}}: unsupported response type"));
}
return localVarResult;
{{/returnType}}
{{/vendorExtensions.x-codegen-response-ishttpcontent}}
});
}
{{/operation}}
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
{{/operations}}

View file

@ -0,0 +1,107 @@
{{>licenseInfo}}
/*
* ApiClient.h
*
* This is an API client responsible for stating the HTTP calls
*/
#ifndef {{apiHeaderGuardPrefix}}_ApiClient_H_
#define {{apiHeaderGuardPrefix}}_ApiClient_H_
{{{defaultInclude}}}
#include "{{packageName}}/ApiConfiguration.h"
#include "{{packageName}}/ApiException.h"
#include "{{packageName}}/IHttpBody.h"
#include "{{packageName}}/HttpContent.h"
{{^hasModelImport}}
#include "{{packageName}}/ModelBase.h"
{{/hasModelImport}}
#if defined (_WIN32) || defined (_WIN64)
#undef U
#endif
#include <cpprest/details/basic_types.h>
#include <cpprest/http_client.h>
#include <memory>
#include <vector>
#include <functional>
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
using namespace {{modelNamespace}};
class {{declspec}} ApiClient
{
public:
ApiClient( std::shared_ptr<const ApiConfiguration> configuration = nullptr );
virtual ~ApiClient();
typedef std::function<void(web::http::status_code, const web::http::http_headers&)> ResponseHandlerType;
const ResponseHandlerType& getResponseHandler() const;
void setResponseHandler(const ResponseHandlerType& responseHandler);
std::shared_ptr<const ApiConfiguration> getConfiguration() const;
void setConfiguration(std::shared_ptr<const ApiConfiguration> configuration);
static utility::string_t parameterToString(utility::string_t value);
static utility::string_t parameterToString(int32_t value);
static utility::string_t parameterToString(int64_t value);
static utility::string_t parameterToString(float value);
static utility::string_t parameterToString(double value);
static utility::string_t parameterToString(const utility::datetime &value);
static utility::string_t parameterToString(bool value);
{{^hasModelImport}}
static utility::string_t parameterToString(const ModelBase& value);
{{/hasModelImport}}
template<class T>
static utility::string_t parameterToString(const std::vector<T>& value);
template<class T>
static utility::string_t parameterToString(const std::shared_ptr<T>& value);
pplx::task<web::http::http_response> callApi(
const utility::string_t& path,
const utility::string_t& method,
const std::map<utility::string_t, utility::string_t>& queryParams,
const std::shared_ptr<IHttpBody> postBody,
const std::map<utility::string_t, utility::string_t>& headerParams,
const std::map<utility::string_t, utility::string_t>& formParams,
const std::map<utility::string_t, std::shared_ptr<HttpContent>>& fileParams,
const utility::string_t& contentType
) const;
protected:
ResponseHandlerType m_ResponseHandler;
std::shared_ptr<const ApiConfiguration> m_Configuration;
};
template<class T>
utility::string_t ApiClient::parameterToString(const std::vector<T>& value)
{
utility::stringstream_t ss;
for( size_t i = 0; i < value.size(); i++)
{
if( i > 0) ss << utility::conversions::to_string_t(", ");
ss << ApiClient::parameterToString(value[i]);
}
return ss.str();
}
template<class T>
utility::string_t ApiClient::parameterToString(const std::shared_ptr<T>& value)
{
return parameterToString(*value.get());
}
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
#endif /* {{apiHeaderGuardPrefix}}_ApiClient_H_ */

View file

@ -0,0 +1,203 @@
{{>licenseInfo}}
#include "{{packageName}}/ApiClient.h"
#include "{{packageName}}/MultipartFormData.h"
#include "{{packageName}}/ModelBase.h"
#include <sstream>
#include <limits>
#include <iomanip>
template <typename T>
utility::string_t toString(const T value)
{
utility::ostringstream_t out;
out << std::setprecision(std::numeric_limits<T>::digits10) << std::fixed << value;
return out.str();
}
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
using namespace {{modelNamespace}};
ApiClient::ApiClient(std::shared_ptr<const ApiConfiguration> configuration )
: m_Configuration(configuration)
{
}
ApiClient::~ApiClient()
{
}
const ApiClient::ResponseHandlerType& ApiClient::getResponseHandler() const {
return m_ResponseHandler;
}
void ApiClient::setResponseHandler(const ResponseHandlerType& responseHandler) {
m_ResponseHandler = responseHandler;
}
std::shared_ptr<const ApiConfiguration> ApiClient::getConfiguration() const
{
return m_Configuration;
}
void ApiClient::setConfiguration(std::shared_ptr<const ApiConfiguration> configuration)
{
m_Configuration = configuration;
}
utility::string_t ApiClient::parameterToString(utility::string_t value)
{
return value;
}
utility::string_t ApiClient::parameterToString(int64_t value)
{
std::stringstream valueAsStringStream;
valueAsStringStream << value;
return utility::conversions::to_string_t(valueAsStringStream.str());
}
utility::string_t ApiClient::parameterToString(int32_t value)
{
std::stringstream valueAsStringStream;
valueAsStringStream << value;
return utility::conversions::to_string_t(valueAsStringStream.str());
}
utility::string_t ApiClient::parameterToString(float value)
{
return utility::conversions::to_string_t(toString(value));
}
utility::string_t ApiClient::parameterToString(double value)
{
return utility::conversions::to_string_t(toString(value));
}
utility::string_t ApiClient::parameterToString(const utility::datetime &value)
{
return utility::conversions::to_string_t(value.to_string(utility::datetime::ISO_8601));
}
{{^hasModelImport}}
utility::string_t ApiClient::parameterToString(const ModelBase& value)
{
return value.toJson().serialize();
}
{{/hasModelImport}}
utility::string_t ApiClient::parameterToString(bool value)
{
std::stringstream valueAsStringStream;
valueAsStringStream << std::boolalpha << value;
return utility::conversions::to_string_t(valueAsStringStream.str());
}
pplx::task<web::http::http_response> ApiClient::callApi(
const utility::string_t& path,
const utility::string_t& method,
const std::map<utility::string_t, utility::string_t>& queryParams,
const std::shared_ptr<IHttpBody> postBody,
const std::map<utility::string_t, utility::string_t>& headerParams,
const std::map<utility::string_t, utility::string_t>& formParams,
const std::map<utility::string_t, std::shared_ptr<HttpContent>>& fileParams,
const utility::string_t& contentType
) const
{
if (postBody != nullptr && formParams.size() != 0)
{
throw ApiException(400, utility::conversions::to_string_t("Cannot have body and form params"));
}
if (postBody != nullptr && fileParams.size() != 0)
{
throw ApiException(400, utility::conversions::to_string_t("Cannot have body and file params"));
}
if (fileParams.size() > 0 && contentType != utility::conversions::to_string_t("multipart/form-data"))
{
throw ApiException(400, utility::conversions::to_string_t("Operations with file parameters must be called with multipart/form-data"));
}
web::http::client::http_client client(m_Configuration->getBaseUrl(), m_Configuration->getHttpConfig());
web::http::http_request request;
for (const auto& kvp : headerParams)
{
request.headers().add(kvp.first, kvp.second);
}
if (fileParams.size() > 0)
{
MultipartFormData uploadData;
for (const auto& kvp : formParams)
{
uploadData.add(ModelBase::toHttpContent(kvp.first, kvp.second));
}
for (const auto& kvp : fileParams)
{
uploadData.add(ModelBase::toHttpContent(kvp.first, kvp.second));
}
std::stringstream data;
uploadData.writeTo(data);
auto bodyString = data.str();
const auto length = bodyString.size();
request.set_body(concurrency::streams::bytestream::open_istream(std::move(bodyString)), length, utility::conversions::to_string_t("multipart/form-data; boundary=") + uploadData.getBoundary());
}
else
{
if (postBody != nullptr)
{
std::stringstream data;
postBody->writeTo(data);
auto bodyString = data.str();
const auto length = bodyString.size();
request.set_body(concurrency::streams::bytestream::open_istream(std::move(bodyString)), length, contentType);
}
else
{
if (contentType == utility::conversions::to_string_t("application/json"))
{
web::json::value body_data = web::json::value::object();
for (auto& kvp : formParams)
{
body_data[kvp.first] = ModelBase::toJson(kvp.second);
}
if (!formParams.empty())
{
request.set_body(body_data);
}
}
else
{
web::http::uri_builder formData;
for (const auto& kvp : formParams)
{
formData.append_query(kvp.first, kvp.second);
}
if (!formParams.empty())
{
request.set_body(formData.query(), utility::conversions::to_string_t("application/x-www-form-urlencoded"));
}
}
}
}
web::http::uri_builder builder(path);
for (const auto& kvp : queryParams)
{
builder.append_query(kvp.first, kvp.second);
}
request.set_request_uri(builder.to_uri());
request.set_method(method);
if ( !request.headers().has( web::http::header_names::user_agent ) )
{
request.headers().add( web::http::header_names::user_agent, m_Configuration->getUserAgent() );
}
return client.request(request);
}
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

View file

@ -0,0 +1,54 @@
{{>licenseInfo}}
/*
* ApiConfiguration.h
*
* This class represents a single item of a multipart-formdata request.
*/
#ifndef {{apiHeaderGuardPrefix}}_ApiConfiguration_H_
#define {{apiHeaderGuardPrefix}}_ApiConfiguration_H_
{{{defaultInclude}}}
#include <cpprest/details/basic_types.h>
#include <cpprest/http_client.h>
#include <map>
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
class {{declspec}} ApiConfiguration
{
public:
ApiConfiguration();
virtual ~ApiConfiguration();
const web::http::client::http_client_config& getHttpConfig() const;
void setHttpConfig( web::http::client::http_client_config& value );
utility::string_t getBaseUrl() const;
void setBaseUrl( const utility::string_t value );
utility::string_t getUserAgent() const;
void setUserAgent( const utility::string_t value );
std::map<utility::string_t, utility::string_t>& getDefaultHeaders();
const std::map<utility::string_t, utility::string_t>& getDefaultHeaders() const;
utility::string_t getApiKey( const utility::string_t& prefix) const;
void setApiKey( const utility::string_t& prefix, const utility::string_t& apiKey );
protected:
utility::string_t m_BaseUrl;
std::map<utility::string_t, utility::string_t> m_DefaultHeaders;
std::map<utility::string_t, utility::string_t> m_ApiKeys;
web::http::client::http_client_config m_HttpConfig;
utility::string_t m_UserAgent;
};
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
#endif /* {{apiHeaderGuardPrefix}}_ApiConfiguration_H_ */

View file

@ -0,0 +1,73 @@
{{>licenseInfo}}
#include "{{packageName}}/ApiConfiguration.h"
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
ApiConfiguration::ApiConfiguration()
{
}
ApiConfiguration::~ApiConfiguration()
{
}
const web::http::client::http_client_config& ApiConfiguration::getHttpConfig() const
{
return m_HttpConfig;
}
void ApiConfiguration::setHttpConfig( web::http::client::http_client_config& value )
{
m_HttpConfig = value;
}
utility::string_t ApiConfiguration::getBaseUrl() const
{
return m_BaseUrl;
}
void ApiConfiguration::setBaseUrl( const utility::string_t value )
{
m_BaseUrl = value;
}
utility::string_t ApiConfiguration::getUserAgent() const
{
return m_UserAgent;
}
void ApiConfiguration::setUserAgent( const utility::string_t value )
{
m_UserAgent = value;
}
std::map<utility::string_t, utility::string_t>& ApiConfiguration::getDefaultHeaders()
{
return m_DefaultHeaders;
}
const std::map<utility::string_t, utility::string_t>& ApiConfiguration::getDefaultHeaders() const
{
return m_DefaultHeaders;
}
utility::string_t ApiConfiguration::getApiKey( const utility::string_t& prefix) const
{
auto result = m_ApiKeys.find(prefix);
if( result != m_ApiKeys.end() )
{
return result->second;
}
return utility::conversions::to_string_t("");
}
void ApiConfiguration::setApiKey( const utility::string_t& prefix, const utility::string_t& apiKey )
{
m_ApiKeys[prefix] = apiKey;
}
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

View file

@ -0,0 +1,48 @@
{{>licenseInfo}}
/*
* ApiException.h
*
* This is the exception being thrown in case the api call was not successful
*/
#ifndef {{apiHeaderGuardPrefix}}_ApiException_H_
#define {{apiHeaderGuardPrefix}}_ApiException_H_
{{{defaultInclude}}}
#include <cpprest/details/basic_types.h>
#include <cpprest/http_msg.h>
#include <memory>
#include <map>
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
class {{declspec}} ApiException
: public web::http::http_exception
{
public:
ApiException( int errorCode
, const utility::string_t& message
, std::shared_ptr<std::istream> content = nullptr );
ApiException( int errorCode
, const utility::string_t& message
, std::map<utility::string_t, utility::string_t>& headers
, std::shared_ptr<std::istream> content = nullptr );
virtual ~ApiException();
std::map<utility::string_t, utility::string_t>& getHeaders();
std::shared_ptr<std::istream> getContent() const;
protected:
std::shared_ptr<std::istream> m_Content;
std::map<utility::string_t, utility::string_t> m_Headers;
};
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}
#endif /* {{apiHeaderGuardPrefix}}_ApiBase_H_ */

View file

@ -0,0 +1,41 @@
{{>licenseInfo}}
#include "{{packageName}}/ApiException.h"
{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}
ApiException::ApiException( int errorCode
, const utility::string_t& message
, std::shared_ptr<std::istream> content /*= nullptr*/ )
: web::http::http_exception( errorCode, message )
, m_Content(content)
{
}
ApiException::ApiException( int errorCode
, const utility::string_t& message
, std::map<utility::string_t, utility::string_t>& headers
, std::shared_ptr<std::istream> content /*= nullptr*/ )
: web::http::http_exception( errorCode, message )
, m_Content(content)
, m_Headers(headers)
{
}
ApiException::~ApiException()
{
}
std::shared_ptr<std::istream> ApiException::getContent() const
{
return m_Content;
}
std::map<utility::string_t, utility::string_t>& ApiException::getHeaders()
{
return m_Headers;
}
{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

View file

@ -0,0 +1,5 @@
@PACKAGE_INIT@
include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake)
check_required_components("@PROJECT_NAME@")

View file

@ -0,0 +1,91 @@
#
# {{{appName}}}
# {{{appDescription}}}
#
# The version of the OpenAPI document: 1.0.0
#
# https://openapi-generator.tech
#
# NOTE: Auto generated by OpenAPI Generator (https://openapi-generator.tech).
cmake_minimum_required (VERSION 3.10)
project({{{packageName}}} CXX)
# Force -fPIC even if the project is configured for building a static library.
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_CXX_STANDARD)
if(DEFINED CMAKE_CXX20_STANDARD_COMPILE_OPTION OR
DEFINED CMAKE_CXX20_EXTENSION_COMPILE_OPTION)
set(CMAKE_CXX_STANDARD 20)
elseif(DEFINED CMAKE_CXX17_STANDARD_COMPILE_OPTION OR
DEFINED CMAKE_CXX17_EXTENSION_COMPILE_OPTION)
set(CMAKE_CXX_STANDARD 17)
elseif(DEFINED CMAKE_CXX14_STANDARD_COMPILE_OPTION OR
DEFINED CMAKE_CXX14_EXTENSION_COMPILE_OPTION)
set(CMAKE_CXX_STANDARD 14)
else()
set(CMAKE_CXX_STANDARD 11)
endif()
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
find_package(cpprestsdk REQUIRED)
target_compile_definitions(cpprestsdk::cpprest INTERFACE _TURN_OFF_PLATFORM_STRING)
find_package(Boost REQUIRED)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
file(GLOB_RECURSE HEADER_FILES "include/*.h")
file(GLOB_RECURSE SOURCE_FILES "src/*.cpp")
add_library(${PROJECT_NAME} ${HEADER_FILES} ${SOURCE_FILES})
target_compile_options(${PROJECT_NAME}
PRIVATE
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
-Wall -Wno-unused-variable -Wno-unused-lambda-capture>
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(${PROJECT_NAME} PUBLIC Boost::headers cpprestsdk::cpprest)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
install(
EXPORT ${PROJECT_NAME}Targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)

View file

@ -0,0 +1,57 @@
#!/bin/sh
# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/
#
# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com"
git_user_id=$1
git_repo_id=$2
release_note=$3
git_host=$4
if [ "$git_host" = "" ]; then
git_host="{{{gitHost}}}"
echo "[INFO] No command line input provided. Set \$git_host to $git_host"
fi
if [ "$git_user_id" = "" ]; then
git_user_id="{{{gitUserId}}}"
echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id"
fi
if [ "$git_repo_id" = "" ]; then
git_repo_id="{{{gitRepoId}}}"
echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id"
fi
if [ "$release_note" = "" ]; then
release_note="{{{releaseNote}}}"
echo "[INFO] No command line input provided. Set \$release_note to $release_note"
fi
# Initialize the local directory as a Git repository
git init
# Adds the files in the local repository and stages them for commit.
git add .
# Commits the tracked changes and prepares them to be pushed to a remote repository.
git commit -m "$release_note"
# Sets the new remote
git_remote=$(git remote)
if [ "$git_remote" = "" ]; then # git remote not defined
if [ "$GIT_TOKEN" = "" ]; then
echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment."
git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git
else
git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git
fi
fi
git pull origin master
# Pushes (Forces) the changes in the local repository up to the remote repository
echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git"
git push origin master 2>&1 | grep -v 'To https'

View file

@ -0,0 +1,29 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app

View file

@ -0,0 +1,57 @@
{{>licenseInfo}}
/*
* HttpContent.h
*
* This class represents a single item of a multipart-formdata request.
*/
#ifndef {{modelHeaderGuardPrefix}}_HttpContent_H_
#define {{modelHeaderGuardPrefix}}_HttpContent_H_
{{{defaultInclude}}}
#include <cpprest/details/basic_types.h>
#include <memory>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
class {{declspec}} HttpContent
{
public:
HttpContent();
virtual ~HttpContent();
virtual utility::string_t getContentDisposition() const;
virtual void setContentDisposition( const utility::string_t& value );
virtual utility::string_t getName() const;
virtual void setName( const utility::string_t& value );
virtual utility::string_t getFileName() const;
virtual void setFileName( const utility::string_t& value );
virtual utility::string_t getContentType() const;
virtual void setContentType( const utility::string_t& value );
virtual std::shared_ptr<std::istream> getData() const;
virtual void setData( std::shared_ptr<std::istream> value );
virtual void writeTo( std::ostream& stream );
protected:
// NOTE: no utility::string_t here because those strings can only contain ascii
utility::string_t m_ContentDisposition;
utility::string_t m_Name;
utility::string_t m_FileName;
utility::string_t m_ContentType;
std::shared_ptr<std::istream> m_Data;
};
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_HttpContent_H_ */

View file

@ -0,0 +1,74 @@
{{>licenseInfo}}
#include "{{packageName}}/HttpContent.h"
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
HttpContent::HttpContent()
{
}
HttpContent::~HttpContent()
{
}
utility::string_t HttpContent::getContentDisposition() const
{
return m_ContentDisposition;
}
void HttpContent::setContentDisposition( const utility::string_t & value )
{
m_ContentDisposition = value;
}
utility::string_t HttpContent::getName() const
{
return m_Name;
}
void HttpContent::setName( const utility::string_t & value )
{
m_Name = value;
}
utility::string_t HttpContent::getFileName() const
{
return m_FileName;
}
void HttpContent::setFileName( const utility::string_t & value )
{
m_FileName = value;
}
utility::string_t HttpContent::getContentType() const
{
return m_ContentType;
}
void HttpContent::setContentType( const utility::string_t & value )
{
m_ContentType = value;
}
std::shared_ptr<std::istream> HttpContent::getData() const
{
return m_Data;
}
void HttpContent::setData( std::shared_ptr<std::istream> value )
{
m_Data = value;
}
void HttpContent::writeTo( std::ostream& stream )
{
m_Data->seekg( 0, m_Data->beg );
stream << m_Data->rdbuf();
}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}

View file

@ -0,0 +1,30 @@
{{>licenseInfo}}
/*
* IHttpBody.h
*
* This is the interface for contents that can be sent to a remote HTTP server.
*/
#ifndef {{modelHeaderGuardPrefix}}_IHttpBody_H_
#define {{modelHeaderGuardPrefix}}_IHttpBody_H_
{{{defaultInclude}}}
#include <iostream>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
class {{declspec}} IHttpBody
{
public:
virtual ~IHttpBody() { }
virtual void writeTo( std::ostream& stream ) = 0;
};
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_IHttpBody_H_ */

View file

@ -0,0 +1,37 @@
{{>licenseInfo}}
/*
* JsonBody.h
*
* This is a JSON http body which can be submitted via http
*/
#ifndef {{modelHeaderGuardPrefix}}_JsonBody_H_
#define {{modelHeaderGuardPrefix}}_JsonBody_H_
{{{defaultInclude}}}
#include "{{packageName}}/IHttpBody.h"
#include <cpprest/json.h>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
class {{declspec}} JsonBody
: public IHttpBody
{
public:
JsonBody( const web::json::value& value );
virtual ~JsonBody();
void writeTo( std::ostream& target ) override;
protected:
web::json::value m_Json;
};
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_JsonBody_H_ */

View file

@ -0,0 +1,24 @@
{{>licenseInfo}}
#include "{{packageName}}/JsonBody.h"
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
JsonBody::JsonBody( const web::json::value& json)
: m_Json(json)
{
}
JsonBody::~JsonBody()
{
}
void JsonBody::writeTo( std::ostream& target )
{
m_Json.serialize(target);
}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}

View file

@ -0,0 +1,15 @@
/**
* {{{appName}}}
* {{{appDescription}}}
*
{{#version}}
* The version of the OpenAPI document: {{{.}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{.}}}
{{/infoEmail}}
*
* NOTE: This class is auto generated by OpenAPI-Generator {{{generatorVersion}}}.
* https://openapi-generator.tech
* Do not edit the class manually.
*/

View file

@ -0,0 +1,288 @@
{{>licenseInfo}}
{{#models}}{{#model}}/*
* {{classname}}.h
*
* {{description}}
*/
#ifndef {{modelHeaderGuardPrefix}}_{{classname}}_H_
#define {{modelHeaderGuardPrefix}}_{{classname}}_H_
{{#hasEnums}}
#include <stdexcept>
{{/hasEnums}}
{{#oneOf}}
{{#-first}}
#include <variant>
{{/-first}}
{{/oneOf}}
{{^parent}}
{{{defaultInclude}}}
#include "{{packageName}}/ModelBase.h"
{{/parent}}
{{#imports}}{{{this}}}
{{/imports}}
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
{{#vendorExtensions.x-has-forward-declarations}}
{{#vendorExtensions.x-forward-declarations}}{{.}}
{{/vendorExtensions.x-forward-declarations}}
{{/vendorExtensions.x-has-forward-declarations}}
{{#oneOf}}{{#-first}}
class {{declspec}} {{classname}}
{
public:
{{classname}}() = default;
~{{classname}}() = default;
/////////////////////////////////////////////
void validate();
web::json::value toJson() const;
template<typename Target>
bool fromJson(const web::json::value& json) {
// convert json to Target type
Target target;
if (!target.fromJson(json)) {
return false;
}
m_variantValue = target;
return true;
}
void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const;
template<typename Target>
bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) {
// convert multipart to Target type
Target target;
if (!target.fromMultiPart(multipart, namePrefix)) {
return false;
}
m_variantValue = target;
return true;
}
/////////////////////////////////////////////
/// {{classname}} members
using VariantType = std::variant<{{#oneOf}}{{^-first}}, {{/-first}}{{{.}}}{{/oneOf}}>;
const VariantType& getVariant() const;
void setVariant(VariantType value);
protected:
VariantType m_variantValue;
};
{{/-first}}{{/oneOf}}
{{^oneOf}}
{{#isEnum}}
class {{declspec}} {{classname}}
: public {{{parent}}}{{^parent}}ModelBase{{/parent}}
{
public:
{{classname}}();
{{classname}}(utility::string_t str);
operator utility::string_t() const {
return enumToStrMap.at(getValue());
}
{{! operator std::string() const {
return enumToStrMap.at(getValue());
} }}
virtual ~{{classname}}();
/////////////////////////////////////////////
/// ModelBase overrides
void validate() override;
web::json::value toJson() const override;
bool fromJson(const web::json::value& json) override;
void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const override;
bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) override;
enum class e{{classname}}
{
{{#allowableValues}}
{{#enumVars}}
{{#enumDescription}}
/// <summary>
/// {{.}}
/// </summary>
{{/enumDescription}}
{{{name}}}{{^last}},{{/last}}
{{/enumVars}}
{{/allowableValues}}
};
e{{classname}} getValue() const;
void setValue(e{{classname}} const value);
protected:
e{{classname}} m_value;
std::map<e{{classname}},utility::string_t> enumToStrMap = {
{{#allowableValues}}
{{#enumVars}}
{ e{{classname}}::{{{name}}}, _XPLATSTR("{{{name}}}") }{{^-last}},{{/-last}}
{{/enumVars}}
{{/allowableValues}}
};
std::map<utility::string_t,e{{classname}}> strToEnumMap = {
{{#allowableValues}}
{{#enumVars}}
{ _XPLATSTR("{{{name}}}"), e{{classname}}::{{{name}}} }{{^-last}},{{/-last}}
{{/enumVars}}
{{/allowableValues}}
};
};
{{/isEnum}}
{{^isEnum}}
{{#description}}
/// <summary>
/// {{description}}
/// </summary>
{{/description}}
class {{declspec}} {{classname}}
: public {{{parent}}}{{^parent}}ModelBase{{/parent}}
{
public:
{{classname}}();
virtual ~{{classname}}();
/////////////////////////////////////////////
/// ModelBase overrides
void validate() override;
web::json::value toJson() const override;
bool fromJson(const web::json::value& json) override;
void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const override;
bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) override;
/////////////////////////////////////////////
/// {{classname}} members
{{! ENUM DEFINITIONS }}
{{#vars}}
{{^isInherited}}
{{#isEnum}}
enum class {{#isContainer}}{{{enumName}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}{{/isContainer}}
{
{{#allowableValues}}
{{#enumVars}}
{{{name}}}{{^last}},{{/last}}
{{/enumVars}}
{{/allowableValues}}
};
{{#description}}
/// <summary>
/// {{description}}
/// </summary>
{{/description}}
{{/isEnum}}
{{/isInherited}}
{{/vars}}
{{#vars}}
{{^isInherited}}
{{#isEnum}}
{{#isContainer}}
{{! ENUM CONVERSIONS }}
{{{enumName}}} to{{{enumName}}}(const utility::string_t& value) const;
const utility::string_t from{{{enumName}}}(const {{{enumName}}} value) const;
{{#isArray}}
{{{datatypeWithEnum}}} to{{{enumName}}}(const {{{dataType}}}& value) const;
{{{dataType}}} from{{{enumName}}}(const {{{datatypeWithEnum}}}& value) const;
{{/isArray}}{{/isContainer}}{{^isContainer}}
{{{datatypeWithEnum}}} to{{{datatypeWithEnum}}}(const utility::string_t& value) const;
const utility::string_t from{{{datatypeWithEnum}}}(const {{{datatypeWithEnum}}} value) const;
{{/isContainer}}
{{/isEnum}}
{{/isInherited}}
{{/vars}}
{{! SETTER AND GETTERS }}
{{#vars}}
{{^isInherited}}
{{#description}}
/// <summary>
/// {{description}}
/// </summary>
{{/description}}
{{#isContainer}}
{{^isEnum}}
{{{dataType}}} {{getter}}() const;
{{/isEnum}}
{{/isContainer}}
{{^isContainer}}
{{^isEnum}}
{{{dataType}}} {{getter}}() const;
{{/isEnum}}
{{/isContainer}}
{{#isEnum}}
{{^isMap}}
{{{datatypeWithEnum}}} {{getter}}() const;
{{/isMap}}
{{#isMap}}
{{{dataType}}} {{getter}}() const;
{{/isMap}}
{{/isEnum}}
bool {{nameInCamelCase}}IsSet() const;
void unset{{name}}();
{{#isPrimitiveType}}
void {{setter}}({{{dataType}}} value);
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{^isEnum}}
void {{setter}}(const {{{dataType}}}& value);
{{/isEnum}}
{{/isPrimitiveType}}
{{#isEnum}}
void {{setter}}(const {{^isMap}}{{{datatypeWithEnum}}}{{/isMap}}{{#isMap}}{{{dataType}}}{{/isMap}} value);
{{/isEnum}}
{{/isInherited}}
{{/vars}}
protected:
{{#vars}}
{{^isInherited}}
{{^isEnum}}
{{{dataType}}} m_{{name}};
{{/isEnum}}
{{#isEnum}}
{{^isMap}}{{{datatypeWithEnum}}}{{/isMap}}{{#isMap}}{{{dataType}}}{{/isMap}} m_{{name}};
{{/isEnum}}
bool m_{{name}}IsSet;
{{/isInherited}}
{{/vars}}
};
{{/isEnum}}
{{/oneOf}}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_{{classname}}_H_ */
{{/model}}
{{/models}}

View file

@ -0,0 +1,457 @@
{{>licenseInfo}}
{{#models}}{{#model}}
#include "{{packageName}}/model/{{classFilename}}.h"
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
{{#oneOf}}
{{#-first}}
void {{classname}}::validate()
{
// TODO: implement validation
}
const {{classname}}::VariantType& {{classname}}::getVariant() const
{
return m_variantValue;
}
void {{classname}}::setVariant({{classname}}::VariantType value)
{
m_variantValue = value;
}
web::json::value {{classname}}::toJson() const
{
web::json::value val = web::json::value::object();
std::visit([&](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::monostate>) {
val = web::json::value::null();
} else {
val = arg.toJson();
}
}, m_variantValue);
return val;
}
void {{classname}}::toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& prefix) const
{
std::visit([&](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (!std::is_same_v<T, std::monostate>) {
arg.toMultipart(multipart, prefix);
}
}, m_variantValue);
}
{{#oneOf}}
template bool {{classname}}::fromJson<{{.}}>(const web::json::value& json);
template bool {{classname}}::fromMultiPart<{{.}}>(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix);
{{/oneOf}}
{{/-first}}
{{/oneOf}}
{{^oneOf}}
{{#isEnum}}
namespace
{
using EnumUnderlyingType = {{#isNumeric}}int64_t{{/isNumeric}}{{^isNumeric}}utility::string_t{{/isNumeric}};
{{classname}}::e{{classname}} toEnum(const EnumUnderlyingType& val)
{
{{#allowableValues}}
{{#isNumeric}}
switch (val)
{
{{#enumVars}}
case {{value}}:
return {{classname}}::e{{classname}}::{{name}};
{{#-last}}
default:
break;
{{/-last}}
{{/enumVars}}
}
{{/isNumeric}}
{{^isNumeric}}
{{#enumVars}}
if (val == utility::conversions::to_string_t(_XPLATSTR("{{{value}}}")))
return {{classname}}::e{{classname}}::{{name}};
{{/enumVars}}
{{/isNumeric}}
{{/allowableValues}}
return {};
}
EnumUnderlyingType fromEnum({{classname}}::e{{classname}} e)
{
{{#allowableValues}}
switch (e)
{
{{#enumVars}}
case {{classname}}::e{{classname}}::{{name}}:
return {{#isNumeric}}{{value}}{{/isNumeric}}{{^isNumeric}}_XPLATSTR("{{value}}"){{/isNumeric}};
{{#-last}}
default:
break;
{{/-last}}
{{/enumVars}}
}
{{/allowableValues}}
return {};
}
}
{{classname}}::{{classname}}()
{
}
{{classname}}::~{{classname}}()
{
}
void {{classname}}::validate()
{
// TODO: implement validation
}
web::json::value {{classname}}::toJson() const
{
auto val = fromEnum(m_value);
return web::json::value(val);
}
bool {{classname}}::fromJson(const web::json::value& val)
{
m_value = toEnum({{#isNumeric}}val.as_number().to_int64(){{/isNumeric}}{{^isNumeric}}val.as_string(){{/isNumeric}});
return true;
}
void {{classname}}::toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& prefix) const
{
utility::string_t namePrefix = prefix;
if (!namePrefix.empty() && namePrefix.back() != _XPLATSTR('.'))
{
namePrefix.push_back(_XPLATSTR('.'));
}
auto e = fromEnum(m_value);
multipart->add(ModelBase::toHttpContent(namePrefix, e));
}
bool {{classname}}::fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& prefix)
{
bool ok = true;
utility::string_t namePrefix = prefix;
if (!namePrefix.empty() && namePrefix.back() != _XPLATSTR('.'))
{
namePrefix.push_back(_XPLATSTR('.'));
}
{
EnumUnderlyingType e;
ok = ModelBase::fromHttpContent(multipart->getContent(namePrefix), e);
if (ok)
{
auto v = toEnum(e);
setValue(v);
}
}
return ok;
}
{{classname}}::e{{classname}} {{classname}}::getValue() const
{
return m_value;
}
void {{classname}}::setValue({{classname}}::e{{classname}} const value)
{
m_value = value;
}
{{classname}}::{{classname}}(utility::string_t str){
setValue( strToEnumMap[str] );
}
{{/isEnum}}
{{^isEnum}}
{{classname}}::{{classname}}()
{
{{#vars}}
{{^isInherited}}
{{^isContainer}}
{{^isEnum}}
{{#isPrimitiveType}}
m_{{name}} = {{{defaultValue}}};
{{/isPrimitiveType}}
{{^isPrimitiveType}}
{{#isString}}
m_{{name}} = {{{defaultValue}}};
{{/isString}}
{{#isDateTime}}
m_{{name}} = {{{defaultValue}}};
{{/isDateTime}}
{{/isPrimitiveType}}
{{/isEnum}}
{{/isContainer}}
m_{{name}}IsSet = false;
{{/isInherited}}
{{/vars}}
}
{{classname}}::~{{classname}}()
{
}
void {{classname}}::validate()
{
// TODO: implement validation
}
web::json::value {{classname}}::toJson() const
{
{{#parent}}
web::json::value val = this->{{{.}}}::toJson();
{{/parent}}
{{^parent}}
web::json::value val = web::json::value::object();
{{/parent}}
{{#vars}}
{{^isInherited}}
if(m_{{name}}IsSet)
{
{{#isEnum}}{{#isContainer}}{{#isArray}}
{{{dataType}}} refVal = from{{{enumName}}}(m_{{name}});
{{/isArray}}{{#isMap}}
val[utility::conversions::to_string_t(_XPLATSTR("{{baseName}}"))] = ModelBase::toJson(m_{{name}});
{{/isMap}}{{/isContainer}}{{^isContainer}}
utility::string_t refVal = from{{{datatypeWithEnum}}}(m_{{name}});
{{/isContainer}}{{^isMap}}val[utility::conversions::to_string_t(_XPLATSTR("{{baseName}}"))] = ModelBase::toJson(refVal);
{{/isMap}}{{/isEnum}}
{{^isEnum}}
val[utility::conversions::to_string_t(_XPLATSTR("{{baseName}}"))] = ModelBase::toJson(m_{{name}});
{{/isEnum}}
}
{{/isInherited}}
{{/vars}}
return val;
}
bool {{classname}}::fromJson(const web::json::value& val)
{
bool ok = true;
{{#parent}}
ok &= this->{{{.}}}::fromJson(val);
{{/parent}}
{{#vars}}
{{^isInherited}}
if(val.has_field(utility::conversions::to_string_t(_XPLATSTR("{{baseName}}"))))
{
const web::json::value& fieldValue = val.at(utility::conversions::to_string_t(_XPLATSTR("{{baseName}}")));
if(!fieldValue.is_null())
{
{{{dataType}}} refVal_{{setter}};
ok &= ModelBase::fromJson(fieldValue, refVal_{{setter}});
{{^isEnum}}
{{setter}}(refVal_{{setter}});
{{/isEnum}}
{{#isEnum}}{{#isContainer}}{{#isArray}}
{{setter}}(to{{{enumName}}}(refVal_{{setter}}));
{{/isArray}}{{#isMap}}
{{setter}}(refVal_{{setter}});
{{/isMap}}{{/isContainer}}{{^isContainer}}
{{setter}}(to{{{datatypeWithEnum}}}(refVal_{{setter}}));
{{/isContainer}}{{/isEnum}}
}
}
{{/isInherited}}
{{/vars}}
return ok;
}
void {{classname}}::toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& prefix) const
{
utility::string_t namePrefix = prefix;
if(namePrefix.size() > 0 && namePrefix.substr(namePrefix.size() - 1) != utility::conversions::to_string_t(_XPLATSTR(".")))
{
namePrefix += utility::conversions::to_string_t(_XPLATSTR("."));
}
{{#vars}}
if(m_{{name}}IsSet)
{
{{^isEnum}}
multipart->add(ModelBase::toHttpContent(namePrefix + utility::conversions::to_string_t(_XPLATSTR("{{baseName}}")), m_{{name}}));
{{/isEnum}}
{{#isEnum}}
{{#isContainer}}
{{#isArray}}
multipart->add(ModelBase::toHttpContent(namePrefix + utility::conversions::to_string_t(_XPLATSTR("{{baseName}}")), from{{{enumName}}}(m_{{name}})));
{{/isArray}}{{#isMap}}
multipart->add(ModelBase::toHttpContent(namePrefix + utility::conversions::to_string_t(_XPLATSTR("{{baseName}}")), m_{{name}}));
{{/isMap}}
{{/isContainer}}
{{^isContainer}}
multipart->add(ModelBase::toHttpContent(namePrefix + utility::conversions::to_string_t(_XPLATSTR("{{baseName}}")), from{{{datatypeWithEnum}}}(m_{{name}})));
{{/isContainer}}
{{/isEnum}}
}
{{/vars}}
}
bool {{classname}}::fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& prefix)
{
bool ok = true;
utility::string_t namePrefix = prefix;
if(namePrefix.size() > 0 && namePrefix.substr(namePrefix.size() - 1) != utility::conversions::to_string_t(_XPLATSTR(".")))
{
namePrefix += utility::conversions::to_string_t(_XPLATSTR("."));
}
{{#vars}}
if(multipart->hasContent(utility::conversions::to_string_t(_XPLATSTR("{{baseName}}"))))
{
{{{dataType}}} refVal_{{setter}};
ok &= ModelBase::fromHttpContent(multipart->getContent(utility::conversions::to_string_t(_XPLATSTR("{{baseName}}"))), refVal_{{setter}} );
{{^isEnum}}
{{setter}}(refVal_{{setter}});
{{/isEnum}}
{{#isEnum}}
{{#isContainer}}
{{#isArray}}
{{setter}}(to{{{enumName}}}(refVal_{{setter}}));
{{/isArray}}
{{#isMap}}
{{setter}}(refVal_{{setter}});
{{/isMap}}
{{/isContainer}}
{{^isContainer}}
{{setter}}(to{{{datatypeWithEnum}}}(refVal_{{setter}}));
{{/isContainer}}
{{/isEnum}}
}
{{/vars}}
return ok;
}
{{#vars}}
{{^isInherited}}
{{#isEnum}}
{{#isContainer}}
{{classname}}::{{{enumName}}} {{classname}}::to{{{enumName}}}(const utility::string_t& value) const
{{/isContainer}}
{{^isContainer}}
{{classname}}::{{{datatypeWithEnum}}} {{classname}}::to{{{datatypeWithEnum}}}(const {{dataType}}& value) const
{{/isContainer}}
{
{{#allowableValues}}{{#enumVars}}
if (value == utility::conversions::to_string_t("{{value}}")) {
return {{#isContainer}}{{{enumName}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}{{/isContainer}}::{{name}};
}
{{/enumVars}}{{/allowableValues}}
throw std::invalid_argument("Invalid value for conversion to {{{datatypeWithEnum}}}");
}
{{#isContainer}}
const utility::string_t {{classname}}::from{{{enumName}}}(const {{{enumName}}} value) const
{{/isContainer}}{{^isContainer}}
const {{dataType}} {{classname}}::from{{{datatypeWithEnum}}}(const {{{datatypeWithEnum}}} value) const
{{/isContainer}}
{
switch(value)
{
{{#allowableValues}}{{#enumVars}}
case {{#isContainer}}{{{enumName}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}{{/isContainer}}::{{name}}: return utility::conversions::to_string_t("{{value}}");
{{/enumVars}}{{/allowableValues}}
}
}
{{#isContainer}}
{{#isArray}}
{{{dataType}}} {{{classname}}}::from{{{enumName}}}(const {{{datatypeWithEnum}}}& value) const
{
{{{dataType}}} ret;
for (auto it = value.begin(); it != value.end(); it++) {
ret.push_back(from{{{enumName}}}(*it));
}
return ret;
}
{{{baseType}}}<{{classname}}::{{{enumName}}}> {{{classname}}}::to{{{enumName}}}(const {{{dataType}}}& value) const
{
{{{datatypeWithEnum}}} ret;
for (auto it = value.begin(); it != value.end(); it++) {
ret.push_back(to{{{enumName}}}(*it));
}
return ret;
}
{{/isArray}}
{{/isContainer}}
{{/isEnum}}
{{/isInherited}}
{{/vars}}
{{#vars}}
{{^isInherited}}
{{#isContainer}}
{{^isEnum}}
{{{dataType}}} {{classname}}::{{getter}}() const
{
return m_{{name}};
}
{{/isEnum}}
{{/isContainer}}
{{^isContainer}}
{{^isEnum}}
{{{dataType}}} {{classname}}::{{getter}}() const
{
return m_{{name}};
}
{{/isEnum}}
{{/isContainer}}
{{#isEnum}}
{{^isMap}}{{#isArray}}{{{baseType}}}<{{/isArray}}{{{classname}}}::{{{enumName}}}{{#isArray}}>{{/isArray}}{{/isMap}}{{#isMap}}{{{dataType}}}{{/isMap}} {{classname}}::{{getter}}() const
{
return m_{{name}};
}
{{/isEnum}}
{{#isPrimitiveType}}
void {{classname}}::{{setter}}({{{dataType}}} value)
{{/isPrimitiveType}}{{^isPrimitiveType}}{{^isEnum}}
void {{classname}}::{{setter}}(const {{{dataType}}}& value)
{{/isEnum}}{{/isPrimitiveType}}{{#isEnum}}
void {{classname}}::{{setter}}(const {{^isMap}}{{{datatypeWithEnum}}}{{/isMap}}{{#isMap}}{{{dataType}}}{{/isMap}} value)
{{/isEnum}}
{
m_{{name}} = value;
m_{{name}}IsSet = true;
}
bool {{classname}}::{{nameInCamelCase}}IsSet() const
{
return m_{{name}}IsSet;
}
void {{classname}}::unset{{name}}()
{
m_{{name}}IsSet = false;
}
{{/isInherited}}{{/vars}}
{{/isEnum}}
{{/oneOf}}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
{{/model}}
{{/models}}

View file

@ -0,0 +1,493 @@
{{>licenseInfo}}
/*
* ModelBase.h
*
* This is the base class for all model classes
*/
#ifndef {{modelHeaderGuardPrefix}}_ModelBase_H_
#define {{modelHeaderGuardPrefix}}_ModelBase_H_
{{{defaultInclude}}}
#include "{{packageName}}/HttpContent.h"
#include "{{packageName}}/MultipartFormData.h"
#include <cpprest/details/basic_types.h>
#include <cpprest/json.h>
#include <map>
#include <set>
#include <vector>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
class {{declspec}} ModelBase
{
public:
ModelBase();
virtual ~ModelBase();
virtual void validate() = 0;
virtual web::json::value toJson() const = 0;
virtual bool fromJson( const web::json::value& json ) = 0;
virtual void toMultipart( std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix ) const = 0;
virtual bool fromMultiPart( std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix ) = 0;
virtual bool isSet() const;
static utility::string_t toString( const bool val );
static utility::string_t toString( const float val );
static utility::string_t toString( const double val );
static utility::string_t toString( const int32_t val );
static utility::string_t toString( const int64_t val );
static utility::string_t toString( const utility::string_t &val );
static utility::string_t toString( const utility::datetime &val );
static utility::string_t toString( const web::json::value &val );
static utility::string_t toString( const std::shared_ptr<HttpContent>& val );
template <typename T>
static utility::string_t toString( const std::shared_ptr<T>& val );
template <typename T>
static utility::string_t toString( const std::vector<T> & val );
template <typename T>
static utility::string_t toString( const std::set<T> & val );
static web::json::value toJson( bool val );
static web::json::value toJson( float val );
static web::json::value toJson( double val );
static web::json::value toJson( int32_t val );
static web::json::value toJson( int64_t val );
static web::json::value toJson( const utility::string_t& val );
static web::json::value toJson( const utility::datetime& val );
static web::json::value toJson( const web::json::value& val );
static web::json::value toJson( const std::shared_ptr<HttpContent>& val );
template<typename T>
static web::json::value toJson( const std::shared_ptr<T>& val );
static web::json::value toJson( const std::shared_ptr<utility::datetime>& val );
template<typename T>
static web::json::value toJson( const std::vector<T>& val );
template<typename T>
static web::json::value toJson( const std::set<T>& val );
template<typename T>
static web::json::value toJson( const std::map<utility::string_t, T>& val );
static bool fromString( const utility::string_t& val, bool & );
static bool fromString( const utility::string_t& val, float & );
static bool fromString( const utility::string_t& val, double & );
static bool fromString( const utility::string_t& val, int32_t & );
static bool fromString( const utility::string_t& val, int64_t & );
static bool fromString( const utility::string_t& val, utility::string_t & );
static bool fromString( const utility::string_t& val, utility::datetime & );
static bool fromString( const utility::string_t& val, web::json::value & );
static bool fromString( const utility::string_t& val, std::shared_ptr<HttpContent> & );
template<typename T>
static bool fromString( const utility::string_t& val, std::shared_ptr<T>& );
static bool fromString( const utility::string_t& val, std::shared_ptr<utility::datetime>& outVal );
template<typename T>
static bool fromString( const utility::string_t& val, std::vector<T> & );
template<typename T>
static bool fromString( const utility::string_t& val, std::set<T> & );
template<typename T>
static bool fromString( const utility::string_t& val, std::map<utility::string_t, T> & );
static bool fromJson( const web::json::value& val, bool & );
static bool fromJson( const web::json::value& val, float & );
static bool fromJson( const web::json::value& val, double & );
static bool fromJson( const web::json::value& val, int32_t & );
static bool fromJson( const web::json::value& val, int64_t & );
static bool fromJson( const web::json::value& val, utility::string_t & );
static bool fromJson( const web::json::value& val, utility::datetime & );
static bool fromJson( const web::json::value& val, web::json::value & );
static bool fromJson( const web::json::value& val, std::shared_ptr<HttpContent> & );
template<typename T>
static bool fromJson( const web::json::value& val, std::shared_ptr<T>& );
static bool fromJson( const web::json::value& val, std::shared_ptr<utility::datetime> &outVal );
template<typename T>
static bool fromJson( const web::json::value& val, std::vector<T> & );
template<typename T>
static bool fromJson( const web::json::value& val, std::set<T> & );
template<typename T>
static bool fromJson( const web::json::value& val, std::map<utility::string_t, T> & );
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, bool value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, float value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, double value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, int32_t value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, int64_t value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const utility::string_t& value, const utility::string_t& contentType = utility::conversions::to_string_t(""));
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const utility::datetime& value, const utility::string_t& contentType = utility::conversions::to_string_t(""));
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const web::json::value& value, const utility::string_t& contentType = utility::conversions::to_string_t("application/json") );
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const std::shared_ptr<HttpContent>& );
template <typename T>
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const std::shared_ptr<T>& , const utility::string_t& contentType = utility::conversions::to_string_t("application/json") );
static std::shared_ptr<HttpContent> toHttpContent(const utility::string_t& name, const std::shared_ptr<utility::datetime>& value , const utility::string_t& contentType = utility::conversions::to_string_t("application/json") );
template <typename T>
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const std::vector<T>& value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
template <typename T>
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const std::set<T>& value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
template <typename T>
static std::shared_ptr<HttpContent> toHttpContent( const utility::string_t& name, const std::map<utility::string_t, T>& value, const utility::string_t& contentType = utility::conversions::to_string_t("") );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, bool & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, float & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, double & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, int64_t & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, int32_t & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, utility::string_t & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, utility::datetime & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, web::json::value & );
static bool fromHttpContent( std::shared_ptr<HttpContent> val, std::shared_ptr<HttpContent>& );
template <typename T>
static bool fromHttpContent( std::shared_ptr<HttpContent> val, std::shared_ptr<T>& );
template <typename T>
static bool fromHttpContent( std::shared_ptr<HttpContent> val, std::vector<T> & );
template <typename T>
static bool fromHttpContent( std::shared_ptr<HttpContent> val, std::set<T> & );
template <typename T>
static bool fromHttpContent( std::shared_ptr<HttpContent> val, std::map<utility::string_t, T> & );
static utility::string_t toBase64( utility::string_t value );
static utility::string_t toBase64( std::shared_ptr<std::istream> value );
static std::shared_ptr<std::istream> fromBase64( const utility::string_t& encoded );
protected:
bool m_IsSet;
};
template <typename T>
utility::string_t ModelBase::toString( const std::shared_ptr<T>& val )
{
utility::stringstream_t ss;
if( val != nullptr )
{
val->toJson().serialize(ss);
}
return utility::string_t(ss.str());
}
// std::vector to string
template<typename T>
utility::string_t ModelBase::toString( const std::vector<T> & val )
{
utility::string_t strArray;
for ( const auto &item : val )
{
strArray.append( toString(item) + "," );
}
if (val.count() > 0)
{
strArray.pop_back();
}
return strArray;
}
// std::set to string
template<typename T>
utility::string_t ModelBase::toString( const std::set<T> & val )
{
utility::string_t strArray;
for ( const auto &item : val )
{
strArray.append( toString(item) + "," );
}
if (val.count() > 0)
{
strArray.pop_back();
}
return strArray;
}
template<typename T>
web::json::value ModelBase::toJson( const std::shared_ptr<T>& val )
{
web::json::value retVal;
if(val != nullptr)
{
retVal = val->toJson();
}
return retVal;
}
// std::vector to json
template<typename T>
web::json::value ModelBase::toJson( const std::vector<T>& value )
{
std::vector<web::json::value> ret;
for ( const auto& x : value )
{
ret.push_back( toJson(x) );
}
return web::json::value::array(ret);
}
// std::set to json
template<typename T>
web::json::value ModelBase::toJson( const std::set<T>& value )
{
// There's no prototype web::json::value::array(...) taking a std::set parameter. Converting to std::vector to get an array.
std::vector<web::json::value> ret;
for ( const auto& x : value )
{
ret.push_back( toJson(x) );
}
return web::json::value::array(ret);
}
template<typename T>
web::json::value ModelBase::toJson( const std::map<utility::string_t, T>& val )
{
web::json::value obj;
for ( const auto &itemkey : val )
{
obj[itemkey.first] = toJson( itemkey.second );
}
return obj;
}
template<typename T>
bool ModelBase::fromString( const utility::string_t& val, std::shared_ptr<T>& outVal )
{
bool ok = false;
if(outVal == nullptr)
{
outVal = std::make_shared<T>();
}
if( outVal != nullptr )
{
ok = outVal->fromJson(web::json::value::parse(val));
}
return ok;
}
template<typename T>
bool ModelBase::fromString(const utility::string_t& val, std::vector<T>& outVal )
{
bool ok = true;
web::json::value jsonValue = web::json::value::parse(val);
if (jsonValue.is_array())
{
for (const web::json::value& jitem : jsonValue.as_array())
{
T item;
ok &= fromJson(jitem, item);
outVal.push_back(item);
}
}
else
{
T item;
ok = fromJson(jsonValue, item);
outVal.push_back(item);
}
return ok;
}
template<typename T>
bool ModelBase::fromString(const utility::string_t& val, std::set<T>& outVal )
{
bool ok = true;
web::json::value jsonValue = web::json::value::parse(val);
if (jsonValue.is_array())
{
for (const web::json::value& jitem : jsonValue.as_array())
{
T item;
ok &= fromJson(jitem, item);
outVal.insert(item);
}
}
else
{
T item;
ok = fromJson(jsonValue, item);
outVal.insert(item);
}
return ok;
}
template<typename T>
bool ModelBase::fromString(const utility::string_t& val, std::map<utility::string_t, T>& outVal )
{
bool ok = false;
web::json::value jsonValue = web::json::value::parse(val);
if (jsonValue.is_array())
{
for (const web::json::value& jitem : jsonValue.as_array())
{
T item;
ok &= fromJson(jitem, item);
outVal.insert({ val, item });
}
}
else
{
T item;
ok = fromJson(jsonValue, item);
outVal.insert({ val, item });
}
return ok;
}
template<typename T>
bool ModelBase::fromJson( const web::json::value& val, std::shared_ptr<T> &outVal )
{
bool ok = false;
if(outVal == nullptr)
{
outVal = std::make_shared<T>();
}
if( outVal != nullptr )
{
ok = outVal->fromJson(val);
}
return ok;
}
template<typename T>
bool ModelBase::fromJson( const web::json::value& val, std::vector<T> &outVal )
{
bool ok = true;
if (val.is_array())
{
for (const web::json::value & jitem : val.as_array())
{
T item;
ok &= fromJson(jitem, item);
outVal.push_back(item);
}
}
else
{
ok = false;
}
return ok;
}
template<typename T>
bool ModelBase::fromJson(const web::json::value& val, std::set<T>& outVal )
{
bool ok = true;
if (val.is_array())
{
for (const web::json::value& jitem : val.as_array())
{
T item;
ok &= fromJson(jitem, item);
outVal.insert(item);
}
}
else
{
T item;
ok = fromJson(val, item);
outVal.insert(item);
}
return ok;
}
template<typename T>
bool ModelBase::fromJson( const web::json::value& jval, std::map<utility::string_t, T> &outVal )
{
bool ok = true;
if ( jval.is_object() )
{
auto obj = jval.as_object();
for( auto objItr = obj.begin() ; objItr != obj.end() ; objItr++ )
{
T itemVal;
ok &= fromJson(objItr->second, itemVal);
outVal.insert(std::pair<utility::string_t, T>(objItr->first, itemVal));
}
}
else
{
ok = false;
}
return ok;
}
template <typename T>
std::shared_ptr<HttpContent> ModelBase::toHttpContent(const utility::string_t& name, const std::shared_ptr<T>& value , const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content = std::make_shared<HttpContent>();
if (value != nullptr )
{
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
content->setData( std::make_shared<std::stringstream>( utility::conversions::to_utf8string(value->toJson().serialize()) ) );
}
return content;
}
template <typename T>
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, const std::vector<T>& value, const utility::string_t& contentType )
{
web::json::value json_array = ModelBase::toJson(value);
std::shared_ptr<HttpContent> content = std::make_shared<HttpContent>();
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
content->setData( std::make_shared<std::stringstream>( utility::conversions::to_utf8string(json_array.serialize()) ) );
return content;
}
template <typename T>
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, const std::set<T>& value, const utility::string_t& contentType )
{
web::json::value json_array = ModelBase::toJson(value);
std::shared_ptr<HttpContent> content = std::make_shared<HttpContent>();
content->setName(name);
content->setContentDisposition(utility::conversions::to_string_t("form-data"));
content->setContentType(contentType);
content->setData( std::make_shared<std::stringstream>( utility::conversions::to_utf8string(json_array.serialize()) ) );
return content;
}
template <typename T>
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, const std::map<utility::string_t, T>& value, const utility::string_t& contentType )
{
web::json::value jobj = ModelBase::toJson(value);
std::shared_ptr<HttpContent> content = std::make_shared<HttpContent>();
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
content->setData( std::make_shared<std::stringstream>( utility::conversions::to_utf8string(jobj.serialize()) ) );
return content;
}
template <typename T>
bool ModelBase::fromHttpContent( std::shared_ptr<HttpContent> val, std::shared_ptr<T>& outVal )
{
utility::string_t str;
if(val == nullptr) return false;
if( outVal == nullptr )
{
outVal = std::make_shared<T>();
}
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
template <typename T>
bool ModelBase::fromHttpContent( std::shared_ptr<HttpContent> val, std::vector<T> & outVal )
{
utility::string_t str;
if (val == nullptr) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
template <typename T>
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, std::set<T>& outVal )
{
utility::string_t str;
if (val == nullptr) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
template <typename T>
bool ModelBase::fromHttpContent( std::shared_ptr<HttpContent> val, std::map<utility::string_t, T> & outVal )
{
utility::string_t str;
if (val == nullptr) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_ModelBase_H_ */

View file

@ -0,0 +1,653 @@
{{>licenseInfo}}
#include "{{packageName}}/ModelBase.h"
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
ModelBase::ModelBase(): m_IsSet(false)
{
}
ModelBase::~ModelBase()
{
}
bool ModelBase::isSet() const
{
return m_IsSet;
}
utility::string_t ModelBase::toString( const bool val )
{
utility::stringstream_t ss;
ss << val;
return utility::string_t(ss.str());
}
utility::string_t ModelBase::toString( const float val )
{
utility::stringstream_t ss;
ss << val;
return utility::string_t(ss.str());
}
utility::string_t ModelBase::toString( const double val )
{
utility::stringstream_t ss;
ss << val;
return utility::string_t(ss.str());
}
utility::string_t ModelBase::toString( const int32_t val )
{
utility::stringstream_t ss;
ss << val;
return utility::string_t(ss.str());
}
utility::string_t ModelBase::toString( const int64_t val )
{
utility::stringstream_t ss;
ss << val;
return utility::string_t(ss.str());
}
utility::string_t ModelBase::toString (const utility::string_t &val )
{
utility::stringstream_t ss;
ss << val;
return utility::string_t(ss.str());
}
utility::string_t ModelBase::toString( const utility::datetime &val )
{
return val.to_string(utility::datetime::ISO_8601);
}
utility::string_t ModelBase::toString( const web::json::value &val )
{
return val.serialize();
}
utility::string_t ModelBase::toString( const std::shared_ptr<HttpContent>& val )
{
utility::stringstream_t ss;
if( val != nullptr )
{
ss << val->getData();
}
return utility::string_t(ss.str());
}
web::json::value ModelBase::toJson(bool value)
{
return web::json::value::boolean(value);
}
web::json::value ModelBase::toJson( float value )
{
return web::json::value::number(value);
}
web::json::value ModelBase::toJson( double value )
{
return web::json::value::number(value);
}
web::json::value ModelBase::toJson( int32_t value )
{
return web::json::value::number(value);
}
web::json::value ModelBase::toJson( int64_t value )
{
return web::json::value::number(value);
}
web::json::value ModelBase::toJson( const utility::string_t& value )
{
return web::json::value::string(value);
}
web::json::value ModelBase::toJson( const utility::datetime& value )
{
return web::json::value::string(value.to_string(utility::datetime::ISO_8601));
}
web::json::value ModelBase::toJson( const web::json::value& value )
{
return value;
}
web::json::value ModelBase::toJson( const std::shared_ptr<HttpContent>& content )
{
web::json::value value;
if(content != nullptr)
{
value[utility::conversions::to_string_t("ContentDisposition")] = ModelBase::toJson(content->getContentDisposition());
value[utility::conversions::to_string_t("ContentType")] = ModelBase::toJson(content->getContentType());
value[utility::conversions::to_string_t("FileName")] = ModelBase::toJson(content->getFileName());
value[utility::conversions::to_string_t("InputStream")] = web::json::value::string( ModelBase::toBase64(content->getData()) );
}
return value;
}
web::json::value ModelBase::toJson( const std::shared_ptr<utility::datetime>& val )
{
web::json::value retVal;
if(val != nullptr)
{
retVal = toJson(*val);
}
return retVal;
}
bool ModelBase::fromString( const utility::string_t& val, bool &outVal )
{
utility::stringstream_t ss(val);
bool success = true;
try
{
ss >> outVal;
}
catch (...)
{
success = false;
}
return success;
}
bool ModelBase::fromString( const utility::string_t& val, float &outVal )
{
utility::stringstream_t ss(val);
bool success = true;
try
{
ss >> outVal;
}
catch (...)
{
int64_t intVal = 0;
success = ModelBase::fromString(val, intVal);
if(success)
{
outVal = static_cast<float>(intVal);
}
}
return success;
}
bool ModelBase::fromString( const utility::string_t& val, double &outVal )
{
utility::stringstream_t ss(val);
bool success = true;
try
{
ss >> outVal;
}
catch (...)
{
int64_t intVal = 0;
success = ModelBase::fromString(val, intVal);
if(success)
{
outVal = static_cast<double>(intVal);
}
}
return success;
}
bool ModelBase::fromString( const utility::string_t& val, int32_t &outVal )
{
utility::stringstream_t ss(val);
bool success = true;
try
{
ss >> outVal;
}
catch (...)
{
success = false;
}
return success;
}
bool ModelBase::fromString( const utility::string_t& val, int64_t &outVal )
{
utility::stringstream_t ss(val);
bool success = true;
try
{
ss >> outVal;
}
catch (...)
{
success = false;
}
return success;
}
bool ModelBase::fromString( const utility::string_t& val, utility::string_t &outVal )
{
utility::stringstream_t ss(val);
bool success = true;
try
{
ss >> outVal;
}
catch (...)
{
success = false;
}
return success;
}
bool ModelBase::fromString( const utility::string_t& val, utility::datetime &outVal )
{
bool success = true;
auto dt = utility::datetime::from_string(val, utility::datetime::ISO_8601);
if( dt.is_initialized() )
{
outVal = dt;
}
else
{
success = false;
}
return success;
}
bool ModelBase::fromString( const utility::string_t& val, web::json::value &outVal )
{
outVal = web::json::value::parse(val);
return !outVal.is_null();
}
bool ModelBase::fromString( const utility::string_t& val, std::shared_ptr<HttpContent>& outVal )
{
bool ok = true;
if(outVal == nullptr)
{
outVal = std::shared_ptr<HttpContent>(new HttpContent());
}
if(outVal != nullptr)
{
outVal->setData(std::shared_ptr<std::istream>(new std::stringstream(utility::conversions::to_utf8string(val))));
}
else
{
ok = false;
}
return ok;
}
bool ModelBase::fromString( const utility::string_t& val, std::shared_ptr<utility::datetime>& outVal )
{
bool ok = false;
if(outVal == nullptr)
{
outVal = std::shared_ptr<utility::datetime>(new utility::datetime());
}
if( outVal != nullptr )
{
ok = fromJson(web::json::value::parse(val), *outVal);
}
return ok;
}
bool ModelBase::fromJson( const web::json::value& val, bool & outVal )
{
outVal = !val.is_boolean() ? false : val.as_bool();
return val.is_boolean();
}
bool ModelBase::fromJson( const web::json::value& val, float & outVal )
{
outVal = (!val.is_double() && !val.is_integer()) ? std::numeric_limits<float>::quiet_NaN(): static_cast<float>(val.as_double());
return val.is_double() || val.is_integer();
}
bool ModelBase::fromJson( const web::json::value& val, double & outVal )
{
outVal = (!val.is_double() && !val.is_integer()) ? std::numeric_limits<double>::quiet_NaN(): val.as_double();
return val.is_double() || val.is_integer();
}
bool ModelBase::fromJson( const web::json::value& val, int32_t & outVal )
{
outVal = !val.is_integer() ? std::numeric_limits<int32_t>::quiet_NaN() : val.as_integer();
return val.is_integer();
}
bool ModelBase::fromJson( const web::json::value& val, int64_t & outVal )
{
outVal = !val.is_number() ? std::numeric_limits<int64_t>::quiet_NaN() : val.as_number().to_int64();
return val.is_number();
}
bool ModelBase::fromJson( const web::json::value& val, utility::string_t & outVal )
{
outVal = val.is_string() ? val.as_string() : utility::conversions::to_string_t("");
return val.is_string();
}
bool ModelBase::fromJson( const web::json::value& val, utility::datetime & outVal )
{
outVal = val.is_null() ? utility::datetime::from_string(utility::conversions::to_string_t("NULL"), utility::datetime::ISO_8601) : utility::datetime::from_string(val.as_string(), utility::datetime::ISO_8601);
return outVal.is_initialized();
}
bool ModelBase::fromJson( const web::json::value& val, web::json::value & outVal )
{
outVal = val;
return !val.is_null();
}
bool ModelBase::fromJson( const web::json::value& val, std::shared_ptr<HttpContent>& content )
{
bool result = false;
if( content != nullptr)
{
result = true;
if(content == nullptr)
{
content = std::shared_ptr<HttpContent>(new HttpContent());
}
if(val.has_field(utility::conversions::to_string_t("ContentDisposition")))
{
utility::string_t value;
result = result && ModelBase::fromJson(val.at(utility::conversions::to_string_t("ContentDisposition")), value);
content->setContentDisposition( value );
}
if(val.has_field(utility::conversions::to_string_t("ContentType")))
{
utility::string_t value;
result = result && ModelBase::fromJson(val.at(utility::conversions::to_string_t("ContentType")), value);
content->setContentType( value );
}
if(val.has_field(utility::conversions::to_string_t("FileName")))
{
utility::string_t value;
result = result && ModelBase::fromJson(val.at(utility::conversions::to_string_t("FileName")), value);
content->setFileName( value );
}
if(val.has_field(utility::conversions::to_string_t("InputStream")))
{
utility::string_t value;
result = result && ModelBase::fromJson(val.at(utility::conversions::to_string_t("InputStream")), value);
content->setData( ModelBase::fromBase64( value ) );
}
}
return result;
}
bool ModelBase::fromJson( const web::json::value& val, std::shared_ptr<utility::datetime> &outVal )
{
bool ok = false;
if(outVal == nullptr)
{
outVal = std::shared_ptr<utility::datetime>(new utility::datetime());
}
if( outVal != nullptr )
{
ok = fromJson(val, *outVal);
}
return ok;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, bool value, const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
std::stringstream* valueAsStringStream = new std::stringstream();
(*valueAsStringStream) << value;
content->setData( std::shared_ptr<std::istream>( valueAsStringStream ) );
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, float value, const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
std::stringstream* valueAsStringStream = new std::stringstream();
(*valueAsStringStream) << value;
content->setData( std::shared_ptr<std::istream>( valueAsStringStream ) );
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, double value, const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
std::stringstream* valueAsStringStream = new std::stringstream();
(*valueAsStringStream) << value;
content->setData( std::shared_ptr<std::istream>( valueAsStringStream ) );
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, int32_t value, const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
std::stringstream* valueAsStringStream = new std::stringstream();
(*valueAsStringStream) << value;
content->setData( std::shared_ptr<std::istream>( valueAsStringStream ) );
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, int64_t value, const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
std::stringstream* valueAsStringStream = new std::stringstream();
(*valueAsStringStream) << value;
content->setData( std::shared_ptr<std::istream>( valueAsStringStream) ) ;
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, const utility::string_t& value, const utility::string_t& contentType)
{
std::shared_ptr<HttpContent> content(new HttpContent);
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
content->setData( std::shared_ptr<std::istream>( new std::stringstream( utility::conversions::to_utf8string(value) ) ) );
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, const utility::datetime& value, const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
content->setData( std::shared_ptr<std::istream>( new std::stringstream( utility::conversions::to_utf8string(value.to_string(utility::datetime::ISO_8601) ) ) ) );
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, const web::json::value& value, const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
content->setData( std::shared_ptr<std::istream>( new std::stringstream( utility::conversions::to_utf8string(value.serialize()) ) ) );
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent( const utility::string_t& name, const std::shared_ptr<HttpContent>& value )
{
std::shared_ptr<HttpContent> content( new HttpContent );
if( value != nullptr )
{
content->setName( name );
content->setContentDisposition( value->getContentDisposition() );
content->setContentType( value->getContentType() );
content->setData( value->getData() );
content->setFileName( value->getFileName() );
}
return content;
}
std::shared_ptr<HttpContent> ModelBase::toHttpContent(const utility::string_t& name, const std::shared_ptr<utility::datetime>& value , const utility::string_t& contentType )
{
std::shared_ptr<HttpContent> content( new HttpContent );
if (value != nullptr )
{
content->setName( name );
content->setContentDisposition( utility::conversions::to_string_t("form-data") );
content->setContentType( contentType );
content->setData( std::shared_ptr<std::istream>( new std::stringstream( utility::conversions::to_utf8string( toJson(*value).serialize() ) ) ) );
}
return content;
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, bool & outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, float & outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, double & outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, int32_t & outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, int64_t & outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, utility::string_t & outVal )
{
if( val == nullptr ) return false;
std::shared_ptr<std::istream> data = val->getData();
data->seekg( 0, data->beg );
std::string str((std::istreambuf_iterator<char>(*data.get())),
std::istreambuf_iterator<char>());
outVal = utility::conversions::to_string_t(str);
return true;
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, utility::datetime & outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
ModelBase::fromHttpContent(val, str);
outVal = utility::datetime::from_string(str, utility::datetime::ISO_8601);
return true;
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, web::json::value & outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
bool ModelBase::fromHttpContent(std::shared_ptr<HttpContent> val, std::shared_ptr<HttpContent>& outVal )
{
utility::string_t str;
if( val == nullptr ) return false;
if( outVal == nullptr )
{
outVal = std::shared_ptr<HttpContent>(new HttpContent());
}
ModelBase::fromHttpContent(val, str);
return fromString(str, outVal);
}
// base64 encoding/decoding based on : https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64#C.2B.2B
const static char Base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const static char Base64PadChar = '=';
utility::string_t ModelBase::toBase64( utility::string_t value )
{
std::shared_ptr<std::istream> source( new std::stringstream( utility::conversions::to_utf8string(value) ) );
return ModelBase::toBase64(source);
}
utility::string_t ModelBase::toBase64( std::shared_ptr<std::istream> value )
{
value->seekg( 0, value->end );
size_t length = value->tellg();
value->seekg( 0, value->beg );
utility::string_t base64;
base64.reserve( ((length / 3) + (length % 3 > 0)) * 4 );
char read[3] = { 0 };
uint32_t temp;
for ( size_t idx = 0; idx < length / 3; idx++ )
{
value->read( read, 3 );
temp = (read[0]) << 16;
temp += (read[1]) << 8;
temp += (read[2]);
base64.append( 1, Base64Chars[(temp & 0x00FC0000) >> 18] );
base64.append( 1, Base64Chars[(temp & 0x0003F000) >> 12] );
base64.append( 1, Base64Chars[(temp & 0x00000FC0) >> 6] );
base64.append( 1, Base64Chars[(temp & 0x0000003F)] );
}
switch ( length % 3 )
{
case 1:
value->read( read, 1 );
temp = read[0] << 16;
base64.append( 1, Base64Chars[(temp & 0x00FC0000) >> 18] );
base64.append( 1, Base64Chars[(temp & 0x0003F000) >> 12] );
base64.append( 2, Base64PadChar );
break;
case 2:
value->read( read, 2 );
temp = read[0] << 16;
temp += read[1] << 8;
base64.append( 1, Base64Chars[(temp & 0x00FC0000) >> 18] );
base64.append( 1, Base64Chars[(temp & 0x0003F000) >> 12] );
base64.append( 1, Base64Chars[(temp & 0x00000FC0) >> 6] );
base64.append( 1, Base64PadChar );
break;
}
return base64;
}
std::shared_ptr<std::istream> ModelBase::fromBase64( const utility::string_t& encoded )
{
std::shared_ptr<std::stringstream> result(new std::stringstream);
char outBuf[3] = { 0 };
uint32_t temp = 0;
utility::string_t::const_iterator cursor = encoded.begin();
while ( cursor < encoded.end() )
{
for ( size_t quantumPosition = 0; quantumPosition < 4; quantumPosition++ )
{
temp <<= 6;
if ( *cursor >= 0x41 && *cursor <= 0x5A )
{
temp |= *cursor - 0x41;
}
else if ( *cursor >= 0x61 && *cursor <= 0x7A )
{
temp |= *cursor - 0x47;
}
else if ( *cursor >= 0x30 && *cursor <= 0x39 )
{
temp |= *cursor + 0x04;
}
else if ( *cursor == 0x2B )
{
temp |= 0x3E; //change to 0x2D for URL alphabet
}
else if ( *cursor == 0x2F )
{
temp |= 0x3F; //change to 0x5F for URL alphabet
}
else if ( *cursor == Base64PadChar ) //pad
{
switch ( encoded.end() - cursor )
{
case 1: //One pad character
outBuf[0] = (temp >> 16) & 0x000000FF;
outBuf[1] = (temp >> 8) & 0x000000FF;
result->write( outBuf, 2 );
return result;
case 2: //Two pad characters
outBuf[0] = (temp >> 10) & 0x000000FF;
result->write( outBuf, 1 );
return result;
default:
throw web::json::json_exception( utility::conversions::to_string_t( "Invalid Padding in Base 64!" ).c_str() );
}
}
else
{
throw web::json::json_exception( utility::conversions::to_string_t( "Non-Valid Character in Base 64!" ).c_str() );
}
++cursor;
}
outBuf[0] = (temp >> 16) & 0x000000FF;
outBuf[1] = (temp >> 8) & 0x000000FF;
outBuf[2] = (temp) & 0x000000FF;
result->write( outBuf, 3 );
}
return result;
}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}

View file

@ -0,0 +1,49 @@
{{>licenseInfo}}
/*
* MultipartFormData.h
*
* This class represents a container for building application/x-multipart-formdata requests.
*/
#ifndef {{modelHeaderGuardPrefix}}_MultipartFormData_H_
#define {{modelHeaderGuardPrefix}}_MultipartFormData_H_
{{{defaultInclude}}}
#include "{{packageName}}/IHttpBody.h"
#include "{{packageName}}/HttpContent.h"
#include <cpprest/details/basic_types.h>
#include <vector>
#include <map>
#include <memory>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
class {{declspec}} MultipartFormData
: public IHttpBody
{
public:
MultipartFormData();
MultipartFormData(const utility::string_t& boundary);
virtual ~MultipartFormData();
virtual void add( std::shared_ptr<HttpContent> content );
virtual utility::string_t getBoundary();
virtual std::shared_ptr<HttpContent> getContent(const utility::string_t& name) const;
virtual bool hasContent(const utility::string_t& name) const;
virtual void writeTo( std::ostream& target );
protected:
std::vector<std::shared_ptr<HttpContent>> m_Contents;
utility::string_t m_Boundary;
std::map<utility::string_t, std::shared_ptr<HttpContent>> m_ContentLookup;
};
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_MultipartFormData_H_ */

View file

@ -0,0 +1,100 @@
{{>licenseInfo}}
#include "{{packageName}}/MultipartFormData.h"
#include "{{packageName}}/ModelBase.h"
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
MultipartFormData::MultipartFormData()
{
utility::stringstream_t uuidString;
uuidString << boost::uuids::random_generator()();
m_Boundary = uuidString.str();
}
MultipartFormData::MultipartFormData(const utility::string_t& boundary)
: m_Boundary(boundary)
{
}
MultipartFormData::~MultipartFormData()
{
}
utility::string_t MultipartFormData::getBoundary()
{
return m_Boundary;
}
void MultipartFormData::add( std::shared_ptr<HttpContent> content )
{
m_Contents.push_back( content );
m_ContentLookup[content->getName()] = content;
}
bool MultipartFormData::hasContent(const utility::string_t& name) const
{
return m_ContentLookup.find(name) != m_ContentLookup.end();
}
std::shared_ptr<HttpContent> MultipartFormData::getContent(const utility::string_t& name) const
{
auto result = m_ContentLookup.find(name);
if(result == m_ContentLookup.end())
{
return std::shared_ptr<HttpContent>(nullptr);
}
return result->second;
}
void MultipartFormData::writeTo( std::ostream& target )
{
for ( size_t i = 0; i < m_Contents.size(); i++ )
{
std::shared_ptr<HttpContent> content = m_Contents[i];
// boundary
target << "\r\n" << "--" << utility::conversions::to_utf8string( m_Boundary ) << "\r\n";
// headers
target << "Content-Disposition: " << utility::conversions::to_utf8string( content->getContentDisposition() );
if ( content->getName().size() > 0 )
{
target << "; name=\"" << utility::conversions::to_utf8string( content->getName() ) << "\"";
}
if ( content->getFileName().size() > 0 )
{
target << "; filename=\"" << utility::conversions::to_utf8string( content->getFileName() ) << "\"";
}
target << "\r\n";
if ( content->getContentType().size() > 0 )
{
target << "Content-Type: " << utility::conversions::to_utf8string( content->getContentType() ) << "\r\n";
}
target << "\r\n";
// body
std::shared_ptr<std::istream> data = content->getData();
data->seekg( 0, data->end );
std::vector<char> dataBytes( data->tellg() );
data->seekg( 0, data->beg );
data->read( &dataBytes[0], dataBytes.size() );
std::copy( dataBytes.begin(), dataBytes.end(), std::ostreambuf_iterator<char>( target ) );
}
target << "\r\n--" << utility::conversions::to_utf8string( m_Boundary ) << "--\r\n";
}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}

View file

@ -0,0 +1,50 @@
{{>licenseInfo}}
/*
* Object.h
*
* This is the implementation of a JSON object.
*/
#ifndef {{modelHeaderGuardPrefix}}_Object_H_
#define {{modelHeaderGuardPrefix}}_Object_H_
{{{defaultInclude}}}
#include "{{packageName}}/ModelBase.h"
#include <cpprest/details/basic_types.h>
#include <cpprest/json.h>
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
class {{declspec}} Object : public ModelBase
{
public:
Object();
virtual ~Object();
/////////////////////////////////////////////
/// ModelBase overrides
void validate() override;
web::json::value toJson() const override;
bool fromJson(const web::json::value& json) override;
void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const override;
bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) override;
/////////////////////////////////////////////
/// Object manipulation
web::json::value getValue(const utility::string_t& key) const;
void setValue(const utility::string_t& key, const web::json::value& value);
private:
web::json::value m_object;
};
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}
#endif /* {{modelHeaderGuardPrefix}}_Object_H_ */

View file

@ -0,0 +1,79 @@
{{>licenseInfo}}
#include "{{packageName}}/Object.h"
{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}
Object::Object()
{
m_object = web::json::value::object();
}
Object::~Object()
{
}
void Object::validate()
{
}
web::json::value Object::toJson() const
{
return m_object;
}
bool Object::fromJson(const web::json::value& val)
{
if (val.is_object())
{
m_object = val;
m_IsSet = true;
}
return isSet();
}
void Object::toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& prefix) const
{
utility::string_t namePrefix = prefix;
if(namePrefix.size() > 0 && namePrefix.substr(namePrefix.size() - 1) != utility::conversions::to_string_t("."))
{
namePrefix += utility::conversions::to_string_t(".");
}
multipart->add(ModelBase::toHttpContent(namePrefix + utility::conversions::to_string_t("object"), m_object));
}
bool Object::fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& prefix)
{
utility::string_t namePrefix = prefix;
if(namePrefix.size() > 0 && namePrefix.substr(namePrefix.size() - 1) != utility::conversions::to_string_t("."))
{
namePrefix += utility::conversions::to_string_t(".");
}
if( ModelBase::fromHttpContent(multipart->getContent(namePrefix + utility::conversions::to_string_t("object")), m_object ) )
{
m_IsSet = true;
}
return isSet();
}
web::json::value Object::getValue(const utility::string_t& key) const
{
return m_object.at(key);
}
void Object::setValue(const utility::string_t& key, const web::json::value& value)
{
if( !value.is_null() )
{
m_object[key] = value;
m_IsSet = true;
}
}
{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}

View file

@ -550,20 +550,13 @@ components:
required:
- id
- name
Tag:
description: 'A localized tag: keys are language codes (ISO 639-1), values are tag names'
type: object
example:
en: Shojo
ru: Сёдзё
ja: 少女
additionalProperties:
type: string
Tags:
description: Array of localized tags
type: array
items:
$ref: '#/components/schemas/Tag'
type: object
additionalProperties:
type: string
example:
- en: Shojo
ru: Сёдзё

2
modules/bot/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
generated-client/
out/

View file

@ -2,13 +2,13 @@ cmake_minimum_required(VERSION 3.10.2)
project(AnimeBot)
set(SOURCES "")
file(GLOB_RECURSE SRC_FRONT "src/*.cpp")
file(GLOB_RECURSE SRC_FRONT "front/src/*.cpp")
list(APPEND SOURCES ${SRC_FRONT})
file(GLOB_RECURSE SRC_BACK "../back/src/*.cpp")
file(GLOB_RECURSE SRC_BACK "back/src/*.cpp")
list(APPEND SOURCES ${SRC_BACK})
file(GLOB_RECURSE SRC_API "../generated-client/src/*.cpp")
file(GLOB_RECURSE SRC_API "generated-client/src/*.cpp")
list(APPEND SOURCES ${SRC_API})
set(CMAKE_CXX_STANDARD 20)
@ -23,9 +23,9 @@ find_package(Boost COMPONENTS system REQUIRED)
find_package(CURL)
find_library(CPPREST_LIB cpprest REQUIRED)
include_directories(/usr/local/include ${OPENSSL_INCLUDE_DIR} ${Boost_INCLUDE_DIR})
include_directories(include/)
include_directories(../back/include)
include_directories(../generated-client/include)
include_directories(front/include/)
include_directories(back/include)
include_directories(generated-client/include)
if (CURL_FOUND)
include_directories(${CURL_INCLUDE_DIRS})
add_definitions(-DHAVE_CURL)

View file

@ -0,0 +1,63 @@
#pragma once
#include <unordered_map>
#include <vector>
#include <mutex>
#include <optional>
#include "constants.hpp"
enum class UserState {
MAIN_MENU, // Главное меню
VIEWING_MY_TITLES, // Список моих тайтлов
AWAITING_TITLE_NAME, // Жду название тайтла для поиска
VIEWING_FOUND_TITLES, // Смотрю найденные тайтлы
VIEWING_TITLE_PAGE, // Смотрю страничку тайтла
AWAITING_REVIEW, // Жду ревью на тайтл
VIEWING_REVIEW_LIST, // Смотрю список ревью на тайтл
VIEWING_REVIEW, // Смотрю (конкретное) ревью на тайтл
VIEWING_DESCRIPTION, // Смотрю описание тайтла
ERROR, // Ошибка состояния
};
struct NavigationStep {
UserState state;
int64_t payload; // ID тайтла, ревью и т.д.
};
struct UserContext {
int64_t userId;
std::vector<NavigationStep> history; // Текущее состояние пользователя + история предыдущих состояний
};
class BotUserContext {
private:
mutable std::mutex mtx;
std::unordered_map<int64_t, UserContext> userContexts;
public:
// Получить копию контекста пользователя (или std::nullopt, если не найден)
std::optional<UserContext> getContext(int64_t userId) const;
// Установить/обновить контекст пользователя
void setContext(int64_t userId, const UserContext& context);
// Добавить шаг навигации к существующему контексту пользователя
// Если пользователя нет — создаётся новый контекст
void pushNavigationStep(int64_t userId, const NavigationStep& step);
// Заменить текущую историю (полезно, например, при сбросе состояния)
void setNavigationHistory(int64_t userId, const std::vector<NavigationStep>& history);
// Получить текущий шаг (последний в истории) или std::nullopt, если нет истории
std::optional<NavigationStep> getCurrentStep(int64_t userId) const;
// pop последнего состояния. true в случае удачи
bool popStep(int64_t userId);
// Удалить контекст пользователя (например, при логауте)
void removeContext(int64_t userId);
/// @brief Создает контекст начального меню для пользователя
/// @param userId
void createInitContext(int64_t userId);
};

View file

@ -4,6 +4,7 @@
#include <structs.hpp>
#include <unordered_map>
#include "BotToServer.hpp"
#include "BotUserContext.hpp"
/// @brief Структура возвращаемого значения класса BotHandlers для изменения текущего сообщения
struct HandlerResult {
@ -11,30 +12,6 @@ struct HandlerResult {
TgBot::InlineKeyboardMarkup::Ptr keyboard;
};
enum class UserState {
MAIN_MENU, // Главное меню
VIEWING_MY_TITLES, // Список моих тайтлов
AWAITING_TITLE_NAME, // Жду название тайтла для поиска
VIEWING_FOUND_TITLES, // Смотрю найденные тайтлы
VIEWING_TITLE_PAGE, // Смотрю страничку тайтла
AWAITING_REVIEW, // Жду ревью на тайтл
VIEWING_REVIEW_LIST, // Смотрю список ревью на тайтл
VIEWING_REVIEW, // Смотрю (конкретное) ревью на тайтл
VIEWING_DESCRIPTION, // Смотрю описание тайтла
ERROR, // Ошибка состояния
};
struct NavigationStep {
UserState state;
int64_t payload; // ID тайтла, ревью и т.д.
};
struct UserContext {
int64_t userId;
std::vector<NavigationStep> history; // Текущее состояние пользователя + история предыдущих состояний
};
class BotHandlers {
public:
BotHandlers(TgBot::Api api) : botApi(api) {;}
@ -51,19 +28,16 @@ public:
/// в боте.
/// @param message обрабатываемое сообщение
void handleMessage(TgBot::Message::Ptr message);
/// @brief Создает контекст начального меню для пользователя
/// @param chatId id чата пользователя
void createInitContext(int64_t chatId);
void initUser(int64_t userId);
private:
TgBot::Api botApi;
std::unordered_map<int64_t, UserContext> userContexts;
BotUserContext contextManager;
BotToServer server_;
void handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext& ctx);
void handleNavigation(TgBot::CallbackQuery::Ptr query);
void handleError(TgBot::CallbackQuery::Ptr query, UserContext& ctx);
void handleError(TgBot::CallbackQuery::Ptr query);
void processCallbackImpl(TgBot::CallbackQuery::Ptr query);
@ -71,18 +45,7 @@ private:
/// @param userId Идентификатор пользователя
/// @param payload Полезная нагрузка
/// @return HandlerResult
static HandlerResult returnMyTitles(int64_t userId, int64_t payload);
/// @brief Вход в новое состояние
/// @param ctx текущий контекст
/// @param newState новое состояние, добавляемое в стек
/// @param payload полезная нагрузка этого состояния
void pushState(UserContext& ctx, UserState newState, int64_t payload);
/// @brief Возврат в предыдущее состояние
/// @param ctx Текущий контекст
/// @return true в случае успеха
bool popState(UserContext& ctx);
/// static HandlerResult returnMyTitles(int64_t userId, int64_t payload);
/// @brief Уменьшает значение нагрузки с учетом текущего состояния
/// @param payload Изменяемое значение нагрузки
@ -101,12 +64,11 @@ private:
/// кнопки в интерфейсе
/// @param query Callback запрос
/// @param response Параметры ответа: клавиатура и текст
void editMessage(TgBot::CallbackQuery::Ptr query, HandlerResult response);
void editMessage(int64_t chatId, int64_t messageId, HandlerResult response);
/// @brief Отрисовка текущего экрана (соотв. контексту)
/// @param ctx - текущий контекст
/// @return HandlerResult для нового состояния сообщения
HandlerResult renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx);
void renderCurrent(TgBot::CallbackQuery::Ptr query);
/// @brief Логика переходов между контекстами (навигация на следующий шаг)
/// @param query - запрос
@ -121,7 +83,7 @@ private:
/// @brief Посылает интерфейс обработки ошибки на callback запрос
/// @param query запрос
void sendError(TgBot::CallbackQuery::Ptr query, const std::string& errText);
void sendError(int64_t chatId, int64_t messageId, const std::string& errText);
// Форматирование для отображения в сообщении
std::string formatTitlesList(const std::vector<BotStructs::Title>& titles);

View file

@ -0,0 +1,58 @@
#include "BotUserContext.hpp"
std::optional<UserContext> BotUserContext::getContext(int64_t userId) const {
std::lock_guard<std::mutex> lock(mtx);
auto it = userContexts.find(userId);
if (it != userContexts.end()) {
return it->second;
}
return std::nullopt;
}
void BotUserContext::setContext(int64_t userId, const UserContext& context) {
std::lock_guard<std::mutex> lock(mtx);
userContexts[userId] = context;
}
void BotUserContext::pushNavigationStep(int64_t userId, const NavigationStep& step) {
std::lock_guard<std::mutex> lock(mtx);
auto& ctx = userContexts[userId];
ctx.userId = userId;
ctx.history.push_back(step);
}
void BotUserContext::setNavigationHistory(int64_t userId, const std::vector<NavigationStep>& history) {
std::lock_guard<std::mutex> lock(mtx);
auto& ctx = userContexts[userId];
ctx.userId = userId;
ctx.history = history;
}
std::optional<NavigationStep> BotUserContext::getCurrentStep(int64_t userId) const {
std::lock_guard<std::mutex> lock(mtx);
auto it = userContexts.find(userId);
if (it != userContexts.end() && !it->second.history.empty()) {
return it->second.history.back();
}
return std::nullopt;
}
void BotUserContext::removeContext(int64_t userId) {
std::lock_guard<std::mutex> lock(mtx);
userContexts.erase(userId);
}
bool BotUserContext::popStep(int64_t userId) {
std::lock_guard<std::mutex> lock(mtx);
auto it = userContexts.find(userId);
if (it != userContexts.end() && (it->second.history.size() > 1)) {
it->second.history.pop_back();
return true;
}
return false;
}
void BotUserContext::createInitContext(int64_t userId) {
NavigationStep initStep = {UserState::MAIN_MENU, BotConstants::NULL_PAYLOAD};
setContext(userId, {userId, {initStep}});
}

View file

@ -22,12 +22,12 @@ TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMyTitles(std::vector<Bot
int counter = 0;
for(BotStructs::Title& title : titles) {
if(counter >= 6) {
if(counter >= BotConstants::DISP_TITLES_NUM) {
break;
}
auto button = std::make_shared<TgBot::InlineKeyboardButton>();
button->text = std::to_string(title.num) + " " + title.name;
button->callbackData = "title:" + std::to_string(title.num);
button->text = std::to_string(title.num + 1) + " " + title.name;
button->callbackData = BotConstants::Callback::CHOICE + std::to_string(title.num);
row.push_back(button);
counter++;
if(counter % 2 == 0) {
@ -40,7 +40,7 @@ TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMyTitles(std::vector<Bot
if(counter % 2 == 1) {
auto button = std::make_shared<TgBot::InlineKeyboardButton>();
button->text = BotConstants::Button::PREV;
if(titles[0].num == 1) {
if(titles[0].num == 0) {
button->callbackData = BotConstants::Callback::NAV_BACK;
}
else {
@ -51,7 +51,7 @@ TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMyTitles(std::vector<Bot
else {
auto button_prev = std::make_shared<TgBot::InlineKeyboardButton>();
button_prev->text = BotConstants::Button::PREV;
if(titles[0].num == 1) {
if(titles[0].num == 0) {
button_prev->callbackData = BotConstants::Callback::NAV_BACK;
}
else {

View file

@ -13,7 +13,7 @@ void AnimeBot::setupHandlers() {
bot.getEvents().onCommand("start", [this](TgBot::Message::Ptr message) {
sendMainMenu(message->chat->id);
//TODO: производить инициализацию контекста только после авторизации
handler.createInitContext(message->chat->id);
handler.initUser(message->from->id);
});
bot.getEvents().onCallbackQuery([this](TgBot::CallbackQuery::Ptr query) {

View file

@ -0,0 +1,159 @@
#include "handlers.hpp"
#include "KeyboardFactory.hpp"
#include "structs.hpp"
#include "constants.hpp"
void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query) {
//const auto& current = ctx.history.back(); // текущий экран
const std::string& data = query->data;
int64_t userId = query->from->id;
int64_t chatId = query->message->chat->id;
int64_t messageId = query->message->messageId;
// Пагинация (в списках)
/* Временно отключаем, все равно не функционирует :)
if ((data == BotConstants::Callback::LIST_PREV || data == BotConstants::Callback::LIST_NEXT)
&& (current.state == UserState::VIEWING_MY_TITLES || current.state == UserState::VIEWING_REVIEW_LIST ||
current.state == UserState::VIEWING_FOUND_TITLES)) {
int64_t newPayload = current.payload;
if (data == BotConstants::Callback::LIST_PREV && newPayload > 0) {
reducePayload(newPayload, current.state);
} else if (data == BotConstants::Callback::LIST_NEXT) {
increasePayload(newPayload, current.state);
} else {
if (data == BotConstants::Callback::LIST_PREV) {
std::cout << "Error: navigation:prev callback for 1st page" << std::endl;
return;
}
// TODO: log
std::cout << "Error: navigation:prev unknown error" << std::endl;
}
ctx.history.back().payload = newPayload;
renderCurrent(query, ctx);
return;
}*/
// Обработка back по интерфейсу
if (data == BotConstants::Callback::NAV_BACK) {
if (!contextManager.popStep(userId)) {
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
return;
}
renderCurrent(query);
return;
}
// Переходы вперёд (push)
std::optional<NavigationStep> currentStep = contextManager.getCurrentStep(userId);
if(!currentStep.has_value()) {
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
return;
}
auto newStepOpt = computeNextStep(query, currentStep.value());
if (!newStepOpt.has_value()) {
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
return;
}
contextManager.pushNavigationStep(userId, newStepOpt.value());
renderCurrent(query);
}
void BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query) {
int64_t userId = query->from->id;
int64_t chatId = query->message->chat->id;
int64_t messageId = query->message->messageId;
auto step = contextManager.getCurrentStep(userId);
if(!step.has_value()) {;
sendError(chatId, messageId, BotConstants::Text::SAD_ERROR);
return;
}
switch (step.value().state) {
case UserState::MAIN_MENU:
editMessage(chatId, messageId, showMainMenu());
return;
case UserState::VIEWING_MY_TITLES:
server_.fetchUserTitlesAsync(std::to_string(2)) // ALARM: тестовое значение вместо userId
.then([this, chatId, messageId](pplx::task<std::vector<BotStructs::Title>> t) {
try {
auto titles = t.get();
std::string message = formatTitlesList(titles);
auto keyboard = KeyboardFactory::createMyTitles(titles);
editMessage(chatId, messageId, {message, keyboard});
} catch (const std::exception& e) {
sendError(chatId, messageId, BotConstants::Text::SERVER_ERROR);
// Логирование ошибки (например, в cerr)
}
});
return;
/*
case UserState::VIEWING_TITLE_PAGE:
return returnTitlePage(step.payload); // payload = titleId
case UserState::VIEWING_REVIEW:
return returnReview(step.payload); // payload = reviewId
case UserState::AWAITING_REVIEW:
return HandlerResult{"Пришлите текст отзыва:", nullptr};
// ...
*/
default:
return editMessage(chatId, messageId, HandlerResult{BotConstants::Text::SAD_ERROR, nullptr});
}
}
std::optional<NavigationStep> BotHandlers::computeNextStep(
const TgBot::CallbackQuery::Ptr& query,
const NavigationStep& current
) {
const std::string& data = query->data;
switch (current.state) {
case UserState::MAIN_MENU:
if (data == BotConstants::Callback::MY_TITLES) {
return NavigationStep{UserState::VIEWING_MY_TITLES, 0};
}
break;
/*
case UserState::VIEWING_MY_TITLES:
if (data.starts_with("title_")) {
int64_t titleId = parseId(data);
return NavigationStep{UserState::VIEWING_TITLE_PAGE, titleId};
}
break;
case UserState::VIEWING_TITLE_PAGE:
if (data == BotConstants::Callback::ACTION_ADD_REVIEW) {
return NavigationStep{UserState::AWAITING_REVIEW, current.payload};
}
if (data.starts_with("review_")) {
int64_t reviewId = parseId(data);
return NavigationStep{UserState::VIEWING_REVIEW, reviewId};
}
break;
*/
default:
break;
}
return std::nullopt;
}
std::string BotHandlers::formatTitlesList(const std::vector<BotStructs::Title>& titles) {
if (titles.empty()) {
return "У вас пока нет тайтлов.";
}
std::string msg;
for (size_t i = 0; i < titles.size(); ++i) {
// num — 0-based, но в сообщении показываем 1-based
msg += std::to_string(i + 1) + ". " + titles[i].name + "\n";
}
return msg;
}

View file

@ -20,6 +20,7 @@ void BotHandlers::handleCallback(TgBot::CallbackQuery::Ptr query) {
processCallbackImpl(query);
}
/* deprecated. will be deleted soon.
HandlerResult BotHandlers::returnMyTitles(int64_t userId, int64_t payload) {
// Здесь должен происходить запрос на сервер
std::vector<BotStructs::Title> titles = {{123, "Школа мертвяков", "", 1}, {321, "KissXsis", "", 2}};
@ -29,7 +30,7 @@ HandlerResult BotHandlers::returnMyTitles(int64_t userId, int64_t payload) {
result.message = "1. Школа мертвяков\n2. KissXsis\n";
return result;
}
}*/
void BotHandlers::handleMessage(TgBot::Message::Ptr message) {
//TODO: просмотр состояния пользователя
@ -39,93 +40,28 @@ void BotHandlers::handleMessage(TgBot::Message::Ptr message) {
void BotHandlers::processCallbackImpl(TgBot::CallbackQuery::Ptr query) {
const std::string& data = query->data;
int64_t userId = query->from->id;
auto it = userContexts.find(userId);
if (it == userContexts.end()) {
int64_t chatId = query->message->chat->id;
int64_t messageId = query->message->messageId;
std::optional<UserContext> ctx = contextManager.getContext(userId);
if (!ctx.has_value()) {
// TODO: log
sendError(query, BotConstants::Text::AUTH_ERROR);
sendError(chatId, messageId, BotConstants::Text::AUTH_ERROR);
std::cout << "Error: Не нашел пользователя " << userId;
return;
}
UserContext& ctx = it->second;
if (data.starts_with(BotConstants::Callback::NAVIGATION)) {
handleNavigation(query, ctx);
handleNavigation(query);
}
else if (data.starts_with(BotConstants::Callback::ERROR)) {
handleError(query, ctx);
handleError(query);
}
else {
botApi.sendMessage(query->message->chat->id, BotConstants::Text::SAD_ERROR, nullptr, nullptr);
}
}
void BotHandlers::handleNavigation(TgBot::CallbackQuery::Ptr query, UserContext& ctx) {
const auto& current = ctx.history.back(); // текущий экран
const std::string& data = query->data;
// Пагинация (в списках)
if ((data == BotConstants::Callback::LIST_PREV || data == BotConstants::Callback::LIST_NEXT)
&& (current.state == UserState::VIEWING_MY_TITLES || current.state == UserState::VIEWING_REVIEW_LIST ||
current.state == UserState::VIEWING_FOUND_TITLES)) {
int64_t newPayload = current.payload;
if (data == BotConstants::Callback::LIST_PREV && newPayload > 0) {
reducePayload(newPayload, current.state);
} else if (data == BotConstants::Callback::LIST_NEXT) {
increasePayload(newPayload, current.state);
} else {
if (data == BotConstants::Callback::LIST_PREV) {
std::cout << "Error: navigation:prev callback for 1st page" << std::endl;
return;
}
// TODO: log
std::cout << "Error: navigation:prev unknown error" << std::endl;
}
ctx.history.back().payload = newPayload;
auto result = renderCurrent(query, ctx);
if(result.message == "meow") return; // TODO: убрать
editMessage(query, result);
return;
}
// Обработка back по интерфейсу
if (data == BotConstants::Callback::NAV_BACK) {
if (!popState(ctx)) {
sendError(query, BotConstants::Text::SAD_ERROR);
return;
}
auto result = renderCurrent(query, ctx);
if(result.message == "meow") return; // TODO: убрать
editMessage(query, result);
return;
}
// Переходы вперёд (push)
auto newStepOpt = computeNextStep(query, current);
if (!newStepOpt.has_value()) {
sendError(query, BotConstants::Text::SAD_ERROR);
return;
}
ctx.history.push_back(*newStepOpt);
auto result = renderCurrent(query, ctx);
if(result.message == "meow") return; // TODO: убрать
editMessage(query, result);
}
void BotHandlers::pushState(UserContext& ctx, UserState newState, int64_t payload) {
ctx.history.push_back({newState, payload});
}
bool BotHandlers::popState(UserContext& ctx) {
if (ctx.history.size() <= 1) return false; // нельзя выйти из MAIN_MENU
ctx.history.pop_back();
return true;
}
void BotHandlers::reducePayload(int64_t& payload, const UserState curState) {
if (curState == UserState::VIEWING_MY_TITLES ||
curState == UserState::VIEWING_FOUND_TITLES) {
@ -152,11 +88,11 @@ void BotHandlers::increasePayload(int64_t& payload, const UserState curState) {
}
}
void BotHandlers::editMessage(TgBot::CallbackQuery::Ptr query, HandlerResult response) {
void BotHandlers::editMessage(int64_t chatId, int64_t messageId, HandlerResult response) {
botApi.editMessageText(
response.message,
query->message->chat->id,
query->message->messageId,
chatId,
messageId,
"",
"",
nullptr,
@ -164,51 +100,13 @@ void BotHandlers::editMessage(TgBot::CallbackQuery::Ptr query, HandlerResult res
);
}
HandlerResult BotHandlers::renderCurrent(TgBot::CallbackQuery::Ptr query, const UserContext& ctx) {
const auto& step = ctx.history.back();
int64_t userId = query->from->id;
switch (step.state) {
case UserState::MAIN_MENU:
return showMainMenu();
case UserState::VIEWING_MY_TITLES:
server_.fetchUserTitlesAsync(std::to_string(2)) // ALARM: тестовое значение вместо userId
.then([this, query](pplx::task<std::vector<BotStructs::Title>> t) {
try {
auto titles = t.get();
std::string message = formatTitlesList(titles);
auto keyboard = KeyboardFactory::createMyTitles(titles);
editMessage(query, {message, keyboard});
} catch (const std::exception& e) {
sendError(query, BotConstants::Text::SERVER_ERROR);
// Логирование ошибки (например, в cerr)
}
});
return {"meow", nullptr};
/*
case UserState::VIEWING_TITLE_PAGE:
return returnTitlePage(step.payload); // payload = titleId
case UserState::VIEWING_REVIEW:
return returnReview(step.payload); // payload = reviewId
case UserState::AWAITING_REVIEW:
return HandlerResult{"Пришлите текст отзыва:", nullptr};
// ...
*/
default:
return HandlerResult{BotConstants::Text::SAD_ERROR, nullptr};
}
}
HandlerResult BotHandlers::showMainMenu() {
auto keyboard = KeyboardFactory::createMainMenu();
return HandlerResult{BotConstants::Text::MAIN_MENU, keyboard};
}
void BotHandlers::sendError(TgBot::CallbackQuery::Ptr query, const std::string& errText) {
void BotHandlers::sendError(int64_t chatId, int64_t messageId, const std::string& errText) {
//TODO: посылать сообщение с кнопкой возврата в главное меню
TgBot::InlineKeyboardMarkup::Ptr keyboard;
if (errText == BotConstants::Text::SAD_ERROR) {
@ -218,75 +116,28 @@ void BotHandlers::sendError(TgBot::CallbackQuery::Ptr query, const std::string&
keyboard = nullptr; //KeyboardFactory::createError(BotConstants::Callback::ERROR_AUTH);
}
editMessage(query, {errText, keyboard});
editMessage(chatId, messageId, {errText, keyboard});
}
std::optional<NavigationStep> BotHandlers::computeNextStep(
const TgBot::CallbackQuery::Ptr& query,
const NavigationStep& current
) {
const std::string& data = query->data;
switch (current.state) {
case UserState::MAIN_MENU:
if (data == BotConstants::Callback::MY_TITLES) {
return NavigationStep{UserState::VIEWING_MY_TITLES, 0};
}
break;
/*
case UserState::VIEWING_MY_TITLES:
if (data.starts_with("title_")) {
int64_t titleId = parseId(data);
return NavigationStep{UserState::VIEWING_TITLE_PAGE, titleId};
}
break;
case UserState::VIEWING_TITLE_PAGE:
if (data == BotConstants::Callback::ACTION_ADD_REVIEW) {
return NavigationStep{UserState::AWAITING_REVIEW, current.payload};
}
if (data.starts_with("review_")) {
int64_t reviewId = parseId(data);
return NavigationStep{UserState::VIEWING_REVIEW, reviewId};
}
break;
*/
default:
break;
}
return std::nullopt;
}
void BotHandlers::createInitContext(int64_t chatId) {
NavigationStep init = {UserState::MAIN_MENU, BotConstants::NULL_PAYLOAD};
userContexts[chatId] = {chatId, {init}};
}
void BotHandlers::handleError(TgBot::CallbackQuery::Ptr query, UserContext& ctx) {
void BotHandlers::handleError(TgBot::CallbackQuery::Ptr query) {
const std::string& data = query->data;
int64_t userId = query->from->id;
int64_t chatId = query->message->chat->id;
int64_t messageId = query->message->messageId;
if(data == BotConstants::Callback::ERROR_NAVIGATION) {
ctx.history.clear();
ctx.history.push_back({UserState::MAIN_MENU, 0});
contextManager.removeContext(userId);
contextManager.createInitContext(userId);
auto result = showMainMenu();
editMessage(query, result);
editMessage(chatId, messageId, result);
}
else if(data == BotConstants::Callback::ERROR_AUTH) {
// TODO: продумать логику
HandlerResult result = {BotConstants::Text::AUTH_ERROR, nullptr};
editMessage(query, result);
editMessage(chatId, messageId, result);
}
}
std::string BotHandlers::formatTitlesList(const std::vector<BotStructs::Title>& titles) {
if (titles.empty()) {
return "У вас пока нет тайтлов.";
}
std::string msg;
for (size_t i = 0; i < titles.size(); ++i) {
// num — 0-based, но в сообщении показываем 1-based
msg += std::to_string(i + 1) + ". " + titles[i].name + "\n";
}
return msg;
void BotHandlers::initUser(int64_t userId) {
contextManager.createInitContext(userId);
}