service: more functions for www<->object

This commit is contained in:
Martin Preuss
2026-05-31 01:28:58 +02:00
parent 10475ec8af
commit ee823eeb3d
6 changed files with 565 additions and 7 deletions

View File

@@ -35,6 +35,7 @@
user.t2d user.t2d
session.t2d session.t2d
permdef.t2d permdef.t2d
object.t2d
objectdef.t2d objectdef.t2d
objectfielddef.t2d objectfielddef.t2d
</setVar> </setVar>
@@ -49,6 +50,7 @@
user.h user.h
session.h session.h
permdef.h permdef.h
object.h
objectdef.h objectdef.h
objectfielddef.h objectfielddef.h
</setVar> </setVar>
@@ -64,6 +66,7 @@
<headers dist="true" install="$(pkgincludedir)/service" > <headers dist="true" install="$(pkgincludedir)/service" >
object_html.h
service.h service.h
</headers> </headers>
@@ -76,6 +79,7 @@
<sources> <sources>
$(local/typefiles) $(local/typefiles)
object_html.c
service.c service.c
</sources> </sources>

View File

@@ -0,0 +1,75 @@
<?xml?>
<tm2>
<type id="AQCGI_OBJECT" type="pointer">
<descr>
</descr>
<lang id="c">
<identifier>AQCGI_OBJECT</identifier>
<prefix>AQCGI_Object</prefix>
<baseFileName>object</baseFileName>
<flags>
with_xml
with_db
with_list1
with_list2
</flags>
<headers>
<header type="sys" loc="pre">aqcgi/api.h</header>
<header type="sys" loc="pre">aqcgi/service/objectdef.h</header>
<header type="sys" loc="pre">gwenhywfar/error.h</header>
</headers>
<inlines>
</inlines>
</lang>
<members>
<member name="id" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember sortbymember</flags>
</member>
<member name="creationTime" type="uint64_t" maxlen="8">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="vars" type="GWEN_DB_NODE">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
<getflags>none</getflags>
<setflags>nocopy</setflags>
</member>
<member name="text" type="char_ptr" maxlen="65536" >
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
</member>
<member name="filePath" type="char_ptr" maxlen="256" >
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own</flags>
</member>
</members>
</type>
</tm2>

View File

@@ -0,0 +1,443 @@
/****************************************************************************
* This file is part of the project AqCGI.
* AqCGI (c) by 2026 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
//#define DISABLE_DEBUGLOG
#include "aqcgi/service/object_html.h"
#include <gwenhywfar/stringlist.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/gwendate.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
#define I18N(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _fieldToForm(const AQCGI_OBJECT *o, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf);
static int _writeBool(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf);
static int _writeInt(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf);
static int _writeString(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf);
static int _writeDate(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf);
static int _writeChoice(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf);
static int _writeText(const AQCGI_OBJECT *o, GWEN_BUFFER *dbuf);
static int _fieldFromPostRq(AQCGI_OBJECT *o, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost);
static int _readBool(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost);
static int _readInt(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost);
static int _readString(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost);
static int _readDate(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost);
static int _readChoice(GWEN_DB_NODE *db, const char *n, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost);
static int _readText(AQCGI_OBJECT *o, GWEN_DB_NODE *dbPost);
/* ------------------------------------------------------------------------------------------------
* implementation
* ------------------------------------------------------------------------------------------------
*/
int AQCGI_ObjectHtml_toForm(const AQCGI_OBJECT *o, const AQCGI_OBJECT_DEF *odef, GWEN_BUFFER *dbuf)
{
const AQCGI_FIELD_DEF_LIST *fdefList;
uint32_t flags;
flags=AQCGI_ObjectDef_GetFlags(odef);
fdefList=AQCGI_ObjectDef_GetFieldDefList(odef);
if (fdefList && AQCGI_FieldDef_List_GetCount(fdefList)) {
const AQCGI_FIELD_DEF *fdef;
GBAS(dbuf,"<table>\n");
fdef=AQCGI_FieldDef_List_First(fdefList);
while(fdef) {
int rv;
rv=_fieldToForm(o, odef, fdef, dbuf);
if (rv<0) {
DBG_INFO(AQCGI_LOGDOMAIN, "here (%d)", rv);
return rv;
}
fdef=AQCGI_FieldDef_List_Next(fdef);
}
GBAS(dbuf,"</table>\n");
}
if (flags & AQCGI_OBJECT_FLAGS_HASTEXT)
_writeText(o, dbuf);
return 0;
}
int AQCGI_ObjectHtml_fromPostRq(AQCGI_OBJECT *o, const AQCGI_OBJECT_DEF *odef, GWEN_DB_NODE *dbPost)
{
const AQCGI_FIELD_DEF_LIST *fdefList;
uint32_t flags;
flags=AQCGI_ObjectDef_GetFlags(odef);
fdefList=AQCGI_ObjectDef_GetFieldDefList(odef);
if (fdefList && AQCGI_FieldDef_List_GetCount(fdefList)) {
const AQCGI_FIELD_DEF *fdef;
fdef=AQCGI_FieldDef_List_First(fdefList);
while(fdef) {
int rv;
rv=_fieldFromPostRq(o, odef, fdef, dbPost);
if (rv<0) {
DBG_INFO(AQCGI_LOGDOMAIN, "here (%d)", rv);
return rv;
}
fdef=AQCGI_FieldDef_List_Next(fdef);
}
}
if (flags & AQCGI_OBJECT_FLAGS_HASTEXT)
_readText(o, dbPost);
return 0;
}
int _fieldToForm(const AQCGI_OBJECT *o, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *db;
db=AQCGI_Object_GetVars(o);
if (db) {
int t;
int rv=GWEN_ERROR_GENERIC;
const char *sName;
const char *sLabel;
/* write label */
sName=AQCGI_FieldDef_GetName(fdef);
sLabel=AQCGI_FieldDef_GetLabel(fdef);
GBAA(dbuf, "<tr><td><label for\"%s\">%s</label></td><td>", sName?sName:"", sLabel?sLabel:"");
/* write field */
t=AQCGI_FieldDef_GetDataType(fdef);
switch(t) {
case AQCGI_ObjectFieldType_Unknown: rv=GWEN_ERROR_BAD_DATA; break;
case AQCGI_ObjectFieldType_Bool: rv=_writeBool(db, sName, odef, fdef, dbuf); break;
case AQCGI_ObjectFieldType_Int: rv=_writeInt(db, sName, odef, fdef, dbuf); break;
case AQCGI_ObjectFieldType_String: rv=_writeString(db, sName, odef, fdef, dbuf); break;
case AQCGI_ObjectFieldType_Date: rv=_writeDate(db, sName, odef, fdef, dbuf); break;
case AQCGI_ObjectFieldType_Choice: rv=_writeChoice(db, sName, odef, fdef, dbuf); break;
}
GBAS(dbuf, "</td></tr>\n");
return rv;
}
else {
DBG_ERROR(AQCGI_LOGDOMAIN, "No vars");
return GWEN_ERROR_NO_DATA;
}
}
int _writeBool(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf)
{
int v;
v=GWEN_DB_GetIntValue(db, sName, 0, 0);
GBAA(dbuf, "<input type=\"checkbox\" name=\"%s\" %s/>", sName, v?"checked":"");
return 0;
}
int _writeInt(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf)
{
int v;
uint32_t flags;
flags=AQCGI_FieldDef_GetFlags(fdef);
v=GWEN_DB_GetIntValue(db, sName, 0, 0);
GBAA(dbuf, "<input type=\"number\" name=\"%s\" value=\"%d\"", sName, v);
if (flags & AQCGI_FIELD_FLAGS_USEMIN)
GBAA(dbuf, " min=\"%d\"", AQCGI_FieldDef_GetMinValue(fdef));
if (flags & AQCGI_FIELD_FLAGS_USEMAX)
GBAA(dbuf, " max=\"%d\"", AQCGI_FieldDef_GetMaxValue(fdef));
if (flags & AQCGI_FIELD_FLAGS_REQUIRED)
GBAS(dbuf, " required");
GBAS(dbuf, "/>");
return 0;
}
int _writeString(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf)
{
const char *v;
uint32_t flags;
flags=AQCGI_FieldDef_GetFlags(fdef);
v=GWEN_DB_GetCharValue(db, sName, 0, NULL);
GBAA(dbuf, "<input type=\"text\" name=\"%s\" value=\"%s\"", sName, v?v:"");
if (flags & AQCGI_FIELD_FLAGS_USEMIN)
GBAA(dbuf, " minlength=\"%d\"", AQCGI_FieldDef_GetMinValue(fdef));
if (flags & AQCGI_FIELD_FLAGS_USEMAX)
GBAA(dbuf, " maxlength=\"%d\"", AQCGI_FieldDef_GetMaxValue(fdef));
if (flags & AQCGI_FIELD_FLAGS_REQUIRED)
GBAS(dbuf, " required");
GBAS(dbuf, "/>");
return 0;
}
int _writeDate(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf)
{
int64_t v;
GWEN_TIMESTAMP *ts;
GWEN_DATE *dt;
v=(int64_t) GWEN_DB_GetIntValue(db, sName, 0, 0);
ts=GWEN_Timestamp_fromInt64(v);
dt=ts?GWEN_Date_fromLocalTime(GWEN_Timestamp_toTimeT(ts)):GWEN_Date_CurrentDate();
GWEN_Timestamp_free(ts);
GBAA(dbuf, "<input type=\"date\" name=\"%s\" value=\"", sName);
GWEN_Date_toStringWithTemplate(dt, "YYYY-MM-DD", dbuf);
GBAS(dbuf, "\"/>");
GWEN_Date_free(dt);
return 0;
}
int _writeChoice(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_BUFFER *dbuf)
{
int v;
const char *sChoices;
v=GWEN_DB_GetIntValue(db, sName, 0, 0);
sChoices=AQCGI_FieldDef_GetChoices(fdef);
if (sChoices && *sChoices) {
GWEN_STRINGLIST *sl;
sl=GWEN_StringList_fromString2(sChoices, ";", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);
if (sl) {
GWEN_STRINGLISTENTRY *se;
int i=0;
GBAA(dbuf, "<td><select name=\"%s\">", sName?sName:"");
se=GWEN_StringList_FirstEntry(sl);
while(se) {
const char *s;
s=GWEN_StringListEntry_Data(se);
GBAA(dbuf, "<option value=\"%s\" %s>%s</option>", s, (i==v)?"selected":"", s);
i++;
se=GWEN_StringListEntry_Next(se);
}
GWEN_StringList_free(sl);
}
}
return 0;
}
int _writeText(const AQCGI_OBJECT *o, GWEN_BUFFER *dbuf)
{
const char *v;
v=AQCGI_Object_GetText(o);
GBAS(dbuf, "<textarea name=\"text\">");
if (v)
GBAS(dbuf, v);
GBAS(dbuf, "</textarea>\n");
return 0;
}
int _fieldFromPostRq(AQCGI_OBJECT *o, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost)
{
GWEN_DB_NODE *db;
int t;
int rv=GWEN_ERROR_GENERIC;
const char *sName;
db=AQCGI_Object_GetVars(o);
if (db==NULL) {
db=GWEN_DB_Group_new("vars");
AQCGI_Object_SetVars(o, db);
}
sName=AQCGI_FieldDef_GetName(fdef);
/* read field */
t=AQCGI_FieldDef_GetDataType(fdef);
switch(t) {
case AQCGI_ObjectFieldType_Unknown: rv=GWEN_ERROR_BAD_DATA; break;
case AQCGI_ObjectFieldType_Bool: rv=_readBool(db, sName, odef, fdef, dbPost); break;
case AQCGI_ObjectFieldType_Int: rv=_readInt(db, sName, odef, fdef, dbPost); break;
case AQCGI_ObjectFieldType_String: rv=_readString(db, sName, odef, fdef, dbPost); break;
case AQCGI_ObjectFieldType_Date: rv=_readDate(db, sName, odef, fdef, dbPost); break;
case AQCGI_ObjectFieldType_Choice: rv=_readChoice(db, sName, odef, fdef, dbPost); break;
}
return rv;
}
int _readBool(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost)
{
const char *v;
v=GWEN_DB_GetCharValue(dbPost, sName, 0, NULL);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, sName, v?1:0);
return 0;
}
int _readInt(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost)
{
int v;
v=GWEN_DB_GetIntValue(dbPost, sName, 0, 0);
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, sName, v);
return 0;
}
int _readString(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost)
{
const char *v;
v=GWEN_DB_GetCharValue(dbPost, sName, 0, NULL);
if (v && *v)
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, sName, v);
else
GWEN_DB_DeleteVar(db, sName);
return 0;
}
int _readDate(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost)
{
const char *v;
int64_t i=0;
v=GWEN_DB_GetCharValue(dbPost, sName, 0, NULL);
if (v && *v) {
GWEN_DATE *dt;
dt=GWEN_Date_fromStringWithTemplate(v, "YYYY-MM-DD");
if (dt) {
GWEN_TIMESTAMP *ts;
ts=GWEN_Timestamp_fromLocalTime(GWEN_Date_toLocalTime(dt));
i=ts?GWEN_Timestamp_toInt64(ts):0;
GWEN_Timestamp_free(ts);
GWEN_Date_free(dt);
}
}
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, sName, i);
return 0;
}
int _readChoice(GWEN_DB_NODE *db, const char *sName, const AQCGI_OBJECT_DEF *odef, const AQCGI_FIELD_DEF *fdef, GWEN_DB_NODE *dbPost)
{
const char *v;
int i=0;
v=GWEN_DB_GetCharValue(dbPost, sName, 0, NULL);
if (v && *v) {
const char *sChoices;
sChoices=AQCGI_FieldDef_GetChoices(fdef);
if (sChoices && *sChoices) {
GWEN_STRINGLIST *sl;
sl=GWEN_StringList_fromString2(sChoices, ";", 0, GWEN_TEXT_FLAGS_DEL_QUOTES | GWEN_TEXT_FLAGS_CHECK_BACKSLASH);
if (sl) {
GWEN_STRINGLISTENTRY *se;
int i=0;
se=GWEN_StringList_FirstEntry(sl);
while(se) {
const char *s;
s=GWEN_StringListEntry_Data(se);
if (s && *s && strcasecmp(s, v)==0)
break;
i++;
se=GWEN_StringListEntry_Next(se);
}
GWEN_StringList_free(sl);
}
}
}
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, sName, i);
return 0;
}
int _readText(AQCGI_OBJECT *o, GWEN_DB_NODE *dbPost)
{
const char *v;
v=GWEN_DB_GetCharValue(dbPost, "text", 0, NULL);
AQCGI_Object_SetText(o, v);
return 0;
}

View File

@@ -0,0 +1,20 @@
/****************************************************************************
* This file is part of the project AqCGI.
* AqCGI (c) by 2026 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 AQCGI_SERVICE_OBJECT_HTML_H
#define AQCGI_SERVICE_OBJECT_HTML_H
#include "aqcgi/service/object.h"
#include "aqcgi/service/objectdef.h"
#endif

View File

@@ -57,7 +57,7 @@
<flags>with_flags</flags> <flags>with_flags</flags>
</member> </member>
<member name="fieldDefList" type="AQCGI_OBJECT_FIELD_DEF_LIST" maxlen="4"> <member name="fieldDefList" type="AQCGI_FIELD_DEF_LIST" maxlen="4">
<default>NULL</default> <default>NULL</default>
<preset>NULL</preset> <preset>NULL</preset>
<access>public</access> <access>public</access>

View File

@@ -1,12 +1,12 @@
<?xml?> <?xml?>
<tm2> <tm2>
<type id="AQCGI_OBJECT_FIELD_DEF" type="pointer"> <type id="AQCGI_FIELD_DEF" type="pointer">
<descr> <descr>
</descr> </descr>
<lang id="c"> <lang id="c">
<identifier>AQCGI_OBJECT_FIELD_DEF</identifier> <identifier>AQCGI_FIELD_DEF</identifier>
<prefix>AQCGI_ObjectFieldDef</prefix> <prefix>AQCGI_FieldDef</prefix>
<baseFileName>objectfielddef</baseFileName> <baseFileName>objectfielddef</baseFileName>
<flags> <flags>
@@ -27,15 +27,17 @@
</lang> </lang>
<defines> <defines>
<define id="AQCGI_OBJECTFIELD_FLAGS" prefix="AQCGI_OBJECTFIELD_FLAGS_"> <define id="AQCGI_FIELD_FLAGS" prefix="AQCGI_FIELD_FLAGS_">
<item name="IMMUTABLE" value="0x00000001" /> <item name="IMMUTABLE" value="0x00000001" />
<item name="REQUIRED" value="0x00000002" /> <item name="REQUIRED" value="0x00000002" />
<item name="USEMIN" value="0x00000004" />
<item name="USEMAX" value="0x00000008" />
</define> </define>
</defines> </defines>
<enums> <enums>
<enum id="AQCGI_OBJECTFIELD_TYPE" prefix="AQCGI_ObjectFieldType_"> <enum id="AQCGI_FIELD_TYPE" prefix="AQCGI_ObjectFieldType_">
<item name="bool"> <item name="bool">
<descr>boolean</descr> <descr>boolean</descr>
</item> </item>
@@ -67,7 +69,7 @@
<default>0</default> <default>0</default>
<preset>0</preset> <preset>0</preset>
<access>public</access> <access>public</access>
<flags>own</flags> <flags>own with_getbymember</flags>
</member> </member>
<member name="label" type="char_ptr" maxlen="64"> <member name="label" type="char_ptr" maxlen="64">
@@ -91,6 +93,20 @@
<flags></flags> <flags></flags>
</member> </member>
<member name="minValue" type="int" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="maxValue" type="int" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="choices" type="char_ptr" maxlen="256"> <member name="choices" type="char_ptr" maxlen="256">
<descr>Semicolon separated list of choices</descr> <descr>Semicolon separated list of choices</descr>
<default>0</default> <default>0</default>