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