aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kusatz <max@trialserver.de>2020-08-22 14:08:46 +0200
committerMax Kusatz <max@trialserver.de>2020-08-22 14:08:46 +0200
commit598218e9e1d6e97b7793b0cff2c0d50cab879fa4 (patch)
treeb0c80ca9c038195f4f473a34cb99d0c01479676a /src
parent537a243882f49cd95b304ecf283de950440fd66a (diff)
downloadn_core-598218e9e1d6e97b7793b0cff2c0d50cab879fa4.tar.gz
n_core-598218e9e1d6e97b7793b0cff2c0d50cab879fa4.zip
Mensa working sort of with JSON
Diffstat (limited to 'src')
-rw-r--r--src/N-Commands/KlingerHandler.cpp7
-rw-r--r--src/N-Commands/KlingerHandler.hpp (renamed from src/N-Commands/KlingerHandler.h)3
-rw-r--r--src/N-Commands/RelationshipHandler.cpp10
-rw-r--r--src/N-Commands/RelationshipHandler.h10
-rw-r--r--src/N-Commands/RelationshipHandler.hpp10
-rw-r--r--src/Utilities/GetEssen.cpp250
-rw-r--r--src/Utilities/GetEssen.hpp38
-rw-r--r--src/Utilities/Logger.cpp48
-rw-r--r--src/Utilities/Logger.hpp38
-rw-r--r--src/Utilities/Utilities.hpp142
-rw-r--r--src/Utilities/sqdb.cpp506
-rw-r--r--src/Utilities/sqdb.hpp207
-rw-r--r--src/main.cpp32
13 files changed, 1273 insertions, 28 deletions
diff --git a/src/N-Commands/KlingerHandler.cpp b/src/N-Commands/KlingerHandler.cpp
index 448532c..c596952 100644
--- a/src/N-Commands/KlingerHandler.cpp
+++ b/src/N-Commands/KlingerHandler.cpp
@@ -2,9 +2,10 @@
// Created by max on 11.08.20.
//
-#include "KlingerHandler.h"
+#include "KlingerHandler.hpp"
+
+void KlingerHandler::onCall(const Mongoose::Request& request, Mongoose::JsonResponse& response) {
-void KlingerHandler::onCall(const Mongoose::Request& request, Mongoose::StreamResponse& response) {
std::cout << "Klinger was called\n";
- response << "Bonjour!";
+ response["text"] = "Bonjour!";
}
diff --git a/src/N-Commands/KlingerHandler.h b/src/N-Commands/KlingerHandler.hpp
index 2fc5267..c078303 100644
--- a/src/N-Commands/KlingerHandler.h
+++ b/src/N-Commands/KlingerHandler.hpp
@@ -2,6 +2,7 @@
// Created by max on 11.08.20.
//
#include <mongoose/Server.h>
+#include <mongoose/JsonResponse.h>
#include <string>
#ifndef DORGODBOTBACKEND_KLINGERHANDLER_H
#define DORGODBOTBACKEND_KLINGERHANDLER_H
@@ -9,7 +10,7 @@
class KlingerHandler {
public:
- void onCall(const Mongoose::Request& request, Mongoose::StreamResponse& response) ;
+ void onCall(const Mongoose::Request& request, Mongoose::JsonResponse& response) ;
};
diff --git a/src/N-Commands/RelationshipHandler.cpp b/src/N-Commands/RelationshipHandler.cpp
index 808e17c..46991a3 100644
--- a/src/N-Commands/RelationshipHandler.cpp
+++ b/src/N-Commands/RelationshipHandler.cpp
@@ -1,4 +1,4 @@
-#include "RelationshipHandler.h"
+#include "RelationshipHandler.hpp"
#include<string>
#include<vector>
#include <algorithm>
@@ -111,12 +111,14 @@ string rsStart(vector<string> names) {
return (names.at(0) + " und " + names.at(1) + " passen nach Angaben von N zu " + to_string(result) + "% zusammen. Gratuliere!\n");
}
-void RelationshipHandler::onCall(Mongoose::Request& request, Mongoose::StreamResponse& response) {
+void RelationshipHandler::onCall(Mongoose::Request& request, Mongoose::JsonResponse& response) {
- // only react when command was issued after this boot
std::cout << "/relation was called\n";
- response << rsStart(vector<string>{request.get("name1", "Lukas"), request.get("name2", "cpp")});
+ response["text"] = rsStart(vector<string>{request.get("name1", "Lukas"), request.get("name2", "cpp")});
+
+ response["success"] = "1";
+ response["session"] = "NULL";
/*if (messagePtr->date > telegram->getBootDate()) {
log(messagePtr->from->username + ": "+messagePtr->text);
diff --git a/src/N-Commands/RelationshipHandler.h b/src/N-Commands/RelationshipHandler.h
deleted file mode 100644
index 251cabf..0000000
--- a/src/N-Commands/RelationshipHandler.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include <mongoose.h>
-#include <mongoose/Request.h>
-#include <mongoose/StreamResponse.h>
-
-class RelationshipHandler {
-public:
- void onCall(Mongoose::Request& request, Mongoose::StreamResponse& response);
-
-};
diff --git a/src/N-Commands/RelationshipHandler.hpp b/src/N-Commands/RelationshipHandler.hpp
new file mode 100644
index 0000000..fe9c0ea
--- /dev/null
+++ b/src/N-Commands/RelationshipHandler.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include <mongoose.h>
+#include <mongoose/Request.h>
+#include <mongoose/JsonResponse.h>
+
+class RelationshipHandler {
+public:
+ void onCall(Mongoose::Request& request, Mongoose::JsonResponse& response);
+
+};
diff --git a/src/Utilities/GetEssen.cpp b/src/Utilities/GetEssen.cpp
new file mode 100644
index 0000000..56742cc
--- /dev/null
+++ b/src/Utilities/GetEssen.cpp
@@ -0,0 +1,250 @@
+//
+// Created by max on 18.12.18.
+//
+
+#include "Utilities/GetEssen.hpp"
+
+
+using namespace boost::posix_time;
+
+void returnEssen(Mongoose::Request &request, Mongoose::JsonResponse &response){
+ std::cout << "mensa was called\n";
+ mensa Mensa_ID;
+ std::string mensa_name = request.get("argument1", "adlershof");
+ std::string offset_request = request.get("argument2", "0");
+
+
+ if(mensa_name == "adlershof"){
+ Mensa_ID = mensa::Adlershof;
+ } else if(mensa_name == "nord"){
+ Mensa_ID = mensa::Nord;
+ }else if (mensa_name == "sued" || mensa_name == "süd"){
+ Mensa_ID = mensa::Sued;
+ }
+
+ int offset = std::stoi(offset_request);
+
+
+ response["success"] = "1";
+ response["session"] = "NULL";
+ response["text"] = getEssen(Mensa_ID, offset);
+
+
+}
+
+bool db_update_mensa_message(const int& mensaID, const ptime& mensaDatum, const string& message){
+ sqdb::Db db("../main.sqlite");
+ string newTime = to_simple_string(ptime(second_clock::local_time()));
+ string mensaDatumString = to_string(mensaDatum.date().year()) + "-" + mensaDatum.date().month().as_short_string() + "-" + to_string(mensaDatum.date().day().as_number());
+ sqdb::QueryStr str;
+ db.Query(str.Format(SQDB_MAKE_TEXT("update mensa set Message = '%s', LastModified = '%s' where ID = %i and Datum = '%s';"), message.c_str(), newTime.c_str(), mensaID, mensaDatumString.c_str())).Next();
+ return true;
+}
+
+bool db_insert_mensa_message(const int& mensaID, const ptime& mensaDatum, const string& message){
+ sqdb::Db db("../main.sqlite");
+ string newTime = to_simple_string(ptime(second_clock::local_time()));
+ string mensaDatumString = to_string(mensaDatum.date().year()) + "-" + mensaDatum.date().month().as_short_string() + "-" + to_string(mensaDatum.date().day().as_number());
+ sqdb::QueryStr str;
+ db.Query(str.Format(SQDB_MAKE_TEXT("insert into mensa values(%i, '%s', '%s', '%s');"), mensaID, message.c_str(), mensaDatumString.c_str(), newTime.c_str())).Next();
+ return true;
+}
+
+Mensa_Essen db_get_mensa_message(const int& mensaID, const ptime& mensaDatum) {
+ Mensa_Essen out;
+ sqdb::Db db("../main.sqlite");
+
+ sqdb::QueryStr str;
+ string mensaDatumString = to_string(mensaDatum.date().year()) + "-" + mensaDatum.date().month().as_short_string() + "-" + to_string(mensaDatum.date().day().as_number());
+ sqdb::Statement s = db.Query(str.Format(SQDB_MAKE_TEXT("SELECT * from mensa WHERE Datum = '%s' AND ID = %i;"), mensaDatumString.c_str(), mensaID ));
+
+ try {
+ if(s.Next()) {
+ int ID = s.GetField(0);
+ string Message = s.GetField(1);
+ string Datum = s.GetField(2);
+ string LastModified = s.GetField(3);
+
+
+ ptime LMDate(time_from_string(LastModified));
+
+ out.ID = ID;
+ out.Message = Message;
+ out.Datum = mensaDatum;
+ out.LastModified = LMDate;
+ return out;
+ }
+ } catch (sqdb::Exception &exception){
+ log("Error code: " + to_string(exception.GetErrorCode()) + " Error Message: " + exception.GetErrorMsg() + "\n");
+ }
+ out.ID = -2;
+ return out;
+
+}
+
+string getEssen(const int mensa_ID, const int offset) {
+ Mensa_Essen Essen;
+ if (offset >= 0) {
+
+ if (offset > 28) {
+ return "Ich fühle mich geschmeichelt, dass du denkst, dass ich so weit in die Zukunft gucken kann (0 bis 28 Tage)";
+ }
+
+ ptime datumNow = second_clock::local_time();
+ ptime datumEssen = datumNow + (boost::gregorian::days(offset));
+
+ Essen = db_get_mensa_message(mensa_ID, datumEssen);
+ if (Essen.ID == -2) { // SQL got nothing back :/
+ //log("sql got nothing back!");
+ if (downloadMensaFile(mensa_ID, datumEssen) != CURLE_OK){
+ log("Error downloading file");
+ return "Error downloading file!";
+ }
+ db_insert_mensa_message(mensa_ID, datumEssen, read_mensa_message_from_file(mensa_ID));
+ Essen = db_get_mensa_message(mensa_ID, datumEssen);
+
+ string out;
+ switch (Essen.ID) {
+ case mensa::Adlershof :
+ out = "<b>Mensa Adlershof</b> am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+ case mensa ::Nord:
+ out = "<b>Mensa Nord</b> am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+ case mensa::Sued :
+ out = "<b>Mensa Sued</b> am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+ default:
+ out = "Mensa Unbekannt am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+
+ }
+ out += Essen.Message;
+ out += "\n (Stand: " + to_simple_string(Essen.LastModified) + ")\n";
+
+ return out;
+ }
+
+ if (Essen.LastModified + hours(2) < datumNow) { //LastModified is more than 2 hours old
+ if (downloadMensaFile(mensa_ID, datumEssen) != CURLE_OK) {
+ return "Error downloading file!";
+ }
+
+ db_update_mensa_message(mensa_ID, datumEssen, read_mensa_message_from_file(mensa_ID));
+ Essen = db_get_mensa_message(mensa_ID, datumEssen);
+ }
+ string out;
+ switch (Essen.ID) {
+ case mensa::Adlershof :
+ out = "<b>Mensa Adlershof</b> am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+ case mensa::Nord :
+ out = "<b>Mensa Nord</b> am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+ case mensa::Sued :
+ out = "<b>Mensa Sued</b> am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+ default:
+ out = "Mensa Unbekannt am " + to_string(Essen.Datum.date().day().as_number()) + "." + to_string(Essen.Datum.date().month().as_number()) + "." + to_string(Essen.Datum.date().year()) + ":";
+ break;
+
+ }
+ out += Essen.Message;
+ out += "\n (Stand: " + to_simple_string(Essen.LastModified) + ")\n";
+ return out;
+ } else return "Wer denkst du bin ich? Ein Zeitreisender?\nIch kann zwar in die Zukunft gucken, aber nur 28 Tage";
+
+}
+
+string read_mensa_message_from_file(const int& mensa_id_file) {
+ string s;
+ string out;
+ bool serious = false;
+
+ std::ifstream inFile(std::to_string(mensa_id_file));
+ while (std::getline(inFile, s)) {
+ //out += mensa;
+ if (s.find("15.png") != string::npos && serious) {
+ string vegan;
+
+ int vegan_byte[4] = {0xF0, 0x9F, 0x8C, 0xB1};
+ for (int i : vegan_byte) {
+ vegan += (char) i;
+ }
+
+ out += vegan;
+ }
+
+ if (s.find("1.png") != string::npos && serious) {
+ string vegetarian;
+
+ int vegetarian_byte[4] = {0xF0, 0x9F, 0x8C, 0xBD};
+ for (int i : vegetarian_byte) {
+ vegetarian += (char) i;
+ }
+
+ out += vegetarian;
+ }
+ if (s.find("splIcon") != string::npos && serious && s.find("1.png") == string::npos &&
+ s.find("15.png") == string::npos) {
+ string emptyEmoji;
+ int emptyEmoji_byte[6] = {0xE2, 0x98, 0xA3, 0xEF, 0xB8, 0x8F};
+ for (int i : emptyEmoji_byte) {
+ emptyEmoji += (char) i;
+ }
+
+ out += emptyEmoji;
+ }
+
+ if (s.find("splGroup\"") != string::npos) { //Getting the Category of the Meal
+ for (int i = 0, j = 0; (unsigned) i < s.length(); ++i) {
+ if (s.at(i) == '>') {
+ j = i + 1;
+ }
+ if (s.at(i) == '<' && j != 0) {
+ s = s.substr(j, i - j);
+ j = 0;
+ }
+
+ }
+ serious = (s == "Aktionen" || s == "Essen" || s == "Beilagen");
+ if (serious) {
+ out += "\n<b>" + s + "</b>\n";
+ }
+ }
+ if (s.find("class=\"bold\"") != string::npos && serious) { //Getting the Meal
+ for (int i = 0, j = 0; (unsigned) i < s.length(); ++i) {
+ if (s.at(i) == '>') {
+ j = i + 1;
+ //logStatus("Zeichen > gefunden in Position" + std::to_string(i));
+ }
+ if (s.at(i) == '<' && j != 0) {
+ s = s.substr(j, i - j);
+ j = 0;
+ }
+
+ }
+
+ out += "\t" + s;
+ }
+
+ if (s.find("euro;") != string::npos && serious) { //geting the price of each Meal
+ for (int i = 0, j = 0; (unsigned) i < s.length(); ++i) {
+ if (s.at(i) == ';') {
+ j = i + 1;
+ }
+ if (s.at(i) == '/') {
+ s = s.substr(j, i - j);
+ j = 0;
+ }
+ }
+ out += "\t<b>" + s + "</b>€\n";
+ }
+ }
+
+ if (out.empty()) {
+ return "Heute kein Essen";
+ }
+ return out;
+
+}
diff --git a/src/Utilities/GetEssen.hpp b/src/Utilities/GetEssen.hpp
new file mode 100644
index 0000000..813d115
--- /dev/null
+++ b/src/Utilities/GetEssen.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "sqdb.hpp"
+#include "Utilities/Utilities.hpp"
+#include "Utilities/Logger.hpp"
+//#include <tgbot/tgbot.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <boost/date_time/date_formatting.hpp>
+#include <curl/curl.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <iostream>
+#include <string>
+#include <mongoose/JsonResponse.h>
+#include <mongoose/Server.h>
+
+using namespace std;
+using namespace boost::posix_time;
+
+void returnEssen(Mongoose::Request &request, Mongoose::JsonResponse &response);
+
+string getEssen(int mensa_ID, int offset);
+
+string read_mensa_message_from_file(const int& mensa_id_file);
+
+struct Mensa_Essen{
+ int ID{191};
+ string Message{"nothing got back! There was an error!!"};
+ boost::posix_time::ptime Datum;
+ boost::posix_time::ptime LastModified;
+};
+enum mensa {
+ Adlershof = 191, Nord = 147, Sued = 367
+};
+
+
+
diff --git a/src/Utilities/Logger.cpp b/src/Utilities/Logger.cpp
new file mode 100644
index 0000000..333ae16
--- /dev/null
+++ b/src/Utilities/Logger.cpp
@@ -0,0 +1,48 @@
+#include "Logger.hpp"
+
+/*void Logger::Log(const TelegramMessage& message, LogLevel logLevel) {
+ Log("[" + message->from->username + "] " + message->text, logLevel);
+}*/
+
+void Logger::Log(const string& inMsg, LogLevel logLevel) {
+ string outMsg;
+
+#ifdef NDEBUG
+ if (logLevel == LogLevel::lDEBUG) {
+ // don't log debug messages in release mode
+ return;
+ }
+#endif
+
+ // prefix message with time
+ outMsg = "[" + NOW_STRING + "]";
+
+ // TODO: let at least some (ERROR, WARN) levels go to stderr, not stdout
+ // prefix log level - TODO: allow filtering based on globally set level?
+ switch (logLevel) {
+ case LogLevel::lSTATUS:
+ outMsg += " [STATUS] " + inMsg;
+ break;
+ case LogLevel::lDEBUG:
+ outMsg += " [DEBUG] " + inMsg;
+ break;
+ case LogLevel::lINFO:
+ outMsg += " [INFO] " + inMsg;
+ break;
+ case LogLevel::lWARN:
+ outMsg += " [WARN] " + inMsg;
+ break;
+ case LogLevel::lERROR:
+ outMsg += " [ERROR] " + inMsg;
+ break;
+ }
+
+ Print(outMsg);
+}
+
+void Logger::Print(const string& msg) {
+ // console output
+ cout << msg << endl;
+
+ // file output | TODO: Logger needs state for that - or at least needs to pretend to have one
+} \ No newline at end of file
diff --git a/src/Utilities/Logger.hpp b/src/Utilities/Logger.hpp
new file mode 100644
index 0000000..f319d93
--- /dev/null
+++ b/src/Utilities/Logger.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <string>
+#include <iostream>
+
+
+#include "Utilities.hpp"
+
+using std::string;
+using std::cout;
+using std::endl;
+
+#define logWarn(x) Logger::Log(x, Logger::LogLevel::lWARN)
+#define logDebug(x) Logger::Log(x, Logger::LogLevel::lDEBUG)
+#define logError(x) Logger::Log(x, Logger::LogLevel::lERROR)
+
+#define logStatus(x) Logger::Log(x, Logger::LogLevel::lSTATUS)
+
+#define log(x) logI(x)
+#define logI(x) Logger::Log(x, Logger::LogLevel::lINFO)
+
+class Logger {
+public:
+ enum class LogLevel {
+ lSTATUS, // general bot status messages, everything it logs o it's own
+ lDEBUG, // messages logged for development purposes
+ lINFO, // messages logged on certain events (eg. command executed)
+ lWARN,
+ lERROR
+ };
+
+ static void Log(const string& msg, LogLevel logLevel);
+ //static void Log(const TelegramMessage& message, LogLevel logLevel);
+
+private:
+ static void Print(const string& msg);
+};
+
diff --git a/src/Utilities/Utilities.hpp b/src/Utilities/Utilities.hpp
new file mode 100644
index 0000000..0c9f435
--- /dev/null
+++ b/src/Utilities/Utilities.hpp
@@ -0,0 +1,142 @@
+#pragma once
+
+#include <ctime>
+#include <string>
+#include <curl/curl.h>
+#include <boost/date_time.hpp>
+
+#define NOW std::time(0)
+#define LOG_TIME_FORMAT "%y-%m-%d %H:%M:%S"
+#define HR_TIME_FORMAT "%d.%m.%y, %H:%M:%S UHR"
+#define NOW_STRING TimeStampToHReadble(NOW, false)
+
+static std::string TimeStampToHReadble(const time_t rawTime, bool HR_READABLE) {
+ struct tm *dt;
+ char buffer[30];
+ dt = localtime(&rawTime);
+ if(HR_READABLE) {
+ strftime(buffer, sizeof(buffer), HR_TIME_FORMAT, dt);
+ } else {
+ strftime(buffer, sizeof(buffer), LOG_TIME_FORMAT, dt);
+ }
+ return std::string(buffer);
+}
+
+#include <fstream>
+static std::string getApiTokenFromFile(const std::string& filePath) {
+ std::string token = "NO-TOKEN";
+
+ std::ifstream inFile(filePath);
+
+ if (inFile) {
+ // TODO: validate, at least a little - currently we just assume the file contains the correct data
+ std::getline(inFile, token);
+ } else {
+ return "";
+ }
+
+ return token;
+}
+
+#ifdef NDEBUG
+
+static std::string getProductionApiToken() {
+ return getApiTokenFromFile("../release.api");
+}
+
+#else
+
+static std::string getDebugApiToken() {
+ return getApiTokenFromFile("../debug.api");
+}
+
+#endif
+
+static CURLcode downloadFile(const std::string& url, const std::string& fileName) {
+
+ CURL *curl;
+ FILE *fp;
+ CURLcode res;
+ curl = curl_easy_init();
+
+ if (curl) {
+ fp = fopen(fileName.c_str(), "wb");
+
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+ curl_easy_setopt(curl, CURLOPT_USERAGENT,
+ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36"); //so apparently the Website stw.berlin blocks the IPwhen accessing it very often with the bot...
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
+ res = curl_easy_perform(curl);
+ if (res != CURLE_OK){
+ //TODO: return int as status instead of boolean - maybe even this curl error?
+ return CURLE_COULDNT_CONNECT;
+ }
+ curl_easy_cleanup(curl);
+ fclose(fp);
+ return CURLE_OK;
+ } else {
+ return CURLE_COULDNT_CONNECT;
+ }
+}
+
+static CURLcode downloadMensaFile(const int& ID, const boost::posix_time::ptime& datum) {
+
+ std::string datumString = std::to_string(datum.date().year()) + "-" + std::to_string(datum.date().month().as_number()) + "-" + std::to_string(datum.date().day());
+
+ std::string postfield = "resources_id=" + std::to_string(ID) + "&date=" + datumString;
+
+ CURL *curl;
+ FILE *fp;
+ CURLcode res;
+ curl = curl_easy_init();
+
+ if (curl) {
+ fp = fopen(std::to_string(ID).c_str(), "wb");
+
+ struct curl_slist *slist1;
+
+ slist1 = nullptr;
+ slist1 = curl_slist_append(slist1, "Cookie: seitenbereich=mensen; _ga=GA1.2.1719763776.1545837849; filterkennz=[]; PHPSESSID=9fa00137a2ad065fe595196ddb34e0ba; _gid=GA1.2.226483670.1549982576; loadDataForResource=191; storedPathname=/mensen.html; _gat=1");
+ slist1 = curl_slist_append(slist1, "Origin: https://www.stw.berlin");
+ slist1 = curl_slist_append(slist1, "Accept-Encoding: gzip, deflate, br");
+ slist1 = curl_slist_append(slist1, "Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7");
+ slist1 = curl_slist_append(slist1, "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36");
+ slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded; charset=UTF-8");
+ slist1 = curl_slist_append(slist1, "Accept: */*");
+ slist1 = curl_slist_append(slist1, "Referer: https://www.stw.berlin/mensen.html");
+ slist1 = curl_slist_append(slist1, "X-Requested-With: XMLHttpRequest");
+ slist1 = curl_slist_append(slist1, "Connection: keep-alive");
+ slist1 = curl_slist_append(slist1, "DNT: 1");
+
+ curl = curl_easy_init();
+ curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 102400L);
+ curl_easy_setopt(curl, CURLOPT_URL, "https://www.stw.berlin/xhr/speiseplan-wochentag.html");
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfield.c_str());
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)32);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.63.0");
+ curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
+ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
+ curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/max/.ssh/known_hosts");
+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
+
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
+ res = curl_easy_perform(curl);
+ if (res != CURLE_OK){
+ //TODO: return int as status instead of boolean - maybe even this curl error?
+ return res;
+ }
+ curl_easy_cleanup(curl);
+ curl = nullptr;
+ curl_slist_free_all(slist1);
+ slist1 = nullptr;
+ fclose(fp);
+ return CURLE_OK;
+ } else {
+ return CURLE_FAILED_INIT;
+ }
+}
diff --git a/src/Utilities/sqdb.cpp b/src/Utilities/sqdb.cpp
new file mode 100644
index 0000000..0b88139
--- /dev/null
+++ b/src/Utilities/sqdb.cpp
@@ -0,0 +1,506 @@
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+
+#include <cstdlib>
+
+#include "sqdb.hpp"
+
+#include <unistd.h>
+
+using namespace sqdb;
+
+Exception::Exception(sqlite3* db)
+{
+ m_errorCode = sqlite3_errcode(db);
+ auto* c = (SQDB_CHAR*)
+#ifdef SQDB_UTF8
+ sqlite3_errmsg
+#else
+ sqlite3_errmsg16
+#endif
+ (db);
+ m_errorMsg = SQDB_STRDUP(c);
+}
+
+Exception::Exception(sqlite3* db, int errorCode)
+ : m_errorCode(errorCode)
+{
+ auto* c = (SQDB_CHAR*)
+#ifdef SQDB_UTF8
+ sqlite3_errmsg
+#else
+ sqlite3_errmsg16
+#endif
+ (db);
+ m_errorMsg = SQDB_STRDUP(c);
+}
+
+Exception::Exception(const SQDB_CHAR* errorMsg)
+ : m_errorCode(-1)
+{
+ m_errorMsg = SQDB_STRDUP(errorMsg);
+}
+
+Exception::~Exception()
+{
+ free(m_errorMsg);
+}
+
+int Exception::GetErrorCode() const
+{
+ return m_errorCode;
+}
+
+const SQDB_CHAR* Exception::GetErrorMsg() const
+{
+ return m_errorMsg;
+}
+
+RefCount::RefCount()
+ : m_refCount(nullptr)
+{
+}
+
+RefCount::RefCount(const RefCount& x)
+ : m_refCount(x.m_refCount)
+{
+}
+
+RefCount& RefCount::operator=(const RefCount& x)
+{
+ if ( this != &x )
+ {
+ m_refCount = x.m_refCount;
+ }
+ return *this;
+}
+
+void RefCount::IncRef()
+{
+ if ( !m_refCount )
+ {
+ m_refCount = new unsigned;
+ *m_refCount = 0;
+ }
+ ++*m_refCount;
+}
+
+unsigned RefCount::DecRef()
+{
+ assert(m_refCount);
+ unsigned value = --*m_refCount;
+ if ( value == 0 )
+ {
+ delete m_refCount;
+ m_refCount = nullptr;
+ }
+ return value;
+}
+
+Blob::Blob(const void* data, int size)
+ : m_size(size)
+{
+ m_data = new char[size];
+ std::uninitialized_copy((char*)data, (char*)data + size, m_data);
+ IncRef();
+}
+
+Blob::Blob(const Blob& x)
+ : RefCount(x), m_data(x.m_data), m_size(x.m_size)
+{
+ IncRef();
+}
+
+Blob& Blob::operator=(const Blob& x)
+{
+ if ( this != &x )
+ {
+ RefCount::operator=(x);
+ IncRef();
+ m_data = x.m_data;
+ m_size = x.m_size;
+ }
+ return *this;
+}
+
+int Blob::GetSize() const
+{
+ return m_size;
+}
+
+const char* Blob::GetData() const
+{
+ return m_data;
+}
+
+Blob::~Blob()
+{
+ if ( DecRef() == 0 )
+ {
+ delete[] m_data;
+ }
+}
+
+Convertor::Convertor(sqlite3* db, sqlite3_stmt* stmt, int field)
+ : m_db(db), m_stmt(stmt), m_field(field)
+{
+}
+
+Convertor::operator int() const
+{
+ return GetInt();
+}
+
+Convertor::operator unsigned long() const
+{
+ return GetUnsignedLong();
+}
+
+Convertor::operator long long() const
+{
+ return GetLongLong();
+}
+
+Convertor::operator double() const
+{
+ return GetDouble();
+}
+
+Convertor::operator SQDB_STD_STRING() const
+{
+ return GetString();
+}
+
+Convertor::operator const SQDB_CHAR*() const
+{
+ return GetText();
+}
+
+Convertor::operator Blob() const
+{
+ return GetBlob();
+}
+
+int Convertor::GetInt() const
+{
+ assert(m_stmt);
+ return sqlite3_column_int(m_stmt, m_field);
+}
+
+unsigned long Convertor::GetUnsignedLong() const
+{
+ assert(m_stmt);
+ const char* data = (char*) sqlite3_column_blob(m_stmt, m_field);
+ return strtoul(data, nullptr, 10);
+}
+
+long long Convertor::GetLongLong() const
+{
+ assert(m_stmt);
+ return sqlite3_column_int64(m_stmt, m_field);
+}
+
+double Convertor::GetDouble() const
+{
+ assert(m_stmt);
+ return sqlite3_column_double(m_stmt, m_field);
+}
+
+SQDB_STD_STRING Convertor::GetString() const
+{
+ assert(m_stmt);
+ const auto* result = (const SQDB_CHAR*)
+#ifdef SQDB_UTF8
+ sqlite3_column_text
+#else
+ sqlite3_column_text16
+#endif
+ (m_stmt, m_field);
+ return result;
+}
+
+const SQDB_CHAR* Convertor::GetText() const
+{
+ assert(m_stmt);
+ const auto* result = (const SQDB_CHAR*)
+#ifdef SQDB_UTF8
+ sqlite3_column_text
+#else
+ sqlite3_column_text16
+#endif
+ (m_stmt, m_field);
+ return result;
+}
+
+Blob Convertor::GetBlob() const
+{
+ assert(m_stmt);
+ const void* data = sqlite3_column_blob(m_stmt, m_field);
+ int size = sqlite3_column_bytes(m_stmt, m_field);
+ return Blob(data, size);
+}
+
+Statement::Statement(sqlite3* db, sqlite3_stmt* stmt)
+ : RefCount(), m_db(db), m_stmt(stmt), m_needReset(false)
+{
+ IncRef();
+}
+
+Statement::Statement(const Statement& x)
+ : RefCount(x), m_db(x.m_db), m_stmt(x.m_stmt), m_needReset(false)
+{
+ IncRef();
+}
+
+Statement& Statement::operator=(const Statement& x)
+{
+ if ( this != &x )
+ {
+ RefCount::operator=(x);
+ IncRef();
+ m_db = x.m_db;
+ m_stmt = x.m_stmt;
+ m_needReset = x.m_needReset;
+ }
+ return *this;
+}
+
+bool Statement::Next() {
+ assert(m_stmt);
+ int ret = SQLITE_BUSY;
+
+ while (ret == SQLITE_BUSY) {
+ ret = sqlite3_step(m_stmt);
+ m_needReset = true;
+ if ( ret == SQLITE_DONE ) {
+ return false;
+ } else if ( ret == SQLITE_ROW ) {
+ return true;
+ } else if ( ret == SQLITE_BUSY ) {
+ sleep(1);
+ continue;
+ } else {
+ throw Exception(m_db, ret);
+ }
+ }
+ return false;
+}
+
+Convertor Statement::GetField(int field) const
+{
+ return {m_db, m_stmt, field};
+}
+
+Statement::~Statement()
+{
+ if ( DecRef() == 0 )
+ {
+ sqlite3_finalize(m_stmt);
+ }
+}
+
+void Statement::BindBlob(int i, const void* value, int n)
+{
+ if ( m_needReset )
+ Reset();
+ DoBind(i, value, n);
+}
+
+void Statement::BindNull(int i)
+{
+ if ( m_needReset )
+ Reset();
+ DoBind(i);
+}
+
+void Statement::DoBind(int i, int value)
+{
+ const int ret = sqlite3_bind_int(m_stmt, i, value);
+ CHECK(m_db, ret);
+}
+
+void Statement::DoBind(int i, long long value)
+{
+ const int ret = sqlite3_bind_int64(m_stmt, i, value);
+ CHECK(m_db, ret);
+}
+
+void Statement::DoBind(int i, double value)
+{
+ const int ret = sqlite3_bind_double(m_stmt, i, value);
+ CHECK(m_db, ret);
+}
+
+void Statement::DoBind(int i, const SQDB_STD_STRING& value)
+{
+ const int ret =
+#ifdef SQDB_UTF8
+ sqlite3_bind_text
+#else
+ sqlite3_bind_text16
+#endif
+ (m_stmt, i, value.c_str(), value.size() * sizeof(SQDB_STD_STRING::value_type), SQLITE_TRANSIENT);
+ CHECK(m_db, ret);
+}
+
+void Statement::DoBind(int i, const SQDB_CHAR* value)
+{
+ const int len = SQDB_STRLEN(value);
+
+ const int ret =
+#ifdef SQDB_UTF8
+ sqlite3_bind_text
+#else
+ sqlite3_bind_text16
+#endif
+ (m_stmt, i, value, len * sizeof(SQDB_CHAR), SQLITE_TRANSIENT);
+
+ CHECK(m_db, ret);
+}
+
+void Statement::DoBind(int i, const void* value, int n)
+{
+ const int ret = sqlite3_bind_blob(m_stmt, i, value, n, SQLITE_TRANSIENT);
+ CHECK(m_db, ret);
+}
+
+void Statement::DoBind(int i)
+{
+ const int ret = sqlite3_bind_null(m_stmt, i);
+ CHECK(m_db, ret);
+}
+
+void Statement::Reset()
+{
+ assert(m_needReset);
+ assert(m_stmt);
+
+ sqlite3_reset(m_stmt);
+ m_needReset = false;
+}
+
+QueryStr::QueryStr()
+ : m_buf(nullptr)
+{
+}
+
+const SQDB_CHAR* QueryStr::Format(const SQDB_CHAR* fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+#ifdef SQDB_UTF8
+ sqlite3_free(m_buf);
+ m_buf = sqlite3_vmprintf(fmt, va);
+#else
+ free(m_buf);
+ int len = _vscwprintf(fmt, va) + 1;
+ m_buf = (SQDB_CHAR*)malloc(len * sizeof(SQDB_CHAR));
+ vswprintf(m_buf, len, fmt, va);
+#endif
+
+ va_end(va);
+
+ return m_buf;
+}
+
+const SQDB_CHAR* QueryStr::Get() const
+{
+ return m_buf;
+}
+
+QueryStr::~QueryStr()
+{
+#ifdef SQDB_UTF8
+ sqlite3_free(m_buf);
+#else
+ free(m_buf);
+#endif
+}
+
+Db::Db(const SQDB_CHAR* fileName)
+ : RefCount()
+{
+#ifdef SQDB_UTF8
+ const int ret = sqlite3_open(fileName, &m_db);
+#else
+ const int ret = sqlite3_open16(fileName, &m_db);
+#endif
+ CHECK(m_db, ret);
+
+ IncRef();
+}
+
+void Db::BeginTransaction()
+{
+ Query(SQDB_MAKE_TEXT("BEGIN;")).Next();
+}
+
+void Db::CommitTransaction()
+{
+ Query(SQDB_MAKE_TEXT("COMMIT;")).Next();
+}
+
+void Db::RollbackTransaction()
+{
+ Query(SQDB_MAKE_TEXT("ROLLBACK;")).Next();
+}
+
+bool Db::TableExists(const SQDB_CHAR* tableName)
+{
+ QueryStr str;
+ Statement s =
+ Query(
+ str.Format(SQDB_MAKE_TEXT("select count(*) from sqlite_master where type='table' and name='%s';"), tableName));
+ s.Next();
+ const int count = s.GetField(0);
+ return count > 0;
+}
+
+Statement Db::Query(const SQDB_CHAR* queryStr)
+{
+ sqlite3_stmt* stmt = nullptr;
+#ifdef SQDB_UTF8
+ const int ret = sqlite3_prepare(m_db, queryStr, -1, &stmt, nullptr);
+#else
+ const int ret = sqlite3_prepare16(m_db, queryStr, -1, &stmt, NULL);
+#endif
+ CHECK(m_db, ret);
+
+ return Statement(m_db, stmt);
+}
+
+long long Db::LastId()
+{
+ long long ret = sqlite3_last_insert_rowid(m_db);
+ return ret;
+}
+
+Db::Db(const Db& x)
+ : RefCount(x),
+ m_db(x.m_db)
+{
+ IncRef();
+}
+
+Db& Db::operator=(const Db& x)
+{
+ if ( this != &x )
+ {
+ RefCount::operator=(x);
+
+ IncRef();
+ m_db = x.m_db;
+ }
+ return *this;
+}
+
+Db::~Db()
+{
+ if ( DecRef() == 0 )
+ {
+ sqlite3_close(m_db);
+ }
+}
+
diff --git a/src/Utilities/sqdb.hpp b/src/Utilities/sqdb.hpp
new file mode 100644
index 0000000..ea38787
--- /dev/null
+++ b/src/Utilities/sqdb.hpp
@@ -0,0 +1,207 @@
+#pragma once
+
+#include <string>
+
+#include "sqlite3.h"
+
+#ifdef _WIN32
+# include <tchar.h>
+# define SQDB_MAKE_TEXT(x) _TEXT(x)
+# define SQDB_STRLEN _tcslen
+# define SQDB_STRDUP _tcsdup
+#else
+# define SQDB_MAKE_TEXT(x) (x)
+# define SQDB_STRLEN strlen
+# define SQDB_STRDUP strdup
+#endif
+
+#if !defined(SQDB_UTF16) && !defined(SQDB_UTF8)
+# ifdef _WIN32
+# if defined(UNICODE) || defined(_UNICODE)
+# define SQDB_UTF16
+# else
+# define SQDB_UTF8
+# endif
+# else
+# define SQDB_UTF8
+# endif
+#endif
+
+#ifdef SQDB_UTF8
+# define SQDB_CHAR char
+# define SQDB_STD_STRING std::string
+#endif
+
+#ifdef SQDB_UTF16
+# define SQDB_CHAR TCHAR
+# define SQDB_STD_STRING std::wstring
+#endif
+
+namespace sqdb
+{
+
+ class Exception
+ {
+ public:
+ Exception(sqlite3* db);
+
+ Exception(sqlite3* db, int errorCode);
+
+ Exception(const SQDB_CHAR* errorMsg);
+
+ ~Exception();
+
+ int GetErrorCode() const;
+
+ const SQDB_CHAR* GetErrorMsg() const;
+ private:
+ int m_errorCode;
+ SQDB_CHAR* m_errorMsg;
+ };
+
+#define CHECK(db, returnCode) \
+ if ( (returnCode) != SQLITE_OK ) throw Exception(db, returnCode)
+
+ class RefCount
+ {
+ protected:
+ RefCount();
+
+ RefCount(const RefCount& x);
+ RefCount& operator=(const RefCount& x);
+
+ void IncRef();
+ unsigned DecRef();
+
+ private:
+ unsigned* m_refCount;
+ };
+
+ class Blob : public RefCount
+ {
+ public:
+ Blob(const void* data, int size);
+
+ Blob(const Blob& x);
+ Blob& operator=(const Blob& x);
+
+ int GetSize() const;
+ const char* GetData() const;
+
+ ~Blob();
+
+ private:
+ char* m_data;
+ int m_size;
+ };
+
+ class Convertor
+ {
+ public:
+ Convertor(sqlite3* db, sqlite3_stmt* stmt, int field);
+
+ operator int() const;
+ operator unsigned long() const;
+ operator long long() const;
+ operator double() const;
+ operator SQDB_STD_STRING() const;
+ operator const SQDB_CHAR*() const;
+ operator Blob() const;
+
+ int GetInt() const;
+ unsigned long GetUnsignedLong() const;
+ long long GetLongLong() const;
+ double GetDouble() const;
+ SQDB_STD_STRING GetString() const;
+ const SQDB_CHAR* GetText() const;
+ Blob GetBlob() const;
+
+ private:
+ sqlite3* m_db;
+ sqlite3_stmt* m_stmt;
+ int m_field;
+ };
+
+ class Statement : public RefCount
+ {
+ public:
+ Statement(sqlite3* db, sqlite3_stmt* stmt);
+
+ Statement(const Statement& x);
+ Statement& operator=(const Statement& x);
+
+ bool Next();
+ Convertor GetField(int field) const;
+
+ template<class T>
+ void Bind(int i, const T& value)
+ {
+ if ( m_needReset )
+ Reset();
+ DoBind(i, value);
+ }
+
+ void BindBlob(int i, const void* value, int n);
+ void BindNull(int i);
+
+ ~Statement();
+
+ private:
+ void DoBind(int i, int value);
+ void DoBind(int i, long long value);
+ void DoBind(int i, double value);
+ void DoBind(int i, const SQDB_STD_STRING& value);
+ void DoBind(int i, const SQDB_CHAR* value);
+
+ // Bind blob.
+ void DoBind(int i, const void* value, int n);
+
+ // Bind null.
+ void DoBind(int i);
+
+ // Reset binders so that new values can be bound.
+ void Reset();
+
+ sqlite3* m_db;
+ sqlite3_stmt* m_stmt;
+ bool m_needReset;
+ };
+
+ class QueryStr
+ {
+ public:
+ QueryStr();
+
+ const SQDB_CHAR* Format(const SQDB_CHAR* fmt, ...);
+
+ const SQDB_CHAR* Get() const;
+
+ ~QueryStr();
+
+ private:
+ SQDB_CHAR* m_buf;
+ };
+
+ class Db : public RefCount
+ {
+ public:
+ Db(const SQDB_CHAR* fileName);
+
+ void BeginTransaction();
+ void CommitTransaction();
+ void RollbackTransaction();
+
+ bool TableExists(const SQDB_CHAR* tableName);
+ Statement Query(const SQDB_CHAR* queryStr);
+ long long LastId();
+
+ Db(const Db& x);
+ Db& operator=(const Db& x);
+
+ ~Db();
+
+ private:
+ sqlite3* m_db;
+ };
+
+}
diff --git a/src/main.cpp b/src/main.cpp
index b11a8e7..8a08b4a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,33 +1,45 @@
-#include "N-Commands/KlingerHandler.h"
-#include "N-Commands/RelationshipHandler.h"
+#include "N-Commands/KlingerHandler.hpp"
+#include "N-Commands/RelationshipHandler.hpp"
+#include "Utilities/GetEssen.hpp"
+#include "Utilities/Logger.hpp"
+#include "Utilities/Utilities.hpp"
+#include "Utilities/sqdb.hpp"
#include <mongoose/Server.h>
#include <mongoose/WebController.h>
+#include <mongoose/JsonController.h>
using namespace std;
using namespace Mongoose;
-class MyController : public WebController
+class MyController : public JsonController
{
public:
- void hello(Request &request, StreamResponse &response)
+ void hello(Request &request, JsonResponse &response)
{
- response << "Hello " << htmlEntities(request.get("name", "... what's your name ?")) << endl;
+ response["text"] = "Hello " + htmlEntities(request.get("name", "... what's your name ?")) + "\n";
+ response["success"] = "1";
+ response["session"] = "NULL";
}
- void klinger(Request &request, StreamResponse &response){
+ void klinger(Request &request, JsonResponse &response){
KlingerHandler klinger;
klinger.onCall(request, response);
}
- void relation(Request &request, StreamResponse &response){
+ void relation(Request &request, JsonResponse &response){
RelationshipHandler relation;
relation.onCall(request, response);
}
+ void mensa(Request &request, JsonResponse &response){
+ returnEssen(request, response);
+ }
void setup()
{
- addRoute("GET", "/hello", MyController, hello);
- addRoute("GET", "/klinger", MyController, klinger);
- addRoute("GET", "/relation", MyController, relation);
+ setPrefix("/api/v1");
+ addRouteResponse("GET", "/hello", MyController, hello, JsonResponse);
+ addRouteResponse("GET", "/klinger", MyController, klinger, JsonResponse);
+ addRouteResponse("GET", "/relation", MyController, relation, JsonResponse);
+ addRouteResponse("GET", "/mensa", MyController, mensa, JsonResponse);
}
};