Compare commits

...
Sign in to create a new pull request.

35 commits

Author SHA1 Message Date
Kirill
da40d7df49 feat(tgbot): add title menu 2025-12-20 01:19:56 +03:00
Kirill
f045eb22b2 feat(tgbot-back): Add functions for processing user authentication 2025-12-19 17:48:16 +03:00
Kirill
d6194ec8be fix: 1 userTitle case error 2025-12-19 17:40:21 +03:00
Kirill
3bbd2c2818 Merge branch 'dev' into dev-karas
Need to get a fresh openapi description for auth
2025-12-06 05:39:18 +03:00
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
Kirill
847aec7bdd feat(tgbot-back): start to develop back
Implemented fetchUserTitlesAsync func and embedded it in the code of the front in the trial mode. It needs to be restructured
2025-12-05 12:38:34 +03:00
Kirill
4ca8b19adb Merge branch 'dev' into dev-karas
Need to update the openapi documentation.
2025-12-05 01:42:08 +03:00
Kirill
6123ee039b feat(tgbot-front): start handleError func develop 2025-12-04 16:38:18 +03:00
Kirill
ccf9722bb7 feat(tgbot-front): implement the back button operation
Add functions to handle navigation callback logic
Also add function for creating initial user context (pay attention to auth and registration later)
2025-12-01 23:28:23 +03:00
Kirill
0fdf577612 feat(tgbot-front): add consts for titles and revs number 2025-11-28 15:22:42 +03:00
Kirill
c815e96f4c feat(tgbot-front): add new funcs to work with payload 2025-11-28 15:21:07 +03:00
Kirill
d69f5fcddf fix(tgbot-front): start fixing navigation callback processing function 2025-11-28 15:18:31 +03:00
Kirill
b368ecc43b Added context navigation logic 2025-11-28 12:57:07 +03:00
Kirill
a8dd448c95 Added a callback to go back through the state stack 2025-11-28 12:42:11 +03:00
Kirill
e09b6658b2 Bad variant of navigation handler (not working) 2025-11-28 12:30:34 +03:00
Kirill
28a7d9e691 Added payload constant 2025-11-28 12:29:53 +03:00
Kirill
12648e1a8f Changing the structure of the UserContext. Adding context history 2025-11-28 12:25:40 +03:00
Kirill
7efd7bb6b0 Added cursor field to UserContext 2025-11-27 18:13:40 +03:00
Kirill
bd309d38c6 Fixed .gitignore 2025-11-27 17:34:04 +03:00
Kirill
167e2323be Announce UserContext struct 2025-11-27 17:33:04 +03:00
Kirill
3d8abc3f0c Changed .gitignore 2025-11-27 16:24:46 +03:00
Kirill
cdc1aa2e6b Forming the BotHandlers class structure 2025-11-27 16:24:29 +03:00
Kirill
ea29fa79f0 getting ready to refactor the handlers structure 2025-11-25 22:05:12 +03:00
Kirill
45a1df4cbb Added MyTitles page passing 2025-11-25 19:45:44 +03:00
Kirill
45ce5da0ac Changed main menu text 2025-11-18 17:44:03 +03:00
Kirill
602e9b62d8 Started creating structure of bot interface 2025-11-18 17:30:43 +03:00
Kirill
879a7981cd Init commit of bot development 2025-11-17 22:15:53 +03:00
54 changed files with 5457 additions and 10 deletions

1
api/.gitignore vendored Normal file
View file

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

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

@ -639,20 +639,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

@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.10.2)
project(AnimeBot)
set(SOURCES "")
file(GLOB_RECURSE SRC_FRONT "front/src/*.cpp")
list(APPEND SOURCES ${SRC_FRONT})
file(GLOB_RECURSE SRC_BACK "back/src/*.cpp")
list(APPEND SOURCES ${SRC_BACK})
file(GLOB_RECURSE SRC_API "generated-client/src/*.cpp")
list(APPEND SOURCES ${SRC_API})
file(GLOB_RECURSE SRC_AUTH "generated-client-auth/src/*.cpp")
list(APPEND SOURCES ${SRC_AUTH})
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
set(Boost_USE_MULTITHREADED ON)
set(CMAKE_BUILD_TYPE Debug)
find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED)
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(front/include/)
include_directories(back/include)
include_directories(generated-client/include)
include_directories(generated-client-auth/include)
if (CURL_FOUND)
include_directories(${CURL_INCLUDE_DIRS})
add_definitions(-DHAVE_CURL)
endif()
add_executable(AnimeBot ${SOURCES})
target_link_libraries(AnimeBot /usr/local/lib/libTgBot.a ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} ${CPPREST_LIB})

1
modules/bot/README.md Normal file
View file

@ -0,0 +1 @@
### Здесь будет часть, отвечающая за телеграм ботика

View file

@ -0,0 +1,35 @@
// AuthImpersonationClient.hpp
#pragma once
#include <memory>
#include <string>
#include <stdexcept>
#include <cstdlib>
#include <map>
#include <cpprest/asyncrt_utils.h>
#include "AuthClient/ApiClient.h"
#include "AuthClient/ApiConfiguration.h"
#include "AuthClient/api/AuthApi.h"
#include "AuthClient/model/GetImpersonationToken_request.h"
#include "AuthClient/model/GetImpersonationToken_200_response.h"
namespace nyanimed {
class AuthImpersonationClient {
public:
AuthImpersonationClient();
// Потокобезопасный вызов — не модифицирует состояние
pplx::task<std::shared_ptr<nyanimed::meow::auth::model::GetImpersonationToken_200_response>>
getImpersonationToken(int64_t userId) const;
private:
std::string m_baseUrl;
std::string m_authToken;
std::shared_ptr<nyanimed::meow::auth::api::ApiClient> m_apiClient;
std::shared_ptr<nyanimed::meow::auth::api::AuthApi> m_authApi;
};
} // namespace nyanimed

View file

@ -0,0 +1,39 @@
#pragma once
#include "CppRestOpenAPIClient/ApiClient.h"
#include "CppRestOpenAPIClient/ApiConfiguration.h"
#include "CppRestOpenAPIClient/api/DefaultApi.h"
#include "CppRestOpenAPIClient/model/User.h"
#include "CppRestOpenAPIClient/model/GetUserTitles_200_response.h"
#include "CppRestOpenAPIClient/model/UserTitle.h"
#include "CppRestOpenAPIClient/model/Title.h"
#include "constants.hpp"
#include "structs.hpp"
#include <iostream>
#include <thread>
#include <functional>
#include <memory>
#include <cpprest/asyncrt_utils.h>
#include <boost/optional.hpp>
#include "AuthImpersonation.hpp"
using namespace org::openapitools::client::api;
class BotToServer {
public:
BotToServer();
// Асинхронный метод: получить список тайтлов пользователя
pplx::task<std::vector<BotStructs::Title>> fetchUserTitlesAsync(const std::string& userId);
pplx::task<BotStructs::Title> fetchTitleAsync(const std::string& userId, int64_t titleId);
private:
std::shared_ptr<org::openapitools::client::api::ApiConfiguration> apiconfiguration;
std::shared_ptr<org::openapitools::client::api::ApiClient> apiclient;
std::shared_ptr<org::openapitools::client::api::DefaultApi> api;
nyanimed::AuthImpersonationClient authClient;
static BotStructs::Title mapTitleToBotTitle(
const std::shared_ptr<org::openapitools::client::model::Title>& titleModel);
};

View file

@ -0,0 +1,34 @@
#include "AuthImpersonation.hpp"
nyanimed::AuthImpersonationClient::AuthImpersonationClient() {
const char* baseUrlEnv = std::getenv("NYANIMEDBAUTHURL");
const char* tokenEnv = std::getenv("NYANIMEDBAUTHTOKEN");
if (!baseUrlEnv || std::string(baseUrlEnv).empty()) {
throw std::runtime_error("Missing required environment variable: NYANIMEDBAUTHURL");
}
if (!tokenEnv || std::string(tokenEnv).empty()) {
throw std::runtime_error("Missing required environment variable: NYANIMEDBAUTHTOKEN");
}
m_baseUrl = baseUrlEnv;
m_authToken = tokenEnv;
auto config = std::make_shared<nyanimed::meow::auth::api::ApiConfiguration>();
config->setBaseUrl(utility::conversions::to_string_t(m_baseUrl));
m_apiClient = std::make_shared<nyanimed::meow::auth::api::ApiClient>(config);
m_authApi = std::make_shared<nyanimed::meow::auth::api::AuthApi>(m_apiClient);
}
pplx::task<std::shared_ptr<nyanimed::meow::auth::model::GetImpersonationToken_200_response>>
nyanimed::AuthImpersonationClient::getImpersonationToken(int64_t userId) const {
auto request = std::make_shared<nyanimed::meow::auth::model::GetImpersonationToken_request>();
request->setUserId(userId);
//request->setExternalId(externalId);
std::map<utility::string_t, utility::string_t> headers;
headers[U("Authorization")] = U("Bearer ") + utility::conversions::to_string_t(m_authToken);
return m_authApi->getImpersonationToken(request, headers);
}

View file

@ -0,0 +1,216 @@
#include "BotToServer.hpp"
BotToServer::BotToServer() {
apiconfiguration = std::make_shared<ApiConfiguration>();
const char* envUrl = getenv("NYANIMEDBBASEURL");
if (!envUrl) {
std::runtime_error("Environment variable NYANIMEDBBASEURL is not set");
}
apiconfiguration->setBaseUrl(utility::conversions::to_string_t(envUrl));
apiconfiguration->setUserAgent(utility::conversions::to_string_t("OpenAPI Client"));
apiclient = std::make_shared<ApiClient>(apiconfiguration);
api = std::make_shared<DefaultApi>(apiclient);
}
// Вспомогательная функция: преобразует UserTitle → BotStructs::Title
static BotStructs::Title mapUserTitleToBotTitle(
const std::shared_ptr<org::openapitools::client::model::UserTitle>& userTitle
) {
if (!userTitle || !userTitle->titleIsSet()) {
return BotStructs::Title{0, "Invalid", "", -1};
}
auto apiTitle = userTitle->getTitle();
if (!apiTitle) {
return BotStructs::Title{0, "No Title", "", -1};
}
int64_t id = apiTitle->getId();
std::string name = "Untitled";
auto titleNames = apiTitle->getTitleNames();
utility::string_t ru = U("ru");
if (titleNames.find(ru) != titleNames.end() && !titleNames.at(ru).empty()) {
name = utility::conversions::to_utf8string(titleNames.at(ru).front());
} else if (!titleNames.empty()) {
const auto& firstLang = *titleNames.begin();
if (!firstLang.second.empty()) {
name = utility::conversions::to_utf8string(firstLang.second.front());
}
}
std::string description = ""; // описание пока не поддерживается в OpenAPI-модели
return BotStructs::Title{id, name, description, -1};
}
pplx::task<std::vector<BotStructs::Title>> BotToServer::fetchUserTitlesAsync(const std::string& userId) {
// Шаг 1: Получаем impersonation-токен
auto impersonationTask = authClient.getImpersonationToken(std::stoi(userId));
// Шаг 2: После получения токена — делаем запрос getUserTitles с этим токеном
return impersonationTask.then([=](pplx::task<std::shared_ptr<nyanimed::meow::auth::model::GetImpersonationToken_200_response>> tokenTask) {
try {
auto tokenResponse = tokenTask.get();
if (!tokenResponse) {
throw std::runtime_error("Null response from getImpersonationToken");
}
utility::string_t accessToken = utility::conversions::to_string_t(tokenResponse->getAccessToken());
// Формируем заголовки с токеном
std::map<utility::string_t, utility::string_t> customHeaders;
customHeaders[U("Cookie")] = U("access_token=") + accessToken;
// Подготавливаем параметры запроса
utility::string_t userIdW = utility::conversions::to_string_t(userId);
int32_t limit = static_cast<int32_t>(BotConstants::DISP_TITLES_NUM);
// Шаг 3: Выполняем getUserTitles с кастомными заголовками
return api->getUserTitles(
userIdW,
boost::none, // cursor
boost::none, // sort
boost::none, // sortForward
boost::none, // word
boost::none, // status
boost::none, // watchStatus
boost::none, // rating
boost::none, // myRate
boost::none, // releaseYear
boost::none, // releaseSeason
limit,
boost::none, // fields
customHeaders
);
} catch (const std::exception& e) {
std::cerr << "Error obtaining impersonation token: " << e.what() << std::endl;
throw; // Пробрасываем, чтобы цепочка task.then завершилась с ошибкой
}
}).then([=](pplx::task<std::shared_ptr<org::openapitools::client::model::GetUserTitles_200_response>> responseTask) {
try {
auto response = responseTask.get();
if (!response) {
throw std::runtime_error("Null response from getUserTitles");
}
const auto& userTitles = response->getData();
std::vector<BotStructs::Title> result;
result.reserve(userTitles.size());
for (size_t i = 0; i < userTitles.size(); ++i) {
BotStructs::Title botTitle = mapUserTitleToBotTitle(userTitles[i]);
botTitle.num = static_cast<int64_t>(i); // 0-based индекс
result.push_back(botTitle);
}
return result;
} catch (const web::http::http_exception& e) {
std::cerr << "HTTP error in fetchUserTitlesAsync: " << e.what() << std::endl;
throw;
} catch (const std::exception& e) {
std::cerr << "Error in fetchUserTitlesAsync: " << e.what() << std::endl;
throw;
}
});
}
pplx::task<BotStructs::Title> BotToServer::fetchTitleAsync(const std::string& userId, int64_t titleId) {
auto impersonationTask = authClient.getImpersonationToken(std::stoi(userId));
// Шаг 2: После получения токена — делаем запрос getTitle с этим токеном
return impersonationTask.then([=](pplx::task<std::shared_ptr<nyanimed::meow::auth::model::GetImpersonationToken_200_response>> tokenTask) {
try {
auto tokenResponse = tokenTask.get();
if (!tokenResponse) {
throw std::runtime_error("Null response from getImpersonationToken");
}
utility::string_t accessToken = utility::conversions::to_string_t(tokenResponse->getAccessToken());
// Формируем заголовки с токеном
std::map<utility::string_t, utility::string_t> customHeaders;
customHeaders[U("Cookie")] = U("access_token=") + accessToken;
// Шаг 3: Выполняем запрос getTitle
return api->getTitle(
titleId,
boost::none, // fields — оставляем по умолчанию (все поля)
customHeaders
);
} catch (const std::exception& e) {
std::cerr << "Error obtaining impersonation token in fetchTitleAsync: " << e.what() << std::endl;
throw;
}
}).then([](pplx::task<std::shared_ptr<org::openapitools::client::model::Title>> responseTask) {
try {
auto response = responseTask.get();
if (!response) {
throw std::runtime_error("Null response from getTitle");
}
// Преобразуем модель OpenAPI в внутреннюю структуру бота
BotStructs::Title botTitle = mapTitleToBotTitle(response);
return botTitle;
} catch (const web::http::http_exception& e) {
std::cerr << "HTTP error in fetchTitleAsync: " << e.what() << std::endl;
throw;
} catch (const std::exception& e) {
std::cerr << "Error in fetchTitleAsync: " << e.what() << std::endl;
throw;
}
});
}
BotStructs::Title BotToServer::mapTitleToBotTitle(
const std::shared_ptr<org::openapitools::client::model::Title>& titleModel)
{
if (!titleModel) {
throw std::invalid_argument("titleModel is null");
}
BotStructs::Title botTitle;
botTitle.id = titleModel->getId();
botTitle.num = 0;
botTitle.description = ""; // Описание недоступно в текущей модели
// Извлекаем название
std::string titleName;
const auto& titleNames = titleModel->getTitleNames();
// Попробуем ru → en → первый попавшийся
std::vector<utility::string_t> preferredLangs = { U("ru"), U("en") };
bool found = false;
for (const auto& lang : preferredLangs) {
auto it = titleNames.find(lang);
if (it != titleNames.end() && !it->second.empty()) {
titleName = utility::conversions::to_utf8string(it->second[0]);
found = true;
break;
}
}
if (!found && !titleNames.empty()) {
// Берём первый язык и первое название
const auto& firstLang = *titleNames.begin();
if (!firstLang.second.empty()) {
titleName = utility::conversions::to_utf8string(firstLang.second[0]);
}
}
botTitle.name = titleName;
// --- Изображение ---
botTitle.imageUrl = "";
if (titleModel->posterIsSet()) {
auto poster = titleModel->getPoster();
if (poster && poster->imagePathIsSet()) {
botTitle.imageUrl = utility::conversions::to_utf8string(poster->getImagePath());
}
}
return botTitle;
}

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

@ -0,0 +1,2 @@
build/
out/

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

@ -0,0 +1,17 @@
#include <tgbot/tgbot.h>
#include "structs.hpp"
class KeyboardFactory {
public:
/// Create keyboard for main menu
static TgBot::InlineKeyboardMarkup::Ptr createMainMenu();
/// Create keyboard for My_Titles
static TgBot::InlineKeyboardMarkup::Ptr createMyTitles(std::vector<BotStructs::Title> titles);
/// Create keyboard for sendError
static TgBot::InlineKeyboardMarkup::Ptr createError(const std::string& errorCallback);
/// Create keyboard for Title page
static TgBot::InlineKeyboardMarkup::Ptr createTitleMenu(int64_t title_id);
};

View file

@ -0,0 +1,44 @@
#pragma once
#include <string>
namespace BotConstants {
const int64_t NULL_PAYLOAD = -1; // Default value для payload
const int64_t DISP_TITLES_NUM = 6; // Количество тайтлов, отображаемых на страничке
const int64_t DISP_REVIEW_NUM = 4; // Количество ревью, отображаемых на страничке
namespace Button {
const std::string TO_MAIN_MENU = "Главное меню";
const std::string FIND_ANIME = "Найти аниме";
const std::string MY_TITLES = "Мои тайтлы";
const std::string PREV = "<<Назад";
const std::string NEXT = "Дальше>>";
}
namespace Callback {
const std::string ACTION = "action:";
const std::string FIND_ANIME = ACTION + "find_anime";
const std::string ADD_REVIEW = ACTION + "add_review";
const std::string ADD_STATUS = ACTION + "add_status";
const std::string STATUS = "status:";
const std::string WATCHING = STATUS + "watching";
const std::string SEEN = STATUS + "seen";
const std::string WANT = STATUS + "want";
const std::string THROWN = STATUS + "thrown";
const std::string NAVIGATION = "navigation:";
const std::string MAIN_MENU = NAVIGATION + "main_menu";
const std::string MY_TITLES = NAVIGATION + "my_titles";
const std::string LIST_PREV = NAVIGATION + "prev"; // Пагинация
const std::string LIST_NEXT = NAVIGATION + "next"; // Пагинация
const std::string NAV_BACK = NAVIGATION + "back"; // Возврат по стеку состояний
const std::string CHOICE = "choice:";
const std::string ERROR = "error:";
const std::string ERROR_NAVIGATION = ERROR + NAVIGATION;
const std::string ERROR_AUTH = ERROR + "auth";
}
namespace Text {
const std::string MAIN_MENU = "Вас приветствует nyanimedb бот:)\nЧего будем делать?";
const std::string SAD_ERROR = "У нас что-то случилось:(\nМы обязательно скоро исправимся";
const std::string AUTH_ERROR = "Проблемы с авторизацией, попробуйте авторизоваться повторно";
const std::string SERVER_ERROR = "Не удалось загрузить данные. Попробуйте позже.";
}
}

View file

@ -0,0 +1,27 @@
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <exception>
#include <string>
#include <tgbot/tgbot.h>
#include "handlers.hpp"
class AnimeBot {
private:
TgBot::Bot bot;
BotHandlers handler;
public:
/// Init Bot
AnimeBot(const std::string& token);
/// Main menu
void setupHandlers();
/// Get TgBot::Bot
TgBot::Bot& getBot();
/// Function creates main menu and sends it to user with chatId
void sendMainMenu(int64_t chatId);
};

View file

@ -0,0 +1,112 @@
#pragma once
#include <tgbot/tgbot.h>
#include <string>
#include <structs.hpp>
#include <unordered_map>
#include <string>
#include <stdexcept>
#include <cctype>
#include "BotToServer.hpp"
#include "BotUserContext.hpp"
/// @brief Структура возвращаемого значения класса BotHandlers для изменения текущего сообщения
struct HandlerResult {
std::string message;
TgBot::InlineKeyboardMarkup::Ptr keyboard;
};
class BotHandlers {
public:
BotHandlers(TgBot::Api api) : botApi(api) {;}
/// @brief Обработка callback'ов из кнопок интерфейса
/// @param query запрос callback
void handleCallback(TgBot::CallbackQuery::Ptr query);
/// @brief Обработка сообщений боту
/// @details
/// Функция для обработки сообщений, которые юзер отправляет
/// боту. Необходима для обработки ревью и названий искомого
/// аниме. Внутри себя проверяет текущий state пользователя
/// в боте.
/// @param message обрабатываемое сообщение
void handleMessage(TgBot::Message::Ptr message);
void initUser(int64_t userId);
private:
TgBot::Api botApi;
BotUserContext contextManager;
BotToServer server_;
void handleNavigation(TgBot::CallbackQuery::Ptr query);
void handleError(TgBot::CallbackQuery::Ptr query);
void processCallbackImpl(TgBot::CallbackQuery::Ptr query);
/// @brief Получить очередную страницу тайтлов из списка пользователя
/// @param userId Идентификатор пользователя
/// @param payload Полезная нагрузка
/// @return HandlerResult
/// static HandlerResult returnMyTitles(int64_t userId, int64_t payload);
/// @brief Уменьшает значение нагрузки с учетом текущего состояния
/// @param payload Изменяемое значение нагрузки
/// @param curState Текущее состояние
void reducePayload(int64_t& payload, const UserState curState);
/// @brief Увеличивает значение нагрузки с учетом текущего состояния
/// @param payload Изменяемое значение нагрузки
/// @param curState Текущее состояние
void increasePayload(int64_t& payload, const UserState curState);
/// @brief Редактирует текущее сообщение в диалоге с пользователем
/// @details Меняет текст сообщения и клавиатуру на те, что передаются
/// в аргументе response. Информацию об id чата и изменяемого сообщения
/// забирает из query, который возвращается с callback'ом после нажатия
/// кнопки в интерфейсе
/// @param query Callback запрос
/// @param response Параметры ответа: клавиатура и текст
void editMessage(int64_t chatId, int64_t messageId, HandlerResult response);
/// @brief Редактирует текущее сообщение в диалоге с пользователем
/// @details Меняет текст сообщения и клавиатуру на те, что передаются
/// в аргументе response, а также прикрепляет картинку
/// @param chatId id чата
/// @param messageId id меняемого сообщения
/// @param imageUrl ссылка на вставляемую картинку (должна быть доступна в публичной сети)
/// @param response Параметры ответа: клавиатура и текст
void editMessageWithPhoto(
int64_t chatId,
int64_t messageId,
const std::string& imageUrl,
HandlerResult response);
/// @brief Отрисовка текущего экрана (соотв. контексту)
/// @param ctx - текущий контекст
void renderCurrent(TgBot::CallbackQuery::Ptr query);
/// @brief Логика переходов между контекстами (навигация на следующий шаг)
/// @param query - запрос
/// @param current - текущий шаг навигации
/// @return следующий NavigationStep при успехе (std::nullopt в случае ошибки)
std::optional<NavigationStep> computeNextStep(const TgBot::CallbackQuery::Ptr& query,
const NavigationStep& current);
/// @brief Получить состояние страницы главного меню
/// @return HandlerResult с параметрами главного меню
HandlerResult showMainMenu();
/// @brief Посылает интерфейс обработки ошибки на callback запрос
/// @param query запрос
void sendError(int64_t chatId, int64_t messageId, const std::string& errText);
// Форматирование для отображения в сообщении
std::string formatTitlesList(const std::vector<BotStructs::Title>& titles);
// Форматирование сообщения на страничке с тайтлом
std::string formatTitle(const BotStructs::Title& title);
// Парсинг id тайтла из callback'а
int64_t parseId(const std::string& data);
};

View file

@ -0,0 +1,11 @@
#pragma once
namespace BotStructs {
struct Title {
int64_t id;
std::string name;
std::string description;
int64_t num;
std::string imageUrl;
};
}

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

@ -0,0 +1,83 @@
#include "KeyboardFactory.hpp"
#include "constants.hpp"
TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMainMenu() {
auto keyboard = std::make_shared<TgBot::InlineKeyboardMarkup>();
TgBot::InlineKeyboardButton::Ptr button1(new TgBot::InlineKeyboardButton);
button1->text = BotConstants::Button::FIND_ANIME;
button1->callbackData = BotConstants::Callback::FIND_ANIME;
TgBot::InlineKeyboardButton::Ptr button2(new TgBot::InlineKeyboardButton);
button2->text = BotConstants::Button::MY_TITLES;
button2->callbackData = BotConstants::Callback::MY_TITLES;
keyboard->inlineKeyboard = {{button1, button2}};
return keyboard;
}
// TODO: Переписать с учетом констант на количество отображаемых тайтлов и нового callback'a
TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createMyTitles(std::vector<BotStructs::Title> titles) {
auto keyboard = std::make_shared<TgBot::InlineKeyboardMarkup>();
std::vector<TgBot::InlineKeyboardButton::Ptr> row;
std::vector<std::vector<TgBot::InlineKeyboardButton::Ptr>> layout;
int counter = 0;
for(BotStructs::Title& title : titles) {
if(counter >= BotConstants::DISP_TITLES_NUM) {
break;
}
auto button = std::make_shared<TgBot::InlineKeyboardButton>();
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) {
layout.push_back(row);
row.clear();
}
}
if (!row.empty()) {
layout.push_back(row);
row.clear();
}
// TODO: Додумать логику, когда пришло 6 записей в конце
if(counter % 2 == 1) {
auto button = std::make_shared<TgBot::InlineKeyboardButton>();
button->text = BotConstants::Button::PREV;
if(titles[0].num == 0) {
button->callbackData = BotConstants::Callback::NAV_BACK;
}
else {
button->callbackData = BotConstants::Callback::LIST_PREV + ':' + std::to_string(titles[0].num);
}
layout.back().push_back(button);
}
else {
auto button_prev = std::make_shared<TgBot::InlineKeyboardButton>();
button_prev->text = BotConstants::Button::PREV;
if(titles[0].num == 0) {
button_prev->callbackData = BotConstants::Callback::NAV_BACK;
}
else {
button_prev->callbackData = BotConstants::Callback::LIST_PREV + ':' + std::to_string(titles[0].num);
}
auto button_next = std::make_shared<TgBot::InlineKeyboardButton>();
button_next->text = BotConstants::Button::NEXT;
button_next->callbackData = BotConstants::Callback::LIST_NEXT + ':' + std::to_string(titles[5].num);
layout.push_back({button_prev, button_next});
}
keyboard->inlineKeyboard = layout;
return keyboard;
}
TgBot::InlineKeyboardMarkup::Ptr KeyboardFactory::createError(const std::string& errorCallback) {
auto keyboard = std::make_shared<TgBot::InlineKeyboardMarkup>();
TgBot::InlineKeyboardButton::Ptr button(new TgBot::InlineKeyboardButton);
button->text = BotConstants::Button::TO_MAIN_MENU;
button->callbackData = errorCallback;
keyboard->inlineKeyboard = {{button}};
return keyboard;
}

View file

@ -0,0 +1,35 @@
#include "front.hpp"
#include "KeyboardFactory.hpp"
#include "constants.hpp"
#include "handlers.hpp"
AnimeBot::AnimeBot(const std::string& token)
: bot(token)
, handler(bot.getApi()) {
setupHandlers();
}
void AnimeBot::setupHandlers() {
bot.getEvents().onCommand("start", [this](TgBot::Message::Ptr message) {
sendMainMenu(message->chat->id);
//TODO: производить инициализацию контекста только после авторизации
handler.initUser(message->from->id);
});
bot.getEvents().onCallbackQuery([this](TgBot::CallbackQuery::Ptr query) {
handler.handleCallback(query);
});
bot.getEvents().onAnyMessage([this](TgBot::Message::Ptr message) {
handler.handleMessage(message);
});
}
void AnimeBot::sendMainMenu(int64_t chatId) {
auto keyboard = KeyboardFactory::createMainMenu();
bot.getApi().sendMessage(chatId, BotConstants::Text::MAIN_MENU, nullptr, nullptr, keyboard);
}
TgBot::Bot& AnimeBot::getBot() {
return bot;
}

View file

@ -0,0 +1,219 @@
#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(22)) // 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:
server_.fetchTitleAsync(std::to_string(22), step.value().payload)
.then([this, chatId, messageId](pplx::task<BotStructs::Title> t) {
try {
auto title = t.get();
std::string message = formatTitle(title);
auto keyboard = KeyboardFactory::createTitleMenu(title.id);
std::string imageUrl = "https://i.pinimg.com/736x/30/2b/49/302b49176e5a74ef43871a462df47e1f.jpg";
editMessageWithPhoto(chatId, messageId, imageUrl, {message, keyboard});
} catch (const std::exception& e) {
sendError(chatId, messageId, BotConstants::Text::SERVER_ERROR);
// Логирование ошибки (например, в cerr)
}
});
return;
/*
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(BotConstants::Callback::CHOICE)) {
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;
}
std::string BotHandlers::formatTitle(const BotStructs::Title& title) {
std::string msg;
msg += title.name + "\n";
return msg;
}
int64_t BotHandlers::parseId(const std::string& data) {
const std::string prefix = "choice:";
if (data.substr(0, prefix.size()) != prefix) {
throw std::invalid_argument("Data does not start with 'choice:'");
}
std::string idPart = data.substr(prefix.size());
// Проверяем, что остаток состоит только из цифр (и, возможно, знака '-')
if (idPart.empty()) {
throw std::invalid_argument("ID part is empty");
}
size_t startPos = 0;
if (idPart[0] == '-') {
if (idPart.size() == 1) {
throw std::invalid_argument("Invalid negative ID");
}
startPos = 1;
}
for (size_t i = startPos; i < idPart.size(); ++i) {
if (!std::isdigit(static_cast<unsigned char>(idPart[i]))) {
throw std::invalid_argument("ID contains non-digit characters");
}
}
try {
return std::stoll(idPart);
} catch (const std::out_of_range&) {
throw std::out_of_range("ID is out of range for int64_t");
}
}

View file

@ -0,0 +1,187 @@
#include "handlers.hpp"
#include "KeyboardFactory.hpp"
#include "structs.hpp"
#include "constants.hpp"
void BotHandlers::handleCallback(TgBot::CallbackQuery::Ptr query) {
if (!query) {
// TODO: log
return;
}
try {
// TODO: Тут mutex на многопоточке
botApi.answerCallbackQuery(query->id);
} catch (const std::exception& e) {
std::cerr << "answerCallbackQuery error";
//TODO: обработка ошибки
}
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}};
struct HandlerResult result;
result.keyboard = KeyboardFactory::createMyTitles(titles);
result.message = "1. Школа мертвяков\n2. KissXsis\n";
return result;
}*/
void BotHandlers::handleMessage(TgBot::Message::Ptr message) {
//TODO: просмотр состояния пользователя
return;
}
void BotHandlers::processCallbackImpl(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;
std::optional<UserContext> ctx = contextManager.getContext(userId);
if (!ctx.has_value()) {
// TODO: log
sendError(chatId, messageId, BotConstants::Text::AUTH_ERROR);
std::cout << "Error: Не нашел пользователя " << userId;
return;
}
if (data.starts_with(BotConstants::Callback::NAVIGATION)) {
handleNavigation(query);
}
else if (data.starts_with(BotConstants::Callback::CHOICE)) {
handleNavigation(query);
}
else if (data.starts_with(BotConstants::Callback::ERROR)) {
handleError(query);
}
else {
botApi.sendMessage(query->message->chat->id, BotConstants::Text::SAD_ERROR, nullptr, nullptr);
}
}
void BotHandlers::reducePayload(int64_t& payload, const UserState curState) {
if (curState == UserState::VIEWING_MY_TITLES ||
curState == UserState::VIEWING_FOUND_TITLES) {
payload -= BotConstants::DISP_TITLES_NUM;
} else if (curState == UserState::VIEWING_REVIEW_LIST) {
payload -= BotConstants::DISP_REVIEW_NUM;
} else {
// TODO: log
payload = BotConstants::NULL_PAYLOAD;
std::cerr << "Error: reducePayload" << std::endl;
}
}
void BotHandlers::increasePayload(int64_t& payload, const UserState curState) {
if (curState == UserState::VIEWING_MY_TITLES ||
curState == UserState::VIEWING_FOUND_TITLES) {
payload += BotConstants::DISP_TITLES_NUM;
} else if (curState == UserState::VIEWING_REVIEW_LIST) {
payload += BotConstants::DISP_REVIEW_NUM;
} else {
// TODO: log
payload = BotConstants::NULL_PAYLOAD;
std::cerr << "Error: increasePayload" << std::endl;
}
}
void BotHandlers::editMessage(int64_t chatId, int64_t messageId, HandlerResult response) {
// botApi.editMessageText быстрее. Реализовать его, где возможно
try {
botApi.deleteMessage(chatId, messageId);
} catch (const std::exception& e) {
std::cerr << "Warning: Failed to delete message " << messageId
<< " in chat " << chatId << ": " << e.what() << std::endl;
// Продолжаем отправку нового сообщения даже при ошибке удаления
}
// 2. Отправляем новое сообщение с правильным порядком параметров
botApi.sendMessage(
chatId, // chatId
response.message, // text
nullptr, // linkPreviewOptions (nullptr = default)
nullptr, // replyParameters (не отвечаем на сообщение)
response.keyboard, // replyMarkup — клавиатура
"HTML", // parseMode — поддержка <b>, <i> и т.д.
false // disableNotification
// остальные параметры по умолчанию
);
}
void BotHandlers::editMessageWithPhoto(
int64_t chatId,
int64_t messageId,
const std::string& imageUrl,
HandlerResult response)
{
// 1. Удаляем старое сообщение
try {
botApi.deleteMessage(chatId, messageId);
} catch (const std::exception& e) {
// Игнорируем ошибку, если сообщение уже удалено или недоступно
std::cerr << "Warning: Failed to delete message: " << e.what() << std::endl;
}
std::string safeCaption = response.message;
if (safeCaption.length() > 1024) {
safeCaption = safeCaption.substr(0, 1021) + "...";
}
// Отправка фото по URL
botApi.sendPhoto(
chatId,
imageUrl,
safeCaption,
nullptr,
response.keyboard,
"HTML"
);
}
HandlerResult BotHandlers::showMainMenu() {
auto keyboard = KeyboardFactory::createMainMenu();
return HandlerResult{BotConstants::Text::MAIN_MENU, keyboard};
}
void BotHandlers::sendError(int64_t chatId, int64_t messageId, const std::string& errText) {
//TODO: посылать сообщение с кнопкой возврата в главное меню
TgBot::InlineKeyboardMarkup::Ptr keyboard;
if (errText == BotConstants::Text::SAD_ERROR) {
keyboard = KeyboardFactory::createError(BotConstants::Callback::ERROR_NAVIGATION);
}
else if (errText == BotConstants::Text::AUTH_ERROR) {
keyboard = nullptr; //KeyboardFactory::createError(BotConstants::Callback::ERROR_AUTH);
}
editMessage(chatId, messageId, {errText, keyboard});
}
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) {
contextManager.removeContext(userId);
contextManager.createInitContext(userId);
auto result = showMainMenu();
editMessage(chatId, messageId, result);
}
else if(data == BotConstants::Callback::ERROR_AUTH) {
// TODO: продумать логику
HandlerResult result = {BotConstants::Text::AUTH_ERROR, nullptr};
editMessage(chatId, messageId, result);
}
}
void BotHandlers::initUser(int64_t userId) {
contextManager.createInitContext(userId);
}

View file

@ -0,0 +1,15 @@
#include <front.hpp>
int main() {
AnimeBot bot(getenv("TOKEN"));
TgBot::TgLongPoll longPoll(bot.getBot());
while (true) {
try {
longPoll.start();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
return 0;
}