diff --git a/CMakeLists.txt b/CMakeLists.txt index 9468462..0b3e2e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,8 +90,6 @@ add_executable( owsec src/RESTAPI/RESTAPI_avatar_handler.cpp src/RESTAPI/RESTAPI_avatar_handler.h src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h - src/storage/storage_avatar.cpp src/storage/storage_avatar.h - src/storage/storage_tables.cpp src/RESTAPI/RESTAPI_suboauth2_handler.h src/RESTAPI/RESTAPI_suboauth2_handler.cpp src/RESTAPI/RESTAPI_subuser_handler.h src/RESTAPI/RESTAPI_subuser_handler.cpp src/RESTAPI/RESTAPI_subusers_handler.h src/RESTAPI/RESTAPI_subusers_handler.cpp @@ -111,7 +109,7 @@ add_executable( owsec src/framework/OpenWifiTypes.h src/RESTAPI/RESTAPI_submfa_handler.cpp src/RESTAPI/RESTAPI_submfa_handler.h src/storage/orm_users.cpp src/storage/orm_users.h - src/storage/orm_tokens.cpp src/storage/orm_tokens.h src/storage/orm_preferences.cpp src/storage/orm_preferences.h src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h) + src/storage/orm_tokens.cpp src/storage/orm_tokens.h src/storage/orm_preferences.cpp src/storage/orm_preferences.h src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h src/storage/orm_avatar.cpp src/storage/orm_avatar.h) if(NOT SMALL_BUILD) target_link_libraries(owsec PUBLIC diff --git a/build b/build index 70e1a64..d7019ae 100644 --- a/build +++ b/build @@ -1 +1 @@ -144 \ No newline at end of file +149 \ No newline at end of file diff --git a/src/RESTAPI/RESTAPI_avatar_handler.cpp b/src/RESTAPI/RESTAPI_avatar_handler.cpp index a1fb9fe..8de3f2b 100644 --- a/src/RESTAPI/RESTAPI_avatar_handler.cpp +++ b/src/RESTAPI/RESTAPI_avatar_handler.cpp @@ -36,7 +36,7 @@ namespace OpenWifi { } // if there is an avatar, just remove it... - StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id); + StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id); Poco::TemporaryFile TmpFile; AvatarPartHandler partHandler(Id, Logger_, TmpFile); @@ -47,7 +47,7 @@ namespace OpenWifi { Answer.set(RESTAPI::Protocol::AVATARID, Id); Answer.set(RESTAPI::Protocol::ERRORCODE, 0); Logger_.information(Poco::format("Uploaded avatar: %s Type: %s", partHandler.Name(), partHandler.ContentType())); - StorageService()->SetAvatar(UserInfo_.userinfo.email, + StorageService()->AvatarDB().SetAvatar(UserInfo_.userinfo.email, Id, TmpFile, partHandler.ContentType(), partHandler.Name()); } else { Answer.set(RESTAPI::Protocol::AVATARID, Id); @@ -64,7 +64,7 @@ namespace OpenWifi { } Poco::TemporaryFile TempAvatar; std::string Type, Name; - if (!StorageService()->GetAvatar(UserInfo_.userinfo.email, Id, TempAvatar, Type, Name)) { + if (!StorageService()->AvatarDB().GetAvatar(UserInfo_.userinfo.email, Id, TempAvatar, Type, Name)) { return NotFound(); } SendFile(TempAvatar, Type, Name); @@ -75,7 +75,7 @@ namespace OpenWifi { if (Id.empty()) { return NotFound(); } - if (!StorageService()->DeleteAvatar(UserInfo_.userinfo.email, Id)) { + if (!StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email, Id)) { return NotFound(); } OK(); diff --git a/src/RESTAPI/RESTAPI_user_handler.cpp b/src/RESTAPI/RESTAPI_user_handler.cpp index 436f692..60bd01e 100644 --- a/src/RESTAPI/RESTAPI_user_handler.cpp +++ b/src/RESTAPI/RESTAPI_user_handler.cpp @@ -63,7 +63,7 @@ namespace OpenWifi { // nothing to do } - StorageService()->DeleteAvatar(UserInfo_.userinfo.email,Id); + StorageService()->AvatarDB().DeleteAvatar(UserInfo_.userinfo.email,Id); StorageService()->PreferencesDB().DeletePreferences(UserInfo_.userinfo.email,Id); Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email)); diff --git a/src/RESTObjects/RESTAPI_SecurityObjects.h b/src/RESTObjects/RESTAPI_SecurityObjects.h index fd01baa..e0765b3 100644 --- a/src/RESTObjects/RESTAPI_SecurityObjects.h +++ b/src/RESTObjects/RESTAPI_SecurityObjects.h @@ -11,6 +11,8 @@ #include #include "framework/OpenWifiTypes.h" #include "Poco/JSON/Object.h" +#include "Poco/Data/LOB.h" +#include "Poco/Data/LOBStream.h" namespace OpenWifi { namespace SecurityObjects { @@ -280,5 +282,13 @@ namespace OpenWifi { bool from_json(Poco::JSON::Object::Ptr &Obj); }; + struct Avatar { + std::string id; + std::string type; + uint64_t created=0; + std::string name; + Poco::Data::LOB avatar; + }; + } } diff --git a/src/StorageService.cpp b/src/StorageService.cpp index 7599c2b..b623eaa 100644 --- a/src/StorageService.cpp +++ b/src/StorageService.cpp @@ -14,7 +14,6 @@ namespace OpenWifi { std::lock_guard Guard(Mutex_); StorageClass::Start(); - Create_Tables(); UserDB_ = std::make_unique("Users", "usr", dbType_,*Pool_, Logger()); SubDB_ = std::make_unique("Subscribers", "sub", dbType_,*Pool_, Logger()); @@ -22,6 +21,7 @@ namespace OpenWifi { SubTokenDB_ = std::make_unique("SubTokens", "stk", dbType_,*Pool_, Logger()); PreferencesDB_ = std::make_unique("Preferences", "pre", dbType_,*Pool_, Logger()); ActionLinksDB_ = std::make_unique("Actions", "act", dbType_,*Pool_, Logger()); + AvatarDB_ = std::make_unique("Avatars", "ava", dbType_,*Pool_, Logger()); UserDB_->Create(); SubDB_->Create(); @@ -29,6 +29,7 @@ namespace OpenWifi { SubTokenDB_->Create(); PreferencesDB_->Create(); ActionLinksDB_->Create(); + AvatarDB_->Create(); UserDB_->InitializeDefaultUser(); diff --git a/src/StorageService.h b/src/StorageService.h index 49e5191..17aeb98 100644 --- a/src/StorageService.h +++ b/src/StorageService.h @@ -19,6 +19,7 @@ #include "storage/orm_tokens.h" #include "storage/orm_preferences.h" #include "storage/orm_actionLinks.h" +#include "storage/orm_avatar.h" namespace OpenWifi { @@ -45,24 +46,9 @@ namespace OpenWifi { OpenWifi::BaseTokenDB & SubTokenDB() { return *SubTokenDB_; } OpenWifi::PreferencesDB & PreferencesDB() { return *PreferencesDB_; } OpenWifi::ActionLinkDB & ActionLinksDB() { return *ActionLinksDB_; } - - /* - * All user management functions - */ - bool SetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); - bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); - bool DeleteAvatar(const std::string & Admin, std::string &Id); + OpenWifi::AvatarDB & AvatarDB() { return *AvatarDB_; } private: - int Create_Tables(); - int Create_AvatarTable(); - -// int Create_ActionLinkTable(); -// int Create_Preferences(); -// int Create_UserTable(); -// int Create_TokensTable(); -// int Create_SubTokensTable(); -// int Create_SubscriberTable(); std::unique_ptr UserDB_; std::unique_ptr SubDB_; @@ -70,6 +56,7 @@ namespace OpenWifi { std::unique_ptr SubTokenDB_; std::unique_ptr PreferencesDB_; std::unique_ptr ActionLinksDB_; + std::unique_ptr AvatarDB_; Poco::Timer Timer_; Archiver Archiver_; diff --git a/src/framework/orm.h b/src/framework/orm.h index e283b92..67fca19 100644 --- a/src/framework/orm.h +++ b/src/framework/orm.h @@ -94,10 +94,10 @@ namespace ORM { inline std::string FieldTypeToChar(OpenWifi::DBType Type, FieldType T, int Size=0) { switch(T) { - case FT_INT: return "INT"; - case FT_BIGINT: return "BIGINT"; - case FT_TEXT: return "TEXT"; - case FT_BOOLEAN: return "BOOLEAN"; + case FT_INT: return "INT"; + case FT_BIGINT: return "BIGINT"; + case FT_TEXT: return "TEXT"; + case FT_BOOLEAN: return "BOOLEAN"; case FT_VARCHAR: if(Size) return std::string("VARCHAR(") + std::to_string(Size) + std::string(")"); diff --git a/src/storage/orm_avatar.cpp b/src/storage/orm_avatar.cpp new file mode 100644 index 0000000..95ad674 --- /dev/null +++ b/src/storage/orm_avatar.cpp @@ -0,0 +1,101 @@ +// +// Created by stephane bourque on 2021-12-27. +// + +#include "orm_avatar.h" + +/* + std::string id; + std::string type; + uint64_t created=0; + std::string name; + Poco::Data::LOB avatar; + + */ +namespace OpenWifi { + + static ORM::FieldVec AvatarDB_Fields{ + ORM::Field{"id", 36, true}, + ORM::Field{"type", ORM::FieldType::FT_BIGINT}, + ORM::Field{"created", ORM::FieldType::FT_BIGINT}, + ORM::Field{"name", ORM::FieldType::FT_TEXT}, + ORM::Field{"avatar", ORM::FieldType::FT_BLOB} + }; + + AvatarDB::AvatarDB(const std::string &Name, const std::string &ShortName, OpenWifi::DBType T, + Poco::Data::SessionPool &P, Poco::Logger &L) : + DB(T, Name.c_str(), AvatarDB_Fields,{}, P, L, ShortName.c_str()) { + } + + bool AvatarDB::SetAvatar(const std::string &Admin, std::string &Id, Poco::TemporaryFile &FileName, + std::string &Type, std::string &Name) { + + try { + std::stringstream ss; + std::ifstream ifs(FileName.path().c_str(), std::ios_base::in | std::ios_base::binary); + Poco::StreamCopier::copyStream(ifs, ss); + + SecurityObjects::Avatar A; + A.id = Id; + A.type = Type; + A.name = Name; + A.created = std::time(nullptr); + A.avatar.assignRaw(ss.str().c_str(), ss.str().size()); + + if (Exists("id", Id)) { + return UpdateRecord("id", Id, A); + } + return CreateRecord(A); + } catch (const Poco::Exception &E) { + Logger().log(E); + } catch (...) { + + } + return false; + } + + bool AvatarDB::GetAvatar(const std::string &Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, + std::string &Name) { + SecurityObjects::Avatar A; + try { + if(GetRecord("id",Id,A)) { + Type = A.type; + Name = A.name; + + Poco::Data::LOBInputStream IL(A.avatar); + std::ofstream f(FileName.path(), std::ios::binary); + Poco::StreamCopier::copyStream(IL, f); + + return true; + } + } catch (const Poco::Exception &E) { + Logger().log(E); + } catch (...) { + + } + return false; + } + + bool AvatarDB::DeleteAvatar(const std::string &Admin, std::string &Id) { + return DeleteRecord("id",Id); + } + +} + +template<> void ORM::DB::Convert(OpenWifi::AvatarRecordTuple &T, OpenWifi::SecurityObjects::Avatar &U) { + U.id = T.get<0>(); + U.type = T.get<1>(); + U.created = T.get<2>(); + U.name = T.get<3>(); + U.avatar = T.get<4>(); +} + +template<> void ORM::DB::Convert(OpenWifi::SecurityObjects::Avatar &U, OpenWifi::AvatarRecordTuple &T) { + T.set<0>(U.id); + T.set<1>(U.type); + T.set<2>(U.created); + T.set<3>(U.name); + T.set<4>(U.avatar); +} diff --git a/src/storage/orm_avatar.h b/src/storage/orm_avatar.h new file mode 100644 index 0000000..917210c --- /dev/null +++ b/src/storage/orm_avatar.h @@ -0,0 +1,40 @@ +// +// Created by stephane bourque on 2021-12-27. +// + +#pragma once + +#include "framework/orm.h" +#include "RESTObjects/RESTAPI_SecurityObjects.h" + +namespace OpenWifi { + +/* + std::string id; + std::string type; + uint64_t created=0; + std::string name; + Poco::Data::LOB avatar; +*/ + + typedef Poco::Tuple < + std::string, // id + std::string, // type + uint64_t, // created + std::string, // name + Poco::Data::LOB // avatar + > AvatarRecordTuple; + typedef std::vector AvatarRecordTupleList; + + class AvatarDB : public ORM::DB { + public: + AvatarDB( const std::string &name, const std::string &shortname, OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L); + + bool SetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); + bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name); + bool DeleteAvatar(const std::string & Admin, std::string &Id); + + private: + + }; +} diff --git a/src/storage/storage_avatar.cpp b/src/storage/storage_avatar.cpp deleted file mode 100644 index 3170bf3..0000000 --- a/src/storage/storage_avatar.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// -// Created by stephane bourque on 2021-07-15. -// - -#include -#include - -#include "storage_avatar.h" -#include "../StorageService.h" - -#include "Poco/File.h" -#include "Poco/Data/LOBStream.h" -#include "../Daemon.h" - -namespace OpenWifi { - - /* - "Id VARCHAR(36) PRIMARY KEY, " - "Type VARCHAR, " - "Created BIGINT, " - "Name VARCHAR, " - "Avatar BLOB" - */ - - bool StorageService::SetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name) { - try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Insert(Sess); - - Poco::Data::LOB L; - Poco::Data::LOBOutputStream OL(L); - - std::ifstream f(FileName.path(), std::ios::binary); - Poco::StreamCopier::copyStream(f, OL); - - uint64_t Now = std::time(nullptr); - - std::string St2{"INSERT INTO Avatars (" + AllAvatarFieldsForSelect + ") VALUES( " + AllAvatarValuesForSelect + " )"}; - - Insert << ConvertParams(St2), - Poco::Data::Keywords::use(Id), - Poco::Data::Keywords::use(Type), - Poco::Data::Keywords::use(Now), - Poco::Data::Keywords::use(Name), - Poco::Data::Keywords::use(L); - Insert.execute(); - return true; - } catch (const Poco::Exception &E) { - Logger().log(E); - } - return false; - } - - bool StorageService::GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string & Type, std::string & Name) { - try { - Poco::Data::LOB L; - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Select(Sess); - - std::string St2{"SELECT " + AllAvatarFieldsForSelect + " FROM Avatars WHERE Id=?"}; - - Poco::Data::Statement Select2(Sess); - - std::string TId; - uint64_t Created; - - Select2 << ConvertParams(St2), - Poco::Data::Keywords::into(TId), - Poco::Data::Keywords::into(Type), - Poco::Data::Keywords::into(Created), - Poco::Data::Keywords::into(Name), - Poco::Data::Keywords::into(L), - Poco::Data::Keywords::use(Id); - Select2.execute(); - - Poco::Data::LOBInputStream IL(L); - std::ofstream f(FileName.path(), std::ios::binary); - Poco::StreamCopier::copyStream(IL, f); - return true; - } catch (const Poco::Exception &E) { - Logger().log(E); - } - return false; - } - - bool StorageService::DeleteAvatar(const std::string & Admin, std::string &Id) { - try { - Poco::Data::Session Sess = Pool_->get(); - Poco::Data::Statement Delete(Sess); - - std::string St1{"delete from avatars where id=?"}; - - Delete << ConvertParams(St1), - Poco::Data::Keywords::use(Id); - Delete.execute(); - return true; - } catch (const Poco::Exception &E) { - Logger().log(E); - } - return false; - } - - -} \ No newline at end of file diff --git a/src/storage/storage_avatar.h b/src/storage/storage_avatar.h deleted file mode 100644 index 98878e0..0000000 --- a/src/storage/storage_avatar.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Created by stephane bourque on 2021-07-15. -// - -#pragma once - -namespace OpenWifi { - - static const std::string AllAvatarFieldsForCreation_sqlite{ - "Id VARCHAR(36) PRIMARY KEY, " - "Type VARCHAR, " - "Created BIGINT, " - "Name VARCHAR, " - "Avatar BLOB" - }; - - static const std::string AllAvatarFieldsForCreation_mysql{ - "Id VARCHAR(36) PRIMARY KEY, " - "Type VARCHAR, " - "Created BIGINT, " - "Name VARCHAR, " - "Avatar LONGBLOB" - }; - - static const std::string AllAvatarFieldsForCreation_pgsql{ - "Id VARCHAR(36) PRIMARY KEY, " - "Type VARCHAR, " - "Created BIGINT, " - "Name VARCHAR, " - "Avatar BYTEA" - }; - - static const std::string AllAvatarFieldsForSelect{ " Id,Type,Created,Name,Avatar " }; - static const std::string AllAvatarValuesForSelect{ "?,?,?,?,?" }; - - - -} diff --git a/src/storage/storage_tables.cpp b/src/storage/storage_tables.cpp deleted file mode 100644 index 47f97d5..0000000 --- a/src/storage/storage_tables.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// -// Created by stephane bourque on 2021-06-13. -// - -#include "StorageService.h" -#include "storage_avatar.h" - -namespace OpenWifi { - - int StorageService::Create_Tables() { - Create_AvatarTable(); - // Create_ActionLinkTable(); - // Create_Preferences(); - // Create_UserTable(); - // Create_TokensTable(); - // Create_SubTokensTable(); - // Create_SubscriberTable(); - return 0; - } - -/* - int StorageService::Create_UserTable() { - Poco::Data::Session Sess = Pool_->get(); - - try { - if (dbType_ == mysql) { - Sess << "CREATE TABLE IF NOT EXISTS Users (" + - AllUsersFieldsForCreation + - " ,INDEX emailindex (email ASC)" - " ,INDEX nameindex (name ASC))", - Poco::Data::Keywords::now; - } else { - Sess << "CREATE TABLE IF NOT EXISTS Users (" + - AllUsersFieldsForCreation + - ")", - Poco::Data::Keywords::now; - Sess << "CREATE INDEX IF NOT EXISTS emailindex ON Users (email ASC)", Poco::Data::Keywords::now; - Sess << "CREATE INDEX IF NOT EXISTS nameindex ON Users (name ASC)", Poco::Data::Keywords::now; - } - return 0; - } catch (const Poco::Exception &E) { - Logger().log(E); - } - return 1; - } - - int StorageService::Create_SubscriberTable() { - Poco::Data::Session Sess = Pool_->get(); - - try { - if (dbType_ == mysql) { - Sess << "CREATE TABLE IF NOT EXISTS Subscribers (" + - AllUsersFieldsForCreation + - " ,INDEX emailindex (email ASC)" - " ,INDEX nameindex (name ASC))", - Poco::Data::Keywords::now; - } else { - Sess << "CREATE TABLE IF NOT EXISTS Subscribers (" + - AllUsersFieldsForCreation + - ")", - Poco::Data::Keywords::now; - Sess << "CREATE INDEX IF NOT EXISTS emailindex ON Subscribers (email ASC)", Poco::Data::Keywords::now; - Sess << "CREATE INDEX IF NOT EXISTS nameindex ON Subscribers (name ASC)", Poco::Data::Keywords::now; - } - return 0; - } catch (const Poco::Exception &E) { - Logger().log(E); - } - return 1; - } - - int StorageService::Create_ActionLinkTable() { - try { - Poco::Data::Session Sess = Pool_->get(); - - Sess << "CREATE TABLE IF NOT EXISTS ActionLinks ( " - + AllActionLinksFieldsForCreation + " ) ", - Poco::Data::Keywords::now; - return 0; - } catch(const Poco::Exception &E) { - Logger().log(E); - } - return 1; - } -*/ - int StorageService::Create_AvatarTable() { - try { - Poco::Data::Session Sess = Pool_->get(); - - if(dbType_==sqlite) { - Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_sqlite + - ") ", Poco::Data::Keywords::now; - } else if(dbType_==mysql) { - Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_mysql + - ") ", Poco::Data::Keywords::now; - } else if(dbType_==pgsql) { - Sess << "CREATE TABLE IF NOT EXISTS Avatars (" + AllAvatarFieldsForCreation_pgsql + - ") ", Poco::Data::Keywords::now; - } - return 0; - } catch(const Poco::Exception &E) { - Logger().log(E); - } - return 1; - } -/* - int StorageService::Create_TokensTable() { - try { - Poco::Data::Session Sess = Pool_->get(); - Sess << "CREATE TABLE IF NOT EXISTS Tokens (" + - AllTokensFieldsForCreation + - ") ", Poco::Data::Keywords::now; - return 0; - } catch(const Poco::Exception &E) { - Logger().log(E); - } - return 1; - } - - int StorageService::Create_SubTokensTable() { - try { - Poco::Data::Session Sess = Pool_->get(); - Sess << "CREATE TABLE IF NOT EXISTS SubTokens (" + - AllTokensFieldsForCreation + - ") ", Poco::Data::Keywords::now; - return 0; - } catch(const Poco::Exception &E) { - Logger().log(E); - } - return 1; - } - - int StorageService::Create_Preferences() { - try { - Poco::Data::Session Sess = Pool_->get(); - - Sess << "CREATE TABLE IF NOT EXISTS Preferences (" + - AllPreferencesFieldsForCreation + - ") ", Poco::Data::Keywords::now; - return 0; - } catch(const Poco::Exception &E) { - Logger().log(E); - } - return 1; - } - - */ - -}