From 5eaf9ec43ea986d3487f50468df437eb2a3f3ace Mon Sep 17 00:00:00 2001 From: Tomasz Golinski Date: Fri, 4 Oct 2019 02:30:17 +0200 Subject: [PATCH] Possibility to grab caches which were not found by a certain user --- geostat.cpp | 29 +++++++++++++++++++++++++-- meson.build | 4 ++-- ocdb.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++- ocdb.h | 1 + 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/geostat.cpp b/geostat.cpp index 01a5a29..011983a 100644 --- a/geostat.cpp +++ b/geostat.cpp @@ -3,6 +3,7 @@ #include "cache.h" #include "debug.h" #include "heat.h" +#include "ocdb.h" #include #include @@ -35,14 +36,17 @@ int main(int argc, char** argv) { std::string heat_map; bool heat_exp = 0; bool use_ocpl = 0; + bool use_ocpl_db = 0; + bool get_not_found = 0; std::string ocpl_user; std::string ocpl_url = "https://opencaching.pl/okapi/"; + const std::string Database = "ocpl.sqlite"; std::string gpx_file; #include "config_user.h" int o; - while ((o = getopt(argc, argv, "g:d:pu:MDOH:s:m:eLTYh?")) != -1) + while ((o = getopt(argc, argv, "qng:d:pu:MDOH:s:m:eLTYh?")) != -1) switch (o) { case 'd': try { @@ -65,6 +69,12 @@ int main(int argc, char** argv) { case 'u': ocpl_user = optarg; break; + case 'q': + use_ocpl_db = 1; + break; + case 'n': + get_not_found = 1; + break; case 'M': show_minmax = 1; break; @@ -106,12 +116,14 @@ int main(int argc, char** argv) { case 'h': case '?': default: - std::cout << "Usage: [-p] [-g file] [-MDHLTOYh] [-s size] [-m map]\n"; + std::cout << "Usage: [-p] [-g file] [-qn] [-MDHLTOYh] [-s size] [-m map]\n"; std::cout << "Generate stats from Opencaching data or GPX files.\n\n"; std::cout << " * Data source:\n"; std::cout << "\t-p\tuse Opencaching.pl\n"; std::cout << "\t-u user\tuser for Opencaching\n"; std::cout << "\t-g file\tuse specified gpx file\n"; + std::cout << "\t-q\tuse local SQLite file\n"; + std::cout << "\t-n\tget only unfound caches (works only with SQLite)\n"; std::cout << " * Output:\n"; std::cout << "\t-M\tprint geographically extreme caches\n"; std::cout << "\t-D\tprint furthest and closest caches\n"; @@ -142,6 +154,19 @@ int main(int argc, char** argv) { cc.merge(gpxfile.get_user_caches()); } + if (use_ocpl_db) { + OCdb db(Database); + Okapi OCpl(ocpl_url, ocpl_key); + if (!ocpl_user.empty()) { + ocpl_user_uuid = OCpl.get_uuid(ocpl_user); + } + if (get_not_found) { + cc.merge(db.get_user_caches_not_found(ocpl_user_uuid)); + } else { + cc.merge(db.get_user_caches(ocpl_user_uuid, 0)); + } + } + // TODO: some cache deduplication is needed Debug(2) << "Caches read: " << cc.size() << '\n'; diff --git a/meson.build b/meson.build index 484d7bb..0fbcfec 100644 --- a/meson.build +++ b/meson.build @@ -15,10 +15,10 @@ else endif link = ['-lgpx', '-lheatmap'] -src = ['geostat.cpp', 'okapi.cpp', 'gpx.cpp', 'cache.cpp', 'debug.cpp', 'heat.cpp'] +src = ['geostat.cpp', 'okapi.cpp', 'gpx.cpp', 'cache.cpp', 'debug.cpp', 'heat.cpp', 'ocdb.cpp'] src_db = ['geodb.cpp', 'debug.cpp', 'ocdb.cpp', 'okapi.cpp'] -executable('geostat', src, dependencies : [curl_dep, json_dep, magick_dep], link_args: link) +executable('geostat', src, dependencies : [curl_dep, json_dep, magick_dep, sqlite_dep], link_args: link) executable('geodb', src_db, dependencies : [sqlite_dep, json_dep, curl_dep]) configure_file(input: 'Poland.png', output: 'Poland.png', copy: true) diff --git a/ocdb.cpp b/ocdb.cpp index 4e772e9..0138070 100644 --- a/ocdb.cpp +++ b/ocdb.cpp @@ -279,7 +279,62 @@ bool OCdb::read_revision() { return 1; } -Caches OCdb::get_user_caches(std::string uuid, int count) { +Caches OCdb::get_user_caches_not_found(std::string uuid) { + int res; Caches cc; + Cache c; + + std::string sql = "SELECT code, location FROM caches WHERE NOT EXISTS (SELECT cache_code FROM logs WHERE cache_code = code AND type = 'Found it' and user = ?);"; + + res = sqlite3_prepare_v2(db, sql.c_str(), sql.length() + 1, &stmt, NULL); + if (res != SQLITE_OK) { + Debug(1) << "Request \"" << sql << "\" failed:\n" << sqlite3_errmsg(db); + throw 0; + } + sqlite3_bind_text(stmt, 1, uuid.c_str(), -1, nullptr); + + res = sqlite3_step(stmt); + while (res == SQLITE_ROW) { + c.code = reinterpret_cast(sqlite3_column_text(stmt, 0)); + c.pos = get_lat_lon(reinterpret_cast(sqlite3_column_text(stmt, 1))); + cc.insert(c); + res = sqlite3_step(stmt); + } + + if (res != SQLITE_DONE) { + Debug(1) << "Request \"" << sql << "\" failed:\n" << sqlite3_errmsg(db); + throw 0; + } + sqlite3_finalize(stmt); + return cc; +} + +Caches OCdb::get_user_caches(std::string uuid, int count) { + int res; + Caches cc; + Cache c; + + std::string sql = "SELECT code, location FROM caches WHERE EXISTS (SELECT cache_code FROM logs WHERE cache_code = code AND type = 'Found it' and user = ?);"; + + res = sqlite3_prepare_v2(db, sql.c_str(), sql.length() + 1, &stmt, NULL); + if (res != SQLITE_OK) { + Debug(1) << "Request \"" << sql << "\" failed:\n" << sqlite3_errmsg(db); + throw 0; + } + sqlite3_bind_text(stmt, 1, uuid.c_str(), -1, nullptr); + + res = sqlite3_step(stmt); + while (res == SQLITE_ROW) { + c.code = reinterpret_cast(sqlite3_column_text(stmt, 0)); + c.pos = get_lat_lon(reinterpret_cast(sqlite3_column_text(stmt, 1))); + cc.insert(c); + res = sqlite3_step(stmt); + } + + if (res != SQLITE_DONE) { + Debug(1) << "Request \"" << sql << "\" failed:\n" << sqlite3_errmsg(db); + throw 0; + } +// sqlite3_finalize(stmt); return cc; } diff --git a/ocdb.h b/ocdb.h index 9f9e534..c09cdc8 100644 --- a/ocdb.h +++ b/ocdb.h @@ -32,5 +32,6 @@ public: bool init(std::string json_file); // read db dump bool update(Okapi& oc); // apply changelog + Caches get_user_caches_not_found(std::string uuid); Caches get_user_caches(std::string uuid, int count = 0); };