diff --git a/skeema/gradido_login/groups.sql b/skeema/gradido_login/groups.sql index 8c5e143bb..7d4c5a185 100644 --- a/skeema/gradido_login/groups.sql +++ b/skeema/gradido_login/groups.sql @@ -2,6 +2,7 @@ CREATE TABLE `groups` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `alias` varchar(190) NOT NULL, `name` varchar(255) NOT NULL, + `url` varchar(255) NOT NULL, `description` text, PRIMARY KEY (`id`), UNIQUE KEY `alias` (`alias`) diff --git a/skeema/gradido_login/hedera_topics.sql b/skeema/gradido_login/hedera_topics.sql index 6a58174c1..02f7e3b39 100644 --- a/skeema/gradido_login/hedera_topics.sql +++ b/skeema/gradido_login/hedera_topics.sql @@ -6,7 +6,7 @@ CREATE TABLE `hedera_topics` ( `group_id` int unsigned NOT NULL, `admin_key_id` int unsigned DEFAULT NULL, `submit_key_id` int unsigned DEFAULT NULL, - `current_timeout` timestamp NOT NULL DEFAULT '0', + `current_timeout` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00', `sequence_number` bigint unsigned DEFAULT '0', `updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), diff --git a/src/cpp/HTTPInterface/AdminGroupsPage.cpp b/src/cpp/HTTPInterface/AdminGroupsPage.cpp new file mode 100644 index 000000000..1e6619801 --- /dev/null +++ b/src/cpp/HTTPInterface/AdminGroupsPage.cpp @@ -0,0 +1,212 @@ +#include "AdminGroupsPage.h" +#include "Poco/Net/HTTPServerRequest.h" +#include "Poco/Net/HTTPServerResponse.h" +#include "Poco/Net/HTMLForm.h" +#include "Poco/DeflatingStream.h" + + +#line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + + #include "../controller/Group.h" +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + +#include "../ServerConfig.h" + + +AdminGroupsPage::AdminGroupsPage(Session* arg): + SessionHTTPRequestHandler(arg) +{ +} + + +void AdminGroupsPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) +{ + response.setChunkedTransferEncoding(true); + response.setContentType("text/html"); + bool _compressResponse(request.hasToken("Accept-Encoding", "gzip")); + if (_compressResponse) response.set("Content-Encoding", "gzip"); + + Poco::Net::HTMLForm form(request, request.stream()); +#line 10 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + + const char* pageName = "Gruppen"; + + // add + if(!form.empty()) { + auto alias = form.get("group-alias"); + if(alias == "") + { + addError(new Error("Add Group", "Alias is empty!")); + } + else + { + auto newGroup = controller::Group::create( + alias, + form.get("group-name", ""), + form.get("group-url", ""), + form.get("group-desc", "") + ); + newGroup->getModel()->insertIntoDB(false); + } + } + + // select all + auto groups = controller::Group::listAll(); + //auto groups = controller::Group::load("gdd1"); + //std::vector> groups; + +#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + + bool withMaterialIcons = false; + std::ostream& _responseStream = response.send(); + Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); + std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; + responseStream << "\n"; + // begin include header.cpsp + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "Gradido Login Server: "; +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + responseStream << ( pageName ); + responseStream << "\n"; + responseStream << "\n"; +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + if(withMaterialIcons) { responseStream << "\n"; + responseStream << "\n"; +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" + } responseStream << "\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << " "; + // end include header.cpsp + responseStream << "\n"; +#line 38 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( getErrorsHtml() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t

Alle Gruppen

\n"; + responseStream << "\t\t
\t\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\t
ID
\n"; + responseStream << "\t\t\t\t
Name
\n"; + responseStream << "\t\t\t\t
Alias
\n"; + responseStream << "\t\t\t\t
Url
\n"; + responseStream << "\t\t\t\t
"; +#line 50 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( gettext("Description") ); + responseStream << "
\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 52 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + for(auto it = groups.begin(); it != groups.end(); it++) { + auto group_model = (*it)->getModel(); responseStream << "\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t\t\t
"; +#line 55 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getID() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 56 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getName() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 57 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getAlias() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 58 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getUrl() ); + responseStream << "
\n"; + responseStream << "\t\t\t\t\t
"; +#line 59 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + responseStream << ( group_model->getDescription()); + responseStream << "
\n"; + responseStream << "\t\t\t\t
\n"; + responseStream << "\t\t\t"; +#line 61 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminGroups.cpsp" + } responseStream << "\n"; + responseStream << "\t\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t

Eine neue Gruppe anlegen

\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t
\n"; + responseStream << "
\n"; + // begin include footer.cpsp + responseStream << "
\n"; + responseStream << "

Copyright © Gradido 2020

\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << " "; +#line 6 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\footer.cpsp" + responseStream << ( mTimeProfiler.string() ); + responseStream << "\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "

Login Server in Entwicklung

\n"; + responseStream << "

Alpha "; +#line 10 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\footer.cpsp" + responseStream << ( ServerConfig::g_versionString ); + responseStream << "

\n"; + responseStream << "
\n"; + responseStream << "
\n"; + responseStream << "\n"; + responseStream << "\n"; + responseStream << ""; + // end include footer.cpsp + responseStream << "\n"; + if (_compressResponse) _gzipStream.close(); +} diff --git a/src/cpp/HTTPInterface/AdminGroupsPage.h b/src/cpp/HTTPInterface/AdminGroupsPage.h new file mode 100644 index 000000000..43a99ffb4 --- /dev/null +++ b/src/cpp/HTTPInterface/AdminGroupsPage.h @@ -0,0 +1,20 @@ +#ifndef AdminGroupsPage_INCLUDED +#define AdminGroupsPage_INCLUDED + + +#include "Poco/Net/HTTPRequestHandler.h" + + +#include "SessionHTTPRequestHandler.h" + + +class AdminGroupsPage: public SessionHTTPRequestHandler +{ +public: + AdminGroupsPage(Session*); + + void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); +}; + + +#endif // AdminGroupsPage_INCLUDED diff --git a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp index 454cc930a..50dc610af 100644 --- a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp +++ b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp @@ -27,6 +27,7 @@ #include "PassphrasedTransaction.h" #include "AdminUserPasswordReset.h" #include "RegisterDirectPage.h" +#include "AdminGroupsPage.h" #include "DecodeTransactionPage.h" #include "RepairDefectPassphrase.h" @@ -206,6 +207,11 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c pageRequestHandler->setProfiler(timeUsed); return pageRequestHandler; } + if (url_first_part == "/groups") { + auto pageRequestHandler = new AdminGroupsPage(s); + pageRequestHandler->setProfiler(timeUsed); + return pageRequestHandler; + } } if(url_first_part == "/logout") { diff --git a/src/cpp/controller/Group.cpp b/src/cpp/controller/Group.cpp new file mode 100644 index 000000000..d5b3eb2ba --- /dev/null +++ b/src/cpp/controller/Group.cpp @@ -0,0 +1,69 @@ + +#include "Group.h" + +namespace controller { + + Group::Group(model::table::Group* dbModel) + { + mDBModel = dbModel; + } + + Group::~Group() + { + + } + + Poco::AutoPtr Group::create(const std::string& alias, const std::string& name, const std::string& url, const std::string& description) + { + auto db = new model::table::Group(alias, name, url, description); + auto group = new Group(db); + return Poco::AutoPtr(group); + } + + std::vector> Group::load(const std::string& alias) + { + auto db = new model::table::Group(); + auto group_list = db->loadFromDB("alias", alias, 0); + + std::vector> resultVector; + resultVector.reserve(group_list.size()); + for (auto it = group_list.begin(); it != group_list.end(); it++) { + resultVector.push_back(new Group(new model::table::Group(*it))); + } + return resultVector; + } + + std::vector> Group::listAll() + { + auto db = new model::table::Group(); + std::vector group_list; + // throw an unresolved external symbol error + //group_list = db->loadAllFromDB(); + + // work around for not working call to loadAllFromDB + auto cm = ConnectionManager::getInstance(); + Poco::Data::Statement select(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER)); + + select << "SELECT id, alias, name, url, description FROM " << db->getTableName() + , Poco::Data::Keywords::into(group_list); + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + printf("[Group::listAll] poco exception: %s\n", ex.displayText().data()); + } + // work around end + std::vector> resultVector; + + resultVector.reserve(group_list.size()); + for (auto it = group_list.begin(); it != group_list.end(); it++) { + Poco::AutoPtr group_ptr(new Group(new model::table::Group(*it))); + resultVector.push_back(group_ptr); + } + return resultVector; + } + +} + diff --git a/src/cpp/controller/Group.h b/src/cpp/controller/Group.h new file mode 100644 index 000000000..e1ff29b64 --- /dev/null +++ b/src/cpp/controller/Group.h @@ -0,0 +1,33 @@ +#ifndef GRADIDO_LOGIN_SERVER_CONTROLLER_GROUP_INCLUDE +#define GRADIDO_LOGIN_SERVER_CONTROLLER_GROUP_INCLUDE + +#include "../model/table/Group.h" + +#include "Poco/SharedPtr.h" + +#include "TableControllerBase.h" + +namespace controller { + class Group : public TableControllerBase + { + public: + + ~Group(); + + static Poco::AutoPtr create(const std::string& alias, const std::string& name, const std::string& url, const std::string& description); + + static std::vector> load(const std::string& alias); + static std::vector> listAll(); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + + + protected: + Group(model::table::Group* dbModel); + + }; +} + +#endif //GRADIDO_LOGIN_SERVER_CONTROLLER_GROUP_INCLUDE \ No newline at end of file diff --git a/src/cpp/model/table/Group.cpp b/src/cpp/model/table/Group.cpp index 458f8f0dd..c1a84e832 100644 --- a/src/cpp/model/table/Group.cpp +++ b/src/cpp/model/table/Group.cpp @@ -8,6 +8,19 @@ namespace model { { } + Group::Group(const std::string& alias, const std::string& name, const std::string& url, const std::string& description) + : mAlias(alias), mName(name), mUrl(url), mDescription(description) + { + + } + + Group::Group(GroupTuple tuple) + : ModelBase(tuple.get<0>()), + mAlias(tuple.get<1>()), mName(tuple.get<2>()), mUrl(tuple.get<3>()), mDescription(tuple.get<4>()) + { + + } + Group::~Group() { @@ -18,6 +31,7 @@ namespace model { std::stringstream ss; ss << "Alias: " << mAlias << std::endl; ss << "Name: " << mName << std::endl; + ss << "Url: " << mUrl << std::endl; ss << "Description:" << mDescription << std::endl; return ss.str(); } @@ -26,9 +40,28 @@ namespace model { { Poco::Data::Statement select(session); - select << "SELECT id, alias, name, description FROM " << getTableName() + select << "SELECT id, alias, name, url, description FROM " << getTableName() << " where " << fieldName << " = ?" - , into(mID), into(mAlias), into(mName), into(mDescription); + , into(mID), into(mAlias), into(mName), into(mUrl), into(mDescription); + + return select; + } + + Poco::Data::Statement Group::_loadAllFromDB(Poco::Data::Session session) + { + Poco::Data::Statement select(session); + + select << "SELECT id, alias, name, url, description FROM " << getTableName(); + + return select; + } + + Poco::Data::Statement Group::_loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName) + { + Poco::Data::Statement select(session); + // typedef Poco::Tuple, int> UserTuple; + select << "SELECT id, alias, name, url, description FROM " << getTableName() + << " where " << fieldName << " LIKE ?"; return select; } @@ -48,8 +81,8 @@ namespace model { Poco::Data::Statement insert(session); lock(); insert << "INSERT INTO " << getTableName() - << " (alias, name, description) VALUES(?,?,?)" - , use(mAlias), use(mName), use(mDescription); + << " (alias, name, url, description) VALUES(?,?,?,?)" + , use(mAlias), use(mName), use(mUrl), use(mDescription); unlock(); return insert; } diff --git a/src/cpp/model/table/Group.h b/src/cpp/model/table/Group.h index bde1b0d68..1f6296b92 100644 --- a/src/cpp/model/table/Group.h +++ b/src/cpp/model/table/Group.h @@ -2,30 +2,47 @@ #define GRADIDO_LOGIN_SERVER_MODEL_TABLE_GROUPS_INCLUDE #include "ModelBase.h" +#include "Poco/Tuple.h" namespace model { namespace table { + typedef Poco::Tuple GroupTuple; + class Group : public ModelBase { public: Group(); + Group(const std::string& alias, const std::string& name, const std::string& url, const std::string& description); + Group(GroupTuple userTuple); ~Group(); // generic db operations const char* getTableName() const { return "groups"; } std::string toString(); + inline const std::string& getAlias() const { return mAlias; } + inline const std::string& getName() const { std::shared_lock _lock(mSharedMutex); return mName; } + inline const std::string& getDescription() const { std::shared_lock _lock(mSharedMutex); return mDescription; } + inline const std::string& getUrl() const { std::shared_lock _lock(mSharedMutex); return mUrl; } + + inline void setName(const std::string& name) { std::unique_lock _lock(mSharedMutex); mName = name; } + inline void setDescription(const std::string& desc) { std::unique_lock _lock(mSharedMutex); mDescription = desc; } + inline void setUrl(const std::string& url) { std::unique_lock _lock(mSharedMutex); mUrl = url; } protected: Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); + Poco::Data::Statement _loadAllFromDB(Poco::Data::Session session); + Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session); Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); - + std::string mAlias; std::string mName; + std::string mUrl; std::string mDescription; + mutable std::shared_mutex mSharedMutex; }; } diff --git a/src/cpp/model/table/ModelBase.cpp b/src/cpp/model/table/ModelBase.cpp index 5ba5a5529..4b55ea084 100644 --- a/src/cpp/model/table/ModelBase.cpp +++ b/src/cpp/model/table/ModelBase.cpp @@ -137,6 +137,13 @@ namespace model { throw Poco::Exception(message); } + Poco::Data::Statement ModelBase::_loadAllFromDB(Poco::Data::Session session) + { + std::string message = getTableName(); + message += "::_loadAllFromDB not implemented"; + throw Poco::Exception(message); + } + Poco::DateTime ModelBase::parseElopageDate(std::string dateString) { std::string decodedDateString = ""; diff --git a/src/cpp/model/table/ModelBase.h b/src/cpp/model/table/ModelBase.h index 579fa8304..82e5c273e 100644 --- a/src/cpp/model/table/ModelBase.h +++ b/src/cpp/model/table/ModelBase.h @@ -42,6 +42,8 @@ namespace model { bool isExistInDB(const std::string& fieldName, const T& fieldValue); template std::vector loadFromDB(const std::string& fieldName, const WhereFieldType& fieldValue, int expectedResults = 0); + template + std::vector loadAllFromDB(); template size_t loadFromDB(const std::vector& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType = MYSQL_CONDITION_AND); template @@ -62,6 +64,7 @@ namespace model { virtual Poco::Data::Statement _loadIdFromDB(Poco::Data::Session session) = 0; virtual Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName) = 0; virtual Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::vector& fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); + virtual Poco::Data::Statement _loadAllFromDB(Poco::Data::Session session); virtual Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::string& fieldName); virtual Poco::Data::Statement _loadMultipleFromDB(Poco::Data::Session session, const std::vector fieldNames, MysqlConditionType conditionType = MYSQL_CONDITION_AND); virtual Poco::Data::Statement _insertIntoDB(Poco::Data::Session session) = 0; @@ -145,6 +148,29 @@ namespace model { return results; } + template + std::vector loadAllFromDB() + { + std::vector results; + Poco::ScopedLock _lock(mWorkMutex); + + auto cm = ConnectionManager::getInstance(); + Poco::Data::Statement select = _loadAllFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER)); + select, Poco::Data::Keywords::into(results); + + size_t resultCount = 0; + try { + resultCount = select.execute(); + } + catch (Poco::Exception& ex) { + lock(); + addError(new ParamError(getTableName(), "mysql error by selecting all", ex.displayText().data())); + unlock(); + } + + return results; + } + template std::vector ModelBase::loadFromDB(const std::vector& fieldNames, const std::vector& fieldValues, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/, int expectedResults/* = 0*/) { diff --git a/src/cpsp/adminGroups.cpsp b/src/cpsp/adminGroups.cpsp new file mode 100644 index 000000000..e357388af --- /dev/null +++ b/src/cpsp/adminGroups.cpsp @@ -0,0 +1,80 @@ +<%@ page class="AdminGroupsPage" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="SessionHTTPRequestHandler" %> +<%@ page ctorArg="Session*" %> +<%@ header include="SessionHTTPRequestHandler.h" %> +<%! + #include "../controller/Group.h" +%> +<%% + const char* pageName = "Gruppen"; + + // add + if(!form.empty()) { + auto alias = form.get("group-alias"); + if(alias == "") + { + addError(new Error("Add Group", "Alias is empty!")); + } + else + { + auto newGroup = controller::Group::create( + alias, + form.get("group-name", ""), + form.get("group-url", ""), + form.get("group-desc", "") + ); + newGroup->getModel()->insertIntoDB(false); + } + } + + // select all + auto groups = controller::Group::listAll(); + //auto groups = controller::Group::load("gdd1"); + //std::vector> groups; + +%><%@ include file="header.cpsp" %> +<%= getErrorsHtml() %> +
+
+
+

Alle Gruppen

+
+
+
+
ID
+
Name
+
Alias
+
Url
+
<%= gettext("Description") %>
+
+ <% for(auto it = groups.begin(); it != groups.end(); it++) { + auto group_model = (*it)->getModel(); %> +
+
<%= group_model->getID() %>
+
<%= group_model->getName() %>
+
<%= group_model->getAlias() %>
+
<%= group_model->getUrl() %>
+
<%= group_model->getDescription()%>
+
+ <% } %> +
+
+
+

Eine neue Gruppe anlegen

+
+
+
+ + + + + + + + + "> +
+
+<%@ include file="footer.cpsp" %>