From 3fb2225392df5bfa659b6cc93a37f84e56c14810 Mon Sep 17 00:00:00 2001 From: tastytea Date: Tue, 12 Feb 2019 01:46:48 +0100 Subject: [PATCH] Ups, habe das committen vergessen. :-) --- .gitmodules | 3 + CMakeLists.txt | 7 +- README.adoc | 17 ++++- feiertagebot.cpp | 190 ++++++++++++++++++++++++++++++++++++++++++++--- xdgjson | 1 + 5 files changed, 201 insertions(+), 17 deletions(-) create mode 100644 .gitmodules create mode 160000 xdgjson diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b472415 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "xdgjson"] + path = xdgjson + url = https://schlomp.space/tastytea/xdgjson.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 7094cab..f44461b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,6 @@ project(feiertagebot include(GNUInstallDirs) find_package(PkgConfig REQUIRED) pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir) -pkg_check_modules(LIBCONFIG REQUIRED libconfig++) pkg_check_modules(CURLPP REQUIRED curlpp) pkg_check_modules(JSONCPP REQUIRED jsoncpp) @@ -19,20 +18,18 @@ set(CMAKE_CXX_FLAGS_DEBUG include_directories(${PROJECT_BINARY_DIR}) include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS}) -include_directories(${LIBCONFIG_INCLUDE_DIRS}) include_directories(${CURL_INCLUDE_DIRS}) include_directories(${CURLPP_INCLUDE_DIRS}) include_directories(${JSONCPP_INCLUDE_DIRS}) link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS}) -link_directories(${LIBCONFIG_LIBRARY_DIRS}) link_directories(${CURL_LIBRARY_DIRS}) link_directories(${CURLPP_LIBRARY_DIRS}) link_directories(${JSONCPP_LIBRARY_DIRS}) -add_executable(${CMAKE_PROJECT_NAME} feiertagebot.cpp) +add_executable(${CMAKE_PROJECT_NAME} feiertagebot.cpp xdgjson/src/xdgjson.cpp) target_link_libraries(${CMAKE_PROJECT_NAME} "${LIBXDG_BASEDIR_LDFLAGS} ${LIBCONFIG_LDFLAGS}" "${CURLPP_LDFLAGS} ${JSONCPP_LDFLAGS}" - "-lstdc++fs") + "-lstdc++fs -lmastodon-cpp") install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/README.adoc b/README.adoc index ec3dae9..57d4dde 100644 --- a/README.adoc +++ b/README.adoc @@ -3,8 +3,6 @@ *feiertagebot* ist ein Mastodon-bot, der über anstehende feiertage in Deutschland informiert. Die daten stammen von https://feiertage-api.de/. -NOTE: Ist noch in arbeit, tut bis jetzt noch nix. - == Installation === Gentoo @@ -17,9 +15,9 @@ https://schlomp.space/tastytea/overlay[repository]. * C++ compiler * https://cmake.org/[cmake] (mindestens 3.2) * http://repo.or.cz/w/libxdg-basedir.git[libxdg-basedir] (getested: 1.2) -* https://github.com/hyperrealm/libconfig[libconfig++] (getested: 1.5) * http://www.curlpp.org/[curlpp] (getested: 0.8) * https://github.com/open-source-parsers/jsoncpp[jsoncpp] (getested: 1.8) +* https://schlomp.space/tastytea/mastodon-cpp[mastodon-cpp] (mindestens 0.30.1) === Kompilieren @@ -35,6 +33,19 @@ make install .cmake options: * `-DCMAKE_BUILD_TYPE=Debug` für ein debug-build +== Benutzung + +Beim ersten aufruf wirst du nach der instanz gefragt, dann wird ein access_token +generiert. Danach kannst du das programm einfach per cron aufrufen +(`crontab -e`). + +.Beispieleintrag crontab +[source,crontab] +---- +# m h dom mon dow command + 10 14 * * * feiertagebot +---- + == Lizenz CC-0 / Public Domain diff --git a/feiertagebot.cpp b/feiertagebot.cpp index d38bb0b..c38d043 100644 --- a/feiertagebot.cpp +++ b/feiertagebot.cpp @@ -5,26 +5,149 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include "xdgjson/src/xdgjson.hpp" namespace curlopts = curlpp::options; using std::string; using std::cout; using std::cerr; using std::endl; +using std::vector; +using std::chrono::system_clock; +using std::chrono::hours; +using std::uint_fast16_t; + +const string version = "2019-02-12_1"; + +struct Holiday +{ + string date; + string description; + vector regions; +}; + +const string decode_state(const string &abbr) +{ + const std::map states = + { + { "BW", "Baden-Württemberg" }, + { "BY", "Bayern" }, + { "BE", "Berlin" }, + { "BB", "Brandenburg" }, + { "HB", "Bremen" }, + { "HH", "Hamburg" }, + { "HE", "Hessen" }, + { "MV", "Mecklenburg-Vorpommern" }, + { "NI", "Niedersachsen" }, + { "NW", "Nordrhein-Westfalen" }, + { "RP", "Rheinland-Pfalz" }, + { "SL", "Saarland" }, + { "SN", "Sachsen" }, + { "ST", "Sachsen-Anhalt" }, + { "SH", "Schleswig-Holstein" }, + { "TH", "Thüringen" } + }; + + if (states.find(abbr) != states.end()) + { + return states.find(abbr)->second; + } + else + { + return abbr; + } +} + +const string get_date(const system_clock::time_point &timepoint, const string &format) +{ + std::time_t time = system_clock::to_time_t(timepoint); + std::tm *timeinfo = std::localtime(&time); + char buffer[1024]; + std::strftime(buffer, 1024, format.c_str(), timeinfo); + return string(buffer); +} + +const string get_token(const string &instance) +{ + Mastodon::API masto(instance, ""); + uint_fast16_t ret = 0; + string client_id, client_secret, url; + string code, access_token; + ret = masto.register_app1("feiertagebot", + "urn:ietf:wg:oauth:2.0:oob", + "write:statuses", + "", + client_id, + client_secret, + url); + if (ret > 0) + { + cerr << "Error " << std::to_string(ret) << endl; + return ""; + } + + cout << "Visit " << url << " to authorize this application.\n"; + cout << "Insert code: "; + std::getline(std::cin, code); + ret = masto.register_app2(client_id, + client_secret, + "urn:ietf:wg:oauth:2.0:oob", + code, + access_token); + if (ret > 0) + { + cerr << "Error " << std::to_string(ret) << endl; + return ""; + } + + return access_token; +} int main() { - const string version = "2019-02-11_1"; + string instance, access_token; + xdgjson config("feiertagebot.json"); + config.read(); + Json::Value &json = config.get_json(); + if (json["instance"].isString()) + { + instance = json["instance"].asString(); + } + else + { + cout << "Instance domain: "; + std::getline(std::cin, instance); + json["instance"] = instance; + } + if (json["access_token"].isString()) + { + access_token = json["access_token"].asString(); + } + else + { + access_token = get_token(instance); + json["access_token"] = access_token; + config.write(); + } try { - string year = "2019"; - string today = "2019-12-25"; - string tomorrow = "2019-12-26"; + string year = get_date(system_clock::now(), "%Y"); + string today = get_date(system_clock::now(), "%F"); + string tomorrow = get_date(system_clock::now() + hours(24), "%F"); + tomorrow = "2019-01-06"; + curlpp::Easy request; std::stringstream ss; @@ -32,19 +155,67 @@ int main() request.setOpt("feiertagebot/" + version); request.setOpt(true); ss << request; - Json::Value root; ss >> root; - for (Json::Value::const_iterator it_root = root.begin(); it_root != root.end(); ++it_root) + string output; + + for (const string &date : { today, tomorrow }) { - for (Json::Value::const_iterator it_region = it_root->begin(); it_region != it_root->end(); ++it_region) + Holiday current_day; + for (Json::Value::const_iterator it_root = root.begin(); it_root != root.end(); ++it_root) { - if ((*it_region)["datum"] == today) + for (Json::Value::const_iterator it_region = it_root->begin(); it_region != it_root->end(); ++it_region) { - cout << it_root.key() << ": " << (*it_region)["datum"] << ": " << it_region.key() << endl; + if ((*it_region)["datum"] == date) + { + current_day.date = date; + current_day.description = it_region.key().asString(); + current_day.regions.push_back(it_root.key().asString()); + } } } + if (current_day.date.empty()) + { + continue; + } + output += "Am " + current_day.date + " ist "+ current_day.description + " in "; + if (std::find(current_day.regions.begin(), current_day.regions.end(), "NATIONAL") != current_day.regions.end()) + { + output += "Deutschland.\n"; + } + else + { + bool firstrun = true; + for (const string ®ion : current_day.regions) + { + if (!firstrun) + { + output += ", "; + } + else + { + firstrun = false; + } + output += decode_state(region); + } + output += "\n"; + } + } + + if (!output.empty()) + { + uint_fast16_t ret; + Mastodon::Easy masto(instance, access_token); + masto.exceptions(true); + Mastodon::Easy::Status status; + status.content(output); + masto.send_post(status, ret); + if (ret > 0) + { + cerr << "Error " << std::to_string(ret) << endl; + return ret; + } } } catch (const std::exception &e) @@ -52,5 +223,6 @@ int main() cerr << e.what() << endl; return 1; } + return 0; } diff --git a/xdgjson b/xdgjson new file mode 160000 index 0000000..1a10ef6 --- /dev/null +++ b/xdgjson @@ -0,0 +1 @@ +Subproject commit 1a10ef6686a34b7170f52490b7b9841da4476a2c