diff options
author | Matthias Schiffer <matthias@gamezock.de> | 2009-08-09 18:52:17 +0200 |
---|---|---|
committer | Matthias Schiffer <matthias@gamezock.de> | 2009-08-09 18:52:17 +0200 |
commit | d7edb4799b63b9bbde25a0d04603476aaf8acd50 (patch) | |
tree | 4ef76e718eac041c8ddeff985b67ea70e293f261 /src/modules/UserDBBackendMysql | |
parent | 758f3cf98f95fc906c2517c0d4537ce81cf7386d (diff) | |
download | mad-d7edb4799b63b9bbde25a0d04603476aaf8acd50.tar mad-d7edb4799b63b9bbde25a0d04603476aaf8acd50.zip |
Renamed UserBackendMysql to UserDBBackendMysql and UserBackendHome to UserConfigBackendHome
Diffstat (limited to 'src/modules/UserDBBackendMysql')
-rw-r--r-- | src/modules/UserDBBackendMysql/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/modules/UserDBBackendMysql/Module.cpp | 28 | ||||
-rw-r--r-- | src/modules/UserDBBackendMysql/Module.h | 52 | ||||
-rw-r--r-- | src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp | 652 | ||||
-rw-r--r-- | src/modules/UserDBBackendMysql/UserDBBackendMysql.h | 159 |
5 files changed, 899 insertions, 0 deletions
diff --git a/src/modules/UserDBBackendMysql/CMakeLists.txt b/src/modules/UserDBBackendMysql/CMakeLists.txt new file mode 100644 index 0000000..8c4f079 --- /dev/null +++ b/src/modules/UserDBBackendMysql/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories(${INCLUDES} ${MYSQL_INCLUDE_DIR}) + +mad_module(UserDBBackendMysql + Module.cpp Module.h + UserDBBackendMysql.cpp UserDBBackendMysql.h +) + +mad_module_libraries(UserDBBackendMysql ${MYSQL_LIBRARIES})
\ No newline at end of file diff --git a/src/modules/UserDBBackendMysql/Module.cpp b/src/modules/UserDBBackendMysql/Module.cpp new file mode 100644 index 0000000..a4b51c4 --- /dev/null +++ b/src/modules/UserDBBackendMysql/Module.cpp @@ -0,0 +1,28 @@ +/* + * Module.cpp + * + * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Module.h" + +extern "C" { + +Mad::Common::Module* UserDBBackendMysql_create(Mad::Common::Application *application) { + return new Mad::Modules::UserDBBackendMysql::Module(application); +} + +} diff --git a/src/modules/UserDBBackendMysql/Module.h b/src/modules/UserDBBackendMysql/Module.h new file mode 100644 index 0000000..ee04409 --- /dev/null +++ b/src/modules/UserDBBackendMysql/Module.h @@ -0,0 +1,52 @@ +/* + * Module.h + * + * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MAD_MODULES_USERDBBACKENDMYSQL_MODULE_H_ +#define MAD_MODULES_USERDBBACKENDMYSQL_MODULE_H_ + +#include "UserDBBackendMysql.h" + +#include <Common/Module.h> +#include <Common/UserManager.h> + +namespace Mad { +namespace Modules { +namespace UserDBBackendMysql { + +class Module : public Common::Module { + private: + Common::Application *application; + + boost::shared_ptr<UserDBBackendMysql> backend; + + public: + Module(Common::Application *application0) : application(application0), backend(new UserDBBackendMysql(application)) { + application->getUserManager()->registerBackend(backend); + } + + virtual ~Module() { + application->getUserManager()->unregisterBackend(backend); + } +}; + +} +} +} + +#endif /* MAD_MODULES_USERDBBACKENDMYSQL_MODULE_H_ */ diff --git a/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp b/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp new file mode 100644 index 0000000..7ca3db2 --- /dev/null +++ b/src/modules/UserDBBackendMysql/UserDBBackendMysql.cpp @@ -0,0 +1,652 @@ +/* + * UserDBBackendMysql.cpp + * + * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "UserDBBackendMysql.h" +#include <Core/ConfigEntry.h> +#include <Core/ConfigManager.h> +#include <Core/ThreadManager.h> + +#include <sstream> + +#include <boost/bind.hpp> +#include <boost/regex.hpp> +#include <boost/thread/locks.hpp> + +#include <mysql/mysqld_error.h> + +namespace Mad { +namespace Modules { +namespace UserDBBackendMysql { + +const std::string UserDBBackendMysql::name("UserDBBackendMysql"); + +bool UserDBBackendMysql::handleConfigEntry(const Core::ConfigEntry &entry, bool /*handled*/) { + if(!entry[0].getKey().matches("UserManager")) + return false; + + if(entry[1].empty()) + return true; + + if(!entry[1].getKey().matches("Mysql")) + return false; + + if(entry[2].getKey().matches("Host")) { + if(entry[3].empty()) + host = entry[2][0]; + } + else if(entry[2].getKey().matches("Username")) { + if(entry[3].empty()) + username = entry[2][0]; + } + else if(entry[2].getKey().matches("Password")) { + if(entry[3].empty()) + passwd = entry[2][0]; + } + else if(entry[2].getKey().matches("Database")) { + if(entry[3].empty()) + db = entry[2][0]; + } + else if(entry[2].getKey().matches("Port")) { + if(entry[3].empty()) { + char *endptr; + long val; + + val = strtol(entry[2][0].c_str(), &endptr, 10); + + if(endptr != 0 || val < 0 || val > 65535) + application->log(Core::LoggerBase::WARNING, "UserDBBackendMysql: Invalid port"); + else + port = val; + } + } + else if(entry[2].getKey().matches("UnixSocket")) { + if(entry[3].empty()) + unixSocket = entry[2][0]; + } + else if(entry[2].getKey().matches("Queries")) { + if(entry[3].getKey().matches("ListUsers")) { + if(entry[4].empty()) + queryListUsers = entry[3][0]; + } + else if(entry[3].getKey().matches("ListGroups")) { + if(entry[4].empty()) + queryListGroups = entry[3][0]; + } + else if(entry[3].getKey().matches("ListUserGroups")) { + if(entry[4].empty()) + queryListUserGroups = entry[3][0]; + } + else if(entry[3].getKey().matches("ListGroupUsers")) { + if(entry[4].empty()) + queryListGroupUsers = entry[3][0]; + } + else if(entry[3].getKey().matches("UserById")) { + if(entry[4].empty()) + queryUserById = entry[3][0]; + } + else if(entry[3].getKey().matches("UserByName")) { + if(entry[4].empty()) + queryUserByName = entry[3][0]; + } + else if(entry[3].getKey().matches("GroupById")) { + if(entry[4].empty()) + queryGroupById = entry[3][0]; + } + else if(entry[3].getKey().matches("GroupByName")) { + if(entry[4].empty()) + queryGroupByName = entry[3][0]; + } + else if(entry[3].getKey().matches("UserGroupTable")) { + if(entry[4].empty()) + queryUserGroupTable = entry[3][0]; + } + else if(entry[3].getKey().matches("AddUser")) { + if(entry[4].empty()) + queryAddUser = entry[3][0]; + } + else if(entry[3].getKey().matches("UpdateUser")) { + if(entry[4].empty()) + queryUpdateUser = entry[3][0]; + } + else if(entry[3].getKey().matches("DeleteUser")) { + if(entry[4].empty()) + queryDeleteUser = entry[3][0]; + } + else if(entry[3].getKey().matches("AddGroup")) { + if(entry[4].empty()) + queryAddGroup = entry[3][0]; + } + else if(entry[3].getKey().matches("UpdateGroup")) { + if(entry[4].empty()) + queryUpdateGroup = entry[3][0]; + } + else if(entry[3].getKey().matches("DeleteGroup")) { + if(entry[4].empty()) + queryDeleteGroup = entry[3][0]; + } + else if(entry[3].getKey().matches("AddUserToGroup")) { + if(entry[4].empty()) + queryAddUserToGroup = entry[3][0]; + } + else if(entry[3].getKey().matches("DeleteUserFromGroup")) { + if(entry[4].empty()) + queryDeleteUserFromGroup = entry[3][0]; + } + else if(!entry[3].empty()) + return false; + } + else if(!entry[2].empty()) + return false; + + return true; +} + +void UserDBBackendMysql::configFinished() { + if(db.empty()) { + application->log(Core::LoggerBase::ERROR, "UserDBBackendMysql: No database name given"); + return; + } + + boost::lock_guard<boost::mutex> lock(mutex); + mysql = mysql_init(0); + mysql_real_connect(mysql, host.c_str(), username.c_str(), passwd.c_str(), db.c_str(), port, unixSocket.empty() ? 0 : unixSocket.c_str(), 0); +} + + +UserDBBackendMysql::Result UserDBBackendMysql::query(const std::string &query, const ArgumentMap &args) throw(Core::Exception) { + if(!mysql || mysql_ping(mysql)) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + if(args.empty()) { + mysql_real_query(mysql, query.c_str(), query.length()); + } + else { + std::string queryStr = query; + + for(ArgumentMap::const_iterator arg = args.begin(); arg != args.end(); ++arg) { + std::string argStr; + + try { + argStr = boost::get<std::string>(arg->second); + } + catch(...) { + std::ostringstream stream; + stream << arg->second; + argStr = stream.str(); + } + + boost::scoped_array<char> escaped(new char[argStr.length()*2+1]); + mysql_real_escape_string(mysql, escaped.get(), argStr.c_str(), argStr.length()); + + queryStr = boost::regex_replace(queryStr, boost::regex("\\{" + arg->first + "\\}"), "\"" + std::string(escaped.get()) + "\"", boost::match_default); + } + + mysql_real_query(mysql, queryStr.c_str(), queryStr.length()); + } + + return Result(mysql); +} + + +boost::shared_ptr<const std::map<unsigned long, Common::UserInfo> > UserDBBackendMysql::getUserList(boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const std::map<unsigned long, Common::UserInfo> >(); + } + + Result result = query(queryListUsers); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 4) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + boost::shared_ptr<std::map<unsigned long, Common::UserInfo> > users(new std::map<unsigned long, Common::UserInfo>()); + + while(MYSQL_ROW row = result.getNextRow()) { + Common::UserInfo user(strtoul(row[0], 0, 10), row[2]); + + user.setGid(strtoul(row[1], 0, 10)); + user.setFullName(row[3]); + + users->insert(std::make_pair(user.getUid(), user)); + } + + return users; +} + +boost::shared_ptr<const Common::UserInfo> UserDBBackendMysql::getUserInfo(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const Common::UserInfo>(); + } + + ArgumentMap args; + args.insert(std::make_pair("UID", uid)); + + Result result = query(queryUserById, args); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 4) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + MYSQL_ROW row = result.getNextRow(); + + if(row) { + boost::shared_ptr<Common::UserInfo> user(new Common::UserInfo(strtoul(row[0], 0, 10), row[2])); + + user->setGid(strtoul(row[1], 0, 10)); + user->setFullName(row[3]); + + return user; + } + + throw Core::Exception(Core::Exception::NOT_FOUND); +} + +boost::shared_ptr<const Common::UserInfo> UserDBBackendMysql::getUserInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const Common::UserInfo>(); + } + + ArgumentMap args; + args.insert(std::make_pair("USER", name)); + + Result result = query(queryUserByName, args); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 4) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + MYSQL_ROW row = result.getNextRow(); + + if(row) { + boost::shared_ptr<Common::UserInfo> user(new Common::UserInfo(strtoul(row[0], 0, 10), row[2])); + + user->setGid(strtoul(row[1], 0, 10)); + user->setFullName(row[3]); + + return user; + } + + throw Core::Exception(Core::Exception::NOT_FOUND); +} + +boost::shared_ptr<const std::set<unsigned long> > UserDBBackendMysql::getUserGroupList(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const std::set<unsigned long> >(); + } + + ArgumentMap args; + args.insert(std::make_pair("UID", uid)); + + Result result = query(queryListUserGroups, args); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 1) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + boost::shared_ptr<std::set<unsigned long> > groups(new std::set<unsigned long>); + + while(MYSQL_ROW row = result.getNextRow()) + groups->insert(strtoul(row[0], 0, 10)); + + return groups; +} + + +boost::shared_ptr<const std::map<unsigned long, Common::GroupInfo> > UserDBBackendMysql::getGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const std::map<unsigned long, Common::GroupInfo> >(); + } + + Result result = query(queryListGroups); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 2) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + boost::shared_ptr<std::map<unsigned long, Common::GroupInfo> > groups(new std::map<unsigned long, Common::GroupInfo>()); + + while(MYSQL_ROW row = result.getNextRow()) { + Common::GroupInfo group(strtoul(row[0], 0, 10), row[1]); + + groups->insert(std::make_pair(group.getGid(), group)); + } + + return groups; +} + +boost::shared_ptr<const Common::GroupInfo> UserDBBackendMysql::getGroupInfo(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const Common::GroupInfo>(); + } + + ArgumentMap args; + args.insert(std::make_pair("GID", gid)); + + Result result = query(queryGroupById, args); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 2) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + MYSQL_ROW row = result.getNextRow(); + + if(row) + return boost::shared_ptr<Common::GroupInfo>(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1])); + + throw Core::Exception(Core::Exception::NOT_FOUND); +} + +boost::shared_ptr<const Common::GroupInfo> UserDBBackendMysql::getGroupInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const Common::GroupInfo>(); + } + + ArgumentMap args; + args.insert(std::make_pair("GROUP", name)); + + Result result = query(queryGroupByName, args); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 2) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + MYSQL_ROW row = result.getNextRow(); + + if(row) + return boost::shared_ptr<Common::GroupInfo>(new Common::GroupInfo(strtoul(row[0], 0, 10), row[1])); + + throw Core::Exception(Core::Exception::NOT_FOUND); +} + +boost::shared_ptr<const std::set<unsigned long> > UserDBBackendMysql::getGroupUserList(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const std::set<unsigned long> >(); + } + + ArgumentMap args; + args.insert(std::make_pair("GID", gid)); + + Result result = query(queryListGroupUsers, args); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 1) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + boost::shared_ptr<std::set<unsigned long> > users(new std::set<unsigned long>); + + while(MYSQL_ROW row = result.getNextRow()) + users->insert(strtoul(row[0], 0, 10)); + + return users; +} + +boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > UserDBBackendMysql::getFullUserGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::unique_lock<boost::mutex> lock(mutex); + + if(timestamp) { + if(timestamp->is_not_a_date_time() || *timestamp < lastUpdate) + *timestamp = lastUpdate; + else + return boost::shared_ptr<const std::multimap<unsigned long, unsigned long> >(); + } + + Result result = query(queryUserGroupTable); + + lock.unlock(); + + if(!result || result.getErrno() || result.getFieldNumber() < 2) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + boost::shared_ptr<std::multimap<unsigned long, unsigned long> > usergroups(new std::multimap<unsigned long, unsigned long>); + + while(MYSQL_ROW row = result.getNextRow()) + usergroups->insert(std::make_pair(strtoul(row[0], 0, 10), strtoul(row[1], 0, 10))); + + return usergroups; +} + +void UserDBBackendMysql::addUser(const Common::UserInfo &userInfo) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("UID", userInfo.getUid())); + args.insert(std::make_pair("GID", userInfo.getGid())); + args.insert(std::make_pair("USER", userInfo.getUsername())); + args.insert(std::make_pair("FULL_NAME", userInfo.getFullName())); + + Result result = query(queryAddUser, args); + + if(result.getErrno()) { + if(result.getErrno() == ER_DUP_ENTRY) + throw Core::Exception(Core::Exception::DUPLICATE_ENTRY); + else + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + } + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +void UserDBBackendMysql::updateUser(unsigned long uid, const Common::UserInfo &userInfo) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("ORIG_UID", uid)); + args.insert(std::make_pair("UID", userInfo.getUid())); + args.insert(std::make_pair("GID", userInfo.getGid())); + args.insert(std::make_pair("USER", userInfo.getUsername())); + args.insert(std::make_pair("FULL_NAME", userInfo.getFullName())); + + Result result = query(queryUpdateUser, args); + + if(result.getErrno()) { + if(result.getErrno() == ER_DUP_ENTRY) + throw Core::Exception(Core::Exception::DUPLICATE_ENTRY); + else + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + } + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +void UserDBBackendMysql::deleteUser(unsigned long uid) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("UID", uid)); + + Result result = query(queryDeleteUser, args); + + if(result.getErrno()) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +void UserDBBackendMysql::addGroup(const Common::GroupInfo &groupInfo) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("GID", groupInfo.getGid())); + args.insert(std::make_pair("GROUP", groupInfo.getName())); + + Result result = query(queryAddGroup, args); + + if(result.getErrno()) { + if(result.getErrno() == ER_DUP_ENTRY) + throw Core::Exception(Core::Exception::DUPLICATE_ENTRY); + else + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + } + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +void UserDBBackendMysql::updateGroup(unsigned long gid, const Common::GroupInfo &groupInfo) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("ORIG_GID", gid)); + args.insert(std::make_pair("GID", groupInfo.getGid())); + args.insert(std::make_pair("GROUP", groupInfo.getName())); + + Result result = query(queryUpdateGroup, args); + + if(result.getErrno()) { + if(result.getErrno() == ER_DUP_ENTRY) + throw Core::Exception(Core::Exception::DUPLICATE_ENTRY); + else + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + } + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +void UserDBBackendMysql::deleteGroup(unsigned long gid) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("GID", gid)); + + Result result = query(queryDeleteGroup, args); + + if(result.getErrno()) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +void UserDBBackendMysql::addUserToGroup(unsigned long uid, unsigned long gid) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("UID", uid)); + args.insert(std::make_pair("GID", gid)); + + Result result = query(queryAddUserToGroup, args); + + if(result.getErrno()) { + if(result.getErrno() == ER_DUP_ENTRY) + return; + else + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + } + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +void UserDBBackendMysql::deleteUserFromGroup(unsigned long uid, unsigned long gid) throw(Core::Exception) { + application->getThreadManager()->detach(); + + boost::lock_guard<boost::mutex> lock(mutex); + + ArgumentMap args; + args.insert(std::make_pair("UID", uid)); + args.insert(std::make_pair("GID", gid)); + + Result result = query(queryDeleteUserFromGroup, args); + + if(result.getErrno()) + throw Core::Exception(Core::Exception::NOT_AVAILABLE); + + lastUpdate = boost::posix_time::microsec_clock::universal_time(); +} + +} +} +} diff --git a/src/modules/UserDBBackendMysql/UserDBBackendMysql.h b/src/modules/UserDBBackendMysql/UserDBBackendMysql.h new file mode 100644 index 0000000..959e133 --- /dev/null +++ b/src/modules/UserDBBackendMysql/UserDBBackendMysql.h @@ -0,0 +1,159 @@ +/* + * UserDBBackendMysql.h + * + * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MAD_MODULES_USERDBBACKENDMYSQL_USERDBBACKENDMYSQL_H_ +#define MAD_MODULES_USERDBBACKENDMYSQL_USERDBBACKENDMYSQL_H_ + +#include <Common/UserDBBackend.h> +#include <Common/Application.h> + +#include <Core/Configurable.h> +#include <Core/ConfigManager.h> + +#include <mysql/mysql.h> + +#include <boost/thread/mutex.hpp> +#include <boost/variant.hpp> + +namespace Mad { +namespace Modules { +namespace UserDBBackendMysql { + +class UserDBBackendMysql : public Common::UserDBBackend, private Core::Configurable, private boost::noncopyable { + private: + typedef std::map<std::string, boost::variant<std::string, unsigned long> > ArgumentMap; + + class Result; + Result query(const std::string &query, const ArgumentMap &args = ArgumentMap()) throw(Core::Exception); + + class Result { + private: + friend Result UserDBBackendMysql::query(const std::string &query, const ArgumentMap &args) throw(Core::Exception); + + boost::shared_ptr<MYSQL_RES> result; + + unsigned int mysqlErrno; + const char *error; + + Result(MYSQL *mysql) { + result = boost::shared_ptr<MYSQL_RES>(mysql_store_result(mysql), mysql_free_result); + + mysqlErrno = mysql_errno(mysql); + error = mysql_error(mysql); + } + + public: + operator bool() const { + return result; + } + + unsigned int getErrno() const { + return mysqlErrno; + } + + const char* getError() const { + return error; + } + + unsigned int getFieldNumber() const { + return mysql_num_fields(result.get()); + } + + my_ulonglong getRowNumber() const { + return mysql_num_rows(result.get()); + } + + MYSQL_ROW getNextRow() { + return mysql_fetch_row(result.get()); + } + }; + + static const std::string name; + + Common::Application *application; + + std::string host, username, passwd, db, unixSocket; + uint16_t port; + + std::string queryListUsers, queryListGroups; + std::string queryListUserGroups, queryListGroupUsers; + std::string queryUserById, queryUserByName; + std::string queryGroupById, queryGroupByName; + std::string queryUserGroupTable; + std::string queryAddUser, queryUpdateUser, queryDeleteUser; + std::string queryAddGroup, queryUpdateGroup, queryDeleteGroup; + std::string queryAddUserToGroup, queryDeleteUserFromGroup; + + MYSQL *mysql; + + boost::posix_time::ptime lastUpdate; + + boost::mutex mutex; + + protected: + virtual bool handleConfigEntry(const Core::ConfigEntry &entry, bool handled); + virtual void configFinished(); + + virtual boost::shared_ptr<const std::map<unsigned long, Common::UserInfo> > getUserList(boost::posix_time::ptime *timestamp) throw(Core::Exception); + virtual boost::shared_ptr<const Common::UserInfo> getUserInfo(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception); + virtual boost::shared_ptr<const Common::UserInfo> getUserInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception); + virtual boost::shared_ptr<const std::set<unsigned long> > getUserGroupList(unsigned long uid, boost::posix_time::ptime *timestamp) throw(Core::Exception); + + virtual boost::shared_ptr<const std::map<unsigned long, Common::GroupInfo> > getGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception); + virtual boost::shared_ptr<const Common::GroupInfo> getGroupInfo(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception); + virtual boost::shared_ptr<const Common::GroupInfo> getGroupInfoByName(const std::string &name, boost::posix_time::ptime *timestamp) throw(Core::Exception); + virtual boost::shared_ptr<const std::set<unsigned long> > getGroupUserList(unsigned long gid, boost::posix_time::ptime *timestamp) throw(Core::Exception); + + virtual boost::shared_ptr<const std::multimap<unsigned long, unsigned long> > getFullUserGroupList(boost::posix_time::ptime *timestamp) throw(Core::Exception); + + virtual void addUser(const Common::UserInfo &userInfo) throw(Core::Exception); + virtual void updateUser(unsigned long uid, const Common::UserInfo &userInfo) throw(Core::Exception); + virtual void deleteUser(unsigned long uid) throw(Core::Exception); + + virtual void addGroup(const Common::GroupInfo &groupInfo) throw(Core::Exception); + virtual void updateGroup(unsigned long gid, const Common::GroupInfo &groupInfo) throw(Core::Exception); + virtual void deleteGroup(unsigned long gid) throw(Core::Exception); + + virtual void addUserToGroup(unsigned long uid, unsigned long gid) throw(Core::Exception); + virtual void deleteUserFromGroup(unsigned long uid, unsigned long gid) throw(Core::Exception); + + public: + UserDBBackendMysql(Common::Application *application0) : application(application0), port(0), mysql(0), lastUpdate(boost::posix_time::microsec_clock::universal_time()) { + application->getConfigManager()->registerConfigurable(this); + } + + virtual ~UserDBBackendMysql() { + application->getConfigManager()->unregisterConfigurable(this); + + if(mysql) { + mysql_close(mysql); + mysql = 0; + } + } + + virtual const std::string& getName() { + return name; + } +}; + +} +} +} + +#endif /* MAD_MODULES_USERDBBACKENDMYSQL_USERBACKENDMYSQL_H_ */ |