/**************************************************************************** * 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_objects_p.h" #include "./u_base.h" #include "./aqhomehttp.h" #include "aqhome/http/httpservice_http.h" #include #include #include GWEN_INHERIT(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS); /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static void GWENHYWFAR_CB _freeData(void *bp, void *p); static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf); static void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf); static void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf); static GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq); static GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, 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 GWEN_MSG *_addOrEditAndCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb); 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 void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ AQH_HTTP_URLHANDLER *AQH_ObjectsHttpUrlHandler_new(AQH_SERVICE *sv, uint32_t neededPermsList, uint32_t neededPermsAdd, uint32_t neededPermsDel, uint32_t neededPermsEdit, const char *urlForObjectList) { AQH_HTTP_URLHANDLER *uh; AQH_URLHANDLER_OBJECTS *xuh; uh=AQH_HttpUrlHandler_new(sv); GWEN_NEW_OBJECT(AQH_URLHANDLER_OBJECTS, xuh); GWEN_INHERIT_SETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh, xuh, _freeData); AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl); xuh->neededPermsList=neededPermsList; xuh->neededPermsAdd=neededPermsAdd; xuh->neededPermsDel=neededPermsDel; xuh->neededPermsEdit=neededPermsEdit; xuh->urlForObjectList=urlForObjectList?strdup(urlForObjectList):NULL; return uh; } void _freeData(void *bp, void *p) { AQH_URLHANDLER_OBJECTS *xuh; xuh=(AQH_URLHANDLER_OBJECTS*)p; free(xuh->urlForObjectList); GWEN_FREE_OBJECT(xuh); } void AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN fn) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh) { xuh->addOrEditObjectFn=fn; } } void AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN fn) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh) { xuh->findObjectByIdAndReturnAsDbFn=fn; } } void AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN fn) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh) { xuh->writeAddPageFn=fn; } } void AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN fn) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh) { xuh->writeEditPageFn=fn; } } void AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN fn) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh) { xuh->listObjectsIntoBufferFn=fn; } } int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { if (GWEN_INHERIT_ISOFTYPE(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh)) { const char *protocol; const char *cmd; GWEN_MSG *msgOut; AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome"); protocol=AQH_HttpRequest_GetProtocol(rq); AQH_HttpRequest_SetupUrlPathMembers(rq); if (AQH_HttpRequest_GetUrlPathMembers(rq)==NULL) { msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL); AQH_HttpRequest_SetResponseMsg(rq, msgOut); return 0; } cmd=AQH_HttpRequest_GetCommand(rq); if (cmd && *cmd) { if (strcasecmp(cmd, "GET")==0) msgOut=_handleGet(uh, rq); else if (strcasecmp(cmd, "POST")==0) msgOut=_handlePost(uh, rq); else { msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL); } AQH_HttpRequest_SetResponseMsg(rq, msgOut); return 0; } else { DBG_ERROR(AQH_LOGDOMAIN, "No command in request"); return GWEN_ERROR_INVALID; } } else { DBG_ERROR(NULL, "Not an AQH_URLHANDLER_OBJECTS object"); return GWEN_ERROR_INTERNAL; } } GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { GWEN_BUFFER *pageBuf; int rv; GWEN_MSG *msgOut=NULL; const char *protocol; const GWEN_STRINGLIST *sl; const char *s; protocol=AQH_HttpRequest_GetProtocol(rq); pageBuf=GWEN_Buffer_new(0, 2048, 0, 1); /* header */ rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf); if (rv<0) { DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers"); GWEN_Buffer_free(pageBuf); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL); } /* middle part (header - middle - footer) */ sl=AQH_HttpRequest_GetUrlPathMembers(rq); s=GWEN_StringList_StringAt(sl, 1); if (!(s && *s)) s="list"; if (strcasecmp(s, "list")==0) _handleGetList(uh, rq, pageBuf); else if (strcasecmp(s, "add")==0) _handleGetAdd(uh, rq, pageBuf); else if (strcasecmp(s, "edit")==0) _handleGetEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0), pageBuf); else { DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s); GWEN_Buffer_free(pageBuf); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); } /* footer */ rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf); if (rv<0) { DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers"); GWEN_Buffer_free(pageBuf); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL); } msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf)); GWEN_Buffer_free(pageBuf); return msgOut; } GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { GWEN_DB_NODE *db; const GWEN_STRINGLIST *sl; const char *protocol; const char *s; DBG_ERROR(NULL, "POST:"); db=AQH_HttpRequest_GetDbPostBody(rq); GWEN_DB_Dump(db, 2); protocol=AQH_HttpRequest_GetProtocol(rq); sl=AQH_HttpRequest_GetUrlPathMembers(rq); s=GWEN_StringList_StringAt(sl, 1); if (s && *s) { if (strcasecmp(s, "add")==0) return _handlePostAdd(uh, rq); else if (strcasecmp(s, "edit")==0) return _handlePostEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0)); else { DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); } } else { DBG_ERROR(NULL, "Invalid url (2nd member missing)"); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL); } } void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); uint32_t perms; DBG_ERROR(NULL, "LIST"); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & xuh->neededPermsList) { _listObjectsIntoBuffer(uh, pageBuf); } else { GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to see list of objects.")); } } void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); uint32_t perms; DBG_ERROR(NULL, "ADD"); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & xuh->neededPermsAdd) { _writeAddPage(uh, rq, NULL, pageBuf); } else { DBG_INFO(NULL, "No permissions to add."); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to add an object.")); } } void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); uint32_t perms; DBG_ERROR(NULL, "EDIT"); perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & xuh->neededPermsEdit) { if (id>0) { GWEN_DB_NODE *db; db=_findObjectByIdAndReturnAsDb(uh, id); if (db) { _writeEditPage(uh, rq, db, pageBuf); GWEN_DB_Group_free(db); } else { DBG_ERROR(NULL, "Object %d not found", id); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Object not found.")); } } else { DBG_ERROR(NULL, "Missing object id"); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("Missing or invalid object id.")); } } else { DBG_INFO(NULL, "No permissions to edit."); GWEN_Buffer_AppendArgs(pageBuf, "

%s

", I18N("No permissions to edit.")); } } GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); uint32_t perms; perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & xuh->neededPermsAdd) return _addOrEditAndCreateResponse(uh, rq, 0, _writeAddPage); else { DBG_INFO(NULL, "No perms to add object"); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 403, "Forbidden", AQH_HttpRequest_GetProtocol(rq), NULL); } } GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); uint32_t perms; perms=AQH_HttpRequest_GetModulePerms(rq); if (perms & xuh->neededPermsEdit) { return _addOrEditAndCreateResponse(uh, rq, id, _writeEditPage); } else { DBG_INFO(NULL, "No perms to edit"); return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 403, "Forbidden", AQH_HttpRequest_GetProtocol(rq), NULL); } } GWEN_MSG *_addOrEditAndCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); AQH_SERVICE *sv; GWEN_DB_NODE *db; int rv; sv=AQH_HttpUrlHandler_GetHttpService(uh); db=AQH_HttpRequest_GetDbPostBody(rq); rv=_addOrEditObject(uh, db, id); if (rv<0) return AQH_BaseHttpUrlHandler_CreateResponseForErrorCode(uh, rq, rv, cb, db); return AQH_HttpService_CreateRedirectingResponseMsg(sv, AQH_HttpRequest_GetProtocol(rq), xuh->urlForObjectList); } int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh->addOrEditObjectFn) return xuh->addOrEditObjectFn(uh, db, id); return GWEN_ERROR_NOT_IMPLEMENTED; } GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh->findObjectByIdAndReturnAsDbFn) return xuh->findObjectByIdAndReturnAsDbFn(uh, id); return NULL; } int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh->writeAddPageFn) return xuh->writeAddPageFn(uh, rq, dbValues, pageBuf); return GWEN_ERROR_NOT_IMPLEMENTED; } int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh->writeEditPageFn) return xuh->writeEditPageFn(uh, rq, dbValues, pageBuf); return GWEN_ERROR_NOT_IMPLEMENTED; } void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf) { AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh); if (xuh->listObjectsIntoBufferFn) xuh->listObjectsIntoBufferFn(uh, pageBuf); }