2019-12-24 18:53:00 +01:00
|
|
|
/* This file is part of mastorss.
|
|
|
|
* Copyright © 2019 tastytea <tastytea@tastytea.de>
|
|
|
|
*
|
|
|
|
* 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 "config.hpp"
|
|
|
|
#include "exceptions.hpp"
|
|
|
|
|
|
|
|
#include <boost/log/trivial.hpp>
|
2020-01-15 19:05:49 +01:00
|
|
|
#include <mastodonpp/mastodonpp.hpp>
|
2019-12-24 18:53:00 +01:00
|
|
|
|
2020-01-09 23:10:41 +01:00
|
|
|
#include <algorithm>
|
2019-12-24 18:53:00 +01:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace mastorss
|
|
|
|
{
|
2020-01-09 23:10:41 +01:00
|
|
|
using std::transform;
|
|
|
|
using std::back_inserter;
|
2019-12-25 07:02:19 +01:00
|
|
|
using std::stoul;
|
2019-12-24 18:53:00 +01:00
|
|
|
using std::getenv;
|
|
|
|
using std::ifstream;
|
|
|
|
using std::ofstream;
|
|
|
|
using std::cin;
|
|
|
|
using std::cout;
|
|
|
|
using std::stringstream;
|
|
|
|
using std::getline;
|
|
|
|
using std::move;
|
|
|
|
|
|
|
|
std::ostream &operator <<(std::ostream &out, const ProfileData &data)
|
|
|
|
{
|
2019-12-29 05:27:16 +01:00
|
|
|
out << "append: \"" << data.append << "\", "
|
2019-12-24 18:53:00 +01:00
|
|
|
<< "feedurl: \"" << data.feedurl << "\", "
|
|
|
|
<< "fixes: [";
|
|
|
|
for (const auto &fix : data.fixes)
|
|
|
|
{
|
|
|
|
out << '"' << fix << '"';
|
|
|
|
if (fix != *data.fixes.rbegin())
|
|
|
|
{
|
|
|
|
out << ", ";
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 13:42:34 +01:00
|
|
|
out << "], "
|
|
|
|
<< "guids: [";
|
2020-01-01 12:43:04 +01:00
|
|
|
for (const auto &guid : data.guids)
|
|
|
|
{
|
|
|
|
out << '"' << guid << '"';
|
2020-01-01 13:42:34 +01:00
|
|
|
if (guid != *data.guids.rbegin())
|
2020-01-01 12:43:04 +01:00
|
|
|
{
|
|
|
|
out << ", ";
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 13:42:34 +01:00
|
|
|
out << "instance: \"" << data.instance << "\", "
|
2019-12-24 18:53:00 +01:00
|
|
|
<< "interval: " << data.interval << ", "
|
2020-01-01 13:25:05 +01:00
|
|
|
<< "keep_looking: " << data.keep_looking << ", "
|
2019-12-24 18:53:00 +01:00
|
|
|
<< "max_size: " << data.max_size << ", "
|
|
|
|
<< "skip: [";
|
|
|
|
for (const auto &skip : data.skip)
|
|
|
|
{
|
|
|
|
out << '"' << skip << '"';
|
|
|
|
if (skip != *data.skip.rbegin())
|
|
|
|
{
|
|
|
|
out << ", ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out << "], "
|
|
|
|
<< "titles_as_cw: " << data.titles_as_cw << ", "
|
|
|
|
<< "titles_only: " << data.titles_only;
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2019-12-28 09:04:52 +01:00
|
|
|
Config::Config(string profile_name)
|
2019-12-28 09:45:15 +01:00
|
|
|
: profile{move(profile_name)}
|
2019-12-24 18:53:00 +01:00
|
|
|
{
|
|
|
|
const fs::path filename = get_filename();
|
|
|
|
BOOST_LOG_TRIVIAL(debug) << "Config filename is: " << filename;
|
|
|
|
|
2019-12-26 03:56:46 +01:00
|
|
|
ifstream file{filename.c_str()};
|
2019-12-24 18:53:00 +01:00
|
|
|
if (file.good())
|
|
|
|
{
|
|
|
|
stringstream rawjson;
|
|
|
|
rawjson << file.rdbuf();
|
|
|
|
rawjson >> _json;
|
2019-12-25 07:02:19 +01:00
|
|
|
parse();
|
2019-12-24 18:53:00 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
generate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-28 08:49:13 +01:00
|
|
|
fs::path Config::get_config_dir() const
|
2019-12-24 18:53:00 +01:00
|
|
|
{
|
|
|
|
char *envdir = getenv("XDG_CONFIG_HOME");
|
|
|
|
fs::path dir;
|
|
|
|
|
|
|
|
if (envdir != nullptr)
|
|
|
|
{
|
|
|
|
dir = envdir;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
envdir = getenv("HOME");
|
|
|
|
if (envdir != nullptr)
|
|
|
|
{
|
|
|
|
dir = fs::path{envdir} /= ".config";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw FileException{"Couldn't find configuration directory."};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-25 07:12:32 +01:00
|
|
|
dir /= "mastorss";
|
|
|
|
if (fs::create_directories(dir))
|
|
|
|
{
|
|
|
|
BOOST_LOG_TRIVIAL(debug) << "Created config dir: " << dir;
|
|
|
|
}
|
|
|
|
|
2019-12-28 08:49:13 +01:00
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs::path Config::get_filename() const
|
|
|
|
{
|
2019-12-28 09:45:15 +01:00
|
|
|
return get_config_dir() /= "config-" + profile + ".json";
|
2019-12-24 18:53:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Config::generate()
|
|
|
|
{
|
|
|
|
string line;
|
|
|
|
|
|
|
|
cout << "Instance (domain): ";
|
|
|
|
getline(cin, line);
|
2019-12-28 09:01:17 +01:00
|
|
|
profiledata.instance = line;
|
2019-12-24 18:53:00 +01:00
|
|
|
|
2019-12-28 09:01:17 +01:00
|
|
|
profiledata.access_token = get_access_token(line);
|
2019-12-24 18:53:00 +01:00
|
|
|
|
|
|
|
cout << "URL of the feed: ";
|
|
|
|
std::getline(cin, line);
|
2019-12-28 09:01:17 +01:00
|
|
|
profiledata.feedurl = line;
|
2019-12-24 18:53:00 +01:00
|
|
|
|
|
|
|
cout << "Post only titles? [y/n]: ";
|
|
|
|
std::getline(cin, line);
|
2019-12-31 08:00:31 +01:00
|
|
|
profiledata.titles_only = (line[0] == 'y');
|
2019-12-25 07:02:19 +01:00
|
|
|
|
|
|
|
cout << "Post titles as cw? [y/n]: ";
|
|
|
|
std::getline(cin, line);
|
2019-12-31 08:00:31 +01:00
|
|
|
profiledata.titles_as_cw = (line[0] == 'y');
|
2019-12-24 18:53:00 +01:00
|
|
|
|
|
|
|
cout << "Append this string to each post: ";
|
|
|
|
std::getline(cin, line);
|
2019-12-28 09:01:17 +01:00
|
|
|
profiledata.append = line;
|
2019-12-24 18:53:00 +01:00
|
|
|
|
|
|
|
cout << "Interval between posts in seconds [30]: ";
|
|
|
|
std::getline(cin, line);
|
|
|
|
if (line.empty())
|
|
|
|
{
|
|
|
|
line = "30";
|
|
|
|
}
|
2019-12-28 09:01:17 +01:00
|
|
|
profiledata.interval = static_cast<uint32_t>(stoul(line));
|
2019-12-24 18:53:00 +01:00
|
|
|
|
|
|
|
cout << "Maximum size of posts [500]: ";
|
|
|
|
std::getline(cin, line);
|
|
|
|
if (line.empty())
|
|
|
|
{
|
|
|
|
line = "500";
|
|
|
|
}
|
2019-12-28 09:01:17 +01:00
|
|
|
profiledata.max_size = stoul(line);
|
2019-12-24 18:53:00 +01:00
|
|
|
|
2019-12-25 06:25:11 +01:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "Generated configuration.";
|
|
|
|
write();
|
2019-12-24 18:53:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
string Config::get_access_token(const string &instance) const
|
|
|
|
{
|
|
|
|
string client_id;
|
|
|
|
string client_secret;
|
|
|
|
string url;
|
2020-01-15 19:05:49 +01:00
|
|
|
mastodonpp::Instance masto{instance, ""};
|
|
|
|
mastodonpp::Instance::ObtainToken token{masto};
|
2019-12-24 18:53:00 +01:00
|
|
|
|
2020-01-15 19:05:49 +01:00
|
|
|
auto ret{token.step_1("mastorss", "write:statuses",
|
|
|
|
"https://schlomp.space/tastytea/mastorss")};
|
2019-12-24 18:53:00 +01:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
string code;
|
|
|
|
string access_token;
|
|
|
|
|
2020-01-15 19:05:49 +01:00
|
|
|
cout << "Visit " << ret << " to authorize this application.\n";
|
2019-12-24 18:53:00 +01:00
|
|
|
cout << "Insert code: ";
|
|
|
|
std::getline(cin, code);
|
2020-01-15 19:05:49 +01:00
|
|
|
ret = token.step_2(code);
|
2019-12-24 18:53:00 +01:00
|
|
|
if (ret)
|
|
|
|
{
|
2020-01-15 19:05:49 +01:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "Got access token.";
|
2019-12-24 18:53:00 +01:00
|
|
|
return access_token;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-16 22:37:53 +01:00
|
|
|
throw CURLException{ret.curl_error_code};
|
2019-12-24 18:53:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Config::parse()
|
|
|
|
{
|
2019-12-28 09:04:52 +01:00
|
|
|
profiledata.access_token = _json[profile]["access_token"].asString();
|
|
|
|
profiledata.append = _json[profile]["append"].asString();
|
|
|
|
profiledata.feedurl = _json[profile]["feedurl"].asString();
|
2020-01-01 12:13:35 +01:00
|
|
|
profiledata.fixes = jsonarray_to_stringlist(_json[profile]["fixes"]);
|
2020-01-01 12:43:04 +01:00
|
|
|
profiledata.guids = jsonarray_to_stringlist(_json[profile]["guids"]);
|
2019-12-28 09:04:52 +01:00
|
|
|
profiledata.instance = _json[profile]["instance"].asString();
|
|
|
|
if (!_json[profile]["interval"].isNull())
|
2019-12-24 18:53:00 +01:00
|
|
|
{
|
2019-12-28 09:01:17 +01:00
|
|
|
profiledata.interval =
|
2019-12-28 09:04:52 +01:00
|
|
|
static_cast<uint32_t>(_json[profile]["interval"].asUInt64());
|
2019-12-24 18:53:00 +01:00
|
|
|
}
|
2020-01-01 13:25:05 +01:00
|
|
|
profiledata.keep_looking = _json[profile]["keep_looking"].asBool();
|
2019-12-28 09:04:52 +01:00
|
|
|
if (!_json[profile]["max_size"].isNull())
|
2019-12-24 18:53:00 +01:00
|
|
|
{
|
2019-12-28 09:04:52 +01:00
|
|
|
profiledata.max_size = _json[profile]["max_size"].asUInt64();
|
2019-12-24 18:53:00 +01:00
|
|
|
}
|
2020-01-01 12:13:35 +01:00
|
|
|
profiledata.skip = jsonarray_to_stringlist(_json[profile]["skip"]);
|
2019-12-28 09:04:52 +01:00
|
|
|
profiledata.titles_as_cw = _json[profile]["titles_as_cw"].asBool();
|
|
|
|
profiledata.titles_only = _json[profile]["titles_only"].asBool();
|
2019-12-24 18:53:00 +01:00
|
|
|
|
2019-12-28 09:01:17 +01:00
|
|
|
BOOST_LOG_TRIVIAL(debug) << "Read config: " << profiledata;
|
2019-12-24 18:53:00 +01:00
|
|
|
}
|
2019-12-25 06:25:11 +01:00
|
|
|
|
2019-12-25 07:02:19 +01:00
|
|
|
void Config::write()
|
2019-12-25 06:25:11 +01:00
|
|
|
{
|
2019-12-28 09:04:52 +01:00
|
|
|
_json[profile]["access_token"] = profiledata.access_token;
|
|
|
|
_json[profile]["append"] = profiledata.append;
|
|
|
|
_json[profile]["feedurl"] = profiledata.feedurl;
|
2020-01-01 12:43:04 +01:00
|
|
|
_json[profile]["guids"] = stringlist_to_jsonarray(profiledata.guids);
|
2020-01-01 12:13:35 +01:00
|
|
|
_json[profile]["fixes"] = stringlist_to_jsonarray(profiledata.fixes);
|
2019-12-28 09:04:52 +01:00
|
|
|
_json[profile]["instance"] = profiledata.instance;
|
|
|
|
_json[profile]["interval"] = profiledata.interval;
|
2020-01-01 13:25:05 +01:00
|
|
|
_json[profile]["keep_looking"] = profiledata.keep_looking;
|
2019-12-28 09:04:52 +01:00
|
|
|
_json[profile]["max_size"]
|
2019-12-28 09:01:17 +01:00
|
|
|
= static_cast<Json::Value::UInt64>(profiledata.max_size);
|
2020-01-01 12:13:35 +01:00
|
|
|
_json[profile]["skip"] = stringlist_to_jsonarray(profiledata.skip);
|
2019-12-28 09:04:52 +01:00
|
|
|
_json[profile]["titles_as_cw"] = profiledata.titles_as_cw;
|
|
|
|
_json[profile]["titles_only"] = profiledata.titles_only;
|
2019-12-25 07:02:19 +01:00
|
|
|
|
2019-12-26 03:56:46 +01:00
|
|
|
ofstream file{get_filename().c_str()};
|
2019-12-25 06:25:11 +01:00
|
|
|
if (file.good())
|
|
|
|
{
|
|
|
|
file << _json.toStyledString();
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOST_LOG_TRIVIAL(debug) << "Wrote config file.";
|
|
|
|
}
|
2020-01-01 12:13:35 +01:00
|
|
|
|
|
|
|
list<string> Config::jsonarray_to_stringlist(const Json::Value &jsonarray) const
|
|
|
|
{
|
|
|
|
list<string> stringlist;
|
2020-01-09 23:32:33 +01:00
|
|
|
std::transform(jsonarray.begin(), jsonarray.end(),
|
|
|
|
back_inserter(stringlist), [](const Json::Value &value)
|
|
|
|
{ return value.asString(); });
|
2020-01-09 23:10:41 +01:00
|
|
|
|
2020-01-01 12:13:35 +01:00
|
|
|
return stringlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
Json::Value Config::stringlist_to_jsonarray(const list<string> &stringlist)
|
|
|
|
const
|
|
|
|
{
|
|
|
|
Json::Value jsonarray;
|
2020-01-09 23:32:33 +01:00
|
|
|
|
|
|
|
for (const auto &entry : stringlist)
|
|
|
|
{
|
|
|
|
jsonarray.append(entry);
|
|
|
|
}
|
2020-01-09 23:10:41 +01:00
|
|
|
|
2020-01-01 12:13:35 +01:00
|
|
|
return jsonarray;
|
|
|
|
}
|
2019-12-24 18:53:00 +01:00
|
|
|
} // namespace mastorss
|