]> git.stg.codes - stg.git/commitdiff
Implemented add-user and chg-user.
authorMaxim Mamontov <faust.madf@gmail.com>
Thu, 29 May 2014 18:01:59 +0000 (21:01 +0300)
committerMaxim Mamontov <faust.madf@gmail.com>
Thu, 29 May 2014 18:01:59 +0000 (21:01 +0300)
include/stg/user_conf.h
projects/sgconf/users.cpp
stglibs/common.lib/include/stg/common.h
stglibs/srvconf.lib/include/stg/servconf.h
stglibs/srvconf.lib/include/stg/servconf_types.h
stglibs/srvconf.lib/parsers/get_user.cpp
stglibs/srvconf.lib/parsers/get_user.h
stglibs/srvconf.lib/servconf.cpp

index 5d65fcee9f606dc053b66a3f66b53bd173b14a43..d5acb23827c2d9cf16f48b0767882809fe1a4c8e 100644 (file)
@@ -30,7 +30,7 @@ struct USER_CONF
           note(),
           realName(),
           corp(),
-          service(),
+          services(),
           group(),
           credit(0),
           nextTariff(),
@@ -51,7 +51,7 @@ struct USER_CONF
     std::string              note;
     std::string              realName;
     std::string              corp;
-    std::vector<std::string> service;
+    std::vector<std::string> services;
     std::string              group;
     double                   credit;
     std::string              nextTariff;
@@ -74,10 +74,12 @@ struct USER_CONF_RES
           email(),
           note(),
           realName(),
+          corp(),
           group(),
           credit(),
           nextTariff(),
           userdata(USERDATA_NUM),
+          services(),
           creditExpire(),
           ips()
     {
@@ -97,10 +99,13 @@ struct USER_CONF_RES
         email        = uc.email;
         note         = uc.note;
         realName     = uc.realName;
+        corp         = uc.corp;
         group        = uc.group;
         credit       = uc.credit;
         nextTariff   = uc.nextTariff;
         for (size_t i = 0; i < USERDATA_NUM; i++) userdata[i]  = uc.userdata[i];
+        services.resize(uc.services.size());
+        for (size_t i = 0; i < uc.services.size(); ++i) services[i]  = uc.services[i];
         creditExpire = uc.creditExpire;
         ips          = uc.ips;
         return *this;
@@ -119,13 +124,17 @@ struct USER_CONF_RES
         uc.email        = email.data();
         uc.note         = note.data();
         uc.realName     = realName.data();
+        uc.corp         = corp.data();
         uc.group        = group.data();
         uc.credit       = credit.data();
         uc.nextTariff   = nextTariff.data();
-        for (int i = 0; i < USERDATA_NUM; i++)
+        for (size_t i = 0; i < USERDATA_NUM; i++)
             {
             uc.userdata[i]  = userdata[i].data();
             }
+        uc.services.resize(services.size());
+        for (size_t i = 0; i < services.size(); ++i)
+            uc.services[i] = services[i].data();
         uc.creditExpire = creditExpire.data();
         uc.ips          = ips.data();
         return uc;
@@ -143,10 +152,12 @@ struct USER_CONF_RES
     RESETABLE<std::string>               email;
     RESETABLE<std::string>               note;
     RESETABLE<std::string>               realName;
+    RESETABLE<std::string>               corp;
     RESETABLE<std::string>               group;
     RESETABLE<double>                    credit;
     RESETABLE<std::string>               nextTariff;
     std::vector<RESETABLE<std::string> > userdata;
+    std::vector<RESETABLE<std::string> > services;
     RESETABLE<time_t>                    creditExpire;
     RESETABLE<USER_IPS>                  ips;
 };
index 8b341b6f89252cf84975424dfe9909dd1ab1bcc5..773ebbbb3ad3a43e15f92a586345a53f8e2dd039 100644 (file)
@@ -3,12 +3,17 @@
 #include "api_action.h"
 #include "options.h"
 #include "config.h"
+#include "utils.h"
 
 #include "stg/servconf.h"
 #include "stg/servconf_types.h"
+#include "stg/user_conf.h"
+#include "stg/user_stat.h"
+#include "stg/user_ips.h"
 #include "stg/common.h"
 
 #include <iostream>
+#include <algorithm>
 #include <string>
 #include <map>
 
@@ -46,6 +51,7 @@ std::cout << Indent(level, true) << "login: " << info.login << "\n"
           << Indent(level)       << "name: " << info.name << "\n"
           << Indent(level)       << "address: " << info.address << "\n"
           << Indent(level)       << "phone: " << info.phone << "\n"
+          << Indent(level)       << "corporation: " << info.corp << "\n"
           << Indent(level)       << "last ping time: " << TimeToString(info.pingTime) << "\n"
           << Indent(level)       << "last activity time: " << TimeToString(info.lastActivityTime) << "\n"
           << Indent(level)       << "traffic:\n";
@@ -60,6 +66,12 @@ for (size_t i = 0; i < DIR_NUM; ++i)
 std::cout << Indent(level)       << "user data:\n";
 for (size_t i = 0; i < USERDATA_NUM; ++i)
     std::cout << Indent(level + 1, true) << "user data " << i << ": " << info.userData[i] << "\n";
+if (!info.services.empty())
+    {
+    std::cout << Indent(level) << "services:\n";
+    for (size_t i = 0; i < info.services.size(); ++i)
+        std::cout << Indent(level + 1, true) << info.services[i] << "\n";
+    }
 if (!info.authBy.empty())
     {
     std::cout << Indent(level) << "auth by:\n";
@@ -89,6 +101,7 @@ params.push_back(SGCONF::API_ACTION::PARAM("email", "<email>", "\t\tuser's email
 params.push_back(SGCONF::API_ACTION::PARAM("name", "<real name>", "\tuser's real name"));
 params.push_back(SGCONF::API_ACTION::PARAM("address", "<address>", "\tuser's postal address"));
 params.push_back(SGCONF::API_ACTION::PARAM("phone", "<phone>", "\t\tuser's phone number"));
+params.push_back(SGCONF::API_ACTION::PARAM("corp", "<corp name>", "\t\tcorporation name"));
 params.push_back(SGCONF::API_ACTION::PARAM("session-traffic", "<up/dn, ...>", "coma-separated session upload and download"));
 params.push_back(SGCONF::API_ACTION::PARAM("month-traffic", "<up/dn, ...>", "coma-separated month upload and download"));
 params.push_back(SGCONF::API_ACTION::PARAM("user-data", "<value, ...>", "coma-separated user data values"));
@@ -110,6 +123,87 @@ params.push_back(SGCONF::API_ACTION::PARAM("text", "<text>", "\t\tmessage text")
 return params;
 }
 
+void ConvBool(const std::string & value, RESETABLE<int> & res)
+{
+res = !value.empty() && value[0] == 'y';
+}
+
+void Splice(std::vector<RESETABLE<std::string> > & lhs, const std::vector<RESETABLE<std::string> > & rhs)
+{
+for (size_t i = 0; i < lhs.size(); ++i)
+    lhs[i].splice(rhs[i]);
+}
+
+RESETABLE<std::string> ConvString(const std::string & value)
+{
+return value;
+}
+
+void ConvStringList(std::string value, std::vector<RESETABLE<std::string> > & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+Splice(res, Split<std::vector<RESETABLE<std::string> > >(value, ',', ConvString));
+}
+
+void ConvCreditExpire(const std::string & value, RESETABLE<time_t> & res)
+{
+struct tm brokenTime;
+if (stg_strptime(value.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime) == NULL)
+    throw SGCONF::ACTION::ERROR("Credit expiration should be in format 'YYYY-MM-DD HH:MM:SS'. Got: '" + value + "'");
+res = stg_timegm(&brokenTime);
+}
+
+void ConvIPs(const std::string & value, RESETABLE<USER_IPS> & res)
+{
+res = StrToIPS(value);
+}
+
+struct TRAFF
+{
+    uint64_t up;
+    uint64_t down;
+};
+
+TRAFF ConvTraff(const std::string & value)
+{
+TRAFF res;
+size_t slashPos = value.find_first_of('/');
+if (slashPos == std::string::npos)
+    throw SGCONF::ACTION::ERROR("Traffic record should be in format 'upload/download'. Got: '" + value + "'");
+
+if (str2x(value.substr(0, slashPos), res.up) < 0)
+    throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(0, slashPos) + "'");
+if (str2x(value.substr(slashPos + 1, value.length() - slashPos), res.down) < 0)
+    throw SGCONF::ACTION::ERROR("Traffic value should be an integer. Got: '" + value.substr(slashPos + 1, value.length() - slashPos) + "'");
+return res;
+}
+
+void ConvSessionTraff(std::string value, USER_STAT_RES & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
+if (traff.size() != DIR_NUM)
+    throw SGCONF::ACTION::ERROR("There should be prcisely " + x2str(DIR_NUM) + " records of session traffic.");
+for (size_t i = 0; i < DIR_NUM; ++i)
+    {
+    res.sessionUp[i] = traff[i].up;
+    res.sessionDown[i] = traff[i].down;
+    }
+}
+
+void ConvMonthTraff(std::string value, USER_STAT_RES & res)
+{
+value.erase(std::remove(value.begin(), value.end(), ' '), value.end());
+std::vector<TRAFF> traff(Split<std::vector<TRAFF> >(value, ',', ConvTraff));
+if (traff.size() != DIR_NUM)
+    throw SGCONF::ACTION::ERROR("There should be prcisely " + x2str(DIR_NUM) + " records of month traffic.");
+for (size_t i = 0; i < DIR_NUM; ++i)
+    {
+    res.monthUp[i] = traff[i].up;
+    res.monthDown[i] = traff[i].down;
+    }
+}
+
 void SimpleCallback(bool result,
                     const std::string & reason,
                     void * /*data*/)
@@ -185,20 +279,72 @@ return proto.DelUser(arg, SimpleCallback, NULL) == STG::st_ok;
 
 bool AddUserFunction(const SGCONF::CONFIG & config,
                      const std::string & arg,
-                     const std::map<std::string, std::string> & /*options*/)
+                     const std::map<std::string, std::string> & options)
 {
-// TODO
-std::cerr << "Unimplemented.\n";
-return false;
+USER_CONF_RES conf;
+SGCONF::MaybeSet(options, "password", conf.password);
+SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
+SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
+SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
+SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
+SGCONF::MaybeSet(options, "tariff", conf.tariffName);
+SGCONF::MaybeSet(options, "address", conf.address);
+SGCONF::MaybeSet(options, "phone", conf.phone);
+SGCONF::MaybeSet(options, "email", conf.email);
+SGCONF::MaybeSet(options, "note", conf.note);
+SGCONF::MaybeSet(options, "name", conf.realName);
+SGCONF::MaybeSet(options, "corp", conf.corp);
+SGCONF::MaybeSet(options, "services", conf.services, ConvStringList);
+SGCONF::MaybeSet(options, "group", conf.group);
+SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
+SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
+SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
+SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
+USER_STAT_RES stat;
+SGCONF::MaybeSet(options, "cash", stat.cash);
+SGCONF::MaybeSet(options, "free", stat.freeMb);
+SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
+SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.AddUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
 }
 
 bool ChgUserFunction(const SGCONF::CONFIG & config,
                      const std::string & arg,
                      const std::map<std::string, std::string> & options)
 {
-// TODO
-std::cerr << "Unimplemented.\n";
-return false;
+USER_CONF_RES conf;
+SGCONF::MaybeSet(options, "password", conf.password);
+SGCONF::MaybeSet(options, "passive", conf.passive, ConvBool);
+SGCONF::MaybeSet(options, "disabled", conf.disabled, ConvBool);
+SGCONF::MaybeSet(options, "disable-detail-stat", conf.disabledDetailStat, ConvBool);
+SGCONF::MaybeSet(options, "always-online", conf.alwaysOnline, ConvBool);
+SGCONF::MaybeSet(options, "tariff", conf.tariffName);
+SGCONF::MaybeSet(options, "address", conf.address);
+SGCONF::MaybeSet(options, "phone", conf.phone);
+SGCONF::MaybeSet(options, "email", conf.email);
+SGCONF::MaybeSet(options, "note", conf.note);
+SGCONF::MaybeSet(options, "name", conf.realName);
+SGCONF::MaybeSet(options, "corp", conf.corp);
+SGCONF::MaybeSet(options, "services", conf.services, ConvStringList);
+SGCONF::MaybeSet(options, "group", conf.group);
+SGCONF::MaybeSet(options, "next-tariff", conf.nextTariff);
+SGCONF::MaybeSet(options, "user-data", conf.userdata, ConvStringList);
+SGCONF::MaybeSet(options, "credit-expire", conf.creditExpire, ConvCreditExpire);
+SGCONF::MaybeSet(options, "ips", conf.ips, ConvIPs);
+USER_STAT_RES stat;
+SGCONF::MaybeSet(options, "cash", stat.cash);
+SGCONF::MaybeSet(options, "free", stat.freeMb);
+SGCONF::MaybeSet(options, "session-traffic", stat, ConvSessionTraff);
+SGCONF::MaybeSet(options, "month-traffic", stat, ConvMonthTraff);
+STG::SERVCONF proto(config.server.data(),
+                    config.port.data(),
+                    config.userName.data(),
+                    config.userPass.data());
+return proto.ChgUser(arg, conf, stat, SimpleCallback, NULL) == STG::st_ok;
 }
 
 bool CheckUserFunction(const SGCONF::CONFIG & config,
index eeb68b5197832c13197e40298e72ba1244336c9c..6af1309fab77bbe101c80c36831fd38187230d43 100644 (file)
@@ -103,6 +103,7 @@ std::string     ToLower(const std::string & value);
 std::string     ToUpper(const std::string & value);
 
 template <typename C, typename F>
+inline
 C Split(const std::string & value, char delim, F conv)
 {
 C res;
@@ -119,6 +120,7 @@ return res;
 }
 
 template <typename T>
+inline
 T FromString(const std::string & value)
 {
 T res;
@@ -127,10 +129,18 @@ stream >> res;
 return res;
 }
 
+template <>
+inline
+std::string FromString<std::string>(const std::string & value)
+{
+return value;
+}
+
 template <typename C>
+inline
 C Split(const std::string & value, char delim)
 {
-    return Split<C>(value, delim, FromString);
+    return Split<C>(value, delim, FromString<typename C::value_type>);
 }
 
 std::string IconvString(const std::string & source, const std::string & from, const std::string & to);
index 2a2dbcaac0a13af69badfc3143eb3fd023c6fbb5..467671db19e3f2582739f4e8a67ded41aaa1106e 100644 (file)
@@ -72,7 +72,10 @@ public:
                 const USER_STAT_RES & stat,
                 SIMPLE::CALLBACK f, void * data);
     int DelUser(const std::string & login, SIMPLE::CALLBACK f, void * data);
-    int AddUser(const std::string & login, SIMPLE::CALLBACK f, void * data);
+    int AddUser(const std::string & login,
+                const USER_CONF_RES & conf,
+                const USER_STAT_RES & stat,
+                SIMPLE::CALLBACK f, void * data);
     int AuthBy(const std::string & login, AUTH_BY::CALLBACK f, void * data);
     int SendMessage(const std::string & login, const std::string & text, SIMPLE::CALLBACK f, void * data);
     int CheckUser(const std::string & login, const std::string & password, SIMPLE::CALLBACK f, void * data);
index 229abb4297212010e1349677fa1447a147976c61..998e3b4747d08e2c02fd1548d743759b2bf74842 100644 (file)
@@ -157,10 +157,12 @@ struct INFO
     std::string name;
     std::string address;
     std::string phone;
+    std::string corp;
     STAT        stat;
     time_t      pingTime;
     time_t      lastActivityTime;
     ARRAY<std::string, USERDATA_NUM> userData;
+    std::vector<std::string> services;
     std::vector<std::string> authBy;
 };
 
index a851e38077ec16b22e25036461e9b08afca6177b..7168c3482385ec6c00fc5e7a50c977a2f01103cb 100644 (file)
@@ -88,6 +88,7 @@ GET_USER::PARSER::PARSER(CALLBACK f, void * d)
     AddParser(propertyParsers, "name", info.name, GetEncodedValue);
     AddParser(propertyParsers, "address", info.address, GetEncodedValue);
     AddParser(propertyParsers, "phone", info.phone, GetEncodedValue);
+    AddParser(propertyParsers, "corp", info.corp);
     AddParser(propertyParsers, "traff", info.stat);
     AddParser(propertyParsers, "pingTime", info.pingTime);
     AddParser(propertyParsers, "lastActivityTime", info.lastActivityTime);
@@ -113,7 +114,10 @@ if (depth == 2 && parsingAnswer)
     ParseUserParams(el, attr);
 
 if (depth == 3 && parsingAnswer)
+    {
     ParseAuthBy(el, attr);
+    ParseServices(el, attr);
+    }
 
 return 0;
 }
@@ -155,6 +159,9 @@ void GET_USER::PARSER::ParseUserParams(const char * el, const char ** attr)
 if (strcasecmp(el, "AuthorizedBy") != 0 &&
     !TryParse(propertyParsers, ToLower(el), attr))
     error = "Invalid parameter.";
+else if (strcasecmp(el, "Services") != 0 &&
+    !TryParse(propertyParsers, ToLower(el), attr))
+    error = "Invalid parameter.";
 }
 //-----------------------------------------------------------------------------
 void GET_USER::PARSER::ParseAuthBy(const char * el, const char ** attr)
@@ -163,6 +170,12 @@ if (strcasecmp(el, "Auth") == 0 &&
     attr && attr[0] && attr[1] &&
     strcasecmp(attr[0], "name") == 0)
     info.authBy.push_back(attr[1]);
-else
-    error = "Invalid auth description.";
+}
+//-----------------------------------------------------------------------------
+void GET_USER::PARSER::ParseServices(const char * el, const char ** attr)
+{
+if (strcasecmp(el, "Service") == 0 &&
+    attr && attr[0] && attr[1] &&
+    strcasecmp(attr[0], "name") == 0)
+    info.services.push_back(attr[1]);
 }
index ffd6f2248d54649d69b2a0e3c16e9e234e82f70e..99163c376bd2b5a2e57706ce184dfa40a7d963d9 100644 (file)
@@ -57,6 +57,7 @@ private:
     void ParseUser(const char * el, const char ** attr);
     void ParseUserParams(const char * el, const char ** attr);
     void ParseAuthBy(const char * el, const char ** attr);
+    void ParseServices(const char * el, const char ** attr);
 };
 
 } // namespace GET_USER
index 915691cf62053f546ac6f7819a508339dfd17a42..0f91a563033c52ba650204b356f05afafa8a5449 100644 (file)
@@ -225,9 +225,15 @@ int SERVCONF::DelUser(const std::string & login, SIMPLE::CALLBACK f, void * data
 return pImpl->Exec<SIMPLE::PARSER>("DelUser", "<DelUser login=\"" + login + "\"/>", f, data);
 }
 
-int SERVCONF::AddUser(const std::string & login, SIMPLE::CALLBACK f, void * data)
+int SERVCONF::AddUser(const std::string & login,
+                      const USER_CONF_RES & conf,
+                      const USER_STAT_RES & stat,
+                      SIMPLE::CALLBACK f, void * data)
 {
-return pImpl->Exec<SIMPLE::PARSER>("AddUser", "<AddUser><Login value=\"" + login + "\"/></AddUser>", f, data);
+int res = pImpl->Exec<SIMPLE::PARSER>("AddUser", "<AddUser><Login value=\"" + login + "\"/></AddUser>", f, data);
+if (res != st_ok)
+    return res;
+return pImpl->Exec<CHG_USER::PARSER>("<SetUser><Login value=\"" + login + "\"/>" + CHG_USER::Serialize(conf, stat) + "</SetUser>", f, data);
 }
 
 int SERVCONF::AuthBy(const std::string & login, AUTH_BY::CALLBACK f, void * data)