2018-04-01 03:36:11 +02:00
|
|
|
/* This file is part of mastodon-cpp.
|
2019-03-20 06:15:43 +01:00
|
|
|
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
|
2019-03-28 13:33:28 +01:00
|
|
|
*
|
2018-04-01 03:36:11 +02:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, version 3.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <iomanip> // get_time
|
|
|
|
#include <sstream>
|
|
|
|
#include <chrono>
|
2019-04-18 04:46:55 +02:00
|
|
|
#include <ctime>
|
2018-04-01 03:36:11 +02:00
|
|
|
#include <regex>
|
2019-03-30 23:15:22 +01:00
|
|
|
#include <algorithm>
|
2019-03-28 15:30:56 +01:00
|
|
|
#include "easy/entity.hpp"
|
2019-02-22 11:35:06 +01:00
|
|
|
#include "debug.hpp"
|
2018-04-01 03:36:11 +02:00
|
|
|
|
|
|
|
using namespace Mastodon;
|
|
|
|
using std::string;
|
|
|
|
using std::chrono::system_clock;
|
|
|
|
|
|
|
|
Easy::Entity::Entity(const string &json)
|
|
|
|
: _tree(Json::nullValue)
|
2018-04-09 21:47:07 +02:00
|
|
|
,_was_set(false)
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
|
|
|
from_string(json);
|
|
|
|
}
|
|
|
|
|
2019-03-11 20:41:52 +01:00
|
|
|
Easy::Entity::Entity(const Json::Value &object)
|
|
|
|
: _tree(object)
|
|
|
|
,_was_set(false)
|
|
|
|
{}
|
|
|
|
|
2019-02-25 14:36:49 +01:00
|
|
|
Easy::Entity::Entity()
|
2019-03-11 21:13:58 +01:00
|
|
|
: _tree(Json::nullValue)
|
|
|
|
, _was_set(false)
|
2019-02-25 14:36:49 +01:00
|
|
|
{}
|
|
|
|
|
|
|
|
Easy::Entity::~Entity()
|
|
|
|
{}
|
|
|
|
|
2019-03-11 20:41:52 +01:00
|
|
|
Easy::Entity::operator const Json::Value() const
|
|
|
|
{
|
|
|
|
return to_object();
|
|
|
|
}
|
|
|
|
|
2018-12-04 11:26:28 +01:00
|
|
|
void Easy::Entity::from_string(const string &json)
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
2019-04-15 03:48:39 +02:00
|
|
|
if (json.find('{') != std::string::npos)
|
|
|
|
{
|
|
|
|
std::stringstream ss(json);
|
|
|
|
ss >> _tree;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_tree.clear();
|
|
|
|
}
|
2018-04-01 03:36:11 +02:00
|
|
|
|
|
|
|
// If the JSON is a single object encapsulated in an array,
|
|
|
|
// transform it into an object. If the JSON string is [], transform to null
|
|
|
|
if (_tree.type() == Json::ValueType::arrayValue && _tree.size() <= 1)
|
|
|
|
{
|
|
|
|
_tree = _tree[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_tree.isNull())
|
|
|
|
{
|
|
|
|
ttdebug << "ERROR: JSON string holds no object\n";
|
|
|
|
ttdebug << "String was: " << json << '\n';
|
|
|
|
}
|
2019-04-15 03:07:04 +02:00
|
|
|
else if (!_tree["error"].isNull() || !_tree["errors"].isNull())
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
|
|
|
ttdebug << "ERROR: Server returned an error\n";
|
|
|
|
ttdebug << "String was: " << json << '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-25 14:36:49 +01:00
|
|
|
const string Easy::Entity::to_string() const
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
2019-02-25 14:36:49 +01:00
|
|
|
return _tree.toStyledString();
|
2018-04-01 03:36:11 +02:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:36:49 +01:00
|
|
|
void Easy::Entity::from_object(const Json::Value &object)
|
|
|
|
{
|
|
|
|
_tree = object;
|
|
|
|
}
|
2019-02-25 13:55:24 +01:00
|
|
|
|
2019-02-25 14:36:49 +01:00
|
|
|
const Json::Value Easy::Entity::to_object() const
|
|
|
|
{
|
|
|
|
return _tree;
|
|
|
|
}
|
2018-04-01 03:36:11 +02:00
|
|
|
|
2018-12-04 11:26:28 +01:00
|
|
|
bool Easy::Entity::check_valid(const std::vector<string> &attributes) const
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
2018-07-14 11:44:30 +02:00
|
|
|
for (const string &attribute: attributes)
|
|
|
|
{
|
|
|
|
get(attribute);
|
|
|
|
if (!was_set())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2018-04-01 03:36:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const string Easy::Entity::error() const
|
|
|
|
{
|
2019-04-15 03:07:04 +02:00
|
|
|
string error = get_string("error");
|
|
|
|
if (error.empty())
|
|
|
|
{
|
|
|
|
// Pleroma uses {"errors":{"detail":"[…]"}} sometimes.
|
|
|
|
const Json::Value node = get("errors.detail");
|
|
|
|
error = node.asString();
|
|
|
|
}
|
|
|
|
return error;
|
2018-04-01 03:36:11 +02:00
|
|
|
}
|
|
|
|
|
2018-12-04 11:26:28 +01:00
|
|
|
bool Easy::Entity::was_set() const
|
2018-04-09 21:47:07 +02:00
|
|
|
{
|
|
|
|
return _was_set;
|
|
|
|
}
|
|
|
|
|
2018-04-01 03:36:11 +02:00
|
|
|
const Json::Value Easy::Entity::get(const string &key) const
|
|
|
|
{
|
|
|
|
const Json::Value *node;
|
|
|
|
if (key.find('.') == std::string::npos)
|
|
|
|
{
|
|
|
|
node = &_tree[key];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If dots in key, we have to walk through the tree
|
|
|
|
std::size_t pos = 0;
|
|
|
|
string current_key = key;
|
|
|
|
node = &_tree;
|
|
|
|
while ((pos = current_key.find('.')) != std::string::npos)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
node = &(*node)[current_key.substr(0, pos)];
|
|
|
|
current_key = current_key.substr(pos + 1);
|
|
|
|
}
|
|
|
|
catch (const Json::LogicError &e)
|
|
|
|
{
|
|
|
|
ttdebug << e.what() << '\n';
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
node = &(*node)[current_key];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!node->isNull())
|
|
|
|
{
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = true;
|
2018-04-01 03:36:11 +02:00
|
|
|
return *node;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
ttdebug << "Could not get data: " << key << '\n';
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = false;
|
2018-04-01 03:36:11 +02:00
|
|
|
return Json::Value();
|
|
|
|
}
|
|
|
|
|
|
|
|
const string Easy::Entity::get_string(const string &key) const
|
|
|
|
{
|
|
|
|
const Json::Value node = get(key);
|
|
|
|
|
|
|
|
if (node.isString())
|
|
|
|
{
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = true;
|
2018-04-01 03:36:11 +02:00
|
|
|
return node.asString();
|
|
|
|
}
|
|
|
|
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = false;
|
2018-04-01 03:36:11 +02:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2019-02-22 08:29:54 +01:00
|
|
|
uint64_t Easy::Entity::get_uint64(const string &key) const
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
|
|
|
const Json::Value node = get(key);
|
|
|
|
|
|
|
|
if (node.isUInt64())
|
|
|
|
{
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = true;
|
2018-04-01 03:36:11 +02:00
|
|
|
return node.asUInt64();
|
|
|
|
}
|
|
|
|
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = false;
|
2018-04-01 03:36:11 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-04 11:26:28 +01:00
|
|
|
double Easy::Entity::get_double(const string &key) const
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
|
|
|
const Json::Value node = get(key);
|
|
|
|
|
|
|
|
if (node.isDouble())
|
|
|
|
{
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = true;
|
2018-04-01 03:36:11 +02:00
|
|
|
return node.asDouble();
|
|
|
|
}
|
|
|
|
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = false;
|
2018-04-01 03:36:11 +02:00
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
2018-12-04 11:26:28 +01:00
|
|
|
bool Easy::Entity::get_bool(const string &key) const
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
|
|
|
const Json::Value node = get(key);
|
|
|
|
|
|
|
|
if (node.isBool())
|
|
|
|
{
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = true;
|
2018-04-01 03:36:11 +02:00
|
|
|
return node.asBool();
|
|
|
|
}
|
|
|
|
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = false;
|
2018-04-01 03:36:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-03-29 14:44:39 +01:00
|
|
|
const Easy::time Easy::Entity::get_time(const string &key) const
|
2018-04-01 03:36:11 +02:00
|
|
|
{
|
|
|
|
const Json::Value node = get(key);
|
|
|
|
|
|
|
|
if (node.isString())
|
|
|
|
{
|
|
|
|
std::stringstream sstime(node.asString());
|
2019-04-18 04:46:55 +02:00
|
|
|
struct std::tm tm = {};
|
|
|
|
tm.tm_isdst = -1; // Detect daylight saving time.
|
2018-04-01 03:36:11 +02:00
|
|
|
sstime >> std::get_time(&tm, "%Y-%m-%dT%T");
|
2019-04-18 04:46:55 +02:00
|
|
|
std::time_t time = timegm(&tm); // Assume time is UTC.
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = true;
|
2019-03-29 14:44:39 +01:00
|
|
|
return { system_clock::from_time_t(time) };
|
2018-04-01 03:36:11 +02:00
|
|
|
}
|
|
|
|
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = false;
|
2018-04-01 03:36:11 +02:00
|
|
|
// Return clocks epoch
|
2019-03-29 14:44:39 +01:00
|
|
|
return { system_clock::time_point() };
|
2018-04-01 03:36:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<string> Easy::Entity::get_vector(const string &key) const
|
|
|
|
{
|
|
|
|
const Json::Value node = get(key);
|
|
|
|
|
|
|
|
if (node.isArray())
|
|
|
|
{
|
|
|
|
std::vector<string> vec;
|
2019-03-30 23:15:22 +01:00
|
|
|
std::transform(node.begin(), node.end(), std::back_inserter(vec),
|
2019-03-30 23:49:08 +01:00
|
|
|
[](const Json::Value &value)
|
2019-03-30 23:15:22 +01:00
|
|
|
{ return value.asString(); });
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = true;
|
2018-04-01 03:36:11 +02:00
|
|
|
return vec;
|
|
|
|
}
|
|
|
|
|
2018-04-10 09:40:26 +02:00
|
|
|
_was_set = false;
|
2018-04-01 03:36:11 +02:00
|
|
|
return {};
|
|
|
|
}
|
2018-05-11 06:12:09 +02:00
|
|
|
|
2018-12-04 11:26:28 +01:00
|
|
|
void Easy::Entity::set(const string &key, const Json::Value &value)
|
2018-06-13 23:55:19 +02:00
|
|
|
{
|
2018-06-14 01:53:28 +02:00
|
|
|
if (key.find('.') == std::string::npos)
|
|
|
|
{
|
|
|
|
_tree[key] = value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::size_t pos = 0;
|
|
|
|
string current_key = key;
|
|
|
|
Json::Value *node = &_tree;
|
|
|
|
|
|
|
|
while ((pos = current_key.find('.')) != std::string::npos)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
node = &(*node)[current_key.substr(0, pos)];
|
|
|
|
if (node->isNull())
|
|
|
|
{
|
|
|
|
*node = Json::Value(Json::objectValue);
|
|
|
|
}
|
|
|
|
current_key = current_key.substr(pos + 1);
|
|
|
|
}
|
|
|
|
catch (const Json::LogicError &e)
|
|
|
|
{
|
|
|
|
ttdebug << e.what() << '\n';
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(*node)[current_key] = value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
ttdebug << "Could not set data: " << key << '\n';
|
2018-06-13 23:55:19 +02:00
|
|
|
}
|
|
|
|
|
2019-02-22 08:29:54 +01:00
|
|
|
std::uint64_t Easy::Entity::stouint64(const string &str) const
|
2018-05-11 06:12:09 +02:00
|
|
|
{
|
|
|
|
if (str == "")
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return stoull(str);
|
|
|
|
}
|
|
|
|
}
|
2019-02-25 13:55:24 +01:00
|
|
|
|
2019-03-28 13:33:28 +01:00
|
|
|
// Easy::GenericEntity::GenericEntity(const string &json)
|
|
|
|
// : Entity(json)
|
|
|
|
// {}
|
2019-02-25 13:55:24 +01:00
|
|
|
|
2019-03-28 13:33:28 +01:00
|
|
|
// Easy::GenericEntity::GenericEntity()
|
|
|
|
// : Entity()
|
|
|
|
// {}
|
2019-02-25 13:55:24 +01:00
|
|
|
|
2019-03-28 13:33:28 +01:00
|
|
|
// bool Easy::GenericEntity::valid() const
|
|
|
|
// {
|
|
|
|
// return true;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// template<typename T> GenericEntity<T>::GenericEntity(const string &json)
|
|
|
|
// : Entity(json)
|
|
|
|
// {}
|
|
|
|
|
|
|
|
// template<typename T> GenericEntity<T>::GenericEntity()
|
|
|
|
// : Entity()
|
|
|
|
// {}
|
|
|
|
|
|
|
|
// template<typename T> bool GenericEntity<T>::valid() const
|
|
|
|
// {
|
|
|
|
// return true;
|
|
|
|
// }
|