From 978d3f6f7a34c3acdbdaf397e3b830db8ec9ed3f Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Fri, 11 Aug 2023 03:21:06 +0200 Subject: [PATCH] editing of values now also works. --- apps/aqhome-storage/0BUILD | 2 + apps/aqhome-storage/init_http.c | 22 +++ apps/aqhome-storage/u_objects.c | 2 +- apps/aqhome-storage/u_rooms.c | 2 +- apps/aqhome-storage/u_values.c | 340 ++++++++++++++++++++++++++++++++ apps/aqhome-storage/u_values.h | 23 +++ aqhome/data/storage.c | 7 + aqhome/data/storage.h | 1 + aqhome/data/value.t2d | 19 ++ 9 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 apps/aqhome-storage/u_values.c create mode 100644 apps/aqhome-storage/u_values.h diff --git a/apps/aqhome-storage/0BUILD b/apps/aqhome-storage/0BUILD index 7fe94e3..2d39297 100644 --- a/apps/aqhome-storage/0BUILD +++ b/apps/aqhome-storage/0BUILD @@ -50,6 +50,7 @@ u_rooms.h u_devices.h u_mqtttopics.h + u_values.h u_static.h u_static_p.h aqhomehttp.h @@ -72,6 +73,7 @@ u_rooms.c u_devices.c u_mqtttopics.c + u_values.c u_static.c main.c aqhomehttp.c diff --git a/apps/aqhome-storage/init_http.c b/apps/aqhome-storage/init_http.c index 895be5b..51c9fbb 100644 --- a/apps/aqhome-storage/init_http.c +++ b/apps/aqhome-storage/init_http.c @@ -18,6 +18,7 @@ #include "./u_rooms.h" #include "./u_devices.h" #include "./u_mqtttopics.h" +#include "./u_values.h" #include "./u_static.h" #include "aqhome/msg/endpoint_tty.h" @@ -77,6 +78,7 @@ static int _createUrlHandler_login(AQHOME_STORAGE *aqh); static int _createUrlHandler_rooms(AQHOME_STORAGE *aqh); static int _createUrlHandler_devices(AQHOME_STORAGE *aqh); static int _createUrlHandler_topics(AQHOME_STORAGE *aqh); +static int _createUrlHandler_values(AQHOME_STORAGE *aqh); static int _createUrlHandler_static(AQHOME_STORAGE *aqh); @@ -128,12 +130,19 @@ int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs) return rv; } + rv=_createUrlHandler_topics(aqh); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); return rv; } + rv=_createUrlHandler_values(aqh); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + rv=_createUrlHandler_static(aqh); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); @@ -291,6 +300,19 @@ int _createUrlHandler_topics(AQHOME_STORAGE *aqh) +int _createUrlHandler_values(AQHOME_STORAGE *aqh) +{ + AQH_HTTP_URLHANDLER *uh; + + uh=AQH_ValuesHttpUrlHandler_new(aqh->httpService); + AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService)); + AQH_HttpUrlHandler_AddUrlPattern(uh, "/values/*"); + AQH_HttpService_AddUrlHandler(aqh->httpService, uh); + return 0; +} + + + int _createUrlHandler_static(AQHOME_STORAGE *aqh) { AQH_HTTP_URLHANDLER *uh; diff --git a/apps/aqhome-storage/u_objects.c b/apps/aqhome-storage/u_objects.c index b8f5221..e385166 100644 --- a/apps/aqhome-storage/u_objects.c +++ b/apps/aqhome-storage/u_objects.c @@ -203,7 +203,7 @@ GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) const char *s; protocol=AQH_HttpRequest_GetProtocol(rq); - pageBuf=GWEN_Buffer_new(0, 256, 0, 1); + pageBuf=GWEN_Buffer_new(0, 2048, 0, 1); /* header */ rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf); if (rv<0) { diff --git a/apps/aqhome-storage/u_rooms.c b/apps/aqhome-storage/u_rooms.c index 499a439..1027966 100644 --- a/apps/aqhome-storage/u_rooms.c +++ b/apps/aqhome-storage/u_rooms.c @@ -252,13 +252,13 @@ void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf) id=(long unsigned int) AQH_Room_GetId(r); name=AQH_Room_GetName(r); descr=AQH_Room_GetDescription(r); + GWEN_Buffer_AppendArgs(pageBuf, "%s%s" "" "" "", name?name:"", descr?descr:"", id); - r=AQH_Room_List_Next(r); } } diff --git a/apps/aqhome-storage/u_values.c b/apps/aqhome-storage/u_values.c new file mode 100644 index 0000000..4b8ee43 --- /dev/null +++ b/apps/aqhome-storage/u_values.c @@ -0,0 +1,340 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "./u_values.h" +#include "./u_objects.h" +#include "./aqhomehttp.h" + +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id); +static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id); +static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf); +static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf); +static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf); + +static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf); +static void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv) +{ + AQH_HTTP_URLHANDLER *uh; + + uh=AQH_ObjectsHttpUrlHandler_new(sv, + AQHOME_HTTP_PERMS_LIST_VALUES, + AQHOME_HTTP_PERMS_ADD_VALUE, + AQHOME_HTTP_PERMS_DEL_VALUE, + AQHOME_HTTP_PERMS_EDIT_VALUE, + "/values/list"); + AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject); + AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb); + AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage); + AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage); + AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer); + + return uh; +} + + + +int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id) +{ + AQH_SERVICE *sv; + AQH_STORAGE *sto; + AQH_VALUE *newValue; + const char *valueName; + int rv; + + sv=AQH_HttpUrlHandler_GetHttpService(uh); + sto=AqHomeHttpService_GetStorage(sv); + + newValue=AQH_Value_fromDb(db); + + valueName=AQH_Value_GetName(newValue); + if (!(valueName && *valueName)) { + DBG_INFO(NULL, "Missing value name"); + AQH_Value_free(newValue); + return GWEN_ERROR_INVALID; + } + + rv=AqHomeHttpService_LockStorage(sv); + if (rv<0) { + DBG_ERROR(NULL, "Error locking storage"); + AQH_Value_free(newValue); + return GWEN_ERROR_IO; + } + + if (id>0) { + AQH_VALUE *value; + + DBG_INFO(NULL, "Edit existing value"); + value=AQH_Storage_GetValueById(sto, id); + if (value==NULL) { + AqHomeHttpService_UnlockStorage(sv); + DBG_ERROR(NULL, "Value %d not found", id); + AQH_Value_free(newValue); + return GWEN_ERROR_NOT_FOUND; + } + AQH_Value_SetId(value, id); + _setFromObject(value, newValue); + AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED); + } + else { + AQH_VALUE *value; + + DBG_INFO(NULL, "Adding new value"); + value=AQH_Storage_GetValueByName(sto, valueName); + if (value) { + AqHomeHttpService_UnlockStorage(sv); + DBG_ERROR(NULL, "Value %s exists", valueName); + AQH_Value_free(newValue); + return GWEN_ERROR_FOUND; + } + value=AQH_Value_new(); + AQH_Value_SetId(value, 0); + _setFromObject(value, newValue); + AQH_Storage_AddValue(sto, value); + AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED); + } + AQH_Value_free(newValue); + + rv=AqHomeHttpService_UnlockStorage(sv); + if (rv<0) { + DBG_ERROR(NULL, "Error unlocking storage"); + return GWEN_ERROR_IO; + } + return 0; +} + + + +void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue) +{ + AQH_Value_SetName(value, AQH_Value_GetName(srcValue)); + AQH_Value_SetTopicId(value, AQH_Value_GetTopicId(srcValue)); + AQH_Value_SetValueType(value, AQH_Value_GetValueType(srcValue)); + AQH_Value_SetValueUnits(value, AQH_Value_GetValueUnits(srcValue)); + AQH_Value_SetDataPath(value, AQH_Value_GetDataPath(srcValue)); +} + + + +GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id) +{ + AQH_SERVICE *sv; + AQH_STORAGE *sto; + const AQH_VALUE *value; + + sv=AQH_HttpUrlHandler_GetHttpService(uh); + sto=AqHomeHttpService_GetStorage(sv); + + value=AQH_Storage_GetValueById(sto, id); + if (value) { + GWEN_DB_NODE *db; + + db=GWEN_DB_Group_new("value"); + AQH_Value_toDb(value, db); + return db; + } + return NULL; +} + + + +int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) +{ + GWEN_Buffer_AppendArgs(pageBuf, + "

%s


\n" + "
", + I18N("Add Value")); + _writeEditingTable(uh, dbValues, pageBuf); + GWEN_Buffer_AppendArgs(pageBuf, "
", I18N("Submit")); + return 0; +} + + + +int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) +{ + + GWEN_Buffer_AppendArgs(pageBuf, + "

%s


\n" + "
", + I18N("Edit Value"), + (long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0)); + _writeEditingTable(uh, dbValues, pageBuf); + GWEN_Buffer_AppendArgs(pageBuf, "
", I18N("Submit")); + return 0; +} + + + +void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) +{ + AQH_SERVICE *sv; + AQH_STORAGE *sto; + const AQH_MQTT_TOPIC_LIST *topicList; + unsigned long int selectedTopicId=0; + char numbuf[16]; + + sv=AQH_HttpUrlHandler_GetHttpService(uh); + sto=AqHomeHttpService_GetStorage(sv); + topicList=AQH_Storage_GetMqttTopicList(sto); + + selectedTopicId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "TopicId", 0, 0):0); + snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedTopicId); + numbuf[sizeof(numbuf)-1]=0; + + GWEN_Buffer_AppendArgs(pageBuf, + " " + " " + " " + " " + " ", + I18N("Name"), + dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):""); + GWEN_Buffer_AppendArgs(pageBuf, + "" + ""); + + GWEN_Buffer_AppendArgs(pageBuf, + " " + " " + " " + " ", + I18N("Units"), + dbValues?GWEN_DB_GetCharValue(dbValues, "valueUnits", 0, ""):""); + GWEN_Buffer_AppendArgs(pageBuf, + " " + " " + " " + " " + "
", + I18N("Data Path (JSON)"), + dbValues?GWEN_DB_GetCharValue(dbValues, "dataPath", 0, ""):""); +} + + + +void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf) +{ + AQH_SERVICE *sv; + AQH_STORAGE *sto; + const AQH_VALUE_LIST *rl; + + sv=AQH_HttpUrlHandler_GetHttpService(uh); + sto=AqHomeHttpService_GetStorage(sv); + + GWEN_Buffer_AppendArgs(pageBuf, + "

%s

" + "" + "" + " " + "", + I18N("Values"), + I18N("Name"), + I18N("Topic"), + I18N("Units"), + I18N("Data Path")); + GWEN_Buffer_AppendString(pageBuf, ""); + rl=AQH_Storage_GetValueList(sto); + if (rl) { + const AQH_VALUE *value; + + value=AQH_Value_List_First(rl); + while(value) { + long unsigned int id; + int topicId; + const char *name; + const char *topicName=NULL; + const char *valueUnits; + const char *dataPath; + const AQH_MQTT_TOPIC *topic=NULL; + + id=(long unsigned int) AQH_Value_GetId(value); + topicId=(long unsigned int) AQH_Value_GetTopicId(value); + if (topicId>0) + topic=AQH_Storage_GetMqttTopicById(sto, topicId); + if (topic) + topicName=AQH_MqttTopic_GetTopic(topic); + + name=AQH_Value_GetName(value); + valueUnits=AQH_Value_GetValueUnits(value); + dataPath=AQH_Value_GetDataPath(value); + GWEN_Buffer_AppendArgs(pageBuf, + "" + "" + "", + name?name:"", + topicName?topicName:"", + valueUnits?valueUnits:"", + dataPath?dataPath:"", + id); + value=AQH_Value_List_Next(value); + } + } + GWEN_Buffer_AppendString(pageBuf, ""); + GWEN_Buffer_AppendArgs(pageBuf, "
%s%s%s%s
%s%s%s%s" + "
%s
", I18N("Add Value")); +} + + + + + diff --git a/apps/aqhome-storage/u_values.h b/apps/aqhome-storage/u_values.h new file mode 100644 index 0000000..b7b13f5 --- /dev/null +++ b/apps/aqhome-storage/u_values.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * + * The license for this file can be found in the file COPYING which you + * should have received along with this file. + ****************************************************************************/ + +#ifndef AQHOME_STORAGE_U_VALUES_H +#define AQHOME_STORAGE_U_VALUES_H + + +#include "aqhome/http/urlhandler.h" + + + +AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv); + + + +#endif + + diff --git a/aqhome/data/storage.c b/aqhome/data/storage.c index 8146c08..d6dae45 100644 --- a/aqhome/data/storage.c +++ b/aqhome/data/storage.c @@ -211,6 +211,13 @@ AQH_VALUE *AQH_Storage_GetValueById(const AQH_STORAGE *sto, uint64_t id) +AQH_VALUE *AQH_Storage_GetValueByName(const AQH_STORAGE *sto, const char *s) +{ + return sto?AQH_Value_List_GetByName(sto->valueList, s):NULL; +} + + + uint32_t AQH_Storage_GetRuntimeFlags(const AQH_STORAGE *sto) { return sto?sto->runtimeFlags:0; diff --git a/aqhome/data/storage.h b/aqhome/data/storage.h index fb605c5..7679949 100644 --- a/aqhome/data/storage.h +++ b/aqhome/data/storage.h @@ -67,6 +67,7 @@ AQHOME_API AQH_MQTT_TOPIC *AQH_Storage_GetMqttTopicByTopic(const AQH_STORAGE *st AQHOME_API void AQH_Storage_AddValue(AQH_STORAGE *sto, AQH_VALUE *value); AQHOME_API AQH_VALUE_LIST *AQH_Storage_GetValueList(const AQH_STORAGE *sto); AQHOME_API AQH_VALUE *AQH_Storage_GetValueById(const AQH_STORAGE *sto, uint64_t id); +AQHOME_API AQH_VALUE *AQH_Storage_GetValueByName(const AQH_STORAGE *sto, const char *s); AQHOME_API const char *AQH_Storage_GetStateFile(const AQH_STORAGE *sto); AQHOME_API void AQH_Storage_SetStateFile(AQH_STORAGE *sto, const char *s); diff --git a/aqhome/data/value.t2d b/aqhome/data/value.t2d index fb7c6ea..23473cb 100644 --- a/aqhome/data/value.t2d +++ b/aqhome/data/value.t2d @@ -28,6 +28,18 @@ + + + + + numeric type + + + + + + + @@ -37,6 +49,13 @@ with_getbymember + + 0 + 0 + public + own with_getbymember + + 0 0