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