175 lines
4.8 KiB
C
175 lines
4.8 KiB
C
|
/**
|
||
|
*
|
||
|
* @file RestfulController.h
|
||
|
* @author An Tao
|
||
|
*
|
||
|
* Copyright 2018, An Tao. All rights reserved.
|
||
|
* https://github.com/an-tao/drogon
|
||
|
* Use of this source code is governed by a MIT license
|
||
|
* that can be found in the License file.
|
||
|
*
|
||
|
* Drogon
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <drogon/exports.h>
|
||
|
#include <drogon/drogon.h>
|
||
|
#include <drogon/orm/DbClient.h>
|
||
|
#include <drogon/orm/Mapper.h>
|
||
|
#include <trantor/utils/NonCopyable.h>
|
||
|
#include <string>
|
||
|
#include <functional>
|
||
|
#include <vector>
|
||
|
|
||
|
namespace drogon
|
||
|
{
|
||
|
/**
|
||
|
* @brief this class is a helper class for the implementation of restful api
|
||
|
* controllers generated by the drogon_ctl command.
|
||
|
*/
|
||
|
class DROGON_EXPORT RestfulController : trantor::NonCopyable
|
||
|
{
|
||
|
public:
|
||
|
void enableMasquerading(const std::vector<std::string> &pMasqueradingVector)
|
||
|
{
|
||
|
masquerading_ = true;
|
||
|
masqueradingVector_ = pMasqueradingVector;
|
||
|
for (size_t i = 0; i < masqueradingVector_.size(); ++i)
|
||
|
{
|
||
|
masqueradingMap_.insert(
|
||
|
std::pair<std::string, size_t>{masqueradingVector_[i], i});
|
||
|
}
|
||
|
}
|
||
|
void disableMasquerading()
|
||
|
{
|
||
|
masquerading_ = false;
|
||
|
masqueradingVector_ = columnsVector_;
|
||
|
for (size_t i = 0; i < masqueradingVector_.size(); ++i)
|
||
|
{
|
||
|
masqueradingMap_.insert(
|
||
|
std::pair<std::string, size_t>{masqueradingVector_[i], i});
|
||
|
}
|
||
|
}
|
||
|
void registerAJsonValidator(
|
||
|
const std::string &fieldName,
|
||
|
const std::function<bool(const Json::Value &, std::string &)>
|
||
|
&validator)
|
||
|
{
|
||
|
validators_.emplace_back(fieldName, validator);
|
||
|
}
|
||
|
void registerAJsonValidator(
|
||
|
const std::string &fieldName,
|
||
|
std::function<bool(const Json::Value &, std::string &)> &&validator)
|
||
|
{
|
||
|
validators_.emplace_back(fieldName, std::move(validator));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief make a criteria object for searching by ORM.
|
||
|
*
|
||
|
* @param pJson the json object presenting search criterias.
|
||
|
* The json object must be an array of depth 3.
|
||
|
* for example:
|
||
|
* [
|
||
|
* [
|
||
|
* ["color","=","red"], //AND
|
||
|
* ["price","<",1000]
|
||
|
* ], //OR
|
||
|
* [
|
||
|
* ["color","=","white"], //AND
|
||
|
* ["price","<",800], //AND
|
||
|
* ["brand","!=",null]
|
||
|
* ]
|
||
|
* ]
|
||
|
* @return orm::Criteria
|
||
|
*/
|
||
|
|
||
|
orm::Criteria makeCriteria(const Json::Value &pJson) noexcept(false);
|
||
|
|
||
|
protected:
|
||
|
RestfulController(const std::vector<std::string> &columnsVector)
|
||
|
: columnsVector_(columnsVector)
|
||
|
{
|
||
|
}
|
||
|
std::vector<std::string> fieldsSelector(const std::set<std::string> &fields)
|
||
|
{
|
||
|
std::vector<std::string> ret;
|
||
|
for (auto &field : masqueradingVector_)
|
||
|
{
|
||
|
if (!field.empty() && fields.find(field) != fields.end())
|
||
|
{
|
||
|
ret.emplace_back(field);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ret.emplace_back(std::string{});
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
template <typename T>
|
||
|
Json::Value makeJson(const HttpRequestPtr &req, const T &obj)
|
||
|
{
|
||
|
auto &queryParams = req->parameters();
|
||
|
auto iter = queryParams.find("fields");
|
||
|
if (masquerading_)
|
||
|
{
|
||
|
if (iter != queryParams.end())
|
||
|
{
|
||
|
auto fields = utils::splitStringToSet(iter->second, ",");
|
||
|
return obj.toMasqueradedJson(fieldsSelector(fields));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return obj.toMasqueradedJson(masqueradingVector_);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (iter != queryParams.end())
|
||
|
{
|
||
|
auto fields = utils::splitString(iter->second, ",");
|
||
|
return obj.toMasqueradedJson(fields);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return obj.toJson();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
bool doCustomValidations(const Json::Value &pJson, std::string &err)
|
||
|
{
|
||
|
for (auto &validator : validators_)
|
||
|
{
|
||
|
if (pJson.isMember(validator.first))
|
||
|
{
|
||
|
if (!validator.second(pJson[validator.first], err))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
bool isMasquerading() const
|
||
|
{
|
||
|
return masquerading_;
|
||
|
}
|
||
|
const std::vector<std::string> &masqueradingVector() const
|
||
|
{
|
||
|
return masqueradingVector_;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
bool masquerading_{true};
|
||
|
std::vector<std::string> masqueradingVector_;
|
||
|
std::vector<
|
||
|
std::pair<std::string,
|
||
|
std::function<bool(const Json::Value &, std::string &)>>>
|
||
|
validators_;
|
||
|
std::unordered_map<std::string, size_t> masqueradingMap_;
|
||
|
const std::vector<std::string> columnsVector_;
|
||
|
};
|
||
|
} // namespace drogon
|