/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2025 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 "./musers.h" #include "aqhome-cgi/service/module.h" #include #include #include /* ------------------------------------------------------------------------------------------------ * defs and enums * ------------------------------------------------------------------------------------------------ */ #define GBAS GWEN_Buffer_AppendString #define GBAA GWEN_Buffer_AppendArgs /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static void _createPermDefList(AQH_MODULE *m); static void _createRoleList(AQH_MODULE *m); static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName); static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem); static void _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); static void _handleRqEditUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); static void _handleRqEditUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); static void _handleRqAddUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); static void _handleRqAddUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); static int _getHighestUserId(const AQH_USER_LIST *userList); static int _modulePermsHasRole(const AQH_MODULE_PERMS *modPerms, uint8_t rid); static void _writeEditUserForm(AQH_MODULE *m, const AQH_USER *u, const char *sAlias, const char *sUrl, const char *sSubmitText, GWEN_BUFFER *dbuf); static void _writeUserModRolesToForm(const AQH_ROLE_LIST *roles, const AQH_MODULE_PERMS *perms, const char *sModName, GWEN_BUFFER *dbuf); static void _readAllModRolesForUserFromForm(AQH_MODULE *m, GWEN_DB_NODE *dbPost, AQH_USER *u); static void _readModRolesFromForm(GWEN_DB_NODE *dbPost, const AQH_ROLE_LIST *roleList, const char *sPrefix, AQH_MODULE_PERMS *modPerms); static void _addLabelAndInputToFormTableH(const char *title, const char *name, const char *value, const char *xxtra, GWEN_BUFFER *dbuf); static void _addUserStateLabelAndSelectionToFormTableH(const char *sTitle, const char *sName, int st, GWEN_BUFFER *dbuf); static void _setLocationHeaderForMod(AQCGI_REQUEST *rq, const char *page, const char *sModName); /* ------------------------------------------------------------------------------------------------ * vars * ------------------------------------------------------------------------------------------------ */ static AQH_MODSERVICE_HANDLER_ENTRY _requestTable[]={ {"index.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMUSERS_PERMS_USERSREAD, _handleRqIndex}, {"edituser.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqEditUserGet}, {"edituser.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqEditUserPost}, {"adduser.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqAddUserGet}, {"adduser.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqAddUserPost}, {NULL, 0, 0, NULL} }; /* ------------------------------------------------------------------------------------------------ * code * ------------------------------------------------------------------------------------------------ */ void AQH_ModAdmUsers_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder) { AQH_ModService_Extend(m, sv, baseFolder); AQH_ModService_SetHandleRequestFn(m, _handleRequest); AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule); } int AQH_ModAdmUsers_Create(AQH_SERVICE *sv) { AQH_MODULE *m; int rv; m=AQH_Module_new(); AQH_Module_SetName(m, "users"); AQH_Module_SetDescr(m, "user administration module"); AQH_Module_SetGuestPerms(m, 0); _createPermDefList(m); _createRoleList(m); rv=AQH_Service_AddModule(sv, m); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); } AQH_Module_free(m); return rv; } void _createPermDefList(AQH_MODULE *m) { AQH_PERMDEF_LIST *permDefList; permDefList=AQH_PermDef_List_new(); AQH_ModService_AddPermDef(permDefList, "UserRead", 0x001, "Read users"); AQH_ModService_AddPermDef(permDefList, "UserWrite", 0x002, "Modify users"); AQH_ModService_AddPermDef(permDefList, "UserAdd", 0x004, "Add users"); AQH_ModService_AddPermDef(permDefList, "UserDel", 0x008, "Remove users"); AQH_Module_SetPermDefList(m, permDefList); } void _createRoleList(AQH_MODULE *m) { AQH_ROLE_LIST *roleList; int id=0; roleList=AQH_Role_List_new(); AQH_ModService_AddRole(roleList, id++, "admin", AQH_MODADMUSERS_PERMS_USERSREAD | AQH_MODADMUSERS_PERMS_USERSWRITE | AQH_MODADMUSERS_PERMS_USERSADD | AQH_MODADMUSERS_PERMS_USERSDEL, "Administrator Role"); AQH_Module_SetRoleList(m, roleList); } AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName) { /* no sub-modules */ return NULL; } int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem) { AQH_ModService_HandleRequestWithTable(m, rq, session, sLastPathElem, _requestTable); return AQCGI_SendResponse(rq); } void _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) { AQH_USER_LIST *userList; uint32_t perms; perms=AQH_ModService_GetUserPerms(m); userList=AQH_ModService_LoadRawUsers(m); GBAS(dbuf, "

Users

\n"); GBAS(dbuf, "\n" "" "\n" "\n" "\n"); if (userList) { const AQH_USER *u; AQH_User_List_SortByAlias(userList, 1); u=AQH_User_List_First(userList); while(u) { const char *sUserAlias; sUserAlias=AQH_User_GetAlias(u); if (sUserAlias && *sUserAlias) { uint32_t id; const char *s; const char *sAlias; id=AQH_User_GetId(u); sAlias=AQH_User_GetAlias(u); GBAS(dbuf, ""); GBAA(dbuf, "", (unsigned long int) id); GBAA(dbuf, "", sAlias?sAlias:""); s=AQH_User_GetName(u); GBAA(dbuf, "", s?s:""); s=AQH_UserState_toString(AQH_User_GetState(u)); GBAA(dbuf, "", s?s:""); s=AQH_User_GetEmail(u); GBAA(dbuf, "", s?s:""); s=AQH_User_GetNotes(u); GBAA(dbuf, "", s?s:""); GBAS(dbuf, "\n"); GBAA(dbuf, "\n"); } u=AQH_User_List_Next(u); } GBAS(dbuf, "\n" "
IdAliasNameStatusEmailNotesActions
%lu%s%s%s%s%s"); if (perms & AQH_MODADMUSERS_PERMS_USERSWRITE) { DBG_ERROR(NULL, "User=%s", sAlias?sAlias:""); GBAS(dbuf, ""); } GBAA(dbuf, "
\n"); AQH_User_List_free(userList); } if (perms & AQH_MODADMUSERS_PERMS_USERSADD) GBAS(dbuf, "
Add User"); } void _handleRqEditUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) { AQH_SERVICE *sv; GWEN_DB_NODE *dbQuery; const char *sAlias; AQH_USER *user; sv=AQH_ModService_GetService(m); dbQuery=AQCGI_Request_GetDbQuery(rq); sAlias=dbQuery?GWEN_DB_GetCharValue(dbQuery, "alias", 0, NULL):NULL; user=(sAlias && *sAlias)?AQH_Service_LoadUser(sv, sAlias):NULL; if (user) { _writeEditUserForm(m, user, sAlias, "edituser.html", "Save", dbuf); AQH_User_free(user); } else { AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html"); AQCGI_Request_SetResponseCode(rq, 303); AQCGI_Request_SetResponseText(rq, "See other"); } } void _handleRqEditUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) { AQH_SERVICE *sv; GWEN_DB_NODE *dbPost; const char *sAlias; AQH_USER *u; sv=AQH_ModService_GetService(m); dbPost=AQCGI_Request_GetDbPostBody(rq); sAlias=dbPost?GWEN_DB_GetCharValue(dbPost, "alias", 0, NULL):NULL; u=(sAlias && *sAlias)?AQH_Service_LoadUser(sv, sAlias):NULL; if (u) { const char *s; int state; int rv; s=GWEN_DB_GetCharValue(dbPost, "name", 0, NULL); AQH_User_SetName(u, s); s=GWEN_DB_GetCharValue(dbPost, "email", 0, NULL); AQH_User_SetEmail(u, s); s=GWEN_DB_GetCharValue(dbPost, "notes", 0, NULL); AQH_User_SetNotes(u, s); s=GWEN_DB_GetCharValue(dbPost, "status", 0, NULL); state=(s && *s)?AQH_UserState_fromString(s):AQH_UserState_Unknown; if (state!=AQH_UserState_Unknown) AQH_User_SetState(u, state); _readAllModRolesForUserFromForm(m, dbPost, u); rv=AQH_Service_SaveUser(sv, u); if (rv<0) { GBAS(dbuf, "

Error

Error saving user

"); DBG_ERROR(NULL, "Could not save user \"%s\"", sAlias); AQH_User_free(u); return; } DBG_ERROR(NULL, "User \"%s\" saved", sAlias); AQH_User_free(u); AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html"); AQCGI_Request_SetResponseCode(rq, 303); AQCGI_Request_SetResponseText(rq, "See other"); } else { DBG_ERROR(NULL, "Could not load user \"%s\"", sAlias?sAlias:""); GBAS(dbuf, "

Error loading user.

\n"); } } void _handleRqAddUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) { DBG_ERROR(NULL, "AddUser"); _writeEditUserForm(m, NULL, NULL, "adduser.html", "Add", dbuf); } void _handleRqAddUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) { AQH_SERVICE *sv; GWEN_DB_NODE *dbPost; const char *sAlias; sv=AQH_ModService_GetService(m); dbPost=AQCGI_Request_GetDbPostBody(rq); sAlias=dbPost?GWEN_DB_GetCharValue(dbPost, "alias", 0, NULL):NULL; // TODO: check alias validity if (sAlias) { AQH_USER *u; const char *s; int state; int rv; uint32_t userId; AQH_USER_LIST *userList; u=AQH_User_new(); userList=AQH_ModService_LoadRawUsers(m); userId=_getHighestUserId(userList)+1; AQH_User_SetId(u, userId); AQH_User_SetAlias(u, sAlias); s=GWEN_DB_GetCharValue(dbPost, "name", 0, NULL); AQH_User_SetName(u, s); s=GWEN_DB_GetCharValue(dbPost, "email", 0, NULL); AQH_User_SetEmail(u, s); s=GWEN_DB_GetCharValue(dbPost, "notes", 0, NULL); AQH_User_SetNotes(u, s); s=GWEN_DB_GetCharValue(dbPost, "status", 0, NULL); state=(s && *s)?AQH_UserState_fromString(s):AQH_UserState_Unknown; if (state!=AQH_UserState_Unknown) AQH_User_SetState(u, state); rv=AQH_Service_AddUser(sv, u); if (rv<0) { GBAS(dbuf, "

Error

Error saving user

"); DBG_ERROR(NULL, "Could not save user \"%s\" (%d)", sAlias, rv); AQH_User_free(u); AQH_User_List_free(userList); return; } DBG_ERROR(NULL, "User \"%s\" saved", sAlias); AQH_User_free(u); AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html"); AQCGI_Request_SetResponseCode(rq, 303); AQCGI_Request_SetResponseText(rq, "See other"); AQH_User_List_free(userList); } else { DBG_ERROR(NULL, "Missing alias"); GBAS(dbuf, "

Missing alias.

\n"); } } int _getHighestUserId(const AQH_USER_LIST *userList) { int id=0; if (userList) { const AQH_USER *user; user=AQH_User_List_First(userList); while(user) { int uid; uid=AQH_User_GetId(user); id=(uid>id)?uid:id; user=AQH_User_List_Next(user); } } return id; } int _modulePermsHasRole(const AQH_MODULE_PERMS *modPerms, uint8_t rid) { if (modPerms) { int arraySize; int i; arraySize=AQH_ModulePerms_GetRoleArrayArraySize(); for(i=0; iUser Info\n"); GBAA(dbuf, "
\n" "\n", sUrl?sUrl:""); _addLabelAndInputToFormTableH("Alias", "alias", sAlias, "required", dbuf); _addLabelAndInputToFormTableH("Name", "name", u?AQH_User_GetName(u):NULL, NULL, dbuf); _addLabelAndInputToFormTableH("Email", "email", u?AQH_User_GetEmail(u):NULL, NULL, dbuf); _addLabelAndInputToFormTableH("Notes", "notes", u?AQH_User_GetNotes(u):NULL, NULL, dbuf); _addUserStateLabelAndSelectionToFormTableH("Status", "status", u?AQH_User_GetState(u):AQH_UserState_Unknown, dbuf); GBAS(dbuf, "
\n"); /* module permissions */ GBAS(dbuf, "

Module Roles

\n"); GBAS(dbuf, "\n" "" "\n" "\n" "\n"); moduleList=AQH_ModService_LoadRawModules(m); if (moduleList) { const AQH_MODULE_PERMS_LIST *modPermsList; const AQH_MODULE *currentMod; modPermsList=u?AQH_User_GetModulePermList(u):NULL; currentMod=AQH_Module_List_First(moduleList); while(currentMod) { const char *sModName; const AQH_MODULE_PERMS *modPerms; sModName=AQH_Module_GetName(currentMod); GBAA(dbuf, "\n"); GBAS(dbuf, "\n" "
ModuleRoles
%s", sModName); modPerms=modPermsList?AQH_ModulePerms_List_GetByModuleId(modPermsList, sModName):NULL; _writeUserModRolesToForm(AQH_Module_GetRoleList(currentMod), modPerms, sModName, dbuf); GBAS(dbuf, "
"); currentMod=AQH_Module_List_Next(currentMod); } /* while */ AQH_Module_List_free(moduleList); } GBAS(dbuf, "
\n"); GBAA(dbuf, "\n", sAlias?sAlias:""); GBAA(dbuf, "\n
\n\n", sSubmitText?sSubmitText:"Save"); } void _readAllModRolesForUserFromForm(AQH_MODULE *m, GWEN_DB_NODE *dbPost, AQH_USER *u) { AQH_MODULE_LIST *moduleList; moduleList=AQH_ModService_LoadRawModules(m); if (moduleList) { AQH_MODULE_PERMS_LIST *permsList; const AQH_MODULE *module; permsList=AQH_User_GetModulePermList(u); if (permsList==NULL) { DBG_ERROR(NULL, "Creating module perms list for user"); permsList=AQH_ModulePerms_List_new(); AQH_User_SetModulePermList(u, permsList); } module=AQH_Module_List_First(moduleList); while(module) { const char *sModName; const AQH_ROLE_LIST *roleList; sModName=AQH_Module_GetName(module); roleList=AQH_Module_GetRoleList(module); if (sModName && *sModName && roleList) { AQH_MODULE_PERMS *modPerms; modPerms=AQH_ModulePerms_List_GetByModuleId(permsList, sModName); if (modPerms==NULL) { modPerms=AQH_ModulePerms_new(); AQH_ModulePerms_SetModuleId(modPerms, sModName); AQH_ModulePerms_List_Add(modPerms, permsList); } _readModRolesFromForm(dbPost, roleList, sModName, modPerms); } module=AQH_Module_List_Next(module); } AQH_Module_List_free(moduleList); } } void _writeUserModRolesToForm(const AQH_ROLE_LIST *roleList, const AQH_MODULE_PERMS *modPerms, const char *sModName, GWEN_BUFFER *dbuf) { if (roleList) { const AQH_ROLE *role; role=AQH_Role_List_First(roleList); while(role) { const char *sRoleName; uint8_t roleId; roleId=AQH_Role_GetId(role); sRoleName=AQH_Role_GetName(role); if (sRoleName && *sRoleName) { int isChecked; isChecked=(modPerms && _modulePermsHasRole(modPerms, roleId)); if (sModName && *sModName) { GBAA(dbuf, "", sModName, sRoleName, isChecked?"checked":""); GBAA(dbuf, "", sModName, sRoleName, sRoleName); } else { GBAA(dbuf, "", sRoleName, isChecked?"checked":""); GBAA(dbuf, "", sRoleName, sRoleName); } } role=AQH_Role_List_Next(role); } } } void _readModRolesFromForm(GWEN_DB_NODE *dbPost, const AQH_ROLE_LIST *roleList, const char *sPrefix, AQH_MODULE_PERMS *modPerms) { AQH_ModulePerms_PresetRoleArray(modPerms, 0); if (roleList) { GWEN_BUFFER *tbuf; uint32_t pos; const AQH_ROLE *role; int nextRolePos=0; tbuf=GWEN_Buffer_new(0, 256, 0, 1); if (sPrefix && *sPrefix) GBAA(tbuf, "%s:", sPrefix); pos=GWEN_Buffer_GetPos(tbuf); role=AQH_Role_List_First(roleList); while(role) { const char *roleName; roleName=AQH_Role_GetName(role); if (roleName && *roleName) { const char *s; GBAS(tbuf, roleName); s=GWEN_DB_GetCharValue(dbPost, GWEN_Buffer_GetStart(tbuf), 0, NULL); if (s && *s) { if (nextRolePos", sName?sName:"", sTitle?sTitle:""); GBAA(dbuf, ""); } void _addLabelAndInputToFormTableH(const char *sTitle, const char *sName, const char *sValue, const char *sExtra, GWEN_BUFFER *dbuf) { GBAS(dbuf, ""); GBAA(dbuf, "", sName?sName:"", sTitle?sTitle:""); GBAA(dbuf, ""); GBAS(dbuf, "\n"); }