editing of values now also works.

This commit is contained in:
Martin Preuss
2023-08-11 03:21:06 +02:00
parent c5171714b2
commit 978d3f6f7a
9 changed files with 416 additions and 2 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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,
"<tr><td>%s</td><td>%s</td>"
"<td><a href=\"/rooms/edit/%lu\">"
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
"</tr>",
name?name:"", descr?descr:"", id);
r=AQH_Room_List_Next(r);
}
}

View File

@@ -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 <config.h>
#endif
#include "./u_values.h"
#include "./u_objects.h"
#include "./aqhomehttp.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
/* ------------------------------------------------------------------------------------------------
* 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,
"<h2>%s</h2><br>\n"
"<form action=\"/values/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Add Value"));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", 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,
"<h2>%s</h2><br>\n"
"<form action=\"/values/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
I18N("Edit Value"),
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
_writeEditingTable(uh, dbValues, pageBuf);
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", 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,
" <table>"
" <tr>"
" <td><label for=\"name\">%s: </label></td>"
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
" </tr>",
I18N("Name"),
dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"");
GWEN_Buffer_AppendArgs(pageBuf,
"<tr><td><label for=\"topicId\">%s: </label></td>"
"<td><select id=\"topicId\" name=\"topicId\">",
I18N("Topic"));
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>", I18N("-- select topic --"));
if (topicList) {
const AQH_MQTT_TOPIC *topic;
topic=AQH_MqttTopic_List_First(topicList);
while(topic) {
const char *topicName;
topicName=AQH_MqttTopic_GetTopic(topic);
if (topicName && *topicName) {
snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_MqttTopic_GetId(topic));
numbuf[sizeof(numbuf)-1]=0;
if (selectedTopicId && AQH_MqttTopic_GetId(topic)==selectedTopicId)
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>", numbuf, topicName);
else
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>", numbuf, topicName);
}
topic=AQH_MqttTopic_List_Next(topic);
}
}
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>");
GWEN_Buffer_AppendArgs(pageBuf,
" <tr>"
" <td><label for=\"valueUnits\">%s: </label></td>"
" <td><input type=\"text\" name=\"valueUnits\" value=\"%s\"></td>"
" </tr>",
I18N("Units"),
dbValues?GWEN_DB_GetCharValue(dbValues, "valueUnits", 0, ""):"");
GWEN_Buffer_AppendArgs(pageBuf,
" <tr>"
" <td><label for=\"dataPath\">%s: </label></td>"
" <td><input type=\"text\" name=\"dataPath\" value=\"%s\"></td>"
" </tr>"
" </table>",
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,
"<h2>%s</h2>"
"<table class=\"dataTable\">"
"<thead>"
" <tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
"</thead>",
I18N("Values"),
I18N("Name"),
I18N("Topic"),
I18N("Units"),
I18N("Data Path"));
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
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,
"<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
"<td><a href=\"/values/edit/%lu\">"
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
"</tr>",
name?name:"",
topicName?topicName:"",
valueUnits?valueUnits:"",
dataPath?dataPath:"",
id);
value=AQH_Value_List_Next(value);
}
}
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/values/add\">%s</a><br>", I18N("Add Value"));
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -28,6 +28,18 @@
</lang>
<enums>
<enum id="AQH_VALUE_TYPE" prefix="AQH_ValueType_">
<item name="num">
<descr>numeric type</descr>
</item>
</enum>
</enums>
<members>
<member name="id" type="uint64_t" maxlen="8">
@@ -37,6 +49,13 @@
<flags>with_getbymember</flags>
</member>
<member name="name" type="char_ptr" maxlen="32">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>own with_getbymember</flags>
</member>
<member name="topicId" type="uint64_t" maxlen="8">
<default>0</default>
<preset>0</preset>