From 51ab1d7982b852d59969d86d62cf3f437d224ad6 Mon Sep 17 00:00:00 2001 From: Tobias Reisinger Date: Sun, 23 Feb 2020 20:06:14 +0100 Subject: [PATCH] fix: save id as blob, not as string add: some progress to new discovery add: some tests remove: migrations. restarting for now --- CMakeLists.txt | 14 ++++- controllers/api_v1_controllers.cc | 40 ++++++++++--- controllers/api_v1_controllers.h | 10 ++-- controllers/api_v1_controllers_discover.cc | 23 ++++--- controllers/api_v1_controllers_relays.cc | 60 +++++++++++++++---- controllers/api_v1_relays.cc | 4 +- controllers/api_v1_schedules.cc | 47 +++++++++++---- filters/relays_valid_json.cc | 10 +++- helpers.h | 3 +- helpers/create_sql_filtered_query.cc | 12 ++-- helpers/migrate_sql.cc | 12 +--- models/controller_dbo.cc | 16 +++-- models/controller_dbo.h | 5 +- models/relay_dbo.cc | 38 +++++++----- models/relay_dbo.h | 11 ++-- models/schedule_dbo.cc | 60 +++++++++++++++++-- models/schedule_dbo.h | 11 +++- sql/migration_0.sql | 9 ++- sql/migration_1.sql | 8 --- tavern_tests/test_get_all.tavern.yaml | 25 ++++++++ tavern_tests/test_minimal.tavern.yaml | 9 --- tavern_tests/test_schedules_basic.tavern.yaml | 39 ++++++++++++ 22 files changed, 345 insertions(+), 121 deletions(-) delete mode 100644 sql/migration_1.sql create mode 100644 tavern_tests/test_get_all.tavern.yaml delete mode 100644 tavern_tests/test_minimal.tavern.yaml create mode 100644 tavern_tests/test_schedules_basic.tavern.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d52657..91da978 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,14 +63,22 @@ configure_file("config.json" "config.json" COPYONLY) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_executable(core ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${PLUGIN_SRC} ${MODEL_SRC} ${HELPER_SRC}) -add_custom_target(compiled_migrations ${CMAKE_CURRENT_SOURCE_DIR}/compile_migrations.sh) -add_dependencies(core compiled_migrations) - add_subdirectory(drogon) target_link_libraries(${PROJECT_NAME} PRIVATE drogon) +add_custom_target(migrations + COMMAND ./compile_migrations.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + add_custom_target(run COMMAND core DEPENDS core WORKING_DIRECTORY ${CMAKE_PROJECT_DIR} ) + +add_custom_target(test + COMMAND tavern-ci --tavern-beta-new-traceback ./tavern_tests + DEPENDS core + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +) diff --git a/controllers/api_v1_controllers.cc b/controllers/api_v1_controllers.cc index 27f2343..484d921 100644 --- a/controllers/api_v1_controllers.cc +++ b/controllers/api_v1_controllers.cc @@ -23,9 +23,17 @@ controllers::get_all(const HttpRequestPtr &req, std::function &&callback, - const std::string& controller_id) + const std::string& controller_id_str) { - controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t) &sqlite3_bind_text); + uuid_t controller_id; + if(uuid_parse(controller_id_str.c_str(), controller_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t)); if(controllers[0]) { @@ -47,7 +55,7 @@ void controllers::get_one_by_tag(const HttpRequestPtr &req, std::function &&callback, const std::string &controller_tag) { - controller_dbo **controllers = controller_dbo::get_by_simple("tag", controller_tag.c_str(), (intptr_t) &sqlite3_bind_text); + controller_dbo **controllers = controller_dbo::get_by_simple("tag", controller_tag.c_str(), (intptr_t) &sqlite3_bind_text, -1); if(controllers[0]) { @@ -66,9 +74,17 @@ controllers::get_one_by_tag(const HttpRequestPtr &req, std::function &&callback, const std::string& controller_id) +controllers::delete_one_by_id(const HttpRequestPtr &req, std::function &&callback, const std::string& controller_id_str) { - controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t) &sqlite3_bind_text); + uuid_t controller_id; + if(uuid_parse(controller_id_str.c_str(), controller_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t)); if(controllers[0]) { @@ -92,11 +108,19 @@ controllers::delete_one_by_id(const HttpRequestPtr &req, std::function &&callback, - const std::string &controller_id) + const std::string &controller_id_str) { Json::Value body = *req->getJsonObject(); - controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t) &sqlite3_bind_text); + uuid_t controller_id; + if(uuid_parse(controller_id_str.c_str(), controller_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + controller_dbo **controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t)); if(controllers[0]) { @@ -127,4 +151,4 @@ controllers::put_one_by_id(const HttpRequestPtr &req, std::function &&callback); static void get_all(const HttpRequestPtr& req, std::function &&callback); - static void get_one_by_id(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id); + static void get_one_by_id(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id_str); static void get_one_by_tag(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_tag); - static void delete_one_by_id(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id); + static void delete_one_by_id(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id_str); static void put_one_by_id(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id); - static void get_relays_all(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id); - static void get_relays_one_by_id_and_num(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id, int relay_num); - static void put_relays_one_by_id_and_num(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id, int relay_num); + static void get_relays_all(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id_str); + static void get_relays_one_by_id_and_num(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id_str, int relay_num); + static void put_relays_one_by_id_and_num(const HttpRequestPtr& req, std::function &&callback, const std::string& controller_id_str, int relay_num); }; } diff --git a/controllers/api_v1_controllers_discover.cc b/controllers/api_v1_controllers_discover.cc index cd5130f..0f9d548 100644 --- a/controllers/api_v1_controllers_discover.cc +++ b/controllers/api_v1_controllers_discover.cc @@ -11,6 +11,14 @@ using namespace api::v1; +enum DISCOVERY_MAPPING +{ + DISCOVERY_MAPPING_ID = 0, + DISCOVERY_MAPPING_NAME = 1, + DISCOVERY_MAPPING_COMMAND_PORT = 2, + DISCOVERY_MAPPING_RELAY_COUNT = 3, +}; + void controllers::post_discover(const HttpRequestPtr &req, std::function &&callback) { @@ -95,12 +103,13 @@ void controllers::post_discover(const HttpRequestPtr &req, std::functionid, discovered_id) == 0) + if(uuid_compare(known_controllers[i]->id, discovered_id) == 0) { known_controllers[i]->active = true; known_controllers[i]->update(); @@ -135,7 +142,7 @@ void controllers::post_discover(const HttpRequestPtr &req, std::function &&callback, - const std::string& controller_id) + const std::string& controller_id_str) { - relay_dbo **all_controller_relays = relay_dbo::get_by_simple("controller_id", (void *) controller_id.c_str(), (intptr_t) sqlite3_bind_text); + uuid_t controller_id; + if(uuid_parse(controller_id_str.c_str(), controller_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + relay_dbo **all_controller_relays = relay_dbo::get_by_simple("controller_id", (void *) controller_id, (intptr_t) sqlite3_bind_blob, sizeof(uuid_t)); Json::Value all_relays_json(Json::arrayValue); for(int i = 0; all_controller_relays[i] != nullptr; i++) @@ -29,10 +37,18 @@ controllers::get_relays_all(const HttpRequestPtr &req, std::function &&callback, const std::string& controller_id, + std::function &&callback, const std::string& controller_id_str, int relay_num) { - relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id.c_str(), relay_num); + uuid_t controller_id; + if(uuid_parse(controller_id_str.c_str(), controller_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id, relay_num); if(relay) { @@ -53,10 +69,18 @@ controllers::get_relays_one_by_id_and_num(const HttpRequestPtr &req, void controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, - std::function &&callback, const std::string& controller_id, + std::function &&callback, const std::string& controller_id_str, int relay_num) { - if(!relay_dbo::valid_num_for_controller(controller_id.c_str(), relay_num)) + uuid_t controller_id; + if(uuid_parse(controller_id_str.c_str(), controller_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + if(!relay_dbo::valid_num_for_controller(controller_id, relay_num)) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k400BadRequest); @@ -64,15 +88,24 @@ controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, return; } - relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id.c_str(), relay_num); Json::Value body = *req->getJsonObject(); + uuid_t active_schedule_id; + if(!schedule_dbo::parse_id(body["active_schedule"].asCString(), active_schedule_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + + relay_dbo *relay = relay_dbo::get_relay_for_controller(controller_id, relay_num); bool db_action_result; if(relay) { strncpy(relay->name, body["name"].asCString(), 127); - strncpy(relay->active_schedule_id, body["active_schedule"].asCString(), 32); + uuid_copy(relay->active_schedule_id, active_schedule_id); db_action_result = relay->update(); } @@ -81,8 +114,9 @@ controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, relay = new relay_dbo(); relay->number = relay_num; strncpy(relay->name, body["name"].asCString(), 127); - strncpy(relay->active_schedule_id, body["active_schedule"].asCString(), 32); - strncpy(relay->controller_id, controller_id.c_str(), 32); + + uuid_copy(relay->active_schedule_id, active_schedule_id); + uuid_copy(relay->controller_id, controller_id); relay->reload_active_schedule(); @@ -97,8 +131,8 @@ controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, } else { - auto schedules = schedule_dbo::get_by_simple("id", body["active_schedule"].asCString(), (intptr_t)&sqlite3_bind_text); - auto controllers = controller_dbo::get_by_simple("id", controller_id.c_str(), (intptr_t)&sqlite3_bind_text); + auto schedules = schedule_dbo::get_by_simple("id", active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); + auto controllers = controller_dbo::get_by_simple("id", controller_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); Json::Value payload; payload["target"] = relay_num; @@ -116,4 +150,4 @@ controllers::put_relays_one_by_id_and_num(const HttpRequestPtr &req, } delete relay; -} \ No newline at end of file +} diff --git a/controllers/api_v1_relays.cc b/controllers/api_v1_relays.cc index 188dc97..e3b261d 100644 --- a/controllers/api_v1_relays.cc +++ b/controllers/api_v1_relays.cc @@ -26,7 +26,7 @@ void relays::get_one_by_tag(const HttpRequestPtr &req, std::function &&callback, const std::string &relay_tag) { - relay_dbo **relays = relay_dbo::get_by_simple("tag", relay_tag.c_str(), (intptr_t)&sqlite3_bind_text); + relay_dbo **relays = relay_dbo::get_by_simple("tag", relay_tag.c_str(), (intptr_t)&sqlite3_bind_text, -1); if(relays[0]) { @@ -42,4 +42,4 @@ relays::get_one_by_tag(const HttpRequestPtr &req, std::function &&callback, const std::string& schedule_id) +schedules::get_one_by_id(const HttpRequestPtr &req, std::function &&callback, const std::string& schedule_id_str) { - schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id.c_str(), (intptr_t) &sqlite3_bind_text); + uuid_t schedule_id; + if(schedule_dbo::parse_id(schedule_id_str.c_str(), schedule_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + + schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t)); if(schedules[0]) { @@ -46,9 +55,9 @@ schedules::get_one_by_id(const HttpRequestPtr &req, std::function &&callback, const std::string& schedule_id) +schedules::delete_one_by_id(const HttpRequestPtr &req, std::function &&callback, const std::string& schedule_id_str) { - if(strcmp(schedule_id.c_str(), "off") == 0 || strcmp(schedule_id.c_str(), "on") == 0) + if(strcmp(schedule_id_str.c_str(), "off") == 0 || strcmp(schedule_id_str.c_str(), "on") == 0) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k403Forbidden); @@ -57,7 +66,15 @@ schedules::delete_one_by_id(const HttpRequestPtr &req, std::functionsetStatusCode(k400BadRequest); + callback(resp); + return; + } + schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t)); if(schedules[0]) { @@ -88,7 +105,7 @@ schedules::post_new(const HttpRequestPtr &req, std::function &&callback, - const std::string &schedule_id) + const std::string &schedule_id_str) { - if(strcmp(schedule_id.c_str(), "off") == 0 || strcmp(schedule_id.c_str(), "on") == 0) + if(strcmp(schedule_id_str.c_str(), "off") == 0 || strcmp(schedule_id_str.c_str(), "on") == 0) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k403Forbidden); @@ -118,9 +135,17 @@ schedules::put_one_by_id(const HttpRequestPtr &req, std::functionjsonObject(); + uuid_t schedule_id; + if(schedule_dbo::parse_id(schedule_id_str.c_str(), schedule_id)) + { + auto resp = HttpResponse::newHttpResponse(); + resp->setStatusCode(k400BadRequest); + callback(resp); + return; + } + schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id, (intptr_t) &sqlite3_bind_blob, sizeof(uuid_t)); - schedule_dbo **schedules = schedule_dbo::get_by_simple("id", schedule_id.c_str(), (intptr_t) &sqlite3_bind_text); + Json::Value body = *req->jsonObject(); if(schedules[0]) { @@ -149,4 +174,4 @@ schedules::put_one_by_id(const HttpRequestPtr &req, std::functionsetStatusCode(k400BadRequest); + fcb(res); + } + if(is_valid) { - schedule_dbo **schedules = schedule_dbo::get_by_simple("id", body["active_schedule"].asCString(), (intptr_t)&sqlite3_bind_text); + schedule_dbo **schedules = schedule_dbo::get_by_simple("id", active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); bool schedule_found = schedules[0] != nullptr; schedule_dbo::free_list(schedules); if(schedule_found) diff --git a/helpers.h b/helpers.h index eaabd0d..c250d2b 100644 --- a/helpers.h +++ b/helpers.h @@ -22,11 +22,12 @@ namespace helpers typedef struct sql_filter_builder { - sql_filter_builder(const char *col_name, const void *value, intptr_t bind_func, const char *logic); + sql_filter_builder(const char *col_name, const void *value, intptr_t bind_func, int bind_func_param, const char *logic); const char *col_name; const void *value; intptr_t bind_func; + int bind_func_param; const char *logic; } sql_filter_builder; diff --git a/helpers/create_sql_filtered_query.cc b/helpers/create_sql_filtered_query.cc index 8ab8551..4e635ca 100644 --- a/helpers/create_sql_filtered_query.cc +++ b/helpers/create_sql_filtered_query.cc @@ -41,18 +41,22 @@ helpers::create_sql_filtered_query(const char *sql, sql_filter_builder **filters } if(filter->bind_func == (intptr_t)&sqlite3_bind_text) { - sqlite3_bind_text(stmt, i + 1, (char*)filter->value, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, i + 1, (char*)filter->value, filter->bind_func_param, SQLITE_STATIC); + } + if(filter->bind_func == (intptr_t)&sqlite3_bind_blob) + { + sqlite3_bind_blob(stmt, i + 1, filter->value, filter->bind_func_param, SQLITE_STATIC); } } return stmt; } -helpers::sql_filter_builder::sql_filter_builder(const char *col_name, const void *value, intptr_t bind_func, - const char *logic) +helpers::sql_filter_builder::sql_filter_builder(const char *col_name, const void *value, intptr_t bind_func, int bind_func_param, const char *logic) { this->col_name = col_name; this->value = value; this->bind_func = bind_func; + this->bind_func_param = bind_func_param; this->logic = logic; -} \ No newline at end of file +} diff --git a/helpers/migrate_sql.cc b/helpers/migrate_sql.cc index 3eea6f0..64b136b 100644 --- a/helpers/migrate_sql.cc +++ b/helpers/migrate_sql.cc @@ -1,11 +1,12 @@ #include #include +#include #include +#include #include #include -#include int helpers::migrate_sql() @@ -41,15 +42,6 @@ helpers::migrate_sql() break; } new_version_num = 1; - case 1: - LOG_INFO << "Migrating LEVEL 1"; - rc = sqlite3_exec(globals::db, (const char *)sql_migration_1_sql, nullptr, nullptr, &err_msg); - if(rc != 0) - { - LOG_FATAL << "Couldn't migrate LEVEL 1 (" << err_msg << ")"; - break; - } - new_version_num = 2; default: break; } diff --git a/models/controller_dbo.cc b/models/controller_dbo.cc index c96b9ee..565f7c2 100644 --- a/models/controller_dbo.cc +++ b/models/controller_dbo.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "controller_dbo.h" #include "globals.h" @@ -19,7 +20,7 @@ static bool controller_db_update_insert(controller_dbo *controller, sqlite3_stmt { int rc; - sqlite3_bind_text(stmt, 1, controller->id, -1, SQLITE_STATIC); + sqlite3_bind_blob(stmt, 1, controller->id, sizeof(uuid_t), SQLITE_STATIC); sqlite3_bind_text(stmt, 2, controller->name, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 3, controller->ip, -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 4, controller->active); @@ -56,7 +57,7 @@ controller_db_select_mapper(sqlite3_stmt *stmt) switch(name[1]) { case 'd': // id - strncpy(new_controller->id, (const char*)sqlite3_column_text(stmt, i), 32); + uuid_copy(new_controller->id, (const unsigned char*)sqlite3_column_blob(stmt, i)); break; case 'p': // ip strncpy(new_controller->ip, (const char*)sqlite3_column_text(stmt, i), 16); @@ -104,7 +105,7 @@ controller_db_select(sqlite3_stmt *stmt) if (s == SQLITE_ROW) { controller_dbo *new_controller = controller_db_select_mapper(stmt); - new_controller->relays = relay_dbo::get_by_simple("controller_id", new_controller->id, (intptr_t)&sqlite3_bind_text); + new_controller->relays = relay_dbo::get_by_simple("controller_id", new_controller->id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); row++; all_controllers = (controller_dbo**)realloc(all_controllers, sizeof(controller_dbo*) * (row + 1)); @@ -158,7 +159,7 @@ controller_dbo::remove() int rc; sqlite3_prepare_v2(globals::db, "DELETE FROM controllers WHERE id=?1;", -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, this->id, -1, SQLITE_STATIC); + sqlite3_bind_blob(stmt, 1, this->id, sizeof(uuid_t), SQLITE_STATIC); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); @@ -169,9 +170,11 @@ controller_dbo::remove() Json::Value controller_dbo::to_json() { + char id_str[37]; + uuid_unparse(this->id, id_str); Json::Value controller_json; controller_json["name"] = this->name; - controller_json["id"] = this->id; + controller_json["id"] = id_str; controller_json["ip"] = this->ip; controller_json["relay_count"] = this->relay_count; controller_json["active"] = this->active; @@ -199,7 +202,7 @@ controller_dbo::get_all() } controller_dbo** -controller_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func) +controller_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param) { helpers::sql_filter_builder *filters[1]; helpers::sql_filter_builder filter @@ -207,6 +210,7 @@ controller_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_ key, value, bind_func, + bind_func_param, ";" }; filters[0] = &filter; diff --git a/models/controller_dbo.h b/models/controller_dbo.h index 9af7d6f..db4138f 100644 --- a/models/controller_dbo.h +++ b/models/controller_dbo.h @@ -2,6 +2,7 @@ #define EMGAUWA_CORE_controller_DBO_H #include +#include #include #include #include @@ -11,7 +12,7 @@ class controller_dbo { public: - char id[33]; + uuid_t id; char name[128]; char ip[17]; bool active; @@ -35,7 +36,7 @@ public: to_json(); static controller_dbo** - get_by_simple(const char *key, const void *value, intptr_t bind_func); + get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param); static controller_dbo** get_by(helpers::sql_filter_builder **filters); diff --git a/models/relay_dbo.cc b/models/relay_dbo.cc index f83ff93..16d460c 100644 --- a/models/relay_dbo.cc +++ b/models/relay_dbo.cc @@ -14,8 +14,8 @@ static bool relay_db_update_insert(relay_dbo *relay, sqlite3_stmt *stmt) sqlite3_bind_int(stmt, 1, relay->id); sqlite3_bind_int(stmt, 2, relay->number); sqlite3_bind_text(stmt, 3, relay->name, -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 4, relay->active_schedule_id, -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 5, relay->controller_id, -1, SQLITE_STATIC); + sqlite3_bind_blob(stmt, 4, relay->active_schedule_id, sizeof(uuid_t), SQLITE_STATIC); + sqlite3_bind_blob(stmt, 5, relay->controller_id, sizeof(uuid_t), SQLITE_STATIC); sqlite3_bind_text(stmt, 6, relay->tag, -1, SQLITE_STATIC); rc = sqlite3_step(stmt); @@ -41,10 +41,10 @@ relay_db_select_mapper(sqlite3_stmt *stmt) switch(name[0]) { case 'a': // active_schedule_id - strncpy(new_relay->active_schedule_id, (const char*)sqlite3_column_text(stmt, i), 32); + uuid_copy(new_relay->active_schedule_id, (const unsigned char*)sqlite3_column_blob(stmt, i)); break; case 'c': // controller_id - strncpy(new_relay->controller_id, (const char*)sqlite3_column_text(stmt, i), 32); + uuid_copy(new_relay->controller_id, (const unsigned char*)sqlite3_column_blob(stmt, i)); break; case 'i': new_relay->id = sqlite3_column_int(stmt, i); @@ -123,13 +123,16 @@ relay_db_select(sqlite3_stmt *stmt) void relay_dbo::reload_active_schedule() { - schedule_dbo **schedules = schedule_dbo::get_by_simple("id", this->active_schedule_id, (intptr_t)&sqlite3_bind_text); + schedule_dbo **schedules = schedule_dbo::get_by_simple("id", this->active_schedule_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); if(!schedules[0]) { free(schedules); - schedules = schedule_dbo::get_by_simple("id", "off", (intptr_t)&sqlite3_bind_text); - strcpy(this->active_schedule_id, "off"); + uuid_t off_uuid; + memset(off_uuid, 0, sizeof(uuid_t)); + memcpy(off_uuid, "off", 3); + schedules = schedule_dbo::get_by_simple("id", off_uuid, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); + uuid_copy(this->active_schedule_id, off_uuid); } this->active_schedule = schedules[0]; @@ -175,11 +178,15 @@ relay_dbo::remove() Json::Value relay_dbo::to_json() { + char controller_id_str[37]; + uuid_unparse(this->controller_id, controller_id_str); + char active_schedule_id_str[37]; + uuid_unparse(this->active_schedule_id, active_schedule_id_str); Json::Value relay_json; relay_json["name"] = this->name; relay_json["number"] = this->number; - relay_json["active_schedule_id"] = this->active_schedule_id; - relay_json["controller_id"] = this->controller_id; + relay_json["active_schedule_id"] = active_schedule_id_str; + relay_json["controller_id"] = controller_id_str; relay_json["active_schedule"] = this->active_schedule->to_json(); relay_json["tag"] = this->tag; @@ -197,7 +204,7 @@ relay_dbo::get_all() } relay_dbo** -relay_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func) +relay_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param) { helpers::sql_filter_builder *filters[1]; helpers::sql_filter_builder filter @@ -205,6 +212,7 @@ relay_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func) key, value, bind_func, + bind_func_param, ";" }; filters[0] = &filter; @@ -221,19 +229,21 @@ relay_dbo::get_by(helpers::sql_filter_builder **filters) } relay_dbo* -relay_dbo::get_relay_for_controller(const char *controller_id, int relay_num) +relay_dbo::get_relay_for_controller(uuid_t controller_id, int relay_num) { helpers::sql_filter_builder *filters[2]; helpers::sql_filter_builder filter( "number", (void*)(intptr_t)relay_num, (intptr_t)&sqlite3_bind_int, + 0, "AND" ); helpers::sql_filter_builder filter2( "controller_id", (void*)controller_id, - (intptr_t)sqlite3_bind_text, + (intptr_t)sqlite3_bind_blob, + sizeof(uuid_t), ";" ); filters[0] = &filter; @@ -247,9 +257,9 @@ relay_dbo::get_relay_for_controller(const char *controller_id, int relay_num) } bool -relay_dbo::valid_num_for_controller(const char *search_controller_id, int relay_num) +relay_dbo::valid_num_for_controller(uuid_t search_controller_id, int relay_num) { - controller_dbo **controllers = controller_dbo::get_by_simple("id", search_controller_id, (intptr_t)&sqlite3_bind_text); + controller_dbo **controllers = controller_dbo::get_by_simple("id", search_controller_id, (intptr_t)&sqlite3_bind_blob, sizeof(uuid_t)); bool valid_id_and_num = controllers[0] && controllers[0]->relay_count > relay_num; controller_dbo::free_list(controllers); diff --git a/models/relay_dbo.h b/models/relay_dbo.h index 90fa305..eced1ce 100644 --- a/models/relay_dbo.h +++ b/models/relay_dbo.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "schedule_dbo.h" @@ -14,8 +15,8 @@ public: int id; char name[128]; int number; - char controller_id[33]; - char active_schedule_id[33]; + uuid_t controller_id; + uuid_t active_schedule_id; char tag[64]; schedule_dbo *active_schedule; @@ -38,16 +39,16 @@ public: free_list(relay_dbo **relays_list); static relay_dbo** - get_by_simple(const char *key, const void *value, intptr_t bind_func); + get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param); static relay_dbo** get_by(helpers::sql_filter_builder **filters); static relay_dbo* - get_relay_for_controller(const char *controller_id, int relay_num); + get_relay_for_controller(uuid_t controller_id, int relay_num); static bool - valid_num_for_controller(const char *search_controller_id, int relay_num); + valid_num_for_controller(uuid_t search_controller_id, int relay_num); static relay_dbo** get_all(); diff --git a/models/schedule_dbo.cc b/models/schedule_dbo.cc index 5d45553..5cf089b 100644 --- a/models/schedule_dbo.cc +++ b/models/schedule_dbo.cc @@ -11,7 +11,7 @@ static bool schedule_db_update_insert(schedule_dbo *schedule, sqlite3_stmt *stmt uint16_t *periods_blob = schedule->periods->to_db_blob(); int blob_size = (int)sizeof(uint16_t) * ((periods_blob[0] * 2) + 1); - sqlite3_bind_text(stmt, 1, schedule->id, -1, SQLITE_STATIC); + sqlite3_bind_blob(stmt, 1, schedule->id, sizeof(uuid_t), SQLITE_STATIC); sqlite3_bind_text(stmt, 2, schedule->name, -1, SQLITE_STATIC); sqlite3_bind_blob(stmt, 3, periods_blob, blob_size, SQLITE_STATIC); @@ -39,8 +39,7 @@ schedule_db_select_mapper(sqlite3_stmt *stmt) switch(name[0]) { case 'i': // id - strncpy(new_schedule->id, (const char*)sqlite3_column_text(stmt, i), 32); - new_schedule->id[32] = '\0'; + uuid_copy(new_schedule->id, (const unsigned char*)sqlite3_column_blob(stmt, i)); break; case 'n': // name strncpy(new_schedule->name, (const char*)sqlite3_column_text(stmt, i), 127); @@ -124,7 +123,7 @@ schedule_dbo::remove() int rc; sqlite3_prepare_v2(globals::db, "DELETE FROM schedules WHERE id=?1;", -1, &stmt, nullptr); - sqlite3_bind_text(stmt, 1, this->id, -1, SQLITE_STATIC); + sqlite3_bind_blob(stmt, 1, this->id, sizeof(uuid_t), SQLITE_STATIC); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); @@ -141,9 +140,11 @@ schedule_dbo::~schedule_dbo() Json::Value schedule_dbo::to_json() { + char id_str[37]; + schedule_dbo::unparse_id(this->id, id_str); Json::Value schedule_json; schedule_json["name"] = this->name; - schedule_json["id"] = this->id; + schedule_json["id"] = id_str; schedule_json["periods"] = this->periods->to_json(); return schedule_json; @@ -160,7 +161,7 @@ schedule_dbo::get_all() } schedule_dbo** -schedule_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func) +schedule_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param) { helpers::sql_filter_builder *filters[1]; helpers::sql_filter_builder filter @@ -168,6 +169,7 @@ schedule_dbo::get_by_simple(const char *key, const void *value, intptr_t bind_fu key, value, bind_func, + bind_func_param, ";" }; filters[0] = &filter; @@ -195,3 +197,49 @@ schedule_dbo::free_list(schedule_dbo **schedules_list) free(schedules_list); } +int +schedule_dbo::parse_id(const char *id_str, uuid_t result) +{ + if(strcmp("off", id_str) == 0) + { + memset(result, 0, sizeof(uuid_t)); + memcpy(result, "off", 3); + return 0; + } + if(strcmp("on", id_str) == 0) + { + memset(result, 0, sizeof(uuid_t)); + memcpy(result, "on", 2); + return 0; + } + + if(uuid_parse(id_str, result)) + { + return 1; + } + return 0; +} + +void +schedule_dbo::unparse_id(const uuid_t id, char *result) +{ + uuid_t tmp_uuid; + + memset(tmp_uuid, 0, sizeof(uuid_t)); + memcpy(tmp_uuid, "off", 3); + if(uuid_compare(id, tmp_uuid) == 0) + { + strcpy(result, "off"); + return; + } + + memset(tmp_uuid, 0, sizeof(uuid_t)); + memcpy(tmp_uuid, "on", 2); + if(uuid_compare(id, tmp_uuid) == 0) + { + strcpy(result, "on"); + return; + } + + uuid_unparse(id, result); +} diff --git a/models/schedule_dbo.h b/models/schedule_dbo.h index 9b9898c..9f4a743 100644 --- a/models/schedule_dbo.h +++ b/models/schedule_dbo.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include "period.h" @@ -12,7 +13,7 @@ class schedule_dbo { public: - char id[33]; + uuid_t id; char name[128]; period_list *periods; @@ -34,13 +35,19 @@ public: free_list(schedule_dbo **schedules_list); static schedule_dbo** - get_by_simple(const char *key, const void *value, intptr_t bind_func); + get_by_simple(const char *key, const void *value, intptr_t bind_func, int bind_func_param); static schedule_dbo** get_by(helpers::sql_filter_builder **filters); static schedule_dbo** get_all(); + + static int + parse_id(const char *id_str, uuid_t result); + + static void + unparse_id(const uuid_t id, char *result); }; diff --git a/sql/migration_0.sql b/sql/migration_0.sql index ad432a4..fc8c912 100644 --- a/sql/migration_0.sql +++ b/sql/migration_0.sql @@ -25,7 +25,8 @@ create table relays controller_id VARCHAR(33) not null references controllers (id), active_schedule_id VARCHAR(33) - references schedules + references schedules, + tag vARCHAR(64) ); create table schedules @@ -34,7 +35,9 @@ create table schedules primary key unique, name VARCHAR(128), - periods BLOB + periods BLOB, + tag vARCHAR(64) ); -INSERT INTO schedules (id, name, periods) VALUES ('off', 'off', x'00'); +INSERT INTO schedules (id, name, periods) VALUES (x'6f666600000000000000000000000000', 'off', x'00'); +INSERT INTO schedules (id, name, periods) VALUES (x'6f6e0000000000000000000000000000', 'on', x'010000009F05'); diff --git a/sql/migration_1.sql b/sql/migration_1.sql deleted file mode 100644 index 12fef78..0000000 --- a/sql/migration_1.sql +++ /dev/null @@ -1,8 +0,0 @@ -alter table relays - add tag varchar(64); - -alter table controllers - add tag varchar(64); - -INSERT INTO schedules (id, name, periods) VALUES ('on', 'on', x'010000009F05'); - diff --git a/tavern_tests/test_get_all.tavern.yaml b/tavern_tests/test_get_all.tavern.yaml new file mode 100644 index 0000000..e05385a --- /dev/null +++ b/tavern_tests/test_get_all.tavern.yaml @@ -0,0 +1,25 @@ +test_name: Test basic get all requests + +stages: + - name: Get all schedules + request: + url: "http://localhost:5000/api/v1/schedules/" + method: GET + response: + status_code: 200 + +stages: + - name: Get all relays + request: + url: "http://localhost:5000/api/v1/relays/" + method: GET + response: + status_code: 200 + +stages: + - name: Get all controllers + request: + url: "http://localhost:5000/api/v1/controllers/" + method: GET + response: + status_code: 200 diff --git a/tavern_tests/test_minimal.tavern.yaml b/tavern_tests/test_minimal.tavern.yaml deleted file mode 100644 index 31cff10..0000000 --- a/tavern_tests/test_minimal.tavern.yaml +++ /dev/null @@ -1,9 +0,0 @@ -test_name: Test basic requests - -stages: - - name: Make sure we get any response - request: - url: http://localhost:5000/api/v1/schedules/ - method: GET - response: - status_code: 200 diff --git a/tavern_tests/test_schedules_basic.tavern.yaml b/tavern_tests/test_schedules_basic.tavern.yaml new file mode 100644 index 0000000..4650f37 --- /dev/null +++ b/tavern_tests/test_schedules_basic.tavern.yaml @@ -0,0 +1,39 @@ +test_name: Test basic requests + +stages: + - name: Make sure we get any response + request: + url: "http://localhost:5000/api/v1/schedules/" + method: GET + response: + status_code: 200 + - name: post schedule, expect it to be echoed back + request: + method: POST + url: "http://localhost:5000/api/v1/schedules/" + json: + name: "hello" + periods: + - start: '00:10' + end: '00:20' + - start: '00:30' + end: '00:40' + - start: '00:50' + end: '01:00' + response: + status_code: 200 + body: + name: "{tavern.request_vars.json.name}" + save: + body: + returned_name: name + returned_id: id + - name: get schedule, check name and some periods + request: + method: GET + url: "http://localhost:5000/api/v1/schedules/{returned_id}" + response: + status_code: 200 + body: + name: "{returned_name}" +