Files
aqhomecontrol/apps/aqhome-storage/u_rooms.c

386 lines
12 KiB
C

/****************************************************************************
* 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_rooms.h"
#include "./aqhomehttp.h"
#include "aqhome/http/httpservice.h"
#include "aqhome/http/httpservice_http.h"
#include "aqhome/http/httpservice_conf.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
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 GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
static GWEN_MSG *_addRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv)
{
AQH_HTTP_URLHANDLER *uh;
uh=AQH_HttpUrlHandler_new(sv);
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
return uh;
}
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
const char *protocol;
const char *cmd;
GWEN_MSG *msgOut;
AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome");
AQH_HttpRequest_SetupUrlPathMembers(rq);
protocol=AQH_HttpRequest_GetProtocol(rq);
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;
}
}
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;
protocol=AQH_HttpRequest_GetProtocol(rq);
pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
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);
}
/* handle middle part (header - middle - footer) */
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
if (sl) {
const char *s;
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 {
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);
}
}
else {
DBG_ERROR(NULL, "No list of url members");
GWEN_Buffer_free(pageBuf);
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
}
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;
DBG_ERROR(NULL, "POST:");
db=AQH_HttpRequest_GetDbPostBody(rq);
GWEN_DB_Dump(db, 2);
protocol=AQH_HttpRequest_GetProtocol(rq);
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
if (sl) {
const char *s;
s=GWEN_StringList_StringAt(sl, 1);
if (s && *s) {
if (strcasecmp(s, "add")==0)
return _handlePostAdd(uh, rq);
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);
}
}
else {
DBG_ERROR(NULL, "No list of url members");
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_SERVICE *sv;
uint32_t perms;
DBG_ERROR(NULL, "LIST");
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & AQHOME_HTTP_PERMS_LIST_ROOMS) {
AQH_STORAGE *sto;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
sto=AqHomeHttpService_GetStorage(sv);
if (sto) {
const AQH_ROOM_LIST *rl;
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2>"
"<table class=\"dataTable\">"
"<thead>"
" <tr><th>Id</th><th>%s</th><th>%s</th></tr>"
"</thead>",
I18N("Rooms"),
I18N("Name"),
I18N("Description"));
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
rl=AQH_Storage_GetRoomList(sto);
if (rl) {
const AQH_ROOM *r;
r=AQH_Room_List_First(rl);
while(r) {
long unsigned int id;
const char *name;
const char *descr;
id=(long unsigned int) AQH_Room_GetId(r);
name=AQH_Room_GetName(r);
descr=AQH_Room_GetDescription(r);
GWEN_Buffer_AppendArgs(pageBuf, "<tr><td>%lu</td><td>%s</td><td>%s</td></tr>", id, name?name:"", descr?descr:"");
r=AQH_Room_List_Next(r);
}
}
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/rooms/add\">%s</a><br>", I18N("Add Room"));
}
else {
GWEN_Buffer_AppendString(pageBuf, "<p>Internal error.</p>");
}
}
else {
GWEN_Buffer_AppendArgs(pageBuf, "<p>%s</p>", I18N("No permissions to see list of rooms."));
}
}
void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
{
uint32_t perms;
DBG_ERROR(NULL, "ADD");
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) {
_writeAddPage(uh, rq, NULL, pageBuf);
}
else {
DBG_INFO(NULL, "No permissions to add a room.");
GWEN_Buffer_AppendString(pageBuf, "<p>No permissions to add a room.</p>");
}
}
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
{
const char *name=NULL;
const char *descr=NULL;
if (dbValues) {
name=GWEN_DB_GetCharValue(dbValues, "name", 0, NULL);
descr=GWEN_DB_GetCharValue(dbValues, "description", 0, NULL);
}
GWEN_Buffer_AppendArgs(pageBuf,
"<h2>%s</h2><br>\n"
"<form action=\"/rooms/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">"
" <table>"
" <tr>"
" <td><label for=\"name\">%s: </label></td>"
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
" </tr>"
" <tr>"
" <td><label for=\"description\">%s: </label></td>"
" <td><input type=\"text\" name=\"description\" value=\"%s\" ></td>"
" </tr>"
" </table>"
" <input type=\"submit\" value=\"%s\">"
"</form>",
I18N("Create a Room"),
I18N("Room Name"),
name?name:"",
I18N("Description"),
descr?descr:"",
I18N("Add Room"));
return 0;
}
GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
const char *protocol;
AQH_SERVICE *sv;
uint32_t perms;
protocol=AQH_HttpRequest_GetProtocol(rq);
sv=AQH_HttpUrlHandler_GetHttpService(uh);
perms=AQH_HttpRequest_GetModulePerms(rq);
if (perms & AQHOME_HTTP_PERMS_ADD_ROOM) {
AQH_STORAGE *sto;
sto=AqHomeHttpService_GetStorage(sv);
if (sto) {
return _addRoomCreateResponse(uh, rq);
}
else {
DBG_ERROR(NULL, "No storage");
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL);
}
}
else {
return AQH_HttpService_CreateResponseMsg(sv, 403, "Forbidden", protocol, NULL);
}
}
GWEN_MSG *_addRoomCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
{
AQH_SERVICE *sv;
const char *protocol;
GWEN_DB_NODE *db;
const char *roomName;
const char *roomDescr;
AQH_STORAGE *sto;
sv=AQH_HttpUrlHandler_GetHttpService(uh);
protocol=AQH_HttpRequest_GetProtocol(rq);
db=AQH_HttpRequest_GetDbPostBody(rq);
roomName=GWEN_DB_GetCharValue(db, "name", 0, NULL);
roomDescr=GWEN_DB_GetCharValue(db, "description", 0, NULL);
if (!(roomName && *roomName)) {
DBG_INFO(NULL, "Missing room name");
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Missing room name"), 1, db, _writeAddPage);
}
sto=AqHomeHttpService_GetStorage(sv);
if (sto) {
AQH_ROOM *r;
int rv;
r=AQH_Room_new();
AQH_Room_SetName(r, roomName);
if (roomDescr && *roomDescr)
AQH_Room_SetDescription(r, roomDescr);
rv=AqHomeHttpService_LockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error locking storage");
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL);
}
if (AQH_Storage_GetRoomByName(sto, roomName)!=NULL) {
DBG_INFO(NULL, "Room \"%s\" already exists", roomName);
AqHomeHttpService_UnlockStorage(sv);
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Room already exists"), 1, db, _writeAddPage);
}
AQH_Storage_AddRoom(sto, r);
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
rv=AqHomeHttpService_UnlockStorage(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking storage");
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL);
}
return AQH_HttpService_CreateRedirectingResponseMsg(sv, protocol, "/rooms/list");
}
else
return AQH_HttpService_CreateResponseMsg(sv, 500, "Internal error", protocol, NULL);
}