]> git.stg.codes - stg.git/blob - include/stg/user_property.h
Check if we can use C++17 with XMLRPC-C.
[stg.git] / include / stg / user_property.h
1 #pragma once
2
3 #include "stg/user_conf.h"
4 #include "stg/user_ips.h"
5 #include "stg/store.h"
6 #include "stg/admin.h"
7 #include "stg/notifer.h"
8 #include "stg/admin_conf.h"
9 #include "stg/logger.h"
10 #include "stg/locker.h"
11 #include "stg/settings.h"
12 #include "stg/scriptexecuter.h"
13 #include "stg/common.h"
14
15 #include <ctime>
16 #include <string>
17 #include <set>
18 #include <map>
19 #include <sstream>
20 #include <iostream>
21 #include <mutex>
22
23 #include <unistd.h> // access
24
25 namespace STG
26 {
27 //-----------------------------------------------------------------------------
28 struct UserPropertyBase {
29     virtual ~UserPropertyBase() = default;
30     virtual std::string ToString() const = 0;
31 };
32 //-----------------------------------------------------------------------------
33 using Registry = std::map<std::string, UserPropertyBase*>;
34 //-----------------------------------------------------------------------------
35 template<typename T>
36 class UserProperty : public UserPropertyBase {
37     public:
38         explicit UserProperty(T& val);
39
40         void Set(const T& rhs);
41         T get() const { return value; }
42
43         UserProperty<T>& operator=(const T& rhs);
44
45         const T* operator&() const noexcept { return &value; }
46         const T& ConstData() const noexcept { return value; }
47
48         operator const T&() const noexcept { return value; }
49
50         void AddBeforeNotifier(PropertyNotifierBase<T>* n);
51         void DelBeforeNotifier(const PropertyNotifierBase<T>* n);
52
53         void AddAfterNotifier(PropertyNotifierBase<T>* n);
54         void DelAfterNotifier(const PropertyNotifierBase<T>* n);
55
56         time_t ModificationTime() const noexcept { return modificationTime; }
57         void   ModifyTime() noexcept;
58
59         std::string ToString() const override;
60     private:
61         T& value;
62         time_t modificationTime;
63         std::set<PropertyNotifierBase<T>*> beforeNotifiers;
64         std::set<PropertyNotifierBase<T>*> afterNotifiers;
65         std::mutex mutex;
66 };
67 //-----------------------------------------------------------------------------
68 template<typename T>
69 class UserPropertyLogged: public UserProperty<T> {
70     public:
71         UserPropertyLogged(T& val,
72                            const std::string& n,
73                            bool isPassword,
74                            bool isStat,
75                            const Settings& s,
76                            Registry& properties);
77
78         UserPropertyLogged<T>* GetPointer() noexcept { return this; }
79         const UserPropertyLogged<T>* GetPointer() const noexcept { return this; }
80         const T& Get() const { return UserProperty<T>::ConstData(); }
81         const std::string& GetName() const { return name; }
82         bool Set(const T& val,
83                  const Admin& admin,
84                  const std::string& login,
85                  const Store& store,
86                  const std::string& msg = "");
87     private:
88         void WriteAccessDenied(const std::string& login,
89                                const Admin& admin,
90                                const std::string& parameter);
91
92         void WriteSuccessChange(const std::string& login,
93                                 const Admin& admin,
94                                 const std::string& parameter,
95                                 const std::string& oldValue,
96                                 const std::string& newValue,
97                                 const std::string& msg,
98                                 const Store& store);
99
100         void OnChange(const std::string& login,
101                       const std::string& paramName,
102                       const std::string& oldValue,
103                       const std::string& newValue,
104                       const Admin& admin);
105
106         Logger&     stgLogger;
107         bool            isPassword;
108         bool            isStat;
109         std::string     name;
110         const Settings& settings;
111 };
112 //-----------------------------------------------------------------------------
113 class UserProperties {
114     /*
115      В этом месте важен порядок следования приватной и открытой частей.
116      Это связано с тем, что часть которая находится в публичной секции
117      по сути является завуалированной ссылкой на закрытую часть. Т.о. нам нужно
118      чтобы конструкторы из закрытой части вызвались раньше открытой. Поэтомому в
119      начале идет закрытая секция
120      * */
121
122     private:
123         UserStat stat;
124         UserConf conf;
125
126         Registry properties;
127     public:
128         explicit UserProperties(const Settings& s);
129
130         UserStat& Stat() { return stat; }
131         UserConf& Conf() { return conf; }
132         const UserStat& GetStat() const { return stat; }
133         const UserConf& GetConf() const { return conf; }
134         void SetStat(const UserStat& s) { stat = s; }
135         void SetConf(const UserConf& c) { conf = c; }
136
137         void SetProperties(const UserProperties& p) { stat = p.stat; conf = p.conf; }
138
139         std::string GetPropertyValue(const std::string & name) const;
140         bool Exists(const std::string & name) const;
141
142         UserPropertyLogged<double>      cash;
143         UserPropertyLogged<DirTraff>    up;
144         UserPropertyLogged<DirTraff>    down;
145         UserPropertyLogged<double>      lastCashAdd;
146         UserPropertyLogged<time_t>      passiveTime;
147         UserPropertyLogged<time_t>      lastCashAddTime;
148         UserPropertyLogged<double>      freeMb;
149         UserPropertyLogged<time_t>      lastActivityTime;
150
151         UserPropertyLogged<std::string> password;
152         UserPropertyLogged<int>         passive;
153         UserPropertyLogged<int>         disabled;
154         UserPropertyLogged<int>         disabledDetailStat;
155         UserPropertyLogged<int>         alwaysOnline;
156         UserPropertyLogged<std::string> tariffName;
157         UserPropertyLogged<std::string> nextTariff;
158         UserPropertyLogged<std::string> address;
159         UserPropertyLogged<std::string> note;
160         UserPropertyLogged<std::string> group;
161         UserPropertyLogged<std::string> email;
162         UserPropertyLogged<std::string> phone;
163         UserPropertyLogged<std::string> realName;
164         UserPropertyLogged<double>      credit;
165         UserPropertyLogged<time_t>      creditExpire;
166         UserPropertyLogged<UserIPs>     ips;
167         UserPropertyLogged<std::string> userdata0;
168         UserPropertyLogged<std::string> userdata1;
169         UserPropertyLogged<std::string> userdata2;
170         UserPropertyLogged<std::string> userdata3;
171         UserPropertyLogged<std::string> userdata4;
172         UserPropertyLogged<std::string> userdata5;
173         UserPropertyLogged<std::string> userdata6;
174         UserPropertyLogged<std::string> userdata7;
175         UserPropertyLogged<std::string> userdata8;
176         UserPropertyLogged<std::string> userdata9;
177 };
178 //=============================================================================
179
180 //-----------------------------------------------------------------------------
181 //-----------------------------------------------------------------------------
182 //-----------------------------------------------------------------------------
183 template <typename T>
184 inline
185 UserProperty<T>::UserProperty(T& val)
186     : value(val),
187       modificationTime(time(NULL)),
188       beforeNotifiers(),
189       afterNotifiers()
190 {
191 }
192 //-----------------------------------------------------------------------------
193 template <typename T>
194 inline
195 void UserProperty<T>::ModifyTime() noexcept
196 {
197     modificationTime = time(NULL);
198 }
199 //-----------------------------------------------------------------------------
200 template <typename T>
201 inline
202 void UserProperty<T>::Set(const T& rvalue)
203 {
204     std::lock_guard<std::mutex> lock(mutex);
205
206     T oldVal = value;
207
208     auto ni = beforeNotifiers.begin();
209     while (ni != beforeNotifiers.end())
210         (*ni++)->Notify(oldVal, rvalue);
211
212     value = rvalue;
213     modificationTime = time(NULL);
214
215     ni = afterNotifiers.begin();
216     while (ni != afterNotifiers.end())
217         (*ni++)->Notify(oldVal, rvalue);
218 }
219 //-----------------------------------------------------------------------------
220 template <typename T>
221 inline
222 UserProperty<T>& UserProperty<T>::operator=(const T& newValue)
223 {
224     Set(newValue);
225     return *this;
226 }
227 //-----------------------------------------------------------------------------
228 template <typename T>
229 inline
230 void UserProperty<T>::AddBeforeNotifier(PropertyNotifierBase<T>* n)
231 {
232     std::lock_guard<std::mutex> lock(mutex);
233     beforeNotifiers.insert(n);
234 }
235 //-----------------------------------------------------------------------------
236 template <typename T>
237 inline
238 void UserProperty<T>::DelBeforeNotifier(const PropertyNotifierBase<T>* n)
239 {
240     std::lock_guard<std::mutex> lock(mutex);
241     beforeNotifiers.erase(const_cast<PropertyNotifierBase<T>*>(n));
242 }
243 //-----------------------------------------------------------------------------
244 template <typename T>
245 inline
246 void UserProperty<T>::AddAfterNotifier(PropertyNotifierBase<T>* n)
247 {
248     std::lock_guard<std::mutex> lock(mutex);
249     afterNotifiers.insert(n);
250 }
251 //-----------------------------------------------------------------------------
252 template <typename T>
253 inline
254 void UserProperty<T>::DelAfterNotifier(const PropertyNotifierBase<T>* n)
255 {
256     std::lock_guard<std::mutex> lock(mutex);
257     afterNotifiers.erase(const_cast<PropertyNotifierBase<T>*>(n));
258 }
259 //-----------------------------------------------------------------------------
260 //-----------------------------------------------------------------------------
261 //-----------------------------------------------------------------------------
262 template <typename T>
263 inline
264 UserPropertyLogged<T>::UserPropertyLogged(T& val,
265                                           const std::string& n,
266                                           bool isPass,
267                                           bool isSt,
268                                           const Settings& s,
269                                           Registry& properties)
270
271     : UserProperty<T>(val),
272       stgLogger(Logger::get()),
273       isPassword(isPass),
274       isStat(isSt),
275       name(n),
276       settings(s)
277 {
278     properties.insert(std::make_pair(ToLower(name), this));
279 }
280 //-------------------------------------------------------------------------
281 template <typename T>
282 inline
283 bool UserPropertyLogged<T>::Set(const T& val,
284                                 const Admin& admin,
285                                 const std::string& login,
286                                 const Store& store,
287                                 const std::string& msg)
288 {
289     const auto& priv = admin.priv();
290
291     if ((priv.userConf && !isStat) ||
292         (priv.userStat && isStat) ||
293         (priv.userPasswd && isPassword) ||
294         (priv.userCash && name == "cash"))
295     {
296         std::stringstream oldVal;
297         std::stringstream newVal;
298
299         oldVal.flags(oldVal.flags() | std::ios::fixed);
300         newVal.flags(newVal.flags() | std::ios::fixed);
301
302         oldVal << UserProperty<T>::ConstData();
303         newVal << val;
304
305         OnChange(login, name, oldVal.str(), newVal.str(), admin);
306
307         if (isPassword)
308             WriteSuccessChange(login, admin, name, "******", "******", msg, store);
309         else
310             WriteSuccessChange(login, admin, name, oldVal.str(), newVal.str(), msg, store);
311
312         UserProperty<T>::Set(val);
313         return true;
314     }
315
316     WriteAccessDenied(login, admin, name);
317     return false;
318 }
319 //-------------------------------------------------------------------------
320 template <typename T>
321 inline
322 void UserPropertyLogged<T>::WriteAccessDenied(const std::string& login,
323                                               const Admin& admin,
324                                               const std::string& parameter)
325 {
326     stgLogger("%s Change user \'%s.\' Parameter \'%s\'. Access denied.",
327               admin.logStr().c_str(), login.c_str(), parameter.c_str());
328 }
329 //-------------------------------------------------------------------------
330 template <typename T>
331 inline
332 void UserPropertyLogged<T>::WriteSuccessChange(const std::string& login,
333                                                const Admin& admin,
334                                                const std::string& parameter,
335                                                const std::string& oldValue,
336                                                const std::string& newValue,
337                                                const std::string& msg,
338                                                const Store& store)
339 {
340     stgLogger("%s User \'%s\': \'%s\' parameter changed from \'%s\' to \'%s\'. %s",
341               admin.logStr().c_str(),
342               login.c_str(),
343               parameter.c_str(),
344               oldValue.c_str(),
345               newValue.c_str(),
346               msg.c_str());
347
348     for (size_t i = 0; i < settings.GetFilterParamsLog().size(); ++i)
349         if (settings.GetFilterParamsLog()[i] == "*" || strcasecmp(settings.GetFilterParamsLog()[i].c_str(), parameter.c_str()) == 0)
350         {
351             store.WriteUserChgLog(login, admin.login(), admin.IP(), parameter, oldValue, newValue, msg);
352             return;
353         }
354 }
355 //-------------------------------------------------------------------------
356 template <typename T>
357 void UserPropertyLogged<T>::OnChange(const std::string& login,
358                                      const std::string& paramName,
359                                      const std::string& oldValue,
360                                      const std::string& newValue,
361                                      const Admin& admin)
362 {
363     const auto filePath = settings.GetScriptsDir() + "/OnChange";
364
365     if (access(filePath.c_str(), X_OK) == 0)
366     {
367         const auto execString = "\"" + filePath + "\" \"" + login + "\" \"" + paramName + "\" \"" + oldValue + "\" \"" + newValue + "\" \"" + admin.login() + "\" \"" + admin.IPStr() + "\"";
368         ScriptExec(execString.c_str());
369     }
370     else
371         stgLogger("Script OnChange cannot be executed. File %s not found.", filePath.c_str());
372 }
373 //-------------------------------------------------------------------------
374 //-------------------------------------------------------------------------
375 //-------------------------------------------------------------------------
376 inline
377 std::string UserProperties::GetPropertyValue(const std::string& name) const
378 {
379     const auto it = properties.find(ToLower(name));
380     if (it == properties.end())
381         return "";
382     return it->second->ToString();
383 }
384 //-----------------------------------------------------------------------------
385 inline
386 bool UserProperties::Exists(const std::string& name) const
387 {
388     return properties.find(ToLower(name)) != properties.end();
389 }
390 //-------------------------------------------------------------------------
391 //-------------------------------------------------------------------------
392 //-------------------------------------------------------------------------
393 template<typename T>
394 inline
395 std::ostream& operator<<(std::ostream& stream, const UserProperty<T>& value)
396 {
397     return stream << value.ConstData();
398 }
399 //-----------------------------------------------------------------------------
400 template<typename T>
401 inline
402 std::string UserProperty<T>::ToString() const
403 {
404     std::ostringstream stream;
405     stream << value;
406     return stream.str();
407 }
408
409 }