From: Elena Mamontova Date: Mon, 28 Nov 2016 13:50:59 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/master' into ticket X-Git-Url: https://git.stg.codes/stg.git/commitdiff_plain/7332bb3cc272f00359cfdc0628bcc68621665d85?hp=cd4be4497c82b49b78567956755727408fe34c1e Merge remote-tracking branch 'origin/master' into ticket --- diff --git a/include/stg/tariff.h b/include/stg/tariff.h index 5d01cba0..4f5b4166 100644 --- a/include/stg/tariff.h +++ b/include/stg/tariff.h @@ -32,10 +32,15 @@ struct TARIFF_DATA; class TARIFF { public: + enum CHANGE_POLICY { ALLOW = 0, TO_CHEAP, TO_EXPENSIVE, DENY }; + enum PERIOD { DAY = 0, MONTH }; enum TRAFF_TYPE { TRAFF_UP = 0, TRAFF_DOWN, TRAFF_UP_DOWN, TRAFF_MAX }; + static std::string ChangePolicyToString(CHANGE_POLICY changePolicy); + static CHANGE_POLICY StringToChangePolicy(const std::string& value); + static std::string PeriodToString(PERIOD period); static PERIOD StringToPeriod(const std::string& value); @@ -53,6 +58,8 @@ public: virtual double GetFee() const = 0; virtual double GetFree() const = 0; virtual PERIOD GetPeriod() const = 0; + virtual CHANGE_POLICY GetChangePolicy() const = 0; + virtual time_t GetChangePolicyTimeout() const = 0; virtual const std::string & GetName() const = 0; virtual void SetName(const std::string & name) = 0; @@ -61,8 +68,34 @@ public: virtual int64_t GetTraffByType(uint64_t up, uint64_t down) const = 0; virtual int GetThreshold(int dir) const = 0; virtual const TARIFF_DATA & GetTariffData() const = 0; + virtual std::string TariffChangeIsAllowed(const TARIFF & to, time_t currentTime) const = 0; }; +inline +std::string TARIFF::ChangePolicyToString(TARIFF::CHANGE_POLICY changePolicy) +{ +switch (changePolicy) + { + case ALLOW: return "allow"; + case TO_CHEAP: return "to_cheap"; + case TO_EXPENSIVE: return "to_expensive"; + case DENY: return "deny"; + } +return "allow"; // Classic behaviour. +} + +inline +TARIFF::CHANGE_POLICY TARIFF::StringToChangePolicy(const std::string& value) +{ +if (strcasecmp(value.c_str(), "to_cheap") == 0) + return TO_CHEAP; +if (strcasecmp(value.c_str(), "to_expensive") == 0) + return TO_EXPENSIVE; +if (strcasecmp(value.c_str(), "deny") == 0) + return DENY; +return ALLOW; // Classic behaviour. +} + inline std::string TARIFF::PeriodToString(TARIFF::PERIOD period) { diff --git a/include/stg/tariff_conf.h b/include/stg/tariff_conf.h index fe94b6e5..79ade2eb 100644 --- a/include/stg/tariff_conf.h +++ b/include/stg/tariff_conf.h @@ -148,6 +148,8 @@ struct TARIFF_CONF double passiveCost; std::string name; TARIFF::PERIOD period; + TARIFF::CHANGE_POLICY changePolicy; + time_t changePolicyTimeout; TARIFF_CONF() : fee(0), @@ -155,7 +157,9 @@ struct TARIFF_CONF traffType(TARIFF::TRAFF_UP_DOWN), passiveCost(0), name(), - period(TARIFF::MONTH) + period(TARIFF::MONTH), + changePolicy(TARIFF::ALLOW), + changePolicyTimeout(0) {} TARIFF_CONF(const std::string & n) @@ -164,7 +168,9 @@ struct TARIFF_CONF traffType(TARIFF::TRAFF_UP_DOWN), passiveCost(0), name(n), - period(TARIFF::MONTH) + period(TARIFF::MONTH), + changePolicy(TARIFF::ALLOW), + changePolicyTimeout(0) {} }; //----------------------------------------------------------------------------- @@ -176,7 +182,9 @@ struct TARIFF_CONF_RES traffType(), passiveCost(), name(), - period() + period(), + changePolicy(), + changePolicyTimeout() {} TARIFF_CONF_RES & operator=(const TARIFF_CONF & tc) @@ -187,6 +195,8 @@ struct TARIFF_CONF_RES passiveCost = tc.passiveCost; name = tc.name; period = tc.period; + changePolicy = tc.changePolicy; + changePolicyTimeout = tc.changePolicyTimeout; return *this; } @@ -199,6 +209,8 @@ struct TARIFF_CONF_RES passiveCost.maybeSet(tc.passiveCost); traffType.maybeSet(tc.traffType); period.maybeSet(tc.period); + changePolicy.maybeSet(tc.changePolicy); + changePolicyTimeout.maybeSet(tc.changePolicyTimeout); return tc; } @@ -208,6 +220,8 @@ struct TARIFF_CONF_RES RESETABLE passiveCost; RESETABLE name; RESETABLE period; + RESETABLE changePolicy; + RESETABLE changePolicyTimeout; }; //----------------------------------------------------------------------------- struct TARIFF_DATA @@ -248,6 +262,14 @@ struct TARIFF_DATA_RES dirPrice(DIR_NUM) {} + TARIFF_DATA_RES & operator=(const TARIFF_DATA & td) + { + tariffConf = td.tariffConf; + for (size_t i = 0; i < DIR_NUM; ++i) + dirPrice[i] = td.dirPrice[i]; + return *this; + } + TARIFF_DATA GetData() const { TARIFF_DATA td; diff --git a/projects/sgconf/tariffs.cpp b/projects/sgconf/tariffs.cpp index 3d63d2a8..6ab4e871 100644 --- a/projects/sgconf/tariffs.cpp +++ b/projects/sgconf/tariffs.cpp @@ -28,6 +28,18 @@ if (level == 0) return dash ? std::string(level * 4 - 2, ' ') + "- " : std::string(level * 4, ' '); } +std::string ChangePolicyToString(TARIFF::CHANGE_POLICY changePolicy) +{ +switch (changePolicy) + { + case TARIFF::ALLOW: return "allow"; + case TARIFF::TO_CHEAP: return "to_cheap"; + case TARIFF::TO_EXPENSIVE: return "to_expensive"; + case TARIFF::DENY: return "deny"; + } +return "unknown"; +} + std::string PeriodToString(TARIFF::PERIOD period) { switch (period) @@ -67,6 +79,29 @@ else throw SGCONF::ACTION::ERROR("Period should be 'daily' or 'monthly'. Got: '" + value + "'"); } +void ConvChangePolicy(const std::string & value, RESETABLE & res) +{ +std::string lowered = ToLower(value); +if (lowered == "allow") + res = TARIFF::ALLOW; +else if (lowered == "to_cheap") + res = TARIFF::TO_CHEAP; +else if (lowered == "to_expensive") + res = TARIFF::TO_EXPENSIVE; +else if (lowered == "deny") + res = TARIFF::DENY; +else + throw SGCONF::ACTION::ERROR("Change policy should be 'allow', 'to_cheap', 'to_expensive' or 'deny'. Got: '" + value + "'"); +} + +void ConvChangePolicyTimeout(const std::string & value, RESETABLE & 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 ConvTraffType(const std::string & value, RESETABLE & res) { std::string lowered = ToLower(value); @@ -214,7 +249,9 @@ std::cout << Indent(level, true) << "name: " << conf.name << "\n" << Indent(level) << "free mb: " << conf.free << "\n" << Indent(level) << "passive cost: " << conf.passiveCost << "\n" << Indent(level) << "traff type: " << TraffTypeToString(conf.traffType) << "\n" - << Indent(level) << "period: " << PeriodToString(conf.period) << "\n"; + << Indent(level) << "period: " << PeriodToString(conf.period) << "\n" + << Indent(level) << "change policy: " << ChangePolicyToString(conf.changePolicy) << "\n" + << Indent(level) << "change policy timeout: " << formatTime(conf.changePolicyTimeout) << "\n"; } void PrintTariff(const STG::GET_TARIFF::INFO & info, size_t level = 0) @@ -233,6 +270,8 @@ params.push_back(SGCONF::API_ACTION::PARAM("free", "", "\tprepaid traff params.push_back(SGCONF::API_ACTION::PARAM("passive-cost", "", "\tpassive cost")); params.push_back(SGCONF::API_ACTION::PARAM("traff-type", "", "\ttraffic type (up, down, up+down, max)")); params.push_back(SGCONF::API_ACTION::PARAM("period", "", "\ttarification period (daily, monthly)")); +params.push_back(SGCONF::API_ACTION::PARAM("change-policy", "", "tariff change policy (allow, to_cheap, to_expensive, deny)")); +params.push_back(SGCONF::API_ACTION::PARAM("change-policy-timeout", "", "tariff change policy timeout")); params.push_back(SGCONF::API_ACTION::PARAM("times", "", "coma-separated day time-spans for each direction")); params.push_back(SGCONF::API_ACTION::PARAM("day-prices", "", "coma-separated day prices for each direction")); params.push_back(SGCONF::API_ACTION::PARAM("night-prices", "", "coma-separated night prices for each direction")); @@ -337,6 +376,8 @@ SGCONF::MaybeSet(options, "free", conf.tariffConf.free); SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost); SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType); SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod); +SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy); +SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout); SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes); SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices); SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices); @@ -370,6 +411,8 @@ SGCONF::MaybeSet(options, "free", conf.tariffConf.free); SGCONF::MaybeSet(options, "passive-cost", conf.tariffConf.passiveCost); SGCONF::MaybeSet(options, "traff-type", conf.tariffConf.traffType, ConvTraffType); SGCONF::MaybeSet(options, "period", conf.tariffConf.period, ConvPeriod); +SGCONF::MaybeSet(options, "change-policy", conf.tariffConf.changePolicy, ConvChangePolicy); +SGCONF::MaybeSet(options, "change-policy-timeout", conf.tariffConf.changePolicyTimeout, ConvChangePolicyTimeout); SGCONF::MaybeSet(options, "times", conf.dirPrice, ConvTimes); SGCONF::MaybeSet(options, "day-prices", conf.dirPrice, ConvDayPrices); SGCONF::MaybeSet(options, "night-prices", conf.dirPrice, ConvNightPrices); diff --git a/projects/stargazer/inst/var/02-alter-03.postgresql.sql b/projects/stargazer/inst/var/02-alter-03.postgresql.sql new file mode 100644 index 00000000..e8b248bf --- /dev/null +++ b/projects/stargazer/inst/var/02-alter-03.postgresql.sql @@ -0,0 +1,16 @@ +/* + * DB migration from v02 to v03 (postgres) + */ +BEGIN; + +CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS TEXT NOT NULL + CONSTRAINT valid_value CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny')); + +ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow'; +ALTER TABLE tb_tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:00'; +ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT; +ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT; + +UPDATE tb_info SET version = 8; + +COMMIT; diff --git a/projects/stargazer/inst/var/02-alter-03.sql b/projects/stargazer/inst/var/02-alter-03.sql new file mode 100644 index 00000000..d2745203 --- /dev/null +++ b/projects/stargazer/inst/var/02-alter-03.sql @@ -0,0 +1,16 @@ +/* + * DB migration from v02 to v03 (firebird) + */ + +CREATE DOMAIN DM_TARIFF_CHANGE_POLICY AS VARCHAR(32) NOT NULL + CHECK (VALUE IN ('allow', 'to_cheap', 'to_expensive', 'deny')); + +ALTER TABLE tb_tariffs ADD change_policy DM_TARIFF_CHANGE_POLICY DEFAULT 'allow'; +ALTER TABLE tb_tariffs ADD change_policy_timeout DM_MOMENT DEFAULT '1970-01-01 00:00:00'; + +UPDATE tb_tariffs SET change_policy = 'allow', change_policy_timeout = '1970-01-01 00:00:00'; + +ALTER TABLE tb_tariffs ALTER COLUMN change_policy DROP DEFAULT; +ALTER TABLE tb_tariffs ALTER COLUMN change_policy_timeout DROP DEFAULT; + +UPDATE tb_info SET version = 2; diff --git a/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp b/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp index 26b4e993..7c023e25 100644 --- a/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp +++ b/projects/stargazer/plugins/configuration/rpcconfig/tariff_helper.cpp @@ -1,6 +1,7 @@ #include // xmlrpc-c devs have missed something :) #include "tariff_helper.h" +#include "stg/common.h" void TARIFF_HELPER::GetTariffInfo(xmlrpc_c::value * info) const { @@ -13,6 +14,8 @@ structVal["freemb"] = xmlrpc_c::value_double(data.tariffConf.free); structVal["passivecost"] = xmlrpc_c::value_double(data.tariffConf.passiveCost); structVal["traffType"] = xmlrpc_c::value_int(data.tariffConf.traffType); structVal["period"] = xmlrpc_c::value_string(TARIFF::PeriodToString(data.tariffConf.period)); +structVal["changePolicy"] = xmlrpc_c::value_string(TARIFF::ChangePolicyToString(data.tariffConf.changePolicy)); +structVal["changePolicyTimeout"] = xmlrpc_c::value_string(formatTime(data.tariffConf.changePolicyTimeout)); std::vector prices(DIR_NUM); @@ -71,6 +74,16 @@ if ((it = structVal.find("period")) != structVal.end()) data.tariffConf.period = TARIFF::StringToPeriod(xmlrpc_c::value_string(it->second)); } +if ((it = structVal.find("changePolicy")) != structVal.end()) + { + data.tariffConf.changePolicy = TARIFF::StringToChangePolicy(xmlrpc_c::value_string(it->second)); + } + +if ((it = structVal.find("changePolicyTimeout")) != structVal.end()) + { + data.tariffConf.changePolicyTimeout = readTime(xmlrpc_c::value_string(it->second)); + } + if ((it = structVal.find("dirprices")) != structVal.end()) { std::vector prices( diff --git a/projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp b/projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp index 89c41587..ac6e7261 100644 --- a/projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp +++ b/projects/stargazer/plugins/configuration/rpcconfig/user_helper.cpp @@ -433,13 +433,27 @@ if ((it = structVal.find("tariff")) != structVal.end()) tariff = tariff.substr(0, pos); } - if (tariffs->FindByName(tariff)) - if (ptr->GetProperty().tariffName.Get() != tariff) - if (!ptr->GetProperty().tariffName.Set(tariff, - admin, - login, - &store)) - return true; + const TARIFF * newTariff = tariffs->FindByName(tariff); + if (newTariff) + { + const TARIFF * currentTariff = ptr->GetTariff(); + std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime); + if (message.empty()) + { + if (ptr->GetProperty().tariffName.Get() != tariff) + { + if (!ptr->GetProperty().tariffName.Set(tariff, + admin, + login, + &store)) + return true; + } + } + else + { + GetStgLogger()("Tariff change is prohibited for user %s. %s", ptr->GetLogin().c_str(), message.c_str()); + } + } if (nextTariff != "" && tariffs->FindByName(nextTariff)) diff --git a/projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp b/projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp index 5adbf441..56167bc2 100644 --- a/projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp +++ b/projects/stargazer/plugins/configuration/rpcconfig/users_methods.cpp @@ -381,16 +381,29 @@ if (tariffs->FindByName(tariff)) } else { - if (u->GetProperty().tariffName.Set(tariff, + const TARIFF * newTariff = tariffs->FindByName(tariff); + if (newTariff) + { + const TARIFF * currentTariff = u->GetTariff(); + std::string message = currentTariff->TariffChangeIsAllowed(*newTariff, stgTime); + if (message.empty()) + { + if (u->GetProperty().tariffName.Set(tariff, admin, login, store, comment)) - { - u->ResetNextTariff(); - u->WriteConf(); - *retvalPtr = xmlrpc_c::value_boolean(true); - return; + { + u->ResetNextTariff(); + u->WriteConf(); + *retvalPtr = xmlrpc_c::value_boolean(true); + return; + } + } + else + { + GetStgLogger()("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str()); + } } } } diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_tariffs.cpp b/projects/stargazer/plugins/configuration/sgconfig/parser_tariffs.cpp index 0607db6f..9c752674 100644 --- a/projects/stargazer/plugins/configuration/sgconfig/parser_tariffs.cpp +++ b/projects/stargazer/plugins/configuration/sgconfig/parser_tariffs.cpp @@ -114,6 +114,8 @@ void GET_TARIFFS::CreateAnswer() "tariffConf.free) + "\"/>" + "tariffConf.traffType) + "\"/>" + "tariffConf.period) + "\"/>" + + "tariffConf.changePolicy) + "\"/>" + + "tariffConf.changePolicyTimeout) + "\"/>" + ""; } @@ -170,7 +172,11 @@ int CHG_TARIFF::Start(void *, const char * el, const char ** attr) { if (strcasecmp(el, m_tag.c_str()) == 0) { - td.tariffConf.name = attr[1]; + const TARIFF * tariff = m_tariffs.FindByName(attr[1]); + if (tariff != NULL) + td = tariff->GetTariffData(); + else + return -1; return 0; } } @@ -288,6 +294,20 @@ int CHG_TARIFF::Start(void *, const char * el, const char ** attr) td.tariffConf.period = TARIFF::StringToPeriod(attr[1]); return 0; } + + if (strcasecmp(el, "ChangePolicy") == 0) + { + td.tariffConf.changePolicy = TARIFF::StringToChangePolicy(attr[1]); + return 0; + } + + if (strcasecmp(el, "ChangePolicyTimeout") == 0) + { + int64_t policyTime = 0; + if (str2x(attr[1], policyTime) == 0) + td.tariffConf.changePolicyTimeout = (time_t)policyTime; + return 0; + } } return -1; } diff --git a/projects/stargazer/plugins/configuration/sgconfig/parser_users.cpp b/projects/stargazer/plugins/configuration/sgconfig/parser_users.cpp index 2e9d7087..5707b726 100644 --- a/projects/stargazer/plugins/configuration/sgconfig/parser_users.cpp +++ b/projects/stargazer/plugins/configuration/sgconfig/parser_users.cpp @@ -594,11 +594,21 @@ int CHG_USER::ApplyChanges() if (!m_ucr.tariffName.empty()) { - if (m_tariffs.FindByName(m_ucr.tariffName.const_data())) + const TARIFF * newTariff = m_tariffs.FindByName(m_ucr.tariffName.const_data()); + if (newTariff) { - if (!u->GetProperty().tariffName.Set(m_ucr.tariffName.const_data(), &m_currAdmin, m_login, &m_store)) - return -1; - u->ResetNextTariff(); + const TARIFF * tariff = u->GetTariff(); + std::string message = tariff->TariffChangeIsAllowed(*newTariff, stgTime); + if (message.empty()) + { + if (!u->GetProperty().tariffName.Set(m_ucr.tariffName.const_data(), &m_currAdmin, m_login, &m_store)) + return -1; + u->ResetNextTariff(); + } + else + { + GetStgLogger()("Tariff change is prohibited for user %s. %s", u->GetLogin().c_str(), message.c_str()); + } } else { diff --git a/projects/stargazer/plugins/store/files/file_store.cpp b/projects/stargazer/plugins/store/files/file_store.cpp index 96add48f..f63d9686 100644 --- a/projects/stargazer/plugins/store/files/file_store.cpp +++ b/projects/stargazer/plugins/store/files/file_store.cpp @@ -1518,6 +1518,19 @@ if (conf.ReadString("Period", &str, "month") < 0) td->tariffConf.period = TARIFF::MONTH; else td->tariffConf.period = TARIFF::StringToPeriod(str); + +if (conf.ReadString("ChangePolicy", &str, "allow") < 0) + td->tariffConf.changePolicy = TARIFF::ALLOW; +else + td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(str); + +if (conf.ReadTime("ChangePolicyTimeout", &td->tariffConf.changePolicyTimeout, 0) < 0) + { + STG_LOCKER lock(&mutex); + errorStr = "Cannot read tariff " + tariffName + ". Parameter ChangePolicyTimeout"; + printfd(__FILE__, "FILES_STORE::RestoreTariff - changepolicytimeout read failed for tariff '%s'\n", tariffName.c_str()); + return -1; + } return 0; } //----------------------------------------------------------------------------- @@ -1579,6 +1592,8 @@ std::string fileName = storeSettings.GetTariffsDir() + "/" + tariffName + ".tf"; cf.WriteDouble("Free", td.tariffConf.free); cf.WriteString("TraffType", TARIFF::TraffTypeToString(td.tariffConf.traffType)); cf.WriteString("Period", TARIFF::PeriodToString(td.tariffConf.period)); + cf.WriteString("ChangePolicy", TARIFF::ChangePolicyToString(td.tariffConf.changePolicy)); + cf.WriteTime("ChangePolicyTimeout", td.tariffConf.changePolicyTimeout); } return 0; diff --git a/projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp b/projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp index 138a9ed9..6f8177ca 100644 --- a/projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp +++ b/projects/stargazer/plugins/store/firebird/firebird_store_tariffs.cpp @@ -150,36 +150,44 @@ try int32_t id; st->Get(1, id); st->Close(); + + std::string query = "update tb_tariffs set \ + fee = ?, \ + free = ?, \ + passive_cost = ?, \ + traff_type = ?"; + + if (schemaVersion > 0) + query += ", period = ?"; + if (schemaVersion > 1) + query += ", change_policy = ?, \ + change_policy_timeout = ?"; + + query += " where pk_tariff = ?"; + + unsigned num = 5; + st->Prepare(query); + st->Set(1, td.tariffConf.fee); + st->Set(2, td.tariffConf.free); + st->Set(3, td.tariffConf.passiveCost); + st->Set(4, td.tariffConf.traffType); + if (schemaVersion > 0) { - st->Prepare("update tb_tariffs set \ - fee = ?, \ - free = ?, \ - passive_cost = ?, \ - traff_type = ?, \ - period = ? \ - where pk_tariff = ?"); - st->Set(1, td.tariffConf.fee); - st->Set(2, td.tariffConf.free); - st->Set(3, td.tariffConf.passiveCost); - st->Set(4, td.tariffConf.traffType); st->Set(5, TARIFF::PeriodToString(td.tariffConf.period)); - st->Set(6, id); + ++num; } - else + + if (schemaVersion > 1) { - st->Prepare("update tb_tariffs set \ - fee = ?, \ - free = ?, \ - passive_cost = ?, \ - traff_type = ? \ - where pk_tariff = ?"); - st->Set(1, td.tariffConf.fee); - st->Set(2, td.tariffConf.free); - st->Set(3, td.tariffConf.passiveCost); - st->Set(4, td.tariffConf.traffType); - st->Set(5, id); + st->Set(6, TARIFF::ChangePolicyToString(td.tariffConf.changePolicy)); + IBPP::Timestamp policyTimeout; + time_t2ts(td.tariffConf.changePolicyTimeout, &policyTimeout); + st->Set(7, policyTimeout); + num += 2; } + + st->Set(num, id); st->Execute(); st->Close(); @@ -285,6 +293,11 @@ try td->tariffConf.traffType = TARIFF::IntToTraffType(Get(st, 6)); if (schemaVersion > 0) td->tariffConf.period = TARIFF::StringToPeriod(Get(st, 7)); + if (schemaVersion > 1) + { + td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(Get(st, 8)); + td->tariffConf.changePolicyTimeout = ts2time_t(Get(st, 9)); + } st->Close(); st->Prepare("select * from tb_tariffs_params where fk_tariff = ?"); st->Set(1, id); diff --git a/projects/stargazer/plugins/store/mysql/mysql_store.cpp b/projects/stargazer/plugins/store/mysql/mysql_store.cpp index 6b16a99d..198b5f3b 100644 --- a/projects/stargazer/plugins/store/mysql/mysql_store.cpp +++ b/projects/stargazer/plugins/store/mysql/mysql_store.cpp @@ -7,6 +7,7 @@ #include #include +#include "stg/common.h" #include "stg/user_ips.h" #include "stg/user_conf.h" #include "stg/user_stat.h" @@ -368,7 +369,9 @@ if(!IsTablePresent("tariffs",sock)) res += "PassiveCost DOUBLE DEFAULT 0.0, Fee DOUBLE DEFAULT 0.0," "Free DOUBLE DEFAULT 0.0, TraffType VARCHAR(10) DEFAULT ''," - "period VARCHAR(32) NOT NULL DEFAULT 'month')"; + "period VARCHAR(32) NOT NULL DEFAULT 'month'," + "change_policy VARCHAR(32) NOT NULL DEFAULT 'allow'," + "change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0)"; if(MysqlQuery(res.c_str(),sock)) { @@ -422,7 +425,8 @@ if(!IsTablePresent("tariffs",sock)) res += "PassiveCost=0.0, Fee=10.0, Free=0,"\ "SinglePrice0=1, SinglePrice1=1,PriceDayA1=0.75,PriceDayB1=0.75,"\ - "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month'"; + "PriceNightA0=1.0,PriceNightB0=1.0,TraffType='up+down',period='month',"\ + "change_policy='allow', change_policy_timeout=0"; if(MysqlQuery(res.c_str(),sock)) { @@ -441,7 +445,7 @@ if(!IsTablePresent("tariffs",sock)) mysql_close(sock); return -1; } - schemaVersion = 1; + schemaVersion = 2; } //users----------------------------------------------------------------------- @@ -599,6 +603,27 @@ if (schemaVersion < 1) schemaVersion = 1; logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion); } + +if (schemaVersion < 2) + { + if (MysqlQuery("ALTER TABLE tariffs ADD change_policy VARCHAR(32) NOT NULL DEFAULT 'allow'", sock) || + MysqlQuery("ALTER TABLE tariffs ADD change_policy_timeout TIMESTAMP NOT NULL DEFAULT 0", sock)) + { + errorStr = "Couldn't update tariffs table to version 2. With error:\n"; + errorStr += mysql_error(sock); + mysql_close(sock); + return -1; + } + if (MysqlQuery("UPDATE info SET version = 2", sock)) + { + errorStr = "Couldn't update DB schema version to 2. With error:\n"; + errorStr += mysql_error(sock); + mysql_close(sock); + return -1; + } + schemaVersion = 2; + logger("MYSQL_STORE: Updated DB schema to version %d", schemaVersion); + } return 0; } //----------------------------------------------------------------------------- @@ -1639,6 +1664,40 @@ else td->tariffConf.period = TARIFF::MONTH; } +if (schemaVersion > 1) + { + str = row[6+8*DIR_NUM]; + param = "ChangePolicy"; + + if (str.length() == 0) + { + mysql_free_result(res); + errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param; + mysql_close(sock); + return -1; + } + + td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(str); + + str = row[7+8*DIR_NUM]; + param = "ChangePolicyTimeout"; + + if (str.length() == 0) + { + mysql_free_result(res); + errorStr = "Cannot read tariff " + tariffName + ". Parameter " + param; + mysql_close(sock); + return -1; + } + + td->tariffConf.changePolicyTimeout = readTime(str); + } +else + { + td->tariffConf.changePolicy = TARIFF::ALLOW; + td->tariffConf.changePolicyTimeout = 0; + } + mysql_free_result(res); mysql_close(sock); return 0; @@ -1706,6 +1765,10 @@ res += " TraffType='" + TARIFF::TraffTypeToString(td.tariffConf.traffType) + "'" if (schemaVersion > 0) res += ", Period='" + TARIFF::PeriodToString(td.tariffConf.period) + "'"; +if (schemaVersion > 1) + res += ", change_policy='" + TARIFF::ChangePolicyToString(td.tariffConf.changePolicy) + "'"\ + ", change_policy_timeout='" + formatTime(td.tariffConf.changePolicy) + "'"; + strprintf(¶m, " WHERE name='%s' LIMIT 1", tariffName.c_str()); res += param; diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store.h b/projects/stargazer/plugins/store/postgresql/postgresql_store.h index 72a2c22c..6bcb3cd0 100644 --- a/projects/stargazer/plugins/store/postgresql/postgresql_store.h +++ b/projects/stargazer/plugins/store/postgresql/postgresql_store.h @@ -128,9 +128,6 @@ private: int EscapeString(std::string & value) const; - std::string Int2TS(time_t value) const; - time_t TS2Int(const std::string & value) const; - int SaveStat(const USER_STAT & stat, const std::string & login, int year = 0, int month = 0) const; int SaveUserServices(uint32_t uid, const std::vector & services) const; diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp index 27401e26..42a19073 100644 --- a/projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp +++ b/projects/stargazer/plugins/store/postgresql/postgresql_store_messages.cpp @@ -33,6 +33,7 @@ #include +#include "stg/common.h" #include "postgresql_store.h" #include "stg/locker.h" #include "stg/message.h" @@ -89,8 +90,8 @@ query << "SELECT sp_add_message(" << "'" << elogin << "', " << "CAST(1 AS SMALLINT), " // Here need to be a version, but, it's uninitiated actually << "CAST(" << msg->header.type << " AS SMALLINT), " - << "CAST('" << Int2TS(msg->header.lastSendTime) << "' AS TIMESTAMP), " - << "CAST('" << Int2TS(msg->header.creationTime) << "' AS TIMESTAMP), " + << "CAST('" << formatTime(msg->header.lastSendTime) << "' AS TIMESTAMP), " + << "CAST('" << formatTime(msg->header.creationTime) << "' AS TIMESTAMP), " << msg->header.showTime << ", " << "CAST(" << msg->header.repeat << " AS SMALLINT), " << msg->header.repeatPeriod << ", " @@ -192,8 +193,8 @@ query << "UPDATE tb_messages SET " << "fk_user = (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), " << "ver = " << msg.header.ver << ", " << "msg_type = " << msg.header.type << ", " - << "last_send_time = CAST('" << Int2TS(msg.header.lastSendTime) << "' AS TIMESTAMP), " - << "creation_time = CAST('" << Int2TS(msg.header.creationTime) << "' AS TIMESTAMP), " + << "last_send_time = CAST('" << formatTime(msg.header.lastSendTime) << "' AS TIMESTAMP), " + << "creation_time = CAST('" << formatTime(msg.header.creationTime) << "' AS TIMESTAMP), " << "show_time = " << msg.header.showTime << ", " << "repeat = " << msg.header.repeat << ", " << "repeat_period = " << msg.header.repeatPeriod << ", " @@ -287,8 +288,8 @@ if (tuples != 1) str2x(PQgetvalue(result, 0, 0), msg->header.ver); str2x(PQgetvalue(result, 0, 1), msg->header.type); -msg->header.lastSendTime = static_cast(TS2Int(PQgetvalue(result, 0, 2))); -msg->header.creationTime = static_cast(TS2Int(PQgetvalue(result, 0, 3))); +msg->header.lastSendTime = static_cast(readTime(PQgetvalue(result, 0, 2))); +msg->header.creationTime = static_cast(readTime(PQgetvalue(result, 0, 3))); str2x(PQgetvalue(result, 0, 4), msg->header.showTime); str2x(PQgetvalue(result, 0, 5), msg->header.repeat); str2x(PQgetvalue(result, 0, 6), msg->header.repeatPeriod); @@ -424,8 +425,8 @@ for (int i = 0; i < tuples; ++i) tuple << PQgetvalue(result, i, 0) << " "; tuple << PQgetvalue(result, i, 1) << " "; tuple << PQgetvalue(result, i, 2) << " "; - header.lastSendTime = static_cast(TS2Int(PQgetvalue(result, i, 3))); - header.creationTime = static_cast(TS2Int(PQgetvalue(result, i, 4))); + header.lastSendTime = static_cast(readTime(PQgetvalue(result, i, 3))); + header.creationTime = static_cast(readTime(PQgetvalue(result, i, 4))); tuple << PQgetvalue(result, i, 5) << " "; tuple << PQgetvalue(result, i, 6) << " "; tuple << PQgetvalue(result, i, 7) << " "; diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp index 045411b1..fd0b38bc 100644 --- a/projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp +++ b/projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp @@ -33,6 +33,7 @@ #include +#include "stg/common.h" #include "postgresql_store.h" #include "stg/locker.h" @@ -317,6 +318,10 @@ int32_t id; if (version > 6) query << ", period = '" << TARIFF::PeriodToString(td.tariffConf.period) << "'"; + if (version > 7) + query << ", change_policy = '" << TARIFF::ChangePolicyToString(td.tariffConf.changePolicy) << "', \ + change_policy_timeout = CAST('" << formatTime(td.tariffConf.changePolicyTimeout) << "' AS TIMESTAMP)"; + query << " WHERE pk_tariff = " << id; result = PQexec(connection, query.str().c_str()); @@ -455,6 +460,10 @@ query << "SELECT pk_tariff, \ if (version > 6) query << ", period"; +if (version > 7) + query << ", change_policy \ + , change_policy_timeout"; + query << " FROM tb_tariffs WHERE name = '" << ename << "'"; result = PQexec(connection, query.str().c_str()); @@ -505,6 +514,12 @@ int id; if (version > 6) td->tariffConf.period = TARIFF::StringToPeriod(PQgetvalue(result, 0, 5)); +if (version > 7) + { + td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(PQgetvalue(result, 0, 6)); + td->tariffConf.changePolicyTimeout = readTime(PQgetvalue(result, 0, 7)); + } + PQclear(result); query.str(""); diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp index db2717ac..1ab5d0e8 100644 --- a/projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp +++ b/projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp @@ -33,6 +33,7 @@ #include +#include "stg/common.h" #include "stg/const.h" #include "stg/locker.h" #include "../../../stg_timer.h" @@ -270,9 +271,9 @@ std::ostringstream query; query << "UPDATE tb_users SET " "cash = " << stat.cash << ", " "free_mb = " << stat.freeMb << ", " - "last_activity_time = CAST('" << Int2TS(stat.lastActivityTime) << "' AS TIMESTAMP), " + "last_activity_time = CAST('" << formatTime(stat.lastActivityTime) << "' AS TIMESTAMP), " "last_cash_add = " << stat.lastCashAdd << ", " - "last_cash_add_time = CAST('" << Int2TS(stat.lastCashAddTime) << "' AS TIMESTAMP), " + "last_cash_add_time = CAST('" << formatTime(stat.lastCashAddTime) << "' AS TIMESTAMP), " "passive_time = " << stat.passiveTime << " " "WHERE name = '" << elogin << "'"; @@ -527,7 +528,7 @@ query << "UPDATE tb_users SET " "address = '" << eaddress << "', " "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", " "credit = " << conf.credit << ", " - "credit_expire = CAST('" << Int2TS(conf.creditExpire) << "' AS TIMESTAMP), " + "credit_expire = CAST('" << formatTime(conf.creditExpire) << "' AS TIMESTAMP), " "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", " "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", " "email = '" << eemail << "', " @@ -681,9 +682,9 @@ if (tuples != 1) std::stringstream tuple; tuple << PQgetvalue(result, 0, 0) << " "; tuple << PQgetvalue(result, 0, 1) << " "; - stat->lastActivityTime = TS2Int(PQgetvalue(result, 0, 2)); + stat->lastActivityTime = readTime(PQgetvalue(result, 0, 2)); tuple << PQgetvalue(result, 0, 3) << " "; - stat->lastCashAddTime = TS2Int(PQgetvalue(result, 0, 4)); + stat->lastCashAddTime = readTime(PQgetvalue(result, 0, 4)); tuple << PQgetvalue(result, 0, 5) << " "; PQclear(result); @@ -699,7 +700,7 @@ if (tuples != 1) query << "SELECT dir_num, upload, download " "FROM tb_stats_traffic " "WHERE fk_user IN (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "') AND " - "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP))"; + "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << formatTime(stgTime) << "' AS TIMESTAMP))"; result = PQexec(connection, query.str().c_str()); } @@ -832,7 +833,7 @@ uint32_t uid; conf->address = PQgetvalue(result, 0, 1); // address conf->alwaysOnline = !strncmp(PQgetvalue(result, 0, 2), "t", 1); tuple << PQgetvalue(result, 0, 3) << " "; // credit - conf->creditExpire = TS2Int(PQgetvalue(result, 0, 4)); // creditExpire + conf->creditExpire = readTime(PQgetvalue(result, 0, 4)); // creditExpire conf->disabled = !strncmp(PQgetvalue(result, 0, 5), "t", 1); conf->disabledDetailStat = !strncmp(PQgetvalue(result, 0, 6), "t", 1); conf->email = PQgetvalue(result, 0, 7); // email @@ -1078,7 +1079,7 @@ query << "SELECT sp_add_param_log_entry(" "'" << eadminLogin << "', CAST('" << inet_ntostring(admIP) << "/32' AS INET), " "'" << eparam << "', " - "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), " + "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), " "'" << eold << "', " "'" << enew << "', " "'" << emessage << "')"; @@ -1149,7 +1150,7 @@ if (version < 6) { query << "SELECT sp_add_session_log_entry(" "'" << elogin << "', " - "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), " + "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), " "'c', CAST('" << inet_ntostring(ip) << "/32' AS INET), 0)"; } @@ -1157,7 +1158,7 @@ else { query << "SELECT sp_add_session_log_entry(" "'" << elogin << "', " - "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), " + "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), " "'c', CAST('" << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')"; } @@ -1249,7 +1250,7 @@ if (EscapeString(ereason)) // Old database version - no freeMb logging support query << "SELECT sp_add_session_log_entry(" "'" << elogin << "', " - "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), " + "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), " "'d', CAST('0.0.0.0/0' AS INET), " << cash << ")"; } @@ -1257,7 +1258,7 @@ if (EscapeString(ereason)) { query << "SELECT sp_add_session_log_entry(" "'" << elogin << "', " - "CAST('" << Int2TS(stgTime) << "' AS TIMESTAMP), " + "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), " "'d', CAST('0.0.0.0/0' AS INET), " << cash << ", " << freeMb << ", '" << ereason << "')"; } @@ -1397,8 +1398,8 @@ for (it = statTree.begin(); it != statTree.end(); ++it) "(till_time, from_time, fk_user, " "dir_num, ip, download, upload, cost) " "VALUES (" - "CAST('" << Int2TS(currTime) << "' AS TIMESTAMP), " - "CAST('" << Int2TS(lastStat) << "' AS TIMESTAMP), " + "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), " + "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), " "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), " << it->first.dir << ", " << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), " diff --git a/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp b/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp index ef705053..9a5101e1 100644 --- a/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp +++ b/projects/stargazer/plugins/store/postgresql/postgresql_store_utils.cpp @@ -113,35 +113,6 @@ delete[] buf; return 0; } -std::string POSTGRESQL_STORE::Int2TS(time_t ts) const -{ -struct tm brokenTime; - -brokenTime.tm_wday = 0; -brokenTime.tm_yday = 0; -brokenTime.tm_isdst = 0; - -gmtime_r(&ts, &brokenTime); - -char buf[32]; -strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime); - -return buf; -} - -time_t POSTGRESQL_STORE::TS2Int(const std::string & ts) const -{ -struct tm brokenTime; - -brokenTime.tm_wday = 0; -brokenTime.tm_yday = 0; -brokenTime.tm_isdst = 0; - -stg_strptime(ts.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime); - -return stg_timegm(&brokenTime); -} - void POSTGRESQL_STORE::MakeDate(std::string & date, int year, int month) const { struct tm brokenTime; diff --git a/projects/stargazer/tariff_impl.cpp b/projects/stargazer/tariff_impl.cpp index c6785cea..2daaeeb3 100644 --- a/projects/stargazer/tariff_impl.cpp +++ b/projects/stargazer/tariff_impl.cpp @@ -145,3 +145,27 @@ else return tariffData.dirPrice[dir].priceDayA; } //----------------------------------------------------------------------------- +std::string TARIFF_IMPL::TariffChangeIsAllowed(const TARIFF & to, time_t currentTime) const +{ +time_t timeout = GetChangePolicyTimeout(); +if ((currentTime > timeout) && (timeout != 0)) + return ""; +switch (GetChangePolicy()) + { + case TARIFF::ALLOW: + return ""; + case TARIFF::TO_CHEAP: + if (to.GetFee() < GetFee()) + return ""; + else + return "New tariff '" + to.GetName() + "' is more expensive than current tariff '" + GetName() + "'. The policy is '" + TARIFF::ChangePolicyToString(GetChangePolicy()) + "'."; + case TARIFF::TO_EXPENSIVE: + if (to.GetFee() >= GetFee()) + return ""; + else + return "New tariff '" + to.GetName() + "' is more cheap than current tariff '" + GetName() + "'. The policy is '" + TARIFF::ChangePolicyToString(GetChangePolicy()) + "'."; + case TARIFF::DENY: + return "Current tariff '" + GetName() + "', new tariff '" + to.GetName() + "'. The policy is '" + TARIFF::ChangePolicyToString(GetChangePolicy()) + "'."; + } +} +//----------------------------------------------------------------------------- diff --git a/projects/stargazer/tariff_impl.h b/projects/stargazer/tariff_impl.h index f2f84d26..0619d50b 100644 --- a/projects/stargazer/tariff_impl.h +++ b/projects/stargazer/tariff_impl.h @@ -72,6 +72,8 @@ public: double GetFee() const { return tariffData.tariffConf.fee; } double GetFree() const { return tariffData.tariffConf.free; } PERIOD GetPeriod() const { return tariffData.tariffConf.period; } + CHANGE_POLICY GetChangePolicy() const { return tariffData.tariffConf.changePolicy; } + time_t GetChangePolicyTimeout() const { return tariffData.tariffConf.changePolicyTimeout; } void Print() const; @@ -87,6 +89,7 @@ public: TARIFF_IMPL & operator=(const TARIFF_IMPL & t); bool operator==(const TARIFF_IMPL & rhs) const { return GetName() == rhs.GetName(); } bool operator!=(const TARIFF_IMPL & rhs) const { return GetName() != rhs.GetName(); } + std::string TariffChangeIsAllowed(const TARIFF & to, time_t currentTime) const; private: TARIFF_DATA tariffData; diff --git a/projects/stargazer/user_impl.cpp b/projects/stargazer/user_impl.cpp index c160db75..0e92975c 100644 --- a/projects/stargazer/user_impl.cpp +++ b/projects/stargazer/user_impl.cpp @@ -1178,10 +1178,24 @@ if (nextTariff.ConstData() != "") { const TARIFF * nt = tariffs->FindByName(nextTariff); if (nt == NULL) + { WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.", login.c_str(), property.tariffName.Get().c_str()); + } else - property.tariffName.Set(nextTariff, sysAdmin, login, store); + { + std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime); + if (message.empty()) + { + property.tariffName.Set(nextTariff, sysAdmin, login, store); + } + else + { + WriteServLog("Tariff change is prohibited for user %s. %s", + login.c_str(), + message.c_str()); + } + } ResetNextTariff(); WriteConf(); } diff --git a/stglibs/common.lib/common.cpp b/stglibs/common.lib/common.cpp index 76a1b421..a4722a00 100644 --- a/stglibs/common.lib/common.cpp +++ b/stglibs/common.lib/common.cpp @@ -749,6 +749,38 @@ void SwapBytes(int64_t & value) value = temp; } //--------------------------------------------------------------------------- +std::string formatTime(time_t ts) +{ +char buf[32]; +struct tm brokenTime; + +brokenTime.tm_wday = 0; +brokenTime.tm_yday = 0; +brokenTime.tm_isdst = 0; + +gmtime_r(&ts, &brokenTime); + +strftime(buf, 32, "%Y-%m-%d %H:%M:%S", &brokenTime); + +return buf; +} +//--------------------------------------------------------------------------- +time_t readTime(const std::string & ts) +{ +if (ts == "0000-00-00 00:00:00") + return 0; + +struct tm brokenTime; + +brokenTime.tm_wday = 0; +brokenTime.tm_yday = 0; +brokenTime.tm_isdst = 0; + +stg_strptime(ts.c_str(), "%Y-%m-%d %H:%M:%S", &brokenTime); + +return stg_timegm(&brokenTime); +} +//--------------------------------------------------------------------------- int str2x(const std::string & str, int32_t & x) { x = static_cast(strtol(str.c_str(), NULL, 10)); diff --git a/stglibs/common.lib/include/stg/common.h b/stglibs/common.lib/include/stg/common.h index 623d82d0..6201233d 100644 --- a/stglibs/common.lib/include/stg/common.h +++ b/stglibs/common.lib/include/stg/common.h @@ -159,6 +159,8 @@ bool WriteAll(int sd, const void * source, size_t size); std::string ToPrintable(const std::string & src); +std::string formatTime(time_t value); +time_t readTime(const std::string & value); //----------------------------------------------------------------------------- int str2x(const std::string & str, int32_t & x); int str2x(const std::string & str, uint32_t & x); diff --git a/stglibs/conffiles.lib/conffiles.cpp b/stglibs/conffiles.lib/conffiles.cpp index ed2e4447..a9c3e555 100644 --- a/stglibs/conffiles.lib/conffiles.cpp +++ b/stglibs/conffiles.lib/conffiles.cpp @@ -35,6 +35,7 @@ #include // E* #include +#include #include #include @@ -345,6 +346,14 @@ param_val[param] = buf; changed = true; } //--------------------------------------------------------------------------- +void CONFIGFILE::WriteTime(const std::string & param, time_t val) +{ +std::stringstream ss; +ss<::const_iterator it(param_val.find(param)); diff --git a/stglibs/conffiles.lib/include/stg/conffiles.h b/stglibs/conffiles.lib/include/stg/conffiles.h index 48e07b62..49bb6ff3 100644 --- a/stglibs/conffiles.lib/include/stg/conffiles.h +++ b/stglibs/conffiles.lib/include/stg/conffiles.h @@ -67,6 +67,7 @@ public: void WriteString(const std::string & param, const std::string& val); void WriteInt(const std::string & param, int64_t val); void WriteDouble(const std::string & param, double val); + void WriteTime(const std::string & param, time_t val); int Error() const; int Flush() const; diff --git a/stglibs/srvconf.lib/parsers/chg_tariff.cpp b/stglibs/srvconf.lib/parsers/chg_tariff.cpp index 158e6f89..16c4b198 100644 --- a/stglibs/srvconf.lib/parsers/chg_tariff.cpp +++ b/stglibs/srvconf.lib/parsers/chg_tariff.cpp @@ -69,6 +69,16 @@ if (!data.tariffConf.period.empty()) case TARIFF::MONTH: stream << ""; break; } +if (!data.tariffConf.changePolicy.empty()) + switch (data.tariffConf.changePolicy.data()) + { + case TARIFF::ALLOW: stream << ""; break; + case TARIFF::TO_CHEAP: stream << ""; break; + case TARIFF::TO_EXPENSIVE: stream << ""; break; + case TARIFF::DENY: stream << ""; break; + } + +appendResetableTag(stream, "changePolicyTimeout", data.tariffConf.changePolicyTimeout); for (size_t i = 0; i < DIR_NUM; ++i) if (!data.dirPrice[i].hDay.empty() && !data.dirPrice[i].mDay.empty() && diff --git a/stglibs/srvconf.lib/parsers/get_tariff.cpp b/stglibs/srvconf.lib/parsers/get_tariff.cpp index 0804b269..e2066363 100644 --- a/stglibs/srvconf.lib/parsers/get_tariff.cpp +++ b/stglibs/srvconf.lib/parsers/get_tariff.cpp @@ -97,6 +97,34 @@ else return true; } +template +bool GetChangePolicy(const char ** attr, T & value, const std::string & attrName) +{ +if (!CheckValue(attr, attrName)) + return false; +std::string type(attr[1]); +if (type == "allow") + value = TARIFF::ALLOW; +else if (type == "to_cheap") + value = TARIFF::TO_CHEAP; +else if (type == "to_expensive") + value = TARIFF::TO_EXPENSIVE; +else if (type == "deny") + value = TARIFF::DENY; +else + return false; +return true; +} + +template +bool GetChangePolicyTimeout(const char ** attr, T & value, const std::string & attrName) +{ +if (!CheckValue(attr, attrName)) + return false; +value = readTime(attr[1]); +return true; +} + template bool GetSlashedValue(const char ** attr, A & array, T A::value_type:: * field) { @@ -131,6 +159,8 @@ GET_TARIFF::PARSER::PARSER(CALLBACK f, void * d, const std::string & e) AddParser(propertyParsers, "free", info.tariffConf.free); AddParser(propertyParsers, "traffType", info.tariffConf.traffType, GetTraffType); AddParser(propertyParsers, "period", info.tariffConf.period, GetPeriod); + AddParser(propertyParsers, "changePolicy", info.tariffConf.changePolicy, GetChangePolicy); + AddParser(propertyParsers, "changePolicyTimeout", info.tariffConf.changePolicyTimeout, GetChangePolicyTimeout); for (size_t i = 0; i < DIR_NUM; ++i) AddParser(propertyParsers, "time" + unsigned2str(i), info.dirPrice[i], GetTimeSpan); AddAOSParser(propertyParsers, "priceDayA", info.dirPrice, &DIRPRICE_DATA::priceDayA, GetSlashedValue); diff --git a/tests/test_tariff.cpp b/tests/test_tariff.cpp index 7252a237..188aee8a 100644 --- a/tests/test_tariff.cpp +++ b/tests/test_tariff.cpp @@ -343,5 +343,113 @@ namespace tut ensure_equals("1101 == 0", tariff.GetPriceWithTraffType(0, 6 * 1024 * 1024, 0, 1286461245), 0); // Near 17:30, 6 > 4 DA (ignore night) ensure_equals("1110 == 0", tariff.GetPriceWithTraffType(0, 0 * 1024 * 1024, 0, 1286479245), 0); // Near 22:30, 0 < 4 DA (ignore night) ensure_equals("1111 == 0", tariff.GetPriceWithTraffType(0, 6 * 1024 * 1024, 0, 1286479245), 0); // Near 22:30, 6 > 4 DA (ignore night) + } + + template<> + template<> + void testobject::test<7>() + { + set_test_name("Check changePolicy - ALLOW"); + + TARIFF_DATA td("test"); + td.tariffConf.changePolicy = TARIFF::ALLOW; + td.tariffConf.fee = 100; + TARIFF_IMPL tariff(td); + + td.tariffConf.fee = 50; + TARIFF_IMPL cheaper(td); + + ensure_equals("Allow cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), true); + + td.tariffConf.fee = 100; + TARIFF_IMPL equal(td); + + ensure_equals("Allow equal", tariff.TariffChangeIsAllowed(equal).empty(), true); + + td.tariffConf.fee = 150; + TARIFF_IMPL expensive(td); + + ensure_equals("Allow expensive", tariff.TariffChangeIsAllowed(expensive).empty(), true); + } + + template<> + template<> + void testobject::test<8>() + { + set_test_name("Check changePolicy - TO_CHEAP"); + + TARIFF_DATA td("test"); + td.tariffConf.changePolicy = TARIFF::TO_CHEAP; + td.tariffConf.fee = 100; + TARIFF_IMPL tariff(td); + + td.tariffConf.fee = 50; + TARIFF_IMPL cheaper(td); + + ensure_equals("Allow cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), true); + + td.tariffConf.fee = 100; + TARIFF_IMPL equal(td); + + ensure_equals("Prohibit equal", tariff.TariffChangeIsAllowed(equal).empty(), false); + + td.tariffConf.fee = 150; + TARIFF_IMPL expensive(td); + + ensure_equals("Prohibit expensive", tariff.TariffChangeIsAllowed(expensive).empty(), false); + } + + template<> + template<> + void testobject::test<9>() + { + set_test_name("Check changePolicy - TO_EXPENSIVE"); + + TARIFF_DATA td("test"); + td.tariffConf.changePolicy = TARIFF::TO_EXPENSIVE; + td.tariffConf.fee = 100; + TARIFF_IMPL tariff(td); + + td.tariffConf.fee = 50; + TARIFF_IMPL cheaper(td); + + ensure_equals("Prohibit cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), false); + + td.tariffConf.fee = 100; + TARIFF_IMPL equal(td); + + ensure_equals("Allow equal", tariff.TariffChangeIsAllowed(equal).empty(), true); + + td.tariffConf.fee = 150; + TARIFF_IMPL expensive(td); + + ensure_equals("Allow expensive", tariff.TariffChangeIsAllowed(expensive).empty(), true); + } + + template<> + template<> + void testobject::test<10>() + { + set_test_name("Check changePolicy - DENY"); + + TARIFF_DATA td("test"); + td.tariffConf.changePolicy = TARIFF::DENY; + td.tariffConf.fee = 100; + TARIFF_IMPL tariff(td); + + td.tariffConf.fee = 50; + TARIFF_IMPL cheaper(td); + + ensure_equals("Prohibit cheaper", tariff.TariffChangeIsAllowed(cheaper).empty(), false); + + td.tariffConf.fee = 100; + TARIFF_IMPL equal(td); + + ensure_equals("Prohibit equal", tariff.TariffChangeIsAllowed(equal).empty(), false); + + td.tariffConf.fee = 150; + TARIFF_IMPL expensive(td); + + ensure_equals("Prohibit expensive", tariff.TariffChangeIsAllowed(expensive).empty(), false); } }