#pragma once #include "stg/user_conf.h" #include "stg/user_ips.h" #include "stg/store.h" #include "stg/admin.h" #include "stg/notifer.h" #include "stg/admin_conf.h" #include "stg/logger.h" #include "stg/locker.h" #include "stg/settings.h" #include "stg/scriptexecuter.h" #include "stg/common.h" #include #include #include #include #include #include #include #include // access extern volatile time_t stgTime; namespace STG { //----------------------------------------------------------------------------- struct UserPropertyBase { virtual ~UserPropertyBase() = default; virtual std::string ToString() const = 0; }; //----------------------------------------------------------------------------- using Registry = std::map; //----------------------------------------------------------------------------- template class UserProperty : public UserPropertyBase { public: explicit UserProperty(T& val); void Set(const T& rhs); T get() const { return value; } UserProperty& operator=(const T& rhs); const T* operator&() const noexcept { return &value; } const T& ConstData() const noexcept { return value; } operator const T&() const noexcept { return value; } void AddBeforeNotifier(PropertyNotifierBase* n); void DelBeforeNotifier(const PropertyNotifierBase* n); void AddAfterNotifier(PropertyNotifierBase* n); void DelAfterNotifier(const PropertyNotifierBase* n); time_t ModificationTime() const noexcept { return modificationTime; } void ModifyTime() noexcept; std::string ToString() const override; private: T& value; time_t modificationTime; std::set*> beforeNotifiers; std::set*> afterNotifiers; std::mutex mutex; }; //----------------------------------------------------------------------------- template class UserPropertyLogged: public UserProperty { public: UserPropertyLogged(T& val, const std::string& n, bool isPassword, bool isStat, const Settings& s, Registry& properties); UserPropertyLogged* GetPointer() noexcept { return this; } const UserPropertyLogged* GetPointer() const noexcept { return this; } const T& Get() const { return UserProperty::ConstData(); } const std::string& GetName() const { return name; } bool Set(const T& val, const Admin& admin, const std::string& login, const Store& store, const std::string& msg = ""); private: void WriteAccessDenied(const std::string& login, const Admin& admin, const std::string& parameter); void WriteSuccessChange(const std::string& login, const Admin& admin, const std::string& parameter, const std::string& oldValue, const std::string& newValue, const std::string& msg, const Store& store); void OnChange(const std::string& login, const std::string& paramName, const std::string& oldValue, const std::string& newValue, const Admin& admin); Logger& stgLogger; bool isPassword; bool isStat; std::string name; const Settings& settings; }; //----------------------------------------------------------------------------- class UserProperties { /* В этом месте важен порядок следования приватной и открытой частей. Это связано с тем, что часть которая находится в публичной секции по сути является завуалированной ссылкой на закрытую часть. Т.о. нам нужно чтобы конструкторы из закрытой части вызвались раньше открытой. Поэтомому в начале идет закрытая секция * */ private: UserStat stat; UserConf conf; Registry properties; public: explicit UserProperties(const Settings& s); UserStat& Stat() { return stat; } UserConf& Conf() { return conf; } const UserStat& GetStat() const { return stat; } const UserConf& GetConf() const { return conf; } void SetStat(const UserStat& s) { stat = s; } void SetConf(const UserConf& c) { conf = c; } void SetProperties(const UserProperties& p) { stat = p.stat; conf = p.conf; } std::string GetPropertyValue(const std::string & name) const; bool Exists(const std::string & name) const; UserPropertyLogged cash; UserPropertyLogged up; UserPropertyLogged down; UserPropertyLogged lastCashAdd; UserPropertyLogged passiveTime; UserPropertyLogged lastCashAddTime; UserPropertyLogged freeMb; UserPropertyLogged lastActivityTime; UserPropertyLogged password; UserPropertyLogged passive; UserPropertyLogged disabled; UserPropertyLogged disabledDetailStat; UserPropertyLogged alwaysOnline; UserPropertyLogged tariffName; UserPropertyLogged nextTariff; UserPropertyLogged address; UserPropertyLogged note; UserPropertyLogged group; UserPropertyLogged email; UserPropertyLogged phone; UserPropertyLogged realName; UserPropertyLogged credit; UserPropertyLogged creditExpire; UserPropertyLogged ips; UserPropertyLogged userdata0; UserPropertyLogged userdata1; UserPropertyLogged userdata2; UserPropertyLogged userdata3; UserPropertyLogged userdata4; UserPropertyLogged userdata5; UserPropertyLogged userdata6; UserPropertyLogged userdata7; UserPropertyLogged userdata8; UserPropertyLogged userdata9; }; //============================================================================= //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template inline UserProperty::UserProperty(T& val) : value(val), modificationTime(stgTime), beforeNotifiers(), afterNotifiers() { } //----------------------------------------------------------------------------- template inline void UserProperty::ModifyTime() noexcept { modificationTime = stgTime; } //----------------------------------------------------------------------------- template inline void UserProperty::Set(const T& rvalue) { std::lock_guard lock(mutex); T oldVal = value; auto ni = beforeNotifiers.begin(); while (ni != beforeNotifiers.end()) (*ni++)->Notify(oldVal, rvalue); value = rvalue; modificationTime = stgTime; ni = afterNotifiers.begin(); while (ni != afterNotifiers.end()) (*ni++)->Notify(oldVal, rvalue); } //----------------------------------------------------------------------------- template inline UserProperty& UserProperty::operator=(const T& newValue) { Set(newValue); return *this; } //----------------------------------------------------------------------------- template inline void UserProperty::AddBeforeNotifier(PropertyNotifierBase* n) { std::lock_guard lock(mutex); beforeNotifiers.insert(n); } //----------------------------------------------------------------------------- template inline void UserProperty::DelBeforeNotifier(const PropertyNotifierBase* n) { std::lock_guard lock(mutex); beforeNotifiers.erase(const_cast*>(n)); } //----------------------------------------------------------------------------- template inline void UserProperty::AddAfterNotifier(PropertyNotifierBase* n) { std::lock_guard lock(mutex); afterNotifiers.insert(n); } //----------------------------------------------------------------------------- template inline void UserProperty::DelAfterNotifier(const PropertyNotifierBase* n) { std::lock_guard lock(mutex); afterNotifiers.erase(const_cast*>(n)); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template inline UserPropertyLogged::UserPropertyLogged(T& val, const std::string& n, bool isPass, bool isSt, const Settings& s, Registry& properties) : UserProperty(val), stgLogger(Logger::get()), isPassword(isPass), isStat(isSt), name(n), settings(s) { properties.insert(std::make_pair(ToLower(name), this)); } //------------------------------------------------------------------------- template inline bool UserPropertyLogged::Set(const T& val, const Admin& admin, const std::string& login, const Store& store, const std::string& msg) { const auto priv = admin.GetPriv(); if ((priv->userConf && !isStat) || (priv->userStat && isStat) || (priv->userPasswd && isPassword) || (priv->userCash && name == "cash")) { std::stringstream oldVal; std::stringstream newVal; oldVal.flags(oldVal.flags() | std::ios::fixed); newVal.flags(newVal.flags() | std::ios::fixed); oldVal << UserProperty::ConstData(); newVal << val; OnChange(login, name, oldVal.str(), newVal.str(), admin); if (isPassword) WriteSuccessChange(login, admin, name, "******", "******", msg, store); else WriteSuccessChange(login, admin, name, oldVal.str(), newVal.str(), msg, store); UserProperty::Set(val); return true; } WriteAccessDenied(login, admin, name); return false; } //------------------------------------------------------------------------- template inline void UserPropertyLogged::WriteAccessDenied(const std::string& login, const Admin& admin, const std::string& parameter) { stgLogger("%s Change user \'%s.\' Parameter \'%s\'. Access denied.", admin.GetLogStr().c_str(), login.c_str(), parameter.c_str()); } //------------------------------------------------------------------------- template inline void UserPropertyLogged::WriteSuccessChange(const std::string& login, const Admin& admin, const std::string& parameter, const std::string& oldValue, const std::string& newValue, const std::string& msg, const Store& store) { stgLogger("%s User \'%s\': \'%s\' parameter changed from \'%s\' to \'%s\'. %s", admin.GetLogStr().c_str(), login.c_str(), parameter.c_str(), oldValue.c_str(), newValue.c_str(), msg.c_str()); for (size_t i = 0; i < settings.GetFilterParamsLog().size(); ++i) if (settings.GetFilterParamsLog()[i] == "*" || strcasecmp(settings.GetFilterParamsLog()[i].c_str(), parameter.c_str()) == 0) { store.WriteUserChgLog(login, admin.GetLogin(), admin.GetIP(), parameter, oldValue, newValue, msg); return; } } //------------------------------------------------------------------------- template void UserPropertyLogged::OnChange(const std::string& login, const std::string& paramName, const std::string& oldValue, const std::string& newValue, const Admin& admin) { const auto filePath = settings.GetScriptsDir() + "/OnChange"; if (access(filePath.c_str(), X_OK) == 0) { const auto execString = "\"" + filePath + "\" \"" + login + "\" \"" + paramName + "\" \"" + oldValue + "\" \"" + newValue + "\" \"" + admin.GetLogin() + "\" \"" + admin.GetIPStr() + "\""; ScriptExec(execString.c_str()); } else stgLogger("Script OnChange cannot be executed. File %s not found.", filePath.c_str()); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- //------------------------------------------------------------------------- inline std::string UserProperties::GetPropertyValue(const std::string& name) const { const auto it = properties.find(ToLower(name)); if (it == properties.end()) return ""; return it->second->ToString(); } //----------------------------------------------------------------------------- inline bool UserProperties::Exists(const std::string& name) const { return properties.find(ToLower(name)) != properties.end(); } //------------------------------------------------------------------------- //------------------------------------------------------------------------- //------------------------------------------------------------------------- template inline std::ostream& operator<<(std::ostream& stream, const UserProperty& value) { return stream << value.ConstData(); } //----------------------------------------------------------------------------- template inline std::string UserProperty::ToString() const { std::ostringstream stream; stream << value; return stream.str(); } }